You are here

EntitySubject.php in Changed Fields API 8.3

File

src/EntitySubject.php
View source
<?php

namespace Drupal\changed_fields;

use Drupal\Core\Entity\ContentEntityInterface;

/**
 * Implements content entity subject.
 */
class EntitySubject implements \SplSubject {

  /**
   * Content entity to look at.
   *
   * @var Drupal\Core\Entity\ContentEntityInterface
   */
  protected $entity;

  /**
   * Map of names of changed fields with values.
   *
   * @var array
   */
  protected $changedFields;

  /**
   * Instance of field comparator plugin.
   *
   * @var Drupal\changed_fields\Plugin\FieldComparator\DefaultFieldComparator
   */
  protected $fieldComparatorPlugin;

  /**
   * Array of attached observers.
   *
   * @var array
   */
  protected $observers;

  /**
   * Constructs content entity subject.
   *
   * @param Drupal\Core\Entity\ContentEntityInterface $entity
   *   Content entity to look at.
   * @param string $field_comparator_plugin_id
   *   Field comparator plugin id.
   */
  public function __construct(ContentEntityInterface $entity, $field_comparator_plugin_id = 'default_field_comparator') {
    $this->entity = $entity;
    $this->changedFields = [];
    $this->fieldComparatorPlugin = \Drupal::service('plugin.manager.changed_fields.field_comparator')
      ->createInstance($field_comparator_plugin_id);
  }

  /**
   * {@inheritdoc}
   */
  public function attach(\SplObserver $observer) {
    if (!$observer instanceof ObserverInterface) {
      throw new \InvalidArgumentException('Observer must implement ObserverInterface interface.');
    }
    $this->observers[spl_object_hash($observer)] = $observer;
  }

  /**
   * {@inheritdoc}
   */
  public function detach(\SplObserver $observer) {
    if (!$observer instanceof ObserverInterface) {
      throw new \InvalidArgumentException('Observer must implement ObserverInterface interface.');
    }
    unset($this->observers[spl_object_hash($observer)]);
  }

  /**
   * {@inheritdoc}
   */
  public function notify() {
    if ($this->entity
      ->isNew()) {
      return;
    }
    foreach ($this->observers as $observer) {
      foreach ($observer
        ->getInfo() as $entity_type => $entity_bundles) {
        if ($this->entity
          ->getEntityTypeId() != $entity_type) {
          continue;
        }
        foreach ($entity_bundles as $bundle => $fields) {
          if ($this->entity
            ->bundle() != $bundle) {
            continue;
          }
          $changed_fields = [];
          foreach ($fields as $field_name) {

            // TODO: what if observer subscribed to un-existing fields?
            $old_value = $this->entity->original
              ->get($field_name)
              ->getValue();
            $new_value = $this->entity
              ->get($field_name)
              ->getValue();
            $field_definition = $this->entity
              ->get($field_name)
              ->getFieldDefinition();
            $result = $this->fieldComparatorPlugin
              ->compareFieldValues($field_definition, $old_value, $new_value);
            if (is_array($result)) {
              $changed_fields[$field_name] = $result;
            }
          }
          if (!empty($changed_fields)) {
            $this->changedFields = $changed_fields;
            $observer
              ->update($this);
          }
        }
      }
    }
  }

  /**
   * Returns entity object.
   *
   * @return Drupal\Core\Entity\ContentEntityInterface
   *   Content entity to look at.
   */
  public function getEntity() {
    return $this->entity;
  }

  /**
   * Returns changed fields.
   *
   * @return array
   *   Map of names of changed fields with values.
   */
  public function getChangedFields() {
    return $this->changedFields;
  }

}

Classes

Namesort descending Description
EntitySubject Implements content entity subject.