EntityMetadataWrapper

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

A common base class for all wrappers.

Hierarchy

Properties

NameDescription
EntityMetadataWrapper::$cache
EntityMetadataWrapper::$data
EntityMetadataWrapper::$info
EntityMetadataWrapper::$type

Functions & methods

NameDescription
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::clearClears the data value and the wrapper cache.
EntityMetadataWrapper::dataAvailableReturns whether data is available to work with.
EntityMetadataWrapper::infoGets info about the wrapped data.
EntityMetadataWrapper::labelReturns the label for the currently set property value if there is one available, i.e. if an options list has been specified.
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::setSet a new data value.
EntityMetadataWrapper::typeGets the (entity)type of the wrapped data.
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::valueReturns the wrapped data. If no options are given the data is returned as described in the info.
EntityMetadataWrapper::__constructConstruct a new wrapper object.
EntityMetadataWrapper::__sleepPrepare for serializiation.
EntityMetadataWrapper::__toString

File

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

View source
abstract class EntityMetadataWrapper {

  protected $type;
  protected $data;
  protected $info;
  protected $cache = array();

  /**
   * Construct a new wrapper object.
   *
   * @param $type
   *   The type of the passed data.
   * @param $data
   *   Optional. The data to wrap.
   * @param $info
   *   Optional. Used internally to pass info about properties down the tree.
   */
  public function __construct($type, $data = NULL, $info = array()) {
    $this->type = $type;
    $this->info = $info + array(
      'langcode' => NULL,
    );
    $this->info['type'] = $type;
    if (isset($data)) {
      $this->set($data);
    }
  }

  /**
   * Gets info about the wrapped data.
   *
   * @return Array
   *   Keys set are all keys as specified for a property in hook_entity_info()
   *   as well as possible the following keys:
   *    - name: If this wraps a property, the name of the property.
   *    - parent: The parent wrapper, if any.
   *    - langcode: The language code, if this data is language specific.
   */
  public function info() {
    return $this->info;
  }

  /**
   * Gets the (entity)type of the wrapped data.
   */
  public function type() {
    return $this->type;
  }

  /**
   * Returns the wrapped data. If no options are given the data is returned as
   * described in the info.
   *
   * @param $options
   *   (optional) A keyed array of options:
   *   - sanitize: A boolean flag indicating that textual properties should be
   *     sanitized for display to a web browser. Defaults to FALSE.
   *   - decode: If set to TRUE and some textual data is already sanitized, it
   *     strips HTML tags and decodes HTML entities. Defaults to FALSE.
   *
   *  @return
   *    The value of the wrapped data. If the data property is not set, NULL
   *    is returned.
   *
   *  @throws EntityMetadataWrapperException
   *    In case there are no data values available to the wrapper, an exception
   *    is thrown. E.g. if the value for an entity property is to be retrieved
   *    and there is no entity available, the exception is thrown. However, if
   *    an entity is available but the property is not set, NULL is returned.
   */
  public function value(array $options = array()) {
    if (!$this->dataAvailable() && isset($this->info['parent'])) {
      throw new EntityMetadataWrapperException('Missing data values.');
    }
    if (!isset($this->data) && isset($this->info['name'])) {
      $this->data = $this->info['parent']->getPropertyValue($this->info['name'], $this->info);
    }
    return $this->data;
  }

  /**
   * Returns 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().
   */
  public function raw() {
    if (!$this->dataAvailable()) {
      throw new EntityMetadataWrapperException('Missing data values.');
    }
    if (isset($this->info['name']) && isset($this->info['parent'])) {
      return $this->info['parent']->getPropertyRaw($this->info['name'], $this->info);
    }
    // Else return the usual value, which should be raw in this case.
    return $this->value();
  }

  /**
   * Returns whether data is available to work with.
   *
   * @return
   *   If we operate without any data FALSE, else TRUE.
   */
  protected function dataAvailable() {
    return isset($this->data) || (isset($this->info['parent']) && $this->info['parent']->dataAvailable());
  }

  /**
   * Set a new data value.
   */
  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.');
    }
    $this->clear();
    $this->data = $value;
    $this->updateParent($value);
    return $this;
  }

  /**
   * Updates the parent data structure of a data property with the latest data value.
   */
  protected function updateParent($value) {
    if (isset($this->info['parent'])) {
      $this->info['parent']->setProperty($this->info['name'], $value);
    }
  }

  /**
   * Returns whether $value is a valid value to set.
   */
  public function validate($value) {
    if (isset($value) && !entity_property_verify_data_type($value, $this->type)) {
      return FALSE;
    }
    // Only proceed with further checks if this is not a list item. If this is
    // a list item, the checks are performed on the list property level.
    if (isset($this->info['parent']) && $this->info['parent'] instanceof EntityListWrapper) {
      return TRUE;
    }
    if (!isset($value) && !empty($this->info['required'])) {
      // Do not allow NULL values if the property is required.
      return FALSE;
    }
    return !isset($this->info['validation callback']) || call_user_func($this->info['validation callback'], $value, $this->info);
  }

  public function __toString() {
    return isset($this->info) ? 'Property ' . $this->info['name'] : $this->type;
  }

  /**
   * Clears the data value and the wrapper cache.
   */
  protected function clear() {
    $this->data = NULL;
    foreach ($this->cache as $wrapper) {
      $wrapper->clear();
    }
  }

  /**
   * Returns the options list specifying possible values for the property, if
   * defined.
   *
   * @param $op
   *   (optional) One of 'edit' or 'view'. In case the list of possible values
   *   a user could set for a property differs from the list of values a
   *   property could have, $op determines which options should be returned.
   *   Defaults to 'edit'.
   *   E.g. all possible roles a user could have include the anonymous and the
   *   authenticated user roles, while those roles cannot be added to a user
   *   account. So their options would be included for 'view', but for 'edit'
   *   not.
   *
   * @return
   *   An array as used by hook_options_list() or FALSE.
   */
  public function optionsList($op = 'edit') {
    if (isset($this->info['options list']) && is_callable($this->info['options list'])) {
      $name = isset($this->info['name']) ? $this->info['name'] : NULL;
      return call_user_func($this->info['options list'], $name, $this->info, $op);
    }
    return FALSE;
  }

  /**
   * Returns the label for the currently set property value if there is one
   * available, i.e. if an options list has been specified.
   */
  public function label() {
    if ($options = $this->optionsList('view')) {
      $options = entity_property_options_flatten($options);
      $value = $this->value();
      if (is_scalar($value) && isset($options[$value])) {
        return $options[$value];
      }
    }
  }

  /**
   * Determines 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:
   *  - Referenced entities can only be viewed, when the user also has
   *    permission to view the entity.
   *  - A property may be only edited, if the user has permission to update the
   *    entity containing the property.
   *
   * @param $op
   *   The operation being performed. One of 'view' or 'edit.
   * @param $account
   *   The user to check for. Leave it to NULL to check for the global user.
   * @return boolean
   *   Whether access to entity property is allowed for the given operation.
   *   However if we wrap no data, it returns whether access is allowed to the
   *   property of all entities of this type.
   *   If there is no access information for this property, TRUE is returned.
   */
  public function access($op, $account = NULL) {
    if (empty($this->info['parent']) && $this instanceof EntityDrupalWrapper) {
      // If there is no parent just incorporate entity based access.
      return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
    }
    return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE;
  }

  /**
   * Prepare for serializiation.
   */
  public function __sleep() {
    $vars = get_object_vars($this);
    unset($vars['cache']);
    return drupal_map_assoc(array_keys($vars));
  }
}