class EntityBCDecorator

Provides backwards compatible (BC) access to entity fields.

Allows using entities converted to the new Entity Field API with the previous way of accessing fields or properties. For example, via the backwards compatible (BC) decorator you can do:

$node->title = $value;
$node->body[LANGUAGE_NONE][0]['value'] = $value;

Without the BC decorator the same assignment would have to look like this:

$node->title->value = $value;
$node->body->value = $value;

Without the BC decorator the language always default to the entity language, whereas a specific translation can be access via the getTranslation() method.

The BC decorator should be only used during conversion to the new entity field API, such that existing code can be converted iteratively. Any new code should directly use the new entity field API and avoid using the EntityBCDecorator, if possible.

@todo: Remove once everything is converted to use the new entity field API.

Hierarchy

Expanded class hierarchy of EntityBCDecorator

3 files declare their use of EntityBCDecorator
NodeBCDecorator.php in drupal/core/modules/node/lib/Drupal/node/NodeBCDecorator.php
Contains \Drupal\node\NodeBCDecorator.
UserBCDecorator.php in drupal/core/modules/user/lib/Drupal/user/UserBCDecorator.php
Contains \Drupal\user\UserBCDecorator.
UserStorageController.php in drupal/core/modules/user/lib/Drupal/user/UserStorageController.php
Definition of Drupal\user\UserStorageController.

File

drupal/core/lib/Drupal/Core/Entity/EntityBCDecorator.php, line 41
Contains \Drupal\Core\Entity\EntityBCDecorator.

Namespace

Drupal\Core\Entity
View source
class EntityBCDecorator implements IteratorAggregate, EntityInterface {

  /**
   * The EntityInterface object being decorated.
   *
   * @var \Drupal\Core\Entity\EntityInterface
   */
  protected $decorated;

  /**
   * Local cache for field definitions.
   *
   * @var array
   */
  protected $definitions;

  /**
   * Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object.
   *
   * @param \Drupal\Core\Entity\EntityInterface $decorated
   *   The decorated entity.
   * @param array &$definitions
   *   An array of field definitions.
   */
  function __construct(EntityNG $decorated, array &$definitions) {
    $this->decorated = $decorated;
    $this->definitions =& $definitions;
  }

  /**
   * Overrides Entity::getNGEntity().
   */
  public function getNGEntity() {
    return $this->decorated;
  }

  /**
   * Overrides Entity::getBCEntity().
   */
  public function getBCEntity() {
    return $this;
  }

  /**
   * Implements the magic method for getting object properties.
   *
   * Directly accesses the plain field values, as done in Drupal 7.
   */
  public function &__get($name) {

    // Directly return the original property.
    if ($name == 'original') {
      return $this->decorated->values[$name];
    }

    // We access the protected 'values' and 'fields' properties of the decorated
    // entity via the magic getter - which returns them by reference for us. We
    // do so, as providing references to these arrays would make $entity->values
    // and $entity->fields reference themselves, which is problematic during
    // __clone() (this is something we cannot work-a-round easily as an unset()
    // on the variable is problematic in conjunction with the magic
    // getter/setter).
    if (!empty($this->decorated->fields[$name])) {

      // Any field value set via the new Entity Field API will be stored inside
      // the field objects managed by the entity, thus we need to ensure
      // $this->decorated->values reflects the latest values first.
      foreach ($this->decorated->fields[$name] as $langcode => $field) {

        // Only set if it's not empty, otherwise there can be ghost values.
        if (!$field
          ->isEmpty()) {
          $this->decorated->values[$name][$langcode] = $field
            ->getValue();
        }
      }

      // The returned values might be changed by reference, so we need to remove
      // the field object to avoid the field object and the value getting out of
      // sync. That way, the next field object instantiated by EntityNG will
      // receive the possibly updated value.
      unset($this->decorated->fields[$name]);
    }

    // When accessing values for entity properties that have been converted to
    // an entity field, provide direct access to the plain value. This makes it
    // possible to use the BC-decorator with properties; e.g., $node->title.
    if (isset($this->definitions[$name]) && empty($this->definitions[$name]['configurable'])) {
      if (!isset($this->decorated->values[$name][Language::LANGCODE_DEFAULT])) {
        $this->decorated->values[$name][Language::LANGCODE_DEFAULT][0]['value'] = NULL;
      }
      if (is_array($this->decorated->values[$name][Language::LANGCODE_DEFAULT])) {

        // This will work with all defined properties that have a single value.
        // We need to ensure the key doesn't matter. Mostly it's 'value' but
        // e.g. EntityReferenceItem uses target_id.
        if (isset($this->decorated->values[$name][Language::LANGCODE_DEFAULT][0]) && count($this->decorated->values[$name][Language::LANGCODE_DEFAULT][0]) == 1) {
          return $this->decorated->values[$name][Language::LANGCODE_DEFAULT][0][key($this->decorated->values[$name][Language::LANGCODE_DEFAULT][0])];
        }
      }
      return $this->decorated->values[$name][Language::LANGCODE_DEFAULT];
    }
    else {

      // Allow accessing field values in an entity default language other than
      // Language::LANGCODE_DEFAULT by mapping the values to
      // Language::LANGCODE_DEFAULT. This is necessary as EntityNG always keys
      // default language values with Language::LANGCODE_DEFAULT while field API
      // expects them to be keyed by langcode.
      $langcode = $this->decorated
        ->language()->langcode;
      if ($langcode != Language::LANGCODE_DEFAULT && isset($this->decorated->values[$name]) && is_array($this->decorated->values[$name])) {
        if (isset($this->decorated->values[$name][Language::LANGCODE_DEFAULT]) && !isset($this->decorated->values[$name][$langcode])) {
          $this->decorated->values[$name][$langcode] =& $this->decorated->values[$name][Language::LANGCODE_DEFAULT];
        }
      }
      if (!isset($this->decorated->values[$name])) {
        $this->decorated->values[$name] = NULL;
      }
      return $this->decorated->values[$name];
    }
  }

  /**
   * Implements the magic method for setting object properties.
   *
   * Directly writes to the plain field values, as done by Drupal 7.
   */
  public function __set($name, $value) {
    $defined = isset($this->definitions[$name]);

    // When updating values for entity properties that have been converted to
    // an entity field, directly write to the plain value. This makes it
    // possible to use the BC-decorator with properties; e.g., $node->title.
    if ($defined && empty($this->definitions[$name]['configurable'])) {
      $this->decorated->values[$name][Language::LANGCODE_DEFAULT] = $value;
    }
    else {
      if ($defined && is_array($value)) {

        // If field API sets a value with a langcode in entity language, move it
        // to Language::LANGCODE_DEFAULT.
        // This is necessary as EntityNG always keys default language values
        // with Language::LANGCODE_DEFAULT while field API expects them to be
        // keyed by langcode.
        foreach ($value as $langcode => $data) {
          if ($langcode != Language::LANGCODE_DEFAULT && $langcode == $this->decorated
            ->language()->langcode) {
            $value[Language::LANGCODE_DEFAULT] = $data;
            unset($value[$langcode]);
          }
        }
      }
      $this->decorated->values[$name] = $value;
    }

    // Remove the field object to avoid the field object and the value getting
    // out of sync. That way, the next field object instantiated by EntityNG
    // will hold the updated value.
    unset($this->decorated->fields[$name]);
  }

  /**
   * Implements the magic method for isset().
   */
  public function __isset($name) {
    $value = $this
      ->__get($name);
    return isset($value);
  }

  /**
   * Implements the magic method for unset().
   */
  public function __unset($name) {

    // Set the value to NULL.
    $value =& $this
      ->__get($name);
    $value = NULL;
  }

  /**
   * Implements the magic method for clone().
   */
  function __clone() {
    $this->decorated = clone $this->decorated;
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function uriRelationships() {
    return $this->decorated
      ->uriRelationships();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function access($operation = 'view', AccountInterface $account = NULL) {
    return $this->decorated
      ->access($operation, $account);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function get($property_name) {

    // Ensure this works with not yet defined fields.
    if (!isset($this->definitions[$property_name])) {
      return $this
        ->__get($property_name);
    }
    return $this->decorated
      ->get($property_name);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function set($property_name, $value, $notify = TRUE) {

    // Ensure this works with not yet defined fields.
    if (!isset($this->definitions[$property_name])) {
      return $this
        ->__set($property_name, $value);
    }
    return $this->decorated
      ->set($property_name, $value);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getProperties($include_computed = FALSE) {
    return $this->decorated
      ->getProperties($include_computed);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getPropertyValues() {
    return $this->decorated
      ->getPropertyValues();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function setPropertyValues($values) {
    return $this->decorated
      ->setPropertyValues($values);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getPropertyDefinition($name) {
    return $this->decorated
      ->getPropertyDefinition($name);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getPropertyDefinitions() {
    return $this->decorated
      ->getPropertyDefinitions();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function isEmpty() {
    return $this->decorated
      ->isEmpty();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getIterator() {
    return $this->decorated
      ->getIterator();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function id() {
    return $this->decorated
      ->id();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function uuid() {
    return $this->decorated
      ->uuid();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function isNew() {
    return $this->decorated
      ->isNew();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function isNewRevision() {
    return $this->decorated
      ->isNewRevision();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function setNewRevision($value = TRUE) {
    return $this->decorated
      ->setNewRevision($value);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function enforceIsNew($value = TRUE) {
    return $this->decorated
      ->enforceIsNew($value);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function entityType() {
    return $this->decorated
      ->entityType();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function bundle() {
    return $this->decorated
      ->bundle();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function label($langcode = NULL) {
    return $this->decorated
      ->label($langcode);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function uri($rel = 'canonical') {
    return $this->decorated
      ->uri($rel);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function save() {
    return $this->decorated
      ->save();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function delete() {
    return $this->decorated
      ->delete();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function createDuplicate() {
    return $this->decorated
      ->createDuplicate();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function entityInfo() {
    return $this->decorated
      ->entityInfo();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getRevisionId() {
    return $this->decorated
      ->getRevisionId();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function isDefaultRevision($new_value = NULL) {
    return $this->decorated
      ->isDefaultRevision($new_value);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function language() {
    return $this->decorated
      ->language();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getTranslationLanguages($include_default = TRUE) {
    return $this->decorated
      ->getTranslationLanguages($include_default);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getTranslation($langcode, $strict = TRUE) {
    return $this->decorated
      ->getTranslation($langcode, $strict);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getType() {
    return $this->decorated
      ->getType();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getDefinition() {
    return $this->decorated
      ->getDefinition();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getValue() {
    return $this->decorated
      ->getValue();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function setValue($value, $notify = TRUE) {
    return $this->decorated
      ->setValue($value, $notify);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getString() {
    return $this->decorated
      ->getString();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getConstraints() {
    return $this->decorated
      ->getConstraints();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function validate() {
    return $this->decorated
      ->validate();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getName() {
    return $this->decorated
      ->getName();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getRoot() {
    return $this->decorated
      ->getRoot();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getPropertyPath() {
    return $this->decorated
      ->getPropertyPath();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getParent() {
    return $this->decorated
      ->getParent();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function setContext($name = NULL, TypedDataInterface $parent = NULL) {
    $this->decorated
      ->setContext($name, $parent);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function getExportProperties() {
    $this->decorated
      ->getExportProperties();
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function onChange($property_name) {
    $this->decorated
      ->onChange($property_name);
  }

  /**
   * Forwards the call to the decorated entity.
   */
  public function isTranslatable() {
    return $this->decorated
      ->isTranslatable();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityBCDecorator::$decorated protected property The EntityInterface object being decorated.
EntityBCDecorator::$definitions protected property Local cache for field definitions.
EntityBCDecorator::access public function Forwards the call to the decorated entity. Overrides AccessibleInterface::access
EntityBCDecorator::bundle public function Forwards the call to the decorated entity. Overrides EntityInterface::bundle
EntityBCDecorator::createDuplicate public function Forwards the call to the decorated entity. Overrides EntityInterface::createDuplicate
EntityBCDecorator::delete public function Forwards the call to the decorated entity. Overrides EntityInterface::delete
EntityBCDecorator::enforceIsNew public function Forwards the call to the decorated entity. Overrides EntityInterface::enforceIsNew
EntityBCDecorator::entityInfo public function Forwards the call to the decorated entity. Overrides EntityInterface::entityInfo
EntityBCDecorator::entityType public function Forwards the call to the decorated entity. Overrides EntityInterface::entityType
EntityBCDecorator::get public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::get
EntityBCDecorator::getBCEntity public function Overrides Entity::getBCEntity(). Overrides EntityInterface::getBCEntity
EntityBCDecorator::getConstraints public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getConstraints
EntityBCDecorator::getDefinition public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getDefinition
EntityBCDecorator::getExportProperties public function Forwards the call to the decorated entity. Overrides EntityInterface::getExportProperties
EntityBCDecorator::getIterator public function Forwards the call to the decorated entity.
EntityBCDecorator::getName public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getName
EntityBCDecorator::getNGEntity public function Overrides Entity::getNGEntity(). Overrides EntityInterface::getNGEntity
EntityBCDecorator::getParent public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getParent
EntityBCDecorator::getProperties public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::getProperties
EntityBCDecorator::getPropertyDefinition public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::getPropertyDefinition
EntityBCDecorator::getPropertyDefinitions public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::getPropertyDefinitions
EntityBCDecorator::getPropertyPath public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getPropertyPath
EntityBCDecorator::getPropertyValues public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::getPropertyValues
EntityBCDecorator::getRevisionId public function Forwards the call to the decorated entity. Overrides EntityInterface::getRevisionId
EntityBCDecorator::getRoot public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getRoot
EntityBCDecorator::getString public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getString
EntityBCDecorator::getTranslation public function Forwards the call to the decorated entity. Overrides TranslatableInterface::getTranslation
EntityBCDecorator::getTranslationLanguages public function Forwards the call to the decorated entity. Overrides TranslatableInterface::getTranslationLanguages
EntityBCDecorator::getType public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getType
EntityBCDecorator::getValue public function Forwards the call to the decorated entity. Overrides TypedDataInterface::getValue
EntityBCDecorator::id public function Forwards the call to the decorated entity. Overrides EntityInterface::id
EntityBCDecorator::isDefaultRevision public function Forwards the call to the decorated entity. Overrides EntityInterface::isDefaultRevision
EntityBCDecorator::isEmpty public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::isEmpty
EntityBCDecorator::isNew public function Forwards the call to the decorated entity. Overrides EntityInterface::isNew
EntityBCDecorator::isNewRevision public function Forwards the call to the decorated entity. Overrides EntityInterface::isNewRevision
EntityBCDecorator::isTranslatable public function Forwards the call to the decorated entity. Overrides EntityInterface::isTranslatable
EntityBCDecorator::label public function Forwards the call to the decorated entity. Overrides EntityInterface::label
EntityBCDecorator::language public function Forwards the call to the decorated entity. Overrides TranslatableInterface::language
EntityBCDecorator::onChange public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::onChange
EntityBCDecorator::save public function Forwards the call to the decorated entity. Overrides EntityInterface::save
EntityBCDecorator::set public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::set
EntityBCDecorator::setContext public function Forwards the call to the decorated entity. Overrides TypedDataInterface::setContext
EntityBCDecorator::setNewRevision public function Forwards the call to the decorated entity. Overrides EntityInterface::setNewRevision
EntityBCDecorator::setPropertyValues public function Forwards the call to the decorated entity. Overrides ComplexDataInterface::setPropertyValues
EntityBCDecorator::setValue public function Forwards the call to the decorated entity. Overrides TypedDataInterface::setValue
EntityBCDecorator::uri public function Forwards the call to the decorated entity. Overrides EntityInterface::uri
EntityBCDecorator::uriRelationships public function Forwards the call to the decorated entity. Overrides EntityInterface::uriRelationships
EntityBCDecorator::uuid public function Forwards the call to the decorated entity. Overrides EntityInterface::uuid
EntityBCDecorator::validate public function Forwards the call to the decorated entity. Overrides TypedDataInterface::validate
EntityBCDecorator::__clone function Implements the magic method for clone().
EntityBCDecorator::__construct function Constructs a Drupal\Core\Entity\EntityCompatibilityDecorator object.
EntityBCDecorator::__get public function Implements the magic method for getting object properties. 1
EntityBCDecorator::__isset public function Implements the magic method for isset().
EntityBCDecorator::__set public function Implements the magic method for setting object properties.
EntityBCDecorator::__unset public function Implements the magic method for unset().