Upgrade Your Drupal Skills
We trained 1,000+ Drupal Developers over the last decade.
See Advanced Courses NAH, I know EnoughChanged Fields API
Changed Fields API supports all the core's field types both for Drupal 7 and Drupal 8. But for Drupal 7 it supports even more. Please visit the project page to find out more information.
Changed Fields API is built on "Observer" pattern. The idea is pretty simple: attach observers to a node subject which will notify all of them about changes in node fields. If you are not familiar with this pattern yet then I suggest you read about it and consider this simple example. So let's find out how to use this API. An example below is based on changed_fields_basic_usage and changed_fields_extended_field_comparator demo modules that are the part of Changed Fields API module.
Observer
<?php /** * @file * Contains BasicUsageObserver.php. */ namespace Drupal\changed_fields_basic_usage; use Drupal\changed_fields\ObserverInterface; use SplSubject; /** * Class BasicUsageObserver. */ class BasicUsageObserver implements ObserverInterface { /** * {@inheritdoc} */ public function getInfo() { return [ 'article' => [ 'title', 'body', ], ]; } /** * {@inheritdoc} */ public function update(SplSubject $nodeSubject) { $node = $nodeSubject->getNode(); $changedFields = $nodeSubject->getChangedFields(); // Do something with $node depends on $changedFields. } }
So here we defined that we want to listen to article content type and we want to check only title and body fields.
Node presave
- Wrap a node object into an instance of
NodeSubject
class and set up the field comparator. Field comparator is an object which checks needed fields and returns differences between old and new field values. Default comparator isdefault_field_comparator
but you can define your own by extending default one. - Then attach your observer
BasicUsageObserver
to instance ofNodeSubject class.
- Finally, execute
NodeSubject::notify()
method and react on this event inBasicUsageObserver::update(SplSubject $nodeSubject)
if some of the field values of registered node types have been changed.
<?php /** * @file * Contains changed_fields_basic_usage.module. */ use Drupal\changed_fields\NodeSubject; use Drupal\changed_fields_basic_usage\BasicUsageObserver; use Drupal\node\NodeInterface; /** * Implements hook_node_presave(). */ function changed_fields_basic_usage_node_presave(NodeInterface $node) { // Create NodeSubject object that will check node fields by DefaultFieldComparator. $nodeSubject = new NodeSubject($node, 'default_field_comparator'); // Add your observer object to NodeSubject. $nodeSubject->attach(new BasicUsageObserver()); // Check if node fields have been changed. $nodeSubject->notify(); }
Basically, that's all but you can say "what about field types that is not supported by Changed Fields API. How can I handle them?". Well, you're right, API supports a limited bunch of field types but it's easy to extend it.
By default, Changed Fields API comes with default_field_comparator
class which supports all the core Drupal's field types. But if you have a field type from a contrib module you have to tell the API how to compare that fields. In order to do that you have to write a custom field comparator.
Custom field comparator
module_name/src/Plugin/FieldComparator
directory. So we need to define a class, extend it from DefaultFieldComparator
and override method DefaultFieldComparator::getDefaultComparableProperties(FieldDefinitionInterface $fieldDefinition)
. All that you need is return field properties to compare depends on a field type. For example for text_with_summary
fields API returns array('value', 'summary').
<?php /** * @file * Contains ExtendedFieldComparator.php. */ namespace Drupal\changed_fields_extended_field_comparator\Plugin\FieldComparator; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\changed_fields\Plugin\FieldComparator\DefaultFieldComparator; /** * @Plugin( * id = "extended_field_comparator" * ) */ class ExtendedFieldComparator extends DefaultFieldComparator { /** * {@inheritdoc} */ public function getDefaultComparableProperties(FieldDefinitionInterface $fieldDefinition) { $properties = []; // Return comparable field properties for extra or custom field type. if ($fieldDefinition->getType() == 'some_field_type') { $properties = [ 'some_field_property_1', 'some_field_property_2', ]; } return $properties; } }
Here we assume that we have a custom field type some_field_type with properties some_field_property_1 and some_field_property_2. In order to compare such fields, we need to tell node subject that it should use our newly defined field comparator:
<?php /** * @file * Contains changed_fields_extended_field_comparator.module. */ use Drupal\changed_fields\NodeSubject; use Drupal\changed_fields_extended_field_comparator\ExtendedFieldComparatorObserver; use Drupal\node\NodeInterface; /** * Implements hook_node_presave(). */ function changed_fields_extended_field_comparator_node_presave(NodeInterface $node) { // Create NodeSubject object that will check node fields by your ExtendedFieldComparator. $nodeSubject = new NodeSubject($node, 'extended_field_comparator'); ... }
Cool, now we know how to add support for custom or additional contrib fields. But there might be cases when you want, for example, compare
text_with_summary
fields only by value
property (by default API compares it by format
and summary
properties as well). In this case you need to override DefaultFieldComparator::extendComparableProperties(FieldDefinitionInterface $fieldDefinition, array $properties)
method like this one:public function extendComparableProperties(FieldDefinitionInterface $fieldDefinition, array $properties) { if ($fieldDefinition->getType() == 'text_with_summary') { unset($properties[array_search('summary', $properties)]); unset($properties[array_search('format', $properties)]); } return $properties; }
When it's done changes in field's
summary
or format
properties will not be taken into consideration by the API.Additional info
About Drupal Sun
Drupal Sun is an Evolving Web project. It allows you to:
- Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
- Facet based on tags, author, or feed
- Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
- View the entire article text inline, or in the context of the site where it was created
See the blog post at Evolving Web