changed_fields.core.inc in Changed Fields API 7.2
Same filename and directory in other branches
File contains core classes and interfaces.
File
includes/changed_fields.core.incView source
<?php
/**
* @file
* File contains core classes and interfaces.
*/
/**
* Interface CFSubjectInterface.
*/
interface CFSubjectInterface {
/**
* Add observer to list.
*
* @param CFObserverInterface $observer
* Observer object to add.
*/
public function addObserver(CFObserverInterface $observer);
/**
* Remove observer from list.
*
* @param CFObserverInterface $observer
* Observer object to remove.
*/
public function removeObserver(CFObserverInterface $observer);
/**
* Notify all registered observers if needed.
*/
public function checkNodeFields();
/**
* Returns node object.
*/
public function getNode();
/**
* Returns changed fields.
*/
public function getChangedFields();
}
/**
* Interface CFObserverInterface.
*/
interface CFObserverInterface {
/**
* Update method with info about event.
*
* It is called by CFNodeSubject when node fields have been changed.
*
* @param CFSubjectInterface $nodeSubject
* Node subject object.
*/
public function update(CFSubjectInterface $nodeSubject);
/**
* Method to get observer id.
*/
public function getId();
}
/**
* Class CFObserver.
*/
abstract class CFObserver implements CFObserverInterface {
/**
* Observer unique identifier.
*
* @var string
*/
private $id;
/**
* Observer constructor.
*
* @param string $id
* Observer unique identifier.
*/
public function __construct($id) {
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public abstract function update(CFSubjectInterface $nodeSubject);
/**
* {@inheritdoc}
*/
public function getId() {
return $this->id;
}
}
/**
* Class CFNodeSubject.
*/
class CFNodeSubject implements CFSubjectInterface {
/**
* Node object.
*
* @var \stdClass
*/
private $node;
/**
* Info array.
*
* Array contains mapping for content types and fields to watch.
*
* @var array
*/
private $info;
/**
* Field comparator object.
*
* @var CFDefaultFieldComparator
*/
private $fieldComparator;
/**
* Array contains all registered observers.
*
* @var array
*/
private $observers;
/**
* Node subject constructor.
*
* @param \stdClass $node
* Node object.
* @param array $info
* Array contains mapping for content types and fields to watch.
* @param CFDefaultFieldComparator $fieldComparator
* Field comparator object.
*/
public function __construct(\stdClass $node, array $info, CFDefaultFieldComparator $fieldComparator) {
$this->node = $node;
$this->info = $info;
$this->fieldComparator = $fieldComparator;
}
/**
* {@inheritdoc}
*/
public function addObserver(CFObserverInterface $observer) {
$this->observers[$observer
->getId()] = $observer;
}
/**
* {@inheritdoc}
*/
public function removeObserver(CFObserverInterface $observer) {
unset($this->observers[$observer
->getId()]);
}
/**
* {@inheritdoc}
*/
public function checkNodeFields() {
foreach ($this->info as $nodeType => $fields) {
if (isset($this->node->original) && $this->node->type == $nodeType) {
$this->node->changed_fields = array();
foreach ($fields as $fieldName) {
if ($fieldName == 'title') {
$oldValue = $this->node->original->{$fieldName};
$newValue = $this->node->{$fieldName};
$fieldInfo['field_base'] = array(
'type' => 'title',
);
}
else {
$oldValue = field_get_items('node', $this->node->original, $fieldName);
$newValue = field_get_items('node', $this->node, $fieldName);
$fieldInfo['field_base'] = field_info_field($fieldName);
}
$fieldInfo['field_instance'] = field_info_instance('node', $fieldName, $nodeType);
$result = $this->fieldComparator
->runFieldComparison($fieldInfo, $oldValue, $newValue);
if (is_array($result)) {
$this->node->changed_fields[$fieldName] = $result;
}
}
if (!empty($this->node->changed_fields)) {
foreach ($this->observers as $observer) {
$observer
->update($this);
}
}
}
}
}
/**
* {@inheritdoc}
*/
public function getNode() {
return $this->node;
}
/**
* {@inheritdoc}
*/
public function getChangedFields() {
return $this->node->changed_fields;
}
}
/**
* Class CFDefaultFieldComparator.
*/
class CFDefaultFieldComparator {
/**
* Method that runs comparison of field values.
*
* @param array $fieldInfo
* Array contains field instance and field base information.
* @param mixed $oldValue
* Old field value to compare.
* @param mixed $newValue
* Old field value to compare.
*
* @return array|bool
* TRUE if fields are identical or array with differences if fields are
* different.
*/
public function runFieldComparison(array $fieldInfo, $oldValue, $newValue) {
$similarFields = TRUE;
if ($fieldInfo['field_base']['type'] == 'field_collection') {
// If collection was added or removed then we have already
// different collections.
if (!$oldValue && $newValue || $oldValue && !$newValue) {
$similarFields = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
}
else {
if ($oldValue && $newValue) {
// If value was added|removed to|from multi-value field then we have
// already different values.
if (count($newValue) != count($oldValue)) {
$similarFields = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
}
else {
foreach ($oldValue as $key => $fc) {
if (is_array($similarFields)) {
break;
}
$oldFc = entity_load('field_collection_item', array(
$fc['value'],
));
$oldFc = reset($oldFc);
$newFc = $newValue[$key]['entity'];
$fcFields = field_info_instances('field_collection_item', $fieldInfo['field_base']['field_name']);
foreach ($fcFields as $fcFieldName => $fcFieldData) {
$fcFieldData = field_info_field($fcFieldName);
$oldFcFieldValue = field_get_items('field_collection_item', $oldFc, $fcFieldName);
$newFcFieldValue = field_get_items('field_collection_item', $newFc, $fcFieldName);
$similarFields = $this
->runFieldComparison($fcFieldData, $oldFcFieldValue, $newFcFieldValue);
// If changes have been detected.
if (is_array($similarFields)) {
// Make result array with old and new
// field collection entities.
$similarFields = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
break;
}
}
}
}
}
}
}
else {
$similarFields = $this
->compareFieldValues($fieldInfo, $oldValue, $newValue);
}
return $similarFields;
}
/**
* Method that returns comparable properties for existing field type.
*
* @param array $fieldInfo
* Array contains field instance and field base information.
*
* @return array
* Array with properties that we need to use to compare two field values.
*/
private function getComparableProperties(array $fieldInfo) {
switch ($fieldInfo['field_base']['type']) {
case 'text_with_summary':
$properties = array(
'value',
'summary',
'format',
);
break;
case 'text':
case 'text_long':
case 'number_decimal':
case 'number_float':
case 'number_integer':
case 'list_float':
case 'list_integer':
case 'list_boolean':
case 'list_text':
case 'phone':
$properties = array(
'value',
);
break;
case 'taxonomy_term_reference':
$properties = array(
'tid',
);
break;
case 'entityreference':
$properties = array(
'target_id',
);
break;
case 'image':
$properties = array(
'fid',
'width',
'height',
);
if (!empty($fieldInfo['field_instance']['settings']['alt_field'])) {
$properties[] = 'alt';
}
if (!empty($fieldInfo['field_instance']['settings']['title_field'])) {
$properties[] = 'title';
}
break;
case 'file':
$properties = array(
'fid',
);
if (!empty($fieldInfo['field_instance']['settings']['description_field'])) {
$properties[] = 'description';
}
if (!empty($fieldInfo['field_instance']['settings']['display_field'])) {
$properties[] = 'display';
}
break;
case 'date':
case 'datetime':
case 'datestamp':
$properties = array(
'value',
'timezone',
);
break;
case 'email':
$properties = array(
'email',
);
break;
case 'link_field':
$properties = array(
'url',
'title',
);
break;
default:
$properties = $this
->getDefaultComparableProperties($fieldInfo);
break;
}
return $this
->extendComparableProperties($fieldInfo, $properties);
}
/**
* Method that returns comparable properties for extra or custom field type.
*
* Use it if you want to add comparison support
* for extra or custom field types.
*
* @param array $fieldInfo
* Array contains field instance and field base information.
*
* @return array
* Array with properties that system needs to use to compare two field
* values depends on custom or extra field type.
*/
protected function getDefaultComparableProperties(array $fieldInfo) {
return array();
}
/**
* Method that returns extended comparable properties for field type.
*
* Use it if you want to extend comparable properties for a given field type.
*
* @param array $fieldInfo
* Array contains field instance and field base information.
* @param array $properties
* Array with properties that we need to use to compare two field values.
*
* @return array
* Array with extended properties that system needs to use to compare two
* field values depends on core field type.
*/
protected function extendComparableProperties(array $fieldInfo, array $properties) {
return $properties;
}
/**
* Method that compares old and new field values.
*
* @param array $fieldInfo
* Array contains field instance and field base information.
* @param mixed $oldValue
* Old field value to compare.
* @param mixed $newValue
* New field value to compare.
*
* @return array|bool
* TRUE if fields are identical or array with differences if fields are
* different.
*/
private function compareFieldValues(array $fieldInfo, $oldValue, $newValue) {
$result = TRUE;
$properties = $this
->getComparableProperties($fieldInfo);
// If value was added or removed then we have already different values.
if (!$oldValue && $newValue || $oldValue && !$newValue) {
$result = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
}
else {
if ($oldValue && $newValue) {
// Simple comparison (for title).
if (empty($properties) && $fieldInfo['field_base']['type'] == 'title') {
if ($newValue != $oldValue) {
$result = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
}
}
else {
// If value was added|removed to|from multi-value field then we have
// already different values.
if (count($newValue) != count($oldValue)) {
$result = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
}
else {
// Walk through each field value and compare it's properties.
foreach ($newValue as $key => $value) {
if (is_array($result)) {
break;
}
foreach ($properties as $property) {
if (array_key_exists($property, $newValue[$key]) && array_key_exists($property, $oldValue[$key]) && $newValue[$key][$property] != $oldValue[$key][$property]) {
$result = $this
->makeResultArray($fieldInfo['field_base']['type'], $oldValue, $newValue);
break;
}
}
}
}
}
}
}
return $result;
}
/**
* Method that generates result array for CFDefaultFieldComparator::compareFieldValues().
*
* @param string $fieldType
* Field type.
* @param mixed $oldValue
* Old field value to compare.
* @param mixed $newValue
* New field value to compare.
*
* @return array
* Array with old and new field values for compareFieldValues() method.
*/
private function makeResultArray($fieldType, $oldValue, $newValue) {
// Return field collection item entities like field values for
// 'field_collection' field type.
if ($fieldType == 'field_collection') {
$resultOldValue = FALSE;
$resultNewValue = FALSE;
if ($oldValue) {
foreach ($oldValue as $key => $fc) {
$oldFc = entity_load('field_collection_item', array(
$fc['value'],
));
$oldFc = reset($oldFc);
$resultOldValue[] = $oldFc;
}
}
if ($newValue) {
foreach ($newValue as $key => $fc) {
$resultNewValue[] = $fc['entity'];
}
}
}
else {
$resultOldValue = $oldValue;
$resultNewValue = $newValue;
}
return array(
'old_value' => $resultOldValue,
'new_value' => $resultNewValue,
);
}
}
Classes
Name | Description |
---|---|
CFDefaultFieldComparator | Class CFDefaultFieldComparator. |
CFNodeSubject | Class CFNodeSubject. |
CFObserver | Class CFObserver. |
Interfaces
Name | Description |
---|---|
CFObserverInterface | Interface CFObserverInterface. |
CFSubjectInterface | Interface CFSubjectInterface. |