diff --git a/core/lib/Drupal/Core/Entity/EntityCreateAnyAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityCreateAnyAccessCheck.php index a6ff09430dd7285e2d50f07166b7b644787e1f20..e0e24a2f9ea200b9847234b7a644d71bbeba8c49 100644 --- a/core/lib/Drupal/Core/Entity/EntityCreateAnyAccessCheck.php +++ b/core/lib/Drupal/Core/Entity/EntityCreateAnyAccessCheck.php @@ -78,13 +78,15 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn if ($entity_type->getBundleEntityType()) { $access->addCacheTags($this->entityTypeManager->getDefinition($entity_type->getBundleEntityType())->getListCacheTags()); - // Check if the user is allowed to create new bundles. If so, allow - // access, so the add page can show a link to create one. - // @see \Drupal\Core\Entity\Controller\EntityController::addPage() - $bundle_access_control_handler = $this->entityTypeManager->getAccessControlHandler($entity_type->getBundleEntityType()); - $access = $access->orIf($bundle_access_control_handler->createAccess(NULL, $account, [], TRUE)); - if ($access->isAllowed()) { - return $access; + if (empty($route->getOption('_ignore_create_bundle_access'))) { + // Check if the user is allowed to create new bundles. If so, allow + // access, so the add page can show a link to create one. + // @see \Drupal\Core\Entity\Controller\EntityController::addPage() + $bundle_access_control_handler = $this->entityTypeManager->getAccessControlHandler($entity_type->getBundleEntityType()); + $access = $access->orIf($bundle_access_control_handler->createAccess(NULL, $account, [], TRUE)); + if ($access->isAllowed()) { + return $access; + } } } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php index e15fe848bf009dd0b1901eed7f3d1c065ee821ab..5550ede34a7d02e285d55f26da45bf320fd96db1 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php @@ -64,7 +64,12 @@ public function setValue($values, $notify = TRUE) { $values = $values->getValue(); } else { - $values = unserialize($values); + if (version_compare(PHP_VERSION, '7.0.0', '>=')) { + $values = unserialize($values, ['allowed_classes' => FALSE]); + } + else { + $values = unserialize($values); + } } } diff --git a/core/modules/hal/src/Normalizer/FieldItemNormalizer.php b/core/modules/hal/src/Normalizer/FieldItemNormalizer.php index 349c4fd5e70307e3e0df807ff9e324aba0a7ef7a..de7ff4b771b7676db3de8095e50935d8a70fdd9b 100644 --- a/core/modules/hal/src/Normalizer/FieldItemNormalizer.php +++ b/core/modules/hal/src/Normalizer/FieldItemNormalizer.php @@ -5,6 +5,7 @@ use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\TypedData\TypedDataInternalPropertiesHelper; use Drupal\serialization\Normalizer\FieldableEntityNormalizerTrait; +use Drupal\serialization\Normalizer\SerializedColumnNormalizerTrait; use Symfony\Component\Serializer\Exception\InvalidArgumentException; /** @@ -13,6 +14,7 @@ class FieldItemNormalizer extends NormalizerBase { use FieldableEntityNormalizerTrait; + use SerializedColumnNormalizerTrait; /** * {@inheritdoc} @@ -45,6 +47,7 @@ public function denormalize($data, $class, $format = NULL, array $context = []) } $field_item = $context['target_instance']; + $this->checkForSerializedStrings($data, $class, $field_item); // If this field is translatable, we need to create a translated instance. if (isset($data['lang'])) { diff --git a/core/modules/hal/tests/src/Kernel/DenormalizeTest.php b/core/modules/hal/tests/src/Kernel/DenormalizeTest.php index 87eb97329f003a3044e875ac4c528b7183330266..fde694fa690f362bdc8416d4ab76446d2c559946 100644 --- a/core/modules/hal/tests/src/Kernel/DenormalizeTest.php +++ b/core/modules/hal/tests/src/Kernel/DenormalizeTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\hal\Kernel; use Drupal\Core\Url; +use Drupal\entity_test\Entity\EntitySerializedField; use Drupal\field\Entity\FieldConfig; use Symfony\Component\Serializer\Exception\UnexpectedValueException; diff --git a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php index 8fa765e0b6cb551f2b6719b781885f90ae4f94d8..431512c290cb08b9e2b0316ac026e92dd32c3a8c 100644 --- a/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php +++ b/core/modules/link/src/Plugin/Field/FieldType/LinkItem.php @@ -191,7 +191,12 @@ public function setValue($values, $notify = TRUE) { // SqlContentEntityStorage::loadFieldItems, see // https://www.drupal.org/node/2414835 if (is_string($values['options'])) { - $values['options'] = unserialize($values['options']); + if (version_compare(PHP_VERSION, '7.0.0', '>=')) { + $values['options'] = unserialize($values['options'], ['allowed_classes' => FALSE]); + } + else { + $values['options'] = unserialize($values['options']); + } } parent::setValue($values, $notify); } diff --git a/core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php b/core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php index 264d610604d69756c118e57ba55b5c81390045c2..a69748ff38458d85ffd719232fb04bd39d4b334f 100644 --- a/core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php +++ b/core/modules/media/tests/src/Functional/Rest/MediaResourceTestBase.php @@ -359,7 +359,7 @@ protected function uploadFile() { // To still run the complete test coverage for POSTing a Media entity, we // must revoke the additional permissions that we granted. - $role = Role::load(static::$auth ? RoleInterface::AUTHENTICATED_ID : RoleInterface::AUTHENTICATED_ID); + $role = Role::load(static::$auth ? RoleInterface::AUTHENTICATED_ID : RoleInterface::ANONYMOUS_ID); $role->revokePermission('create camelids media'); $role->trustData()->save(); } diff --git a/core/modules/node/src/NodeAccessControlHandler.php b/core/modules/node/src/NodeAccessControlHandler.php index 5ccc6425e36daf45dab23af61fe64dc14536b826..7fd27dea0403a7bb14649d64badb9d5ef2fc186a 100644 --- a/core/modules/node/src/NodeAccessControlHandler.php +++ b/core/modules/node/src/NodeAccessControlHandler.php @@ -80,7 +80,7 @@ public function createAccess($entity_bundle = NULL, AccountInterface $account = return $return_as_object ? $result : $result->isAllowed(); } if (!$account->hasPermission('access content')) { - $result = AccessResult::forbidden()->cachePerPermissions(); + $result = AccessResult::forbidden("The 'access content' permission is required.")->cachePerPermissions(); return $return_as_object ? $result : $result->isAllowed(); } diff --git a/core/modules/node/tests/src/Functional/Rest/NodeResourceTestBase.php b/core/modules/node/tests/src/Functional/Rest/NodeResourceTestBase.php index 9f9a114924fde51a8a0c68c54fbff6dadabe0a0f..ebf967ed64d725f250c35c6d7ffdf9124c48b82d 100644 --- a/core/modules/node/tests/src/Functional/Rest/NodeResourceTestBase.php +++ b/core/modules/node/tests/src/Functional/Rest/NodeResourceTestBase.php @@ -210,7 +210,7 @@ protected function getExpectedUnauthorizedAccessMessage($method) { return parent::getExpectedUnauthorizedAccessMessage($method); } - if ($method === 'GET' || $method == 'PATCH' || $method == 'DELETE') { + if ($method === 'GET' || $method == 'PATCH' || $method == 'DELETE' || $method == 'POST') { return "The 'access content' permission is required."; } return parent::getExpectedUnauthorizedAccessMessage($method); diff --git a/core/modules/rest/rest.post_update.php b/core/modules/rest/rest.post_update.php index 8ed5a6dbff124f821c031a24e2ca98c7800da0ab..e1e1d20301f6380f3ffeffce337d206fc6306d63 100644 --- a/core/modules/rest/rest.post_update.php +++ b/core/modules/rest/rest.post_update.php @@ -61,3 +61,10 @@ function rest_post_update_resource_granularity() { } } } + +/** + * Clear caches due to changes in route definitions. + */ +function rest_post_update_161923() { + // Empty post-update hook. +} diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php index a56de490abfaa886aa17ce2594efa05592408727..988b6415a6434fdd13f343205b0b0907ce05fe25 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php @@ -377,6 +377,10 @@ protected function getBaseRoute($canonical_path, $method) { case 'GET': $route->setRequirement('_entity_access', $this->entityType->id() . '.view'); break; + case 'POST': + $route->setRequirement('_entity_create_any_access', $this->entityType->id()); + $route->setOption('_ignore_create_bundle_access', TRUE); + break; case 'PATCH': $route->setRequirement('_entity_access', $this->entityType->id() . '.update'); break; diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index 7b6011ee06762a6a03c6ed08125668af87e6a3c6..1bc41be84e3d42d58d98b3a156b2963011433076 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -872,18 +872,6 @@ public function testPost() { $request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType; - // DX: 400 when no request body. - $response = $this->request('POST', $url, $request_options); - $this->assertResourceErrorResponse(400, 'No entity content received.', $response); - - $request_options[RequestOptions::BODY] = $unparseable_request_body; - - // DX: 400 when unparseable request body. - $response = $this->request('POST', $url, $request_options); - $this->assertResourceErrorResponse(400, 'Syntax error', $response); - - $request_options[RequestOptions::BODY] = $parseable_invalid_request_body; - if (static::$auth) { // DX: forgetting authentication: authentication provider-specific error // response. @@ -895,16 +883,22 @@ public function testPost() { // DX: 403 when unauthorized. $response = $this->request('POST', $url, $request_options); - // @todo Remove this if-test in https://www.drupal.org/project/drupal/issues/2820364 - if (static::$entityTypeId === 'media' && !static::$auth) { - $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nname: Name: this field cannot hold more than 1 values.\nfield_media_file.0: You do not have access to the referenced entity (file: 3).\n", $response); - } - else { - $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response); - } + $this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('POST'), $response); $this->setUpAuthorization('POST'); + // DX: 400 when no request body. + $response = $this->request('POST', $url, $request_options); + $this->assertResourceErrorResponse(400, 'No entity content received.', $response); + + $request_options[RequestOptions::BODY] = $unparseable_request_body; + + // DX: 400 when unparseable request body. + $response = $this->request('POST', $url, $request_options); + $this->assertResourceErrorResponse(400, 'Syntax error', $response); + + $request_options[RequestOptions::BODY] = $parseable_invalid_request_body; + // DX: 422 when invalid entity: multiple values sent for single-value field. $response = $this->request('POST', $url, $request_options); $label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName; diff --git a/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php b/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php index a463956b6242cb7c8f7aa821185ee1e8b99ac9ed..2af0afc86ab03111c444ef8453f77dbde567bc7e 100644 --- a/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php +++ b/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php @@ -12,6 +12,7 @@ class FieldItemNormalizer extends ComplexDataNormalizer implements DenormalizerInterface { use FieldableEntityNormalizerTrait; + use SerializedColumnNormalizerTrait; /** * {@inheritdoc} @@ -32,6 +33,7 @@ public function denormalize($data, $class, $format = NULL, array $context = []) /** @var \Drupal\Core\Field\FieldItemInterface $field_item */ $field_item = $context['target_instance']; + $this->checkForSerializedStrings($data, $class, $field_item); $field_item->setValue($this->constructValue($data, $context)); return $field_item; diff --git a/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php b/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php index 3eff65a9be1e5f4374091ecf5d54c57bf3a861b3..0240da8f3b9b5476f272c9fa7aff3a01fa6f139b 100644 --- a/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php +++ b/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php @@ -223,15 +223,24 @@ protected function constructValue($data, $context) { assert($item_definition instanceof FieldItemDataDefinitionInterface); $property_definitions = $item_definition->getPropertyDefinitions(); - if (!is_array($data)) { - $property_value = $data; - $property_value_class = $property_definitions[$item_definition->getMainPropertyName()]->getClass(); + $serialized_property_names = $this->getCustomSerializedPropertyNames($field_item); + $denormalize_property = function ($property_name, $property_value, $property_value_class, $context) use ($serialized_property_names) { if ($this->serializer->supportsDenormalization($property_value, $property_value_class, NULL, $context)) { return $this->serializer->denormalize($property_value, $property_value_class, NULL, $context); } else { + if (in_array($property_name, $serialized_property_names, TRUE)) { + $property_value = serialize($property_value); + } return $property_value; } + }; + + if (!is_array($data)) { + $property_value = $data; + $property_name = $item_definition->getMainPropertyName(); + $property_value_class = $property_definitions[$property_name]->getClass(); + return $denormalize_property($property_name, $property_value, $property_value_class, $context); } $data_internal = []; @@ -243,12 +252,7 @@ protected function constructValue($data, $context) { } $property_value = $data[$property_name]; $property_value_class = $property_definition->getClass(); - if ($this->serializer->supportsDenormalization($property_value, $property_value_class, NULL, $context)) { - $data_internal[$property_name] = $this->serializer->denormalize($property_value, $property_value_class, NULL, $context); - } - else { - $data_internal[$property_name] = $property_value; - } + $data_internal[$property_name] = $denormalize_property($property_name, $property_value, $property_value_class, $context); } } else { diff --git a/core/modules/serialization/src/Normalizer/PrimitiveDataNormalizer.php b/core/modules/serialization/src/Normalizer/PrimitiveDataNormalizer.php index 7294d6f051a0ce9fcc7e14fba28ea0e03a71cabf..a594757e7dca7e4bc94b18e9db09e7785ca41e14 100644 --- a/core/modules/serialization/src/Normalizer/PrimitiveDataNormalizer.php +++ b/core/modules/serialization/src/Normalizer/PrimitiveDataNormalizer.php @@ -2,6 +2,7 @@ namespace Drupal\serialization\Normalizer; +use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\TypedData\PrimitiveInterface; /** @@ -9,6 +10,8 @@ */ class PrimitiveDataNormalizer extends NormalizerBase { + use SerializedColumnNormalizerTrait; + /** * {@inheritdoc} */ @@ -18,6 +21,14 @@ class PrimitiveDataNormalizer extends NormalizerBase { * {@inheritdoc} */ public function normalize($object, $format = NULL, array $context = []) { + $parent = $object->getParent(); + if ($parent instanceof FieldItemInterface && $object->getValue()) { + $serialized_property_names = $this->getCustomSerializedPropertyNames($parent); + if (in_array($object->getName(), $serialized_property_names, TRUE)) { + return unserialize($object->getValue()); + } + } + // Typed data casts NULL objects to their empty variants, so for example // the empty string ('') for string type data, or 0 for integer typed data. // In a better world with typed data implementing algebraic data types, diff --git a/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php b/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..bf6eb0643cd51fd474afbd1a8837f88bd6812a98 --- /dev/null +++ b/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php @@ -0,0 +1,116 @@ +<?php + +namespace Drupal\serialization\Normalizer; + +use Drupal\Component\Plugin\PluginInspectionInterface; +use Drupal\Core\Field\FieldItemInterface; + +/** + * A trait providing methods for serialized columns. + */ +trait SerializedColumnNormalizerTrait { + + /** + * Checks if there is a serialized string for a column. + * + * @param mixed $data + * The field item data to denormalize. + * @param string $class + * The expected class to instantiate. + * @param \Drupal\Core\Field\FieldItemInterface $field_item + * The field item. + */ + protected function checkForSerializedStrings($data, $class, FieldItemInterface $field_item) { + // Require specialized denormalizers for fields with 'serialize' columns. + // Note: this cannot be checked in ::supportsDenormalization() because at + // that time we only have the field item class. ::hasSerializeColumn() + // must be able to call $field_item->schema(), which requires a field + // storage definition. To determine that, the entity type and bundle + // must be known, which is contextual information that the Symfony + // serializer does not pass to ::supportsDenormalization(). + if (!is_array($data)) { + $data = [$field_item->getDataDefinition()->getMainPropertyName() => $data]; + } + if ($this->dataHasStringForSerializeColumn($field_item, $data)) { + $field_name = $field_item->getParent() ? $field_item->getParent()->getName() : $field_item->getName(); + throw new \LogicException(sprintf('The generic FieldItemNormalizer cannot denormalize string values for "%s" properties of the "%s" field (field item class: %s).', implode('", "', $this->getSerializedPropertyNames($field_item)), $field_name, $class)); + } + } + + /** + * Checks if the data contains string value for serialize column. + * + * @param \Drupal\Core\Field\FieldItemInterface $field_item + * The field item. + * @param array $data + * The data being denormalized. + * + * @return bool + * TRUE if there is a string value for serialize column, otherwise FALSE. + */ + protected function dataHasStringForSerializeColumn(FieldItemInterface $field_item, array $data) { + foreach ($this->getSerializedPropertyNames($field_item) as $property_name) { + if (isset($data[$property_name]) && is_string($data[$property_name])) { + return TRUE; + } + } + return FALSE; + } + + /** + * Gets the names of all serialized properties. + * + * @param \Drupal\Core\Field\FieldItemInterface $field_item + * The field item. + * + * @return string[] + * The property names for serialized properties. + */ + protected function getSerializedPropertyNames(FieldItemInterface $field_item) { + $field_storage_definition = $field_item->getFieldDefinition()->getFieldStorageDefinition(); + + if ($custom_property_names = $this->getCustomSerializedPropertyNames($field_item)) { + return $custom_property_names; + } + + $field_storage_schema = $field_item->schema($field_storage_definition); + // If there are no columns then there are no serialized properties. + if (!isset($field_storage_schema['columns'])) { + return []; + } + $serialized_columns = array_filter($field_storage_schema['columns'], function ($column_schema) { + return isset($column_schema['serialize']) && $column_schema['serialize'] === TRUE; + }); + return array_keys($serialized_columns); + } + + /** + * Gets the names of all properties the plugin treats as serialized data. + * + * This allows the field storage definition or entity type to provide a + * setting for serialized properties. This can be used for fields that + * handle serialized data themselves and do not rely on the serialized schema + * flag. + * + * @param \Drupal\Core\Field\FieldItemInterface $field_item + * The field item. + * + * @return string[] + * The property names for serialized properties. + */ + protected function getCustomSerializedPropertyNames(FieldItemInterface $field_item) { + if ($field_item instanceof PluginInspectionInterface) { + $definition = $field_item->getPluginDefinition(); + $serialized_fields = $field_item->getEntity()->getEntityType()->get('serialized_field_property_names'); + $field_name = $field_item->getFieldDefinition()->getName(); + if (is_array($serialized_fields) && isset($serialized_fields[$field_name]) && is_array($serialized_fields[$field_name])) { + return $serialized_fields[$field_name]; + } + if (isset($definition['serialized_property_names']) && is_array($definition['serialized_property_names'])) { + return $definition['serialized_property_names']; + } + } + return []; + } + +} diff --git a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php index c95a9d96e60f6a7af84a15a45e91ef5eadf9eaf0..e9dcf5c50483d5fa4d6075c5b15b7a62606e1eaa 100644 --- a/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php +++ b/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php @@ -4,6 +4,7 @@ use Drupal\Component\Serialization\Json; use Drupal\Component\Render\FormattableMarkup; +use Drupal\entity_test\Entity\EntitySerializedField; use Drupal\entity_test\Entity\EntityTestMulRev; use Drupal\filter\Entity\FilterFormat; use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait; diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php index 67bd3b6625579f8170dfb1addd6666ee9f4f6ab6..a783d0928c630a0b37209f73f20c4a48ded7d6c9 100644 --- a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php +++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\serialization\Unit\Normalizer; use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\TypedData\FieldItemDataDefinition; use Drupal\Core\GeneratedUrl; @@ -435,6 +436,33 @@ protected function assertDenormalize(array $data) { ->shouldBeCalled(); } + // Avoid a static method call by returning dummy property data. + $this->fieldDefinition + ->getFieldStorageDefinition() + ->willReturn() + ->shouldBeCalled(); + $this->fieldDefinition + ->getName() + ->willReturn('field_reference') + ->shouldBeCalled(); + $entity = $this->prophesize(EntityInterface::class); + $entity_type = $this->prophesize(EntityTypeInterface::class); + $entity->getEntityType() + ->willReturn($entity_type->reveal()) + ->shouldBeCalled(); + $this->fieldItem + ->getPluginDefinition() + ->willReturn([ + 'serialized_property_names' => [ + 'foo' => 'bar', + ], + ]) + ->shouldBeCalled(); + $this->fieldItem + ->getEntity() + ->willReturn($entity->reveal()) + ->shouldBeCalled(); + $context = ['target_instance' => $this->fieldItem->reveal()]; $denormalized = $this->normalizer->denormalize($data, EntityReferenceItem::class, 'json', $context); $this->assertSame($context['target_instance'], $denormalized); diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php index 4d0127926e1da8b022e0b15079cc7acf31ba19f1..af19ba339dc875cea0447ffb3759e321b5985ca0 100644 --- a/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php +++ b/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php @@ -2,6 +2,9 @@ namespace Drupal\Tests\serialization\Unit\Normalizer; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\Plugin\Field\FieldType\CreatedItem; use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem; use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem; @@ -120,6 +123,29 @@ public function testDenormalize() { $timestamp_item->setValue(['value' => $timestamp_data_denormalization]) ->shouldBeCalled(); + // Avoid a static method call by returning dummy property data. + $field_definition = $this->prophesize(FieldDefinitionInterface::class); + $timestamp_item + ->getFieldDefinition() + ->willReturn($field_definition->reveal()) + ->shouldBeCalled(); + $timestamp_item->getPluginDefinition() + ->willReturn([ + 'serialized_property_names' => [ + 'foo' => 'bar', + ], + ]) + ->shouldBeCalled(); + $entity = $this->prophesize(EntityInterface::class); + $entity_type = $this->prophesize(EntityTypeInterface::class); + $entity->getEntityType() + ->willReturn($entity_type->reveal()) + ->shouldBeCalled(); + $timestamp_item + ->getEntity() + ->willReturn($entity->reveal()) + ->shouldBeCalled(); + $context = [ 'target_instance' => $timestamp_item->reveal(), 'datetime_allowed_formats' => [\DateTime::RFC3339],