diff --git a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php index 1ef4245..4a730d1 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php @@ -234,8 +234,8 @@ protected function hasFieldValueChanged(FieldDefinitionInterface $field_definiti return TRUE; } - $items = $entity->getTranslation($langcode)->get($field_name); - $originalItems = $original->getTranslation($langcode)->get($field_name); + $items = $entity->getTranslation($langcode)->get($field_name)->filterEmptyItems(); + $originalItems = $original->getTranslation($langcode)->get($field_name)->filterEmptyItems(); // If the field items are not equal, we need to save. if (!$items->equals($originalItems)) { return TRUE; diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php index 58e66e1..86bac79 100644 --- a/core/lib/Drupal/Core/Field/FieldItemList.php +++ b/core/lib/Drupal/Core/Field/FieldItemList.php @@ -98,6 +98,7 @@ public function filterEmptyItems() { $this->filter(function ($item) { return !$item->isEmpty(); }); + return $this; } /** @@ -375,8 +376,6 @@ protected function defaultValueWidget(FormStateInterface $form_state) { */ public function equals(FieldItemListInterface $list_to_compare) { $columns = $this->getFieldDefinition()->getFieldStorageDefinition()->getColumns(); - $this->filterEmptyItems(); - $list_to_compare->filterEmptyItems(); $count1 = count($this); $count2 = count($list_to_compare); if ($count1 === 0 && $count2 === 0) { diff --git a/core/lib/Drupal/Core/Field/FieldItemListInterface.php b/core/lib/Drupal/Core/Field/FieldItemListInterface.php index f6078c6..e4ea12c 100644 --- a/core/lib/Drupal/Core/Field/FieldItemListInterface.php +++ b/core/lib/Drupal/Core/Field/FieldItemListInterface.php @@ -94,6 +94,8 @@ public function defaultAccess($operation = 'view', AccountInterface $account = N /** * Filters out empty field items and re-numbers the item deltas. + * + * @return $this */ public function filterEmptyItems(); diff --git a/core/tests/Drupal/Tests/Core/Field/FieldItemListTest.php b/core/tests/Drupal/Tests/Core/Field/FieldItemListTest.php index b694f5d..65e996e 100644 --- a/core/tests/Drupal/Tests/Core/Field/FieldItemListTest.php +++ b/core/tests/Drupal/Tests/Core/Field/FieldItemListTest.php @@ -43,18 +43,9 @@ public function testEquals($expected, FieldItemInterface $first_field_item = NUL $field_list_b = new FieldItemList($field_definition); // Set up the mocking necessary for creating field items. - $at = 0; - if ($first_field_item instanceof FieldItemInterface) { - $field_type_manager->expects($this->at($at)) - ->method('createFieldItem') - ->willReturn($first_field_item); - $at++; - } - if ($second_field_item instanceof FieldItemInterface) { - $field_type_manager->expects($this->at($at)) - ->method('createFieldItem') - ->willReturn($second_field_item); - } + $field_type_manager->expects($this->any()) + ->method('createFieldItem') + ->willReturnOnConsecutiveCalls($first_field_item, $second_field_item); // Set the field item values. if ($first_field_item instanceof FieldItemInterface) { @@ -100,4 +91,59 @@ public function providerTestEquals() { return $datasets; } + + /** + * @covers ::equals + */ + public function testEqualsEmptyItems() { + /** @var \Drupal\Core\Field\FieldItemBase $fv */ + $first_field_item = $this->getMockForAbstractClass('Drupal\Core\Field\FieldItemBase', [], '', FALSE); + $first_field_item->setValue(['0' => 1, '1' => 2]); + $second_field_item = $this->getMockForAbstractClass('Drupal\Core\Field\FieldItemBase', [], '', FALSE); + $second_field_item->setValue(['1' => 2, '0' => 1]); + $empty_field_item = $this->getMockForAbstractClass('Drupal\Core\Field\FieldItemBase', [], '', FALSE); + // Mock the field type manager and place it in the container. + $field_type_manager = $this->getMock('Drupal\Core\Field\FieldTypePluginManagerInterface'); + $container = new ContainerBuilder(); + $container->set('plugin.manager.field.field_type', $field_type_manager); + \Drupal::setContainer($container); + + $field_storage_definition = $this->getMock('Drupal\Core\Field\FieldStorageDefinitionInterface'); + $field_storage_definition->expects($this->any()) + ->method('getColumns') + ->willReturn([0 => '0', 1 => '1']); + $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface'); + $field_definition->expects($this->any()) + ->method('getFieldStorageDefinition') + ->willReturn($field_storage_definition); + + $field_list_a = new FieldItemList($field_definition); + $field_list_b = new FieldItemList($field_definition); + + // Set up the mocking necessary for creating field items. + $field_type_manager->expects($this->any()) + ->method('createFieldItem') + ->willReturnOnConsecutiveCalls($first_field_item, $second_field_item, $empty_field_item, $empty_field_item); + + // Set the field item values. + $field_list_a->setValue($first_field_item); + $field_list_b->setValue($second_field_item); + $field_list_a->appendItem($empty_field_item); + + // Field list A has an empty item. + $this->assertEquals(FALSE, $field_list_a->equals($field_list_b)); + + // Field lists A and B have empty items. + $field_list_b->appendItem($empty_field_item); + $this->assertEquals(TRUE, $field_list_a->equals($field_list_b)); + + // Field list B has an empty item. + $field_list_a->filterEmptyItems(); + $this->assertEquals(FALSE, $field_list_a->equals($field_list_b)); + + // Neither field lists A and B have empty items. + $field_list_b->filterEmptyItems(); + $this->assertEquals(TRUE, $field_list_a->equals($field_list_b)); + } + }