EntityDrupalWrapper

  1. drupal
    1. 7 contributions/entity/includes/entity.wrapper.inc

Provides a wrapper for entities registrered in hook_entity_info().

The wrapper eases applying getter and setter callbacks of entity properties specified in hook_entity_property_info().

Hierarchy

Properties

NameDescription
EntityDrupalWrapper::$bundle
EntityDrupalWrapper::$entityInfo
EntityDrupalWrapper::$idContains the entity id.
EntityMetadataWrapper::$cache
EntityMetadataWrapper::$data
EntityMetadataWrapper::$info
EntityMetadataWrapper::$type
EntityStructureWrapper::$langcode
EntityStructureWrapper::$propertyInfo
EntityStructureWrapper::$propertyInfoDefaults

Functions & methods

NameDescription
EntityDrupalWrapper::clearOverridden. Overrides EntityStructureWrapper::clear
EntityDrupalWrapper::deletePermanently delete the wrapped entity.
EntityDrupalWrapper::entityAccessChecks whether the operation $op is allowed on the entity.
EntityDrupalWrapper::entityInfoGets the info about the wrapped entity.
EntityDrupalWrapper::entityKeyReturns the name of the key used by the entity for given entity key.
EntityDrupalWrapper::getBundleReturns the bundle of an entity, or FALSE if it has no bundles.
EntityDrupalWrapper::getIdentifierReturns the identifier of the wrapped entity. Overrides EntityStructureWrapper::getIdentifier
EntityDrupalWrapper::labelReturns the entity label. Overrides EntityMetadataWrapper::label
EntityDrupalWrapper::savePermanently save the wrapped entity.
EntityDrupalWrapper::setOverridden to support setting the entity by either the object or the id. Overrides EntityMetadataWrapper::set
EntityDrupalWrapper::setEntitySets the entity internally accepting both the entity id and object.
EntityDrupalWrapper::setUp
EntityDrupalWrapper::spotBundleInfoTries to determine the bundle and adds in the according property info.
EntityDrupalWrapper::spotInfoUsed to lazy-load bundle info. So the wrapper can be loaded e.g. just for setting without the data being loaded. Overrides EntityStructureWrapper::spotInfo
EntityDrupalWrapper::typeOverridden. Overrides EntityMetadataWrapper::type
EntityDrupalWrapper::valueOverridden.
EntityDrupalWrapper::viewReturns the entity prepared for rendering.
EntityDrupalWrapper::__constructConstruct a new EntityDrupalWrapper object. Overrides EntityStructureWrapper::__construct
EntityDrupalWrapper::__sleepPrepare for serializiation. Overrides EntityStructureWrapper::__sleep
EntityDrupalWrapper::__wakeup
EntityMetadataWrapper::accessDetermines whether the given user has access to view or edit this property. Apart from relying on access metadata of properties, this takes into account information about entity level access, if available:
EntityMetadataWrapper::dataAvailableReturns whether data is available to work with.
EntityMetadataWrapper::infoGets info about the wrapped data.
EntityMetadataWrapper::optionsListReturns the options list specifying possible values for the property, if defined.
EntityMetadataWrapper::rawReturns the raw, unprocessed data. Most times this is the same as returned by value(), however for already processed and sanitized textual data, this will return the unprocessed data in contrast to value().
EntityMetadataWrapper::updateParentUpdates the parent data structure of a data property with the latest data value.
EntityMetadataWrapper::validateReturns whether $value is a valid value to set.
EntityMetadataWrapper::__toString
EntityStructureWrapper::getGet the wrapper for a property.
EntityStructureWrapper::getIteratorImplements IteratorAggregate::getIterator().
EntityStructureWrapper::getPropertyInfoGets the info about the given property.
EntityStructureWrapper::getPropertyLanguageGets the language used for retrieving properties.
EntityStructureWrapper::getPropertyRawGets the raw value of a property.
EntityStructureWrapper::getPropertyValueGets the value of a property.
EntityStructureWrapper::languageSets a new language to use for retrieving properties.
EntityStructureWrapper::propertyAccess
EntityStructureWrapper::refPropertyInfoReturns a reference on the property info.
EntityStructureWrapper::setPropertySets a property.
EntityStructureWrapper::__getMagic method: Get a wrapper for a property.
EntityStructureWrapper::__issetMagic method: Can be used to check if a property is known.
EntityStructureWrapper::__setMagic method: Set a property.

File

contributions/entity/includes/entity.wrapper.inc, line 571
Provides wrappers allowing easy usage of the entity metadata.

View source
class EntityDrupalWrapper extends EntityStructureWrapper {

  /**
   * Contains the entity id.
   */
  protected $id = FALSE;
  protected $bundle;
  protected $entityInfo;

  /**
   * Construct a new EntityDrupalWrapper object.
   *
   * @param $type
   *   The type of the passed data.
   * @param $data
   *   Optional. The entity to wrap or its identifier.
   * @param $info
   *   Optional. Used internally to pass info about properties down the tree.
   */
  public function __construct($type, $data = NULL, $info = array()) {
    parent::__construct($type, $data, $info);
    $this->setUp();
  }

  protected function setUp() {
    $this->propertyInfo = entity_get_property_info($this->type) + array('properties' => array());
    $info = $this->info + array(
      'property info' => array(),
      'bundle' => NULL,
    );
    $this->propertyInfo['properties'] += $info['property info'];
    $this->bundle = $info['bundle'];
    $this->entityInfo = entity_get_info($this->type);
    if (isset($this->bundle)) {
      $this->spotBundleInfo(FALSE);
    }
  }

  /**
   * Sets the entity internally accepting both the entity id and object.
   */
  protected function setEntity($data) {
    // For entities we allow getter callbacks to return FALSE, which we
    // interpret like NULL values as unset properties.
    if (isset($data) && $data !== FALSE && !is_object($data)) {
      $this->id = $data;
      $this->data = FALSE;
    }
    elseif (is_object($data) && $data instanceof EntityDrupalWrapper) {
      // We got a wrapped entity passed, so take over its values.
      $this->id = $data->id;
      $this->data = $data->data;
      // For generic entity references, also update the entity type accordingly.
      if ($this->info['type'] == 'entity') {
        $this->type = $data->type;
      }
    }
    elseif (is_object($data)) {
      // We got the entity object passed.
      $this->data = $data;
      $id = entity_id($this->type, $data);
      $this->id = isset($id) ? $id : FALSE;
    }
    else {
      $this->id = FALSE;
      $this->data = NULL;
    }
  }

  /**
   * Used to lazy-load bundle info. So the wrapper can be loaded e.g. just
   * for setting without the data being loaded.
   */
  protected function spotInfo() {
    if (!$this->propertyInfoAltered) {
      if ($this->info['type'] == 'entity' && $this->dataAvailable() && $this->value()) {
        // Add in entity-type specific details.
        $this->setUp();
      }
      $this->spotBundleInfo(TRUE);
      parent::spotInfo();
      $this->propertyInfoAltered = TRUE;
    }
  }

  /**
   * Tries to determine the bundle and adds in the according property info.
   *
   * @param $load
   *   Whether the entity should be loaded to spot the info if necessary.
   */
  protected function spotBundleInfo($load = TRUE) {
    // Like entity_extract_ids() assume the entity type if no key is given.
    if (empty($this->entityInfo['entity keys']['bundle']) && $this->type != 'entity') {
      $this->bundle = $this->type;
    }
    // Detect the bundle if not set yet and add in properties from the bundle.
    elseif (!$this->bundle && !empty($this->entityInfo['fieldable']) && $load && $this->dataAvailable()) {
      try {
        if ($entity = $this->value()) {
          list($id, $vid, $bundle) = entity_extract_ids($this->type, $entity);
          $this->bundle = $bundle;
        }
      }
      catch (EntityMetadataWrapperException $e) {
        // Loading data failed, so we cannot derive the used bundle.
      }
    }

    if ($this->bundle && isset($this->propertyInfo['bundles'][$this->bundle])) {
      $bundle_info = (array) $this->propertyInfo['bundles'][$this->bundle] + array('properties' => array());
      // Allow bundles to re-define existing properties, such that the bundle
      // can add in more bundle-specific details like the bundle of a referenced
      // entity.
      $this->propertyInfo['properties'] = $bundle_info['properties'] + $this->propertyInfo['properties'];
    }
  }

  /**
   * Returns the identifier of the wrapped entity.
   *
   * @see entity_id()
   */
  public function getIdentifier() {
    return $this->dataAvailable() ? $this->value(array('identifier' => TRUE)) : NULL;
  }

  /**
   * Returns the bundle of an entity, or FALSE if it has no bundles.
   */
  public function getBundle() {
    if ($this->dataAvailable()) {
      $this->spotInfo();
      return $this->bundle;
    }
  }

  /**
   * Overridden.
   *
   * @param $options
   *   An array of options. Known keys:
   *   - identifier: If set to TRUE, the entity identifier is returned.
   */
  public function value(array $options = array()) {
    // Try loading the data via the getter callback if there is none yet.
    if (!isset($this->data)) {
      $this->setEntity(parent::value());
    }
    if (!empty($options['identifier'])) {
      return $this->id;
    }
    elseif (!$this->data && !empty($this->id)) {
      // Lazy load the entity if necessary.
      $return = entity_load($this->type, array($this->id));
      // In case the entity cannot be loaded, we return NULL just as for empty
      // properties.
      $this->data = $return ? reset($return) : NULL;
    }
    return $this->data;
  }

  /**
   * Returns the entity prepared for rendering.
   *
   * @see entity_view()
   */
  public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
    return entity_view($this->type(), array($this->value()), $view_mode, $langcode, $page);
  }

  /**
   * Overridden to support setting the entity by either the object or the id.
   */
  public function set($value) {
    if (!$this->validate($value)) {
      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
    }
    if ($this->info['type'] == 'entity' && $value === $this) {
      // Nothing to do.
      return $this;
    }
    $previous_id = $this->id;
    $previous_type = $this->type;
    // Set value, so we get the identifier and pass it to the normal setter.
    $this->clear();
    $this->setEntity($value);
    // Generally, we have to update the parent only if the entity reference
    // has changed. In case of a generic entity reference, we pass the entity
    // wrapped. Else we just pass the id of the entity to the setter callback.
    if ($this->info['type'] == 'entity' && ($previous_id != $this->id || $previous_type != $this->type)) {
      // We need to clone the wrapper we pass through as value, so it does not
      // get cleared when the current wrapper instance gets cleared.
      $this->updateParent(clone $this);
    }
    // In case the entity has been unset, we cannot properly detect changes as
    // the previous id defaults to FALSE for unloaded entities too. So in that
    // case we just always update the parent.
    elseif ($this->id === FALSE && !$this->data) {
      $this->updateParent(NULL);
    }
    elseif ($previous_id != $this->id) {
      $this->updateParent($this->id);
    }
    return $this;
  }

  /**
   * Overridden.
   */
  public function clear() {
    $this->id = NULL;
    $this->bundle = isset($this->info['bundle']) ? $this->info['bundle'] : NULL;
    if ($this->type != $this->info['type']) {
      // Reset entity info / property info based upon the info provided during
      // the creation of the wrapper.
      $this->type = $this->info['type'];
      $this->setUp();
    }
    parent::clear();
  }

  /**
   * Overridden.
   */
  public function type() {
    // In case of a generic entity wrapper, load the data first to determine
    // the type of the concrete entity.
    if ($this->dataAvailable() && $this->info['type'] == 'entity') {
      try {
        $this->value(array('identifier' => TRUE));
      }
      catch (EntityMetadataWrapperException $e) {
        // If loading data fails, we cannot determine the concrete entity type.
      }
    }
    return $this->type;
  }

  /**
   * Checks whether the operation $op is allowed on the entity.
   *
   * @see entity_access()
   */
  public function entityAccess($op, $account = NULL) {
    $entity = $this->dataAvailable() ? $this->value() : NULL;
    return entity_access($op, $this->type, $entity, $account);
  }

  /**
   * Permanently save the wrapped entity.
   *
   * @throws EntityMetadataWrapperException
   *   If the entity type does not support saving.
   *
   * @return EntityDrupalWrapper
   */
  public function save() {
    if ($this->data) {
      if (!entity_type_supports($this->type, 'save')) {
        throw new EntityMetadataWrapperException("There is no information about how to save entities of type " . check_plain($this->type) . '.');
      }
      entity_save($this->type, $this->data);
      // On insert, update the identifier afterwards.
      if (!$this->id) {
        list($this->id, ,  ) = entity_extract_ids($this->type, $this->data);
      }
    }
    // If the entity hasn't been loaded yet, don't bother saving it.
    return $this;
  }

  /**
   * Permanently delete the wrapped entity.
   *
   * @return EntityDrupalWrapper
   */
  public function delete() {
    if ($this->dataAvailable() && $this->value()) {
      $return = entity_delete($this->type, $this->id);
      if ($return === FALSE) {
        throw new EntityMetadataWrapperException("There is no information about how to delete entities of type " . check_plain($this->type) . '.');
      }
    }
    return $this;
  }

  /**
   * Gets the info about the wrapped entity.
   */
  public function entityInfo() {
    return $this->entityInfo;
  }

  /**
   * Returns the name of the key used by the entity for given entity key.
   *
   * @param $name
   *   One of 'id', 'name', 'bundle' or 'revision'.
   * @return
   *   The name of the key used by the entity.
   */
  public function entityKey($name) {
    return isset($this->entityInfo['entity keys'][$name]) ? $this->entityInfo['entity keys'][$name] : FALSE;
  }

  /**
   * Returns the entity label.
   *
   * @see entity_label()
   */
  public function label() {
    if ($entity = $this->value()) {
      return entity_label($this->type, $entity);
    }
  }

  /**
   * Prepare for serializiation.
   */
  public function __sleep() {
    $vars = parent::__sleep();
    // Don't serialize the loaded entity and its property info.
    unset($vars['data'], $vars['propertyInfo'], $vars['propertyInfoAltered'], $vars['entityInfo']);
    // In case the entity is not saved yet, serialize the unsaved data.
    if ($this->dataAvailable() && $this->id === FALSE) {
      $vars['data'] = 'data';
    }
    return $vars;
  }

  public function __wakeup() {
    $this->setUp();
    if ($this->id !== FALSE) {
      // Make sure data is set, so the entity will be loaded when needed.
      $this->data = FALSE;
    }
  }
}