diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module index 3031931afec29b22e0ae95103470cfab9ef96d62..6e52d9e3655f02c9d431d1f144ebbb6f9376700b 100644 --- a/core/modules/editor/editor.module +++ b/core/modules/editor/editor.module @@ -396,13 +396,19 @@ function editor_entity_update(EntityInterface $entity) { // File references that existed both in the previous version of the revision // and in the new one don't need their usage to be updated. else { - $original_uuids_by_field = _editor_get_file_uuids_by_field($entity->original); + $original_uuids_by_field = empty($entity->original) ? [] : + _editor_get_file_uuids_by_field($entity->original); + $uuids_by_field = _editor_get_file_uuids_by_field($entity); // Detect file usages that should be incremented. foreach ($uuids_by_field as $field => $uuids) { - $added_files = array_diff($uuids_by_field[$field], $original_uuids_by_field[$field]); - _editor_record_file_usage($added_files, $entity); + $original_uuids = isset($original_uuids_by_field[$field]) ? + $original_uuids_by_field[$field] : []; + + if ($added_files = array_diff($uuids_by_field[$field], $original_uuids)) { + _editor_record_file_usage($added_files, $entity); + } } // Detect file usages that should be decremented. diff --git a/core/modules/editor/tests/modules/editor_test.module b/core/modules/editor/tests/modules/editor_test.module index 70fe59fa4151a984bc6f688e712cd3ddd4d79547..bdb7292d62a83ac1801728de8c8fc14121ba2a93 100644 --- a/core/modules/editor/tests/modules/editor_test.module +++ b/core/modules/editor/tests/modules/editor_test.module @@ -5,9 +5,45 @@ * Helper module for the Text Editor tests. */ +use Drupal\Core\Entity\EntityInterface; +use Drupal\node\NodeInterface; use Drupal\filter\FilterFormatInterface; use Drupal\file\FileInterface; +/** + * Implements hook_entity_update(). + * + * @see \Drupal\Tests\editor\Kernel\EntityUpdateTest + */ +function editor_test_entity_update(EntityInterface $entity) { + // Only act on nodes. + if (!$entity instanceof NodeInterface) { + return; + } + + // Avoid infinite loop by only going through our post save logic once. + if (!empty($entity->editor_test_updating)) { + return; + } + + // Set flag for whether or not the entity needs to be resaved. + $needs_update = FALSE; + + // Perform our post save logic. + if ($entity->title->value == 'test updated') { + // Change the node title. + $entity->title->value = 'test updated 2'; + $needs_update = TRUE; + } + + if ($needs_update) { + // Set flag on entity that our logic was already executed. + $entity->editor_test_updating = TRUE; + // And resave entity. + $entity->save(); + } +} + /** * Implements hook_editor_js_settings_alter(). */ diff --git a/core/modules/editor/tests/src/Kernel/EntityUpdateTest.php b/core/modules/editor/tests/src/Kernel/EntityUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1a454ea349e432cdb9d07d27fca0ca6e0770a8e6 --- /dev/null +++ b/core/modules/editor/tests/src/Kernel/EntityUpdateTest.php @@ -0,0 +1,68 @@ +<?php + +namespace Drupal\Tests\editor\Kernel; + +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\node\Entity\NodeType; +use Drupal\node\Entity\Node; + +/** + * Tests updating an entity. + * + * @group editor + */ +class EntityUpdateTest extends EntityKernelTestBase { + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = ['editor', 'editor_test', 'node']; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $this->installSchema('node', ['node_access']); + $this->installConfig(['node']); + + // Create a node type for testing. + $type = NodeType::create(['type' => 'page', 'name' => 'page']); + $type->save(); + + // Set editor_test module weight to be lower than editor module's weight so + // that editor_test_entity_update() is called before editor_entity_update(). + $extension_config = \Drupal::configFactory()->get('core.extension'); + $editor_module_weight = $extension_config->get('module.editor'); + module_set_weight('editor_test', $editor_module_weight - 1); + } + + /** + * Tests updating an existing entity. + * + * @see editor_test_entity_update() + */ + public function testEntityUpdate() { + // Create a node. + $node = Node::create([ + 'type' => 'page', + 'title' => 'test', + ]); + $node->save(); + + // Update the node. + // What happens is the following: + // 1. \Drupal\Core\Entity\EntityStorageBase::doPostSave() gets called. + // 2. editor_test_entity_update() gets called. + // 3. A resave of the updated entity gets triggered (second save call). + // 4. \Drupal\Core\Entity\EntityStorageBase::doPostSave() gets called. + // 5. editor_test_entity_update() gets called. + // 6. editor_entity_update() gets called (caused by the second save call). + // 7. editor_entity_update() gets called (caused by the first save call). + $node->title->value = 'test updated'; + $node->save(); + } + +}