You are here

abstract class EntityMetadataWrapper in Entity API 7

A common base class for all wrappers.

Hierarchy

Expanded class hierarchy of EntityMetadataWrapper

File

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 mixed|null
   *   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 bool
   *   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(t('Invalid data value given. Be sure it matches the required data type and format. Value at !location: !value.', array(
        // An exception's message is output through check_plain().
        '!value' => is_array($value) || is_object($value) ? var_export($value, TRUE) : $value,
        '!location' => $this
          ->debugIdentifierLocation(),
      )));
    }
    $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 array|false
   *   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 bool
   *   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) {
    return !empty($this->info['parent']) ? $this->info['parent']
      ->propertyAccess($this->info['name'], $op, $account) : TRUE;
  }

  /**
   * Returns a string to use to identify this wrapper in error messages.
   *
   * @return string
   *   A string that identifies this wrapper and its chain of ancestors, of the
   *   form 'grandparentidentifier->parentidentifier->identifier'.
   */
  public function debugIdentifierLocation() {
    $debug = $this->info['name'];
    if (isset($this->info['parent'])) {
      $debug = $this->info['parent']
        ->debugIdentifierLocation() . '->' . $debug;
    }
    return $debug;
  }

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

}

Members

Namesort descending Modifiers Type Description Overrides
EntityMetadataWrapper::$cache protected property
EntityMetadataWrapper::$data protected property
EntityMetadataWrapper::$info protected property
EntityMetadataWrapper::$type protected property 1
EntityMetadataWrapper::access public function 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: 1
EntityMetadataWrapper::clear protected function Clears the data value and the wrapper cache. 1
EntityMetadataWrapper::dataAvailable protected function Returns whether data is available to work with.
EntityMetadataWrapper::debugIdentifierLocation public function Returns a string to use to identify this wrapper in error messages. 1
EntityMetadataWrapper::info public function Gets info about the wrapped data.
EntityMetadataWrapper::label public function Returns the label for the currently set property value if there is one available, i.e. if an options list has been specified. 2
EntityMetadataWrapper::optionsList public function Returns the options list specifying possible values for the property, if defined.
EntityMetadataWrapper::raw public function 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().
EntityMetadataWrapper::set public function Set a new data value. 2
EntityMetadataWrapper::type public function Gets the (entity)type of the wrapped data. 1
EntityMetadataWrapper::updateParent protected function Updates the parent data structure of a data property with the latest data value.
EntityMetadataWrapper::validate public function Returns whether $value is a valid value to set. 1
EntityMetadataWrapper::value public function Returns the wrapped data. If no options are given the data is returned as described in the info. 3
EntityMetadataWrapper::__construct public function Construct a new wrapper object. 2
EntityMetadataWrapper::__sleep public function Prepare for serializiation. 1
EntityMetadataWrapper::__toString public function