You are here

class FieldModifier in Realistic Dummy Content 8

Field modifier class.

All manipulation of generated content to make it more realistic passes through modifiers (direct or indirect subclasses of EntityBase).

This class (\FieldModifier) allows active modules to put files in a specific directory hierarchy resembling realistic_dummy_content/fields/ [entity_type]/[bundle]/[field_name], and for these files to define data which will replace the values of the corresponding property or field in any given entity.

The difference between a field and a property is that a field is managed by Drupal's Field system, whereas a property is not. Example of fields include field_image, which define images in articles (in a standard installation); examples of properties include the user entity's picture property, and the title of nodes.

Drupal stores field values differently depending on the type of field, and third-party modules can define their own schemes for storing values; an extensible system has been defined to allow any module (including this one) to define field formats and interpret data from files. To do so, modules must implement hook_realistic_dummy_content_field_manipular_alter(). Please see the example in this module's .module file, with more documentation in realistic_dummy_content_api.api.php. (Realistic Dummy Content API defines specific manipulators for the fields image, text_with_summary, taxonomy_term_reference...).

Hierarchy

  • class \Drupal\realistic_dummy_content_api\manipulators\Base
    • class \Drupal\realistic_dummy_content_api\manipulators\EntityBase
      • class \Drupal\realistic_dummy_content_api\manipulators\FieldModifier

Expanded class hierarchy of FieldModifier

2 files declare their use of FieldModifier
RealisticDummyContent.php in api/src/facade/RealisticDummyContent.php
Define autoload class.
RealisticDummyContentDbTestCase.php in api/src/Tests/RealisticDummyContentDbTestCase.php
This file contains the testing code which requires the database. These tests are slower than the unit tests so we want to limit them.
1 string reference to 'FieldModifier'
hook_realistic_dummy_content_api_class in api/realistic_dummy_content_api.api.php
hook_realistic_dummy_content_api_class().

File

api/src/manipulators/FieldModifier.php, line 44
Define autoload class.

Namespace

Drupal\realistic_dummy_content_api\manipulators
View source
class FieldModifier extends EntityBase {

  /**
   * Get properties for the entity, for example user's picture or node's name.
   *
   * This is deprecated for Drupal 8
   *
   * @return
   *   An empty array is returned in case of an error.
   *   An array of Attribute objects, keyed by attribute name,
   *   e.g. title => [Attribute],
   *        field_image => [Attribute]
   */
  function GetProperties() {
    try {

      // Deprecated for Drupal 8.
      return array();
    } catch (\Exception $e) {
      return array();
    }
  }

  /**
   * Get fields for the entity, for example body or field_image.
   *
   * @return
   *   An empty array is returned in case of an error.
   *   An array of Attribute objects, keyed by attribute name,
   *   e.g. title => [\Drupal\realistic_dummy_content_api\attributes\Attribute],
   *        field_image => [...]
   */
  function GetFields() {
    try {
      $entity = $this
        ->GetEntity();

      // We now have an entity object, for example \Drupal\node\Entity\Node
      $modifiable_fields = $entity
        ->getFields();

      // $fields is now an array of things like nid, uuid, created, body,
      // field_image, etc.
      foreach ($modifiable_fields as $field => $object) {
        $this
          ->AddModifier($modifiable_fields, 'field_config', $field);
      }
      return $modifiable_fields;
    } catch (\Exception $e) {
      return array();
    }
  }

  /**
   * Helper function, returns the original class and attribute type from type and name.
   *
   * @param $type
   *   Either 'property' or 'field_config'
   * @param $name
   *   Name of the property or field, for example 'nid', 'body', 'picture', 'title',
   *  'field_image'.
   *
   * @return
   *   Associative array with:
   *     original_class => string, corresponds to the fully qualified (with namespace)
   *       class name of the class which should manipulate this type of attribute. For
   *       example, any fields are manipulate by a "value field" manipulator, and and
   *       any properties (titles, created) are manipulated by a text property
   *       manipulator. Certain fields are complex, though, so this module provides
   *       an alter hook (see hook_realistic_dummy_content_attribute_manipulator_alter()).
   *     attribute_type => string, corresponds the type of attribute with which we are
   *       dealing, for example text_with_summary, title...
   *
   * @throws
   *   Exception
   */
  protected function getBaseInfo($type, $name) {
    $full_name = $this
      ->getType() . '.' . $this
      ->getBundle() . '.' . $name;
    $field_info = entity_load('field_config', $full_name);
    if (!$field_info) {

      // if an field cannot be loaded, then it is a property
      $type = 'property';
    }
    switch ($type) {
      case 'property':
        $original_class = '\\Drupal\\realistic_dummy_content_api\\attributes\\TextProperty';
        $attribute_type = $name;
        break;
      case 'field_config':
        $original_class = '\\Drupal\\realistic_dummy_content_api\\attributes\\ValueField';
        $field_info = entity_load('field_config', $full_name);
        if (!$field_info) {
          throw new Exception('Unable to load field_config entity named ' . $full_name);
        }
        $attribute_type = $field_info
          ->getType();
        break;
      default:
        throw new Exception('Please use the type property or field_config');
        break;
    }
    $return = array(
      'original_class' => $original_class,
      'attribute_type' => $attribute_type,
    );
    return $return;
  }

  /**
   * Adds a modifier to a list of attribute modifiers.
   *
   * To abstract away the difference between fields and properties, we
   * call them all attributes. Modifiers will modify attributes depending on
   * what they are. For example, a user picture is modified differently than
   * an image in an article. This is managed through an extensible class
   * hierarchy. Modules, including this one, can implement
   * hook_realistic_dummy_content_attribute_manipular_alter() to determine
   * which class should modify which attribute (field or property).
   *
   * By default, we will consider that properties are text properties and that
   * fields' [value] property should be modified. This is not the case, however
   * for user pictures (which should load a file), body fields (which contain
   * a text format), and others. These are all defined in subclasses and can
   * be extended by module developers.
   *
   * @param &$modifiers
   *   Existing array of subclasses of Attribute, to which
   *   new modifiers will be added.
   * @param $type
   *   Either 'property' or 'field_config'
   * @param $name
   *   Name of the property or field, for example 'body', 'picture', 'title',
   *  'field_image'.
   *
   * @throws
   *   Exception
   */
  function AddModifier(&$modifiers, $type, $name) {
    $class = '';
    if (!$name) {
      throw new Exception('Name must not be empty');
    }
    if (!is_string($name)) {
      throw new Exception('Name must be a string');
    }
    $info = $this
      ->getBaseInfo($type, $name);
    $original_class = $info['original_class'];
    $attribute_type = $info['attribute_type'];
    $class = $original_class;
    \Drupal::moduleHandler()
      ->alter('realistic_dummy_content_attribute_manipulator', $class, $type, $attribute_type);
    if (!$class) {

      // third-parties might want to signal that certain fields cannot be
      // modified (they can be too complex for the default modifier and do not yet
      // have a custom modifier).
      return;
    }
    elseif (class_exists($class)) {
      $modifier = new $class($this, $name);
    }
    else {
      \Drupal::logger('realistic_dummy_content_api')
        ->notice(t('Class does not exist: @c. This might be because a third-party module has implemented realistic_dummy_content_api_realistic_dummy_content_attribute_manipular_alter() with a class that cannot be implemented, or which is not fully qualified with its namespace. @original will used instead.', array(
        '@c' => $class,
        '@original' => $original_class,
      )));
      $modifier = new $original_class($this, $name);
    }
    if (isset($modifier)) {

      // It's OK to index by name because attributes and fields can never have
      // the same names.
      $modifiers[$name] = $modifier;
    }
  }

  /**
   * {@inheritdoc}
   */
  function Modify() {
    $attributes = $this
      ->GetAttributes();
    foreach ($attributes as $attribute) {
      $attribute
        ->Change();
    }
  }

  /**
   * Returns all fields and properties.
   *
   * We implement fields and properties as subclasses of the same parent class,
   * which defines a common interface for dealing with them.
   *
   * @return
   *   An empty array if an error occurred, or an array of Attribute
   *   objects, keyed by attribute name,
   *     title => [Attribute],
   *     field_image => [Attribute]
   */
  function GetAttributes() {
    try {
      return array_merge($this
        ->GetFields(), $this
        ->GetProperties());
    } catch (\Exception $e) {
      return array();
    }
  }

  /**
   * Generate a random number, or during tests, give the first available number.
   */
  function rand($start, $end) {
    $return = realistic_dummy_content_api_rand($start, $end, $this
      ->GetHash());
    return $return;
  }

  /**
   * Get the uid property of this entity, or 0.
   *
   * @return
   *   The uid of the associated entity.
   */
  function GetUid() {
    $entity = $this
      ->GetEntity();
    if (isset($entity->uid)) {
      return $entity->uid;
    }
    else {
      return 0;
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Base::env function
EntityBase::$entity private property
EntityBase::$hash private property
EntityBase::$type private property
EntityBase::GetBundle function Get the bundle of the entity being manipulated.
EntityBase::GetEntity function Getter for the entity.
EntityBase::GetHash function Getter for the hash which uniquely identifies this entity.
EntityBase::GetType function Get the entity type of the entity being manipulated.
EntityBase::SetEntity function Updates the entity object.
EntityBase::__construct function Constructor.
FieldModifier::AddModifier function Adds a modifier to a list of attribute modifiers.
FieldModifier::GetAttributes function Returns all fields and properties.
FieldModifier::getBaseInfo protected function Helper function, returns the original class and attribute type from type and name.
FieldModifier::GetFields function Get fields for the entity, for example body or field_image.
FieldModifier::GetProperties function Get properties for the entity, for example user's picture or node's name.
FieldModifier::GetUid function Get the uid property of this entity, or 0.
FieldModifier::Modify function Modify the entity. Overrides EntityBase::Modify
FieldModifier::rand function Generate a random number, or during tests, give the first available number.