plus-8.x-4.x-dev/src/Utility/Attributes.php

src/Utility/Attributes.php
<?php

namespace Drupal\plus\Utility;

use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Component\Utility\ToStringTrait;

/**
 * Replace core's horribly incomplete "Attribute" implementation.
 *
 * Note: this class has a JavaScript counterpart that is nearly identical
 * located at ./js/attributes.js.
 *
 * @ingroup utility
 *
 * @see \Drupal\Core\Template\Attribute
 *
 * @todo Replace all "Attribute" instances before the preprocess phase.
 * @todo Replace all "Attribute" instances during Twig rendering as a fallback.
 *
 * @method \Drupal\plus\Utility\AttributeBase __get($key)
 * @method \Drupal\plus\Utility\AttributeBase get($key, $default = NULL, $setIfNotExists = TRUE)
 * @method \Drupal\plus\Utility\AttributeBase offsetGet($key)
 */
class Attributes extends ArrayObject {

  use ToStringTrait;

  /**
   * Add class(es) to Attributes.
   *
   * @param string|string[] ...
   *   One or more classes to add.
   *
   * @return static
   *
   * @see \Drupal\plus\Utility\AttributeClasses
   * @see \Drupal\plus\Utility\Attributes::getClasses()
   */
  public function addClass(...$classes) {
    $this->getClasses()->merge(...$classes);
    return $this;
  }

  /**
   * Add class(es) to Attributes.
   *
   * @param string|string[] ...
   *   One or more data attributes to add.
   *
   * @return static
   *
   * @see \Drupal\plus\Utility\AttributeData
   * @see \Drupal\plus\Utility\Attributes::getData()
   */
  public function addData(...$data) {
    $this->getData()->merge(...$data);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  protected function convertValue($key, $value = NULL) {
    // If value is an AttributeValueBase object, clone it and set the new name.
    if ($value instanceof AttributeBase) {
      return $value->copy()->setName($key);
    }

    // Handle classes.
    if ($key === 'class') {
      // An array value or 'class' attribute name are forced to always be an
      // AttributeArray value for consistency.
      if (!is_array($value)) {
        // Cast the value to string in case it implements MarkupInterface.
        $value = [(string) $value];
      }
      return new AttributeClasses($value);
    }

    // Handle data attributes.
    if ($key === 'data') {
      return new AttributeData($value);
    }
    if (preg_match('/^data-/', $key)) {
      return new AttributeDataValue($key, $value);
    }

    // Handle arrays.
    if (is_array($value)) {
      return new AttributeArray($key, $value);
    }

    // Handle booleans.
    if (is_bool($value)) {
      return new AttributeBoolean($key, $value);
    }

    // As a development aid, we allow the value to be a safe string object.
    if ($value instanceof MarkupInterface) {
      // Attributes are not supposed to display HTML markup, so we just convert
      // the value to plain text.
      $value = PlainTextOutput::renderFromHtml($value);
      return new AttributeString($key, $value);
    }

    if (!is_object($value)) {
      return new AttributeString($key, $value);
    }

    return $value;
  }

  /**
   * {@inheritdoc}
   */
  public function getArrayCopy() {
    $array = [];
    /* @var \Drupal\Core\Template\AttributeValueBase $value */
    foreach (parent::getArrayCopy() as $name => $value) {
      $array[$name] = $value->value();
    }
    return $array;
  }

  /**
   * Retrieves classes.
   *
   * @return \Drupal\plus\Utility\AttributeClasses
   *   An AttributeClasses object.
   *
   * @see \Drupal\plus\Utility\ArrayObject::offsetGet()
   */
  public function getClasses() {
    if (!isset($this['class'])) {
      $this['class'] = new AttributeClasses();
    }
    return $this['class'];
  }

  /**
   * Retrieves data attributes.
   *
   * @return \Drupal\plus\Utility\AttributeData
   *   An AttributeData object.
   *
   * @see \Drupal\plus\Utility\ArrayObject::offsetGet()
   */
  public function getData() {
    if (!isset($this['data'])) {
      $this['data'] = new AttributeData();
    }
    return $this['data'];
  }

  /**
   * Indicates whether a class is present in the array.
   *
   * @param string|array $class
   *   The class or array of classes to search for.
   * @param bool $all
   *   Flag determining to check if all classes are present.
   *
   * @return bool
   *   TRUE or FALSE
   *
   * @see \Drupal\plus\Utility\Attributes::getClasses()
   */
  public function hasClass($class, $all = FALSE) {
    $classes = (array) $class;
    $result = array_intersect($classes, $this->getClasses()->getArrayCopy());
    return $all ? $result && count($classes) === count($result) : !!$result;
  }

  /**
   * {@inheritdoc}
   */
  public function merge(&...$arguments) {
    $this->convertArguments($arguments);

    // Handle classes and data attributes uniquely.
    $classes = [];
    $data = [];
    foreach ($arguments as &$argument) {
      if (isset($argument['class'])) {
        $classes[] = &$argument['class'];
        unset($argument['class']);
      }
      if (isset($argument['data'])) {
        $data[] = &$argument['data'];
        unset($argument['data']);
      }
    }

    // Merge in any classes.
    if ($classes) {
      $this->addClass($classes);
    }

    // Merge in any data.
    if ($data) {
      $this->addData($data);
    }

    // Merge in the rest of the attributes.
    $this->mergeByReference($this->__storage, $arguments);

    return $this;
  }

  /**
   * {@inheritdoc}
   *
   * @deprecated There are no "deep" multi-dimensional arrays in attributes.
   *   This just proxies to the ::merge method.
   */
  public function mergeDeep(&...$arguments) {
    return $this->merge(...$arguments);
  }

  /**
   * Removes an attribute from an Attribute object.
   *
   * @param string|string[] ...
   *   Attributes to remove from the attribute array.
   *
   * @return $this
   *
   * @deprecated Use ::remove() instead.
   */
  public function removeAttribute(...$arguments) {
    return $this->remove(...$arguments);
  }

  /**
   * Removes a class from the attributes array.
   *
   * @param string|string[] ...
   *   Class(es) to remove from the attribute array.
   *
   * @return static
   *
   * @see \Drupal\plus\Utility\Attributes::getClasses()
   */
  public function removeClass(...$classes) {
    $this->getClasses()->remove(...$classes);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function render() {
    $output = '';
    /** @var \Drupal\plus\Utility\AttributeBase $value */
    foreach ($this->value() as $name => $value) {
      $rendered = $value->render();
      if ($rendered) {
        $output .= ' ' . $rendered;
      }
    }
    return $output;
  }

  /**
   * Replaces a class in the attributes array.
   *
   * @param string $oldClassName
   *   The old class to remove.
   * @param string $newClassName
   *   The new class. It will not be added if the $old class does not exist.
   * @param bool $onlyIfExists
   *   (optional) Flag indicating whether to add $newClassName only if
   *   $oldClassName exists, defaults to TRUE.
   *
   * @return static
   *
   * @see \Drupal\plus\Utility\Attributes::getClasses()
   */
  public function replaceClass($oldClassName, $newClassName, $onlyIfExists = TRUE) {
    $this->getClasses()->replaceClass($oldClassName, $newClassName, $onlyIfExists);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function set($key, $value = NULL) {
    // Handle class attribute differently.
    if ($key === 'class') {
      $this->getClasses()->replace();
      return $this->addClass($value);
    }
    if ($key === 'data') {
      $this->getData()->replace();
      return $this->addData($value);
    }
    return parent::set($key, $value);
  }

  /**
   * {@inheritdoc}
   *
   * @deprecated Use ::set() instead.
   */
  public function setAttribute($key, $value) {
    return $this->set($key, $value);
  }

  /**
   * Sets multiple attributes on the array.
   *
   * @param array $values
   *   An associative key/value array of attributes to set.
   *
   * @see \Drupal\plus\Utility\ArrayObject::merge()
   */
  public function setAttributes(array $values) {
    // Handle class attribute differently.
    $classes = isset($values['class']) ? $values['class'] : [];
    unset($values['class']);
    if ($classes) {
      $this->addClass($classes);
    }

    $data = isset($values['data']) ? $values['data'] : [];
    unset($values['data']);
    if ($data) {
      $this->addData($data);
    }

    // Merge the reset of the attributes.
    $this->merge($values);
  }

  /**
   * Returns the whole array.
   *
   * @deprecated Use ::value() instead.
   */
  public function storage() {
    return $this->value();
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc