You are here

FieldModifier.php in Realistic Dummy Content 8

Define autoload class.

File

api/src/manipulators/FieldModifier.php
View source
<?php

/**
 * @file
 *
 * Define autoload class.
 */
namespace Drupal\realistic_dummy_content_api\manipulators;

use Drupal\realistic_dummy_content_api\manipulators\EntityBase;
use Drupal\realistic_dummy_content_api\attributes\Field;
use Drupal\realistic_dummy_content_api\attributes\TextProperty;
use Drupal\realistic_dummy_content_api\attributes\ValueField;
use Drupal\realistic_dummy_content_api\environments\Drupal;
use Drupal\realistic_dummy_content_api\loggers\Exception;

/**
 * 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...).
 */
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;
    }
  }

}

Classes

Namesort descending Description
FieldModifier Field modifier class.