upgrades core to 8.4.2
This commit is contained in:
@@ -2,3 +2,10 @@
|
||||
# this was usually returned from database storage. A primitive data normalizer
|
||||
# has been introduced to get the casted value instead.
|
||||
bc_primitives_as_strings: false
|
||||
# Before Drupal 8.3, timestamps were always returned as Unix timestamps, which
|
||||
# are not a universal format for interchange. Now, RFC3339 timestamps are
|
||||
# returned. New Drupal installations opt out from this by default (hence this
|
||||
# is set to false), existing installations opt in to it.
|
||||
# @see serialization_update_8301()
|
||||
# @see https://www.drupal.org/node/2768651
|
||||
bc_timestamp_normalizer_unix: false
|
||||
|
||||
@@ -5,3 +5,6 @@ serialization.settings:
|
||||
bc_primitives_as_strings:
|
||||
type: boolean
|
||||
label: 'Whether to retain pre Drupal 8.3 behavior of serializing all primitive items as strings.'
|
||||
bc_timestamp_normalizer_unix:
|
||||
type: boolean
|
||||
label: 'Whether the pre Drupal 8.4 behavior of returning Unix timestamps instead of RFC3339 timestamps for TimestampItem fields is enabled or not.'
|
||||
|
||||
@@ -5,8 +5,8 @@ package: Web services
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
# Information added by Drupal.org packaging script on 2017-11-03
|
||||
version: '8.4.2'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1502903957
|
||||
datestamp: 1509719929
|
||||
|
||||
@@ -46,3 +46,12 @@ function serialization_update_8302() {
|
||||
|
||||
return t('The REST API will no longer output all values as strings. Integers/booleans will be used where appropriate. If your site depends on these value being strings, <a href="https://www.drupal.org/node/2837696">read the change record to learn how to enable the BC mode.</a>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable BC for timestamp formatting: continue to return UNIX timestamps.
|
||||
*/
|
||||
function serialization_update_8401() {
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$serialization_settings = $config_factory->getEditable('serialization.settings');
|
||||
$serialization_settings->set('bc_timestamp_normalizer_unix', TRUE)->save(TRUE);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ services:
|
||||
# this modules generic field item normalizer.
|
||||
# @todo Find a better way for this in https://www.drupal.org/node/2575761.
|
||||
- { name: normalizer, priority: 8 }
|
||||
arguments: ['@entity.repository']
|
||||
serialization.normalizer.field_item:
|
||||
class: Drupal\serialization\Normalizer\FieldItemNormalizer
|
||||
tags:
|
||||
@@ -51,6 +52,12 @@ services:
|
||||
# Priority must be higher than serialization.normalizer.field but less
|
||||
# than hal field normalizer.
|
||||
- { name: normalizer, priority: 9 }
|
||||
serializer.normalizer.timestamp_item:
|
||||
class: Drupal\serialization\Normalizer\TimestampItemNormalizer
|
||||
tags:
|
||||
# Priority must be higher than serializer.normalizer.field_item and lower
|
||||
# than hal normalizers.
|
||||
- { name: normalizer, priority: 8, bc: bc_timestamp_normalizer_unix, bc_config_name: 'serialization.settings' }
|
||||
serializer.normalizer.password_field_item:
|
||||
class: Drupal\serialization\Normalizer\NullNormalizer
|
||||
arguments: ['Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem']
|
||||
|
||||
@@ -46,7 +46,7 @@ class BcConfigSubscriber implements EventSubscriberInterface {
|
||||
$saved_config = $event->getConfig();
|
||||
|
||||
if ($saved_config->getName() === 'serialization.settings') {
|
||||
if ($event->isChanged('bc_primitives_as_strings')) {
|
||||
if ($event->isChanged('bc_primitives_as_strings') || $event->isChanged('bc_timestamp_normalizer_unix')) {
|
||||
$this->kernel->invalidateContainer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ class UserRouteAlterSubscriber implements EventSubscriberInterface {
|
||||
'user.login_status.http',
|
||||
'user.login.http',
|
||||
'user.logout.http',
|
||||
'user.pass.http',
|
||||
];
|
||||
$routes = $event->getRouteCollection();
|
||||
foreach ($route_names as $route_name) {
|
||||
|
||||
@@ -26,9 +26,9 @@ class ComplexDataNormalizer extends NormalizerBase {
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$attributes = [];
|
||||
/** @var \Drupal\Core\TypedData\TypedDataInterface $field */
|
||||
foreach ($object as $name => $field) {
|
||||
$attributes[$name] = $this->serializer->normalize($field, $format, $context);
|
||||
/** @var \Drupal\Core\TypedData\TypedDataInterface $property */
|
||||
foreach ($object as $name => $property) {
|
||||
$attributes[$name] = $this->serializer->normalize($property, $format, $context);
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
@@ -15,15 +15,15 @@ class ContentEntityNormalizer extends EntityNormalizer {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
public function normalize($entity, $format = NULL, array $context = []) {
|
||||
$context += [
|
||||
'account' => NULL,
|
||||
];
|
||||
|
||||
$attributes = [];
|
||||
foreach ($object as $name => $field) {
|
||||
if ($field->access('view', $context['account'])) {
|
||||
$attributes[$name] = $this->serializer->normalize($field, $format, $context);
|
||||
foreach ($entity as $name => $field_items) {
|
||||
if ($field_items->access('view', $context['account'])) {
|
||||
$attributes[$name] = $this->serializer->normalize($field_items, $format, $context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,13 +40,20 @@ class EntityNormalizer extends ComplexDataNormalizer implements DenormalizerInte
|
||||
|
||||
// The bundle property will be required to denormalize a bundleable
|
||||
// fieldable entity.
|
||||
if ($entity_type_definition->hasKey('bundle') && $entity_type_definition->isSubclassOf(FieldableEntityInterface::class)) {
|
||||
// Get an array containing the bundle only. This also remove the bundle
|
||||
// key from the $data array.
|
||||
$bundle_data = $this->extractBundleData($data, $entity_type_definition);
|
||||
if ($entity_type_definition->isSubclassOf(FieldableEntityInterface::class)) {
|
||||
// Extract bundle data to pass into entity creation if the entity type uses
|
||||
// bundles.
|
||||
if ($entity_type_definition->hasKey('bundle')) {
|
||||
// Get an array containing the bundle only. This also remove the bundle
|
||||
// key from the $data array.
|
||||
$create_params = $this->extractBundleData($data, $entity_type_definition);
|
||||
}
|
||||
else {
|
||||
$create_params = [];
|
||||
}
|
||||
|
||||
// Create the entity from bundle data only, then apply field values after.
|
||||
$entity = $this->entityManager->getStorage($entity_type_id)->create($bundle_data);
|
||||
$entity = $this->entityManager->getStorage($entity_type_id)->create($create_params);
|
||||
|
||||
$this->denormalizeFieldData($data, $entity, $format, $context);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Adds the file URI to embedded file entities.
|
||||
*/
|
||||
class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
|
||||
class EntityReferenceFieldItemNormalizer extends FieldItemNormalizer {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
@@ -16,6 +19,23 @@ class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = EntityReferenceItem::class;
|
||||
|
||||
/**
|
||||
* The entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
||||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* Constructs a EntityReferenceFieldItemNormalizer object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
*/
|
||||
public function __construct(EntityRepositoryInterface $entity_repository) {
|
||||
$this->entityRepository = $entity_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -35,8 +55,32 @@ class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
|
||||
$values['url'] = $url;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
if (isset($data['target_uuid'])) {
|
||||
/** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $field_item */
|
||||
$field_item = $context['target_instance'];
|
||||
if (empty($data['target_uuid'])) {
|
||||
throw new InvalidArgumentException(sprintf('If provided "target_uuid" cannot be empty for field "%s".', $data['target_type'], $data['target_uuid'], $field_item->getName()));
|
||||
}
|
||||
$target_type = $field_item->getFieldDefinition()->getSetting('target_type');
|
||||
if (!empty($data['target_type']) && $target_type !== $data['target_type']) {
|
||||
throw new UnexpectedValueException(sprintf('The field "%s" property "target_type" must be set to "%s" or omitted.', $field_item->getFieldDefinition()->getName(), $target_type));
|
||||
}
|
||||
if ($entity = $this->entityRepository->loadEntityByUuid($target_type, $data['target_uuid'])) {
|
||||
return ['target_id' => $entity->id()];
|
||||
}
|
||||
else {
|
||||
// Unable to load entity by uuid.
|
||||
throw new InvalidArgumentException(sprintf('No "%s" entity found with UUID "%s" for field "%s".', $data['target_type'], $data['target_uuid'], $field_item->getName()));
|
||||
}
|
||||
}
|
||||
return parent::constructValue($data, $context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,13 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
||||
*/
|
||||
protected $supportedInterfaceOrClass;
|
||||
|
||||
/**
|
||||
* List of formats which supports (de-)normalization.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -29,7 +36,7 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
||||
|
||||
$supported = (array) $this->supportedInterfaceOrClass;
|
||||
|
||||
return (bool) array_filter($supported, function($name) use ($data) {
|
||||
return (bool) array_filter($supported, function ($name) use ($data) {
|
||||
return $data instanceof $name;
|
||||
});
|
||||
}
|
||||
@@ -49,7 +56,7 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
||||
|
||||
$supported = (array) $this->supportedInterfaceOrClass;
|
||||
|
||||
$subclass_check = function($name) use ($type) {
|
||||
$subclass_check = function ($name) use ($type) {
|
||||
return (class_exists($name) || interface_exists($name)) && is_subclass_of($type, $name, TRUE);
|
||||
};
|
||||
|
||||
@@ -71,7 +78,7 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return in_array($format, (array) $this->format);
|
||||
return in_array($format, (array) $this->format, TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* A trait for TimestampItem normalization functionality.
|
||||
*/
|
||||
trait TimeStampItemNormalizerTrait {
|
||||
|
||||
/**
|
||||
* Allowed timestamps formats for the denormalizer.
|
||||
*
|
||||
* The denormalizer allows deserialization to timestamps from three
|
||||
* different formats. Validation of the input data and creation of the
|
||||
* numerical timestamp value is handled with \DateTime::createFromFormat().
|
||||
* The list is chosen to be unambiguous and language neutral, but also common
|
||||
* for data interchange.
|
||||
*
|
||||
* @var string[]
|
||||
*
|
||||
* @see http://php.net/manual/en/datetime.createfromformat.php
|
||||
*/
|
||||
protected $allowedFormats = [
|
||||
'UNIX timestamp' => 'U',
|
||||
'ISO 8601' => \DateTime::ISO8601,
|
||||
'RFC 3339' => \DateTime::RFC3339,
|
||||
];
|
||||
|
||||
/**
|
||||
* Processes normalized timestamp values to add a formatted date and format.
|
||||
*
|
||||
* @param array $normalized
|
||||
* The normalized field data to process.
|
||||
* @return array
|
||||
* The processed data.
|
||||
*/
|
||||
protected function processNormalizedValues(array $normalized) {
|
||||
// Use a RFC 3339 timestamp with the time zone set to UTC to replace the
|
||||
// timestamp value.
|
||||
$date = new \DateTime();
|
||||
$date->setTimestamp($normalized['value']);
|
||||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
$normalized['value'] = $date->format(\DateTime::RFC3339);
|
||||
// 'format' is not a property on TimestampItem fields. This is present to
|
||||
// assist consumers of this data.
|
||||
$normalized['format'] = \DateTime::RFC3339;
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
// Loop through the allowed formats and create a TimestampItem from the
|
||||
// input data if it matches the defined pattern. Since the formats are
|
||||
// unambiguous (i.e., they reference an absolute time with a defined time
|
||||
// zone), only one will ever match.
|
||||
$timezone = new \DateTimeZone('UTC');
|
||||
|
||||
// First check for a provided format.
|
||||
if (!empty($data['format']) && in_array($data['format'], $this->allowedFormats)) {
|
||||
$date = \DateTime::createFromFormat($data['format'], $data['value'], $timezone);
|
||||
return ['value' => $date->getTimestamp()];
|
||||
}
|
||||
// Otherwise, loop through formats.
|
||||
else {
|
||||
foreach ($this->allowedFormats as $format) {
|
||||
if (($date = \DateTime::createFromFormat($format, $data['value'], $timezone)) !== FALSE) {
|
||||
return ['value' => $date->getTimestamp()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$format_strings = [];
|
||||
|
||||
foreach ($this->allowedFormats as $label => $format) {
|
||||
$format_strings[] = "\"$format\" ($label)";
|
||||
}
|
||||
|
||||
$formats = implode(', ', $format_strings);
|
||||
throw new UnexpectedValueException(sprintf('The specified date "%s" is not in an accepted format: %s.', $data['value'], $formats));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Converts values for TimestampItem to and from common formats.
|
||||
*/
|
||||
class TimestampItemNormalizer extends FieldItemNormalizer {
|
||||
|
||||
use TimeStampItemNormalizerTrait;
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = TimestampItem::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($field_item, $format = NULL, array $context = []) {
|
||||
$data = parent::normalize($field_item, $format, $context);
|
||||
|
||||
return $this->processNormalizedValues($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
if (empty($data['value'])) {
|
||||
throw new InvalidArgumentException('No "value" attribute present');
|
||||
}
|
||||
|
||||
return parent::denormalize($data, $class, $format, $context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,4 +10,4 @@ use Drupal\Tests\serialization\Kernel\NormalizerTestBase as SerializationNormali
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\serialization\Kernel\NormalizerTestBase instead.
|
||||
*/
|
||||
abstract class NormalizerTestBase extends SerializationNormalizerTestBase { }
|
||||
abstract class NormalizerTestBase extends SerializationNormalizerTestBase {}
|
||||
|
||||
+3
-3
@@ -5,8 +5,8 @@ package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
# Information added by Drupal.org packaging script on 2017-11-03
|
||||
version: '8.4.2'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1502903957
|
||||
datestamp: 1509719929
|
||||
|
||||
+3
-3
@@ -5,8 +5,8 @@ package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
# Information added by Drupal.org packaging script on 2017-11-03
|
||||
version: '8.4.2'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1502903957
|
||||
datestamp: 1509719929
|
||||
|
||||
@@ -5,8 +5,8 @@ package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
# Information added by Drupal.org packaging script on 2017-11-03
|
||||
version: '8.4.2'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1502903957
|
||||
datestamp: 1509719929
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* Tests that entities can be serialized to supported core formats.
|
||||
@@ -12,6 +13,8 @@ use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
*/
|
||||
class EntitySerializationTest extends NormalizerTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
@@ -106,7 +109,7 @@ class EntitySerializationTest extends NormalizerTestBase {
|
||||
['value' => 'entity_test_mulrev'],
|
||||
],
|
||||
'created' => [
|
||||
['value' => $this->entity->created->value],
|
||||
$this->formatExpectedTimestampItemValues($this->entity->created->value),
|
||||
],
|
||||
'user_id' => [
|
||||
[
|
||||
@@ -123,6 +126,9 @@ class EntitySerializationTest extends NormalizerTestBase {
|
||||
'default_langcode' => [
|
||||
['value' => TRUE],
|
||||
],
|
||||
'revision_translation_affected' => [
|
||||
['value' => TRUE],
|
||||
],
|
||||
'non_rev_field' => [],
|
||||
'field_test_text' => [
|
||||
[
|
||||
@@ -182,16 +188,19 @@ class EntitySerializationTest extends NormalizerTestBase {
|
||||
|
||||
// Generate the expected xml in a way that allows changes to entity property
|
||||
// order.
|
||||
$expected_created = $this->formatExpectedTimestampItemValues($this->entity->created->value);
|
||||
|
||||
$expected = [
|
||||
'id' => '<id><value>' . $this->entity->id() . '</value></id>',
|
||||
'uuid' => '<uuid><value>' . $this->entity->uuid() . '</value></uuid>',
|
||||
'langcode' => '<langcode><value>en</value></langcode>',
|
||||
'name' => '<name><value>' . $this->values['name'] . '</value></name>',
|
||||
'type' => '<type><value>entity_test_mulrev</value></type>',
|
||||
'created' => '<created><value>' . $this->entity->created->value . '</value></created>',
|
||||
'created' => '<created><value>' . $expected_created['value'] . '</value><format>' . $expected_created['format'] . '</format></created>',
|
||||
'user_id' => '<user_id><target_id>' . $this->user->id() . '</target_id><target_type>' . $this->user->getEntityTypeId() . '</target_type><target_uuid>' . $this->user->uuid() . '</target_uuid><url>' . $this->user->url() . '</url></user_id>',
|
||||
'revision_id' => '<revision_id><value>' . $this->entity->getRevisionId() . '</value></revision_id>',
|
||||
'default_langcode' => '<default_langcode><value>1</value></default_langcode>',
|
||||
'revision_translation_affected' => '<revision_translation_affected><value>1</value></revision_translation_affected>',
|
||||
'non_rev_field' => '<non_rev_field/>',
|
||||
'field_test_text' => '<field_test_text><value>' . $this->values['field_test_text']['value'] . '</value><format>' . $this->values['field_test_text']['format'] . '</format></field_test_text>',
|
||||
];
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ namespace Drupal\Tests\serialization\Unit\CompilerPass;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\serialization\RegisterSerializationClassesCompilerPass;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
@@ -11,7 +12,7 @@ use Symfony\Component\Serializer\Serializer;
|
||||
* @coversDefaultClass \Drupal\serialization\RegisterSerializationClassesCompilerPass
|
||||
* @group serialization
|
||||
*/
|
||||
class RegisterSerializationClassesCompilerPassTest extends \PHPUnit_Framework_TestCase {
|
||||
class RegisterSerializationClassesCompilerPassTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
|
||||
@@ -302,6 +302,10 @@ class EntityNormalizerTest extends UnitTestCase {
|
||||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(TRUE);
|
||||
$entity_type->expects($this->once())
|
||||
->method('hasKey')
|
||||
->with('bundle')
|
||||
@@ -314,6 +318,76 @@ class EntityNormalizerTest extends UnitTestCase {
|
||||
->with('test')
|
||||
->will($this->returnValue($entity_type));
|
||||
|
||||
$key_1 = $this->getMock(FieldItemListInterface::class);
|
||||
$key_2 = $this->getMock(FieldItemListInterface::class);
|
||||
|
||||
$entity = $this->getMock(FieldableEntityInterface::class);
|
||||
$entity->expects($this->at(0))
|
||||
->method('get')
|
||||
->with('key_1')
|
||||
->willReturn($key_1);
|
||||
$entity->expects($this->at(1))
|
||||
->method('get')
|
||||
->with('key_2')
|
||||
->willReturn($key_2);
|
||||
|
||||
$storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
$storage->expects($this->once())
|
||||
->method('create')
|
||||
->with([])
|
||||
->will($this->returnValue($entity));
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getStorage')
|
||||
->with('test')
|
||||
->will($this->returnValue($storage));
|
||||
|
||||
$this->entityManager->expects($this->never())
|
||||
->method('getBaseFieldDefinitions');
|
||||
|
||||
// Setup expectations for the serializer. This will be called for each field
|
||||
// item.
|
||||
$serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['denormalize'])
|
||||
->getMock();
|
||||
$serializer->expects($this->at(0))
|
||||
->method('denormalize')
|
||||
->with('value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']);
|
||||
$serializer->expects($this->at(1))
|
||||
->method('denormalize')
|
||||
->with('value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']);
|
||||
|
||||
$this->entityNormalizer->setSerializer($serializer);
|
||||
|
||||
$this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the denormalize method with no bundle defined.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithNoFieldableEntityType() {
|
||||
$test_data = [
|
||||
'key_1' => 'value_1',
|
||||
'key_2' => 'value_2',
|
||||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(FALSE);
|
||||
|
||||
$entity_type->expects($this->never())
|
||||
->method('getKey');
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getDefinition')
|
||||
->with('test')
|
||||
->will($this->returnValue($entity_type));
|
||||
|
||||
$storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
$storage->expects($this->once())
|
||||
->method('create')
|
||||
|
||||
+179
-1
@@ -3,11 +3,18 @@
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\FieldItemInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
@@ -37,11 +44,26 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
*/
|
||||
protected $fieldItem;
|
||||
|
||||
/**
|
||||
* The mock entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* The mock field definition.
|
||||
*
|
||||
* @var \Drupal\Core\Field\FieldDefinitionInterface|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $fieldDefinition;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->normalizer = new EntityReferenceFieldItemNormalizer();
|
||||
$this->entityRepository = $this->prophesize(EntityRepositoryInterface::class);
|
||||
$this->normalizer = new EntityReferenceFieldItemNormalizer($this->entityRepository->reveal());
|
||||
|
||||
$this->serializer = $this->prophesize(Serializer::class);
|
||||
// Set up the serializer to return an entity property.
|
||||
@@ -53,6 +75,9 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
$this->fieldItem = $this->prophesize(EntityReferenceItem::class);
|
||||
$this->fieldItem->getIterator()
|
||||
->willReturn(new \ArrayIterator(['target_id' => []]));
|
||||
|
||||
$this->fieldDefinition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,6 +88,14 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsDenormalization
|
||||
*/
|
||||
public function testSupportsDenormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsDenormalization([], EntityReferenceItem::class));
|
||||
$this->assertFalse($this->normalizer->supportsDenormalization([], FieldItemInterface::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
@@ -121,4 +154,149 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithTypeAndUuid() {
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
];
|
||||
|
||||
$entity = $this->prophesize(FieldableEntityInterface::class);
|
||||
$entity->id()
|
||||
->willReturn('test')
|
||||
->shouldBeCalled();
|
||||
$this->entityRepository
|
||||
->loadEntityByUuid($data['target_type'], $data['target_uuid'])
|
||||
->willReturn($entity)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->setValue(['target_id' => 'test'])->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithUuidWithoutType() {
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
];
|
||||
|
||||
$entity = $this->prophesize(FieldableEntityInterface::class);
|
||||
$entity->id()
|
||||
->willReturn('test')
|
||||
->shouldBeCalled();
|
||||
$this->entityRepository
|
||||
->loadEntityByUuid('test_type', $data['target_uuid'])
|
||||
->willReturn($entity)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->setValue(['target_id' => 'test'])->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithUuidWithIncorrectType() {
|
||||
$this->setExpectedException(UnexpectedValueException::class, 'The field "field_reference" property "target_type" must be set to "test_type" or omitted.');
|
||||
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_type' => 'wrong_type',
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
];
|
||||
|
||||
$this->fieldDefinition
|
||||
->getName()
|
||||
->willReturn('field_reference')
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithTypeWithIncorrectUuid() {
|
||||
$this->setExpectedException(InvalidArgumentException::class, 'No "test_type" entity found with UUID "unique-but-none-non-existent" for field "field_reference"');
|
||||
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => 'unique-but-none-non-existent',
|
||||
];
|
||||
$this->entityRepository
|
||||
->loadEntityByUuid($data['target_type'], $data['target_uuid'])
|
||||
->willReturn(NULL)
|
||||
->shouldBeCalled();
|
||||
$this->fieldItem
|
||||
->getName()
|
||||
->willReturn('field_reference')
|
||||
->shouldBeCalled();
|
||||
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithEmtpyUuid() {
|
||||
$this->setExpectedException(InvalidArgumentException::class, 'If provided "target_uuid" cannot be empty for field "test_type".');
|
||||
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => '',
|
||||
];
|
||||
$this->fieldItem
|
||||
->getName()
|
||||
->willReturn('field_reference')
|
||||
->shouldBeCalled();
|
||||
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithId() {
|
||||
$data = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
];
|
||||
$this->fieldItem->setValue($data)->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts denormalization process is correct for give data.
|
||||
*
|
||||
* @param array $data
|
||||
* The data to denormalize.
|
||||
*/
|
||||
protected function assertDenormalize(array $data) {
|
||||
$this->fieldItem->getParent()
|
||||
->willReturn($this->prophesize(FieldItemListInterface::class)->reveal());
|
||||
$this->fieldItem->getFieldDefinition()->willReturn($this->fieldDefinition->reveal());
|
||||
if (!empty($data['target_uuid'])) {
|
||||
$this->fieldDefinition
|
||||
->getSetting('target_type')
|
||||
->willReturn('test_type')
|
||||
->shouldBeCalled();
|
||||
}
|
||||
|
||||
$context = ['target_instance' => $this->fieldItem->reveal()];
|
||||
$denormalized = $this->normalizer->denormalize($data, EntityReferenceItem::class, 'json', $context);
|
||||
$this->assertSame($context['target_instance'], $denormalized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class NormalizerBaseTest extends UnitTestCase {
|
||||
* @param mixed $data
|
||||
* The data passed to supportsNormalization.
|
||||
* @param string $supported_interface_or_class
|
||||
* (optional) the supported interface or class to set on the normalizer.
|
||||
* (optional) The supported interface or class to set on the normalizer.
|
||||
*/
|
||||
public function testSupportsNormalization($expected_return, $data, $supported_interface_or_class = NULL) {
|
||||
$normalizer_base = $this->getMockForAbstractClass('Drupal\Tests\serialization\Unit\Normalizer\TestNormalizerBase');
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\CreatedItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem;
|
||||
use Drupal\serialization\Normalizer\TimestampItemNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* Tests that entities can be serialized to supported core formats.
|
||||
*
|
||||
* @group serialization
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\TimestampItemNormalizer
|
||||
*/
|
||||
class TimestampItemNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\serialization\Normalizer\TimestampItemNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* The test TimestampItem.
|
||||
*
|
||||
* @var \Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->normalizer = new TimestampItemNormalizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$timestamp_item = $this->createTimestampItemProphecy();
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($timestamp_item->reveal()));
|
||||
|
||||
$entity_ref_item = $this->prophesize(EntityReferenceItem::class);
|
||||
$this->assertFalse($this->normalizer->supportsNormalization($entity_ref_item->reveal()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsDenormalization
|
||||
*/
|
||||
public function testSupportsDenormalization() {
|
||||
$timestamp_item = $this->createTimestampItemProphecy();
|
||||
$this->assertTrue($this->normalizer->supportsDenormalization($timestamp_item->reveal(), TimestampItem::class));
|
||||
|
||||
// CreatedItem extends regular TimestampItem.
|
||||
$timestamp_item = $this->prophesize(CreatedItem::class);
|
||||
$this->assertTrue($this->normalizer->supportsDenormalization($timestamp_item->reveal(), TimestampItem::class));
|
||||
|
||||
$entity_ref_item = $this->prophesize(EntityReferenceItem::class);
|
||||
$this->assertFalse($this->normalizer->supportsNormalization($entity_ref_item->reveal(), TimestampItem::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize function.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$expected = ['value' => '2016-11-06T09:02:00+00:00', 'format' => \DateTime::RFC3339];
|
||||
|
||||
$timestamp_item = $this->createTimestampItemProphecy();
|
||||
$timestamp_item->getIterator()
|
||||
->willReturn(new \ArrayIterator(['value' => 1478422920]));
|
||||
|
||||
$serializer = new Serializer();
|
||||
$this->normalizer->setSerializer($serializer);
|
||||
|
||||
$normalized = $this->normalizer->normalize($timestamp_item->reveal());
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the denormalize function with good data.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
* @dataProvider providerTestDenormalizeValidFormats
|
||||
*/
|
||||
public function testDenormalizeValidFormats($value, $expected) {
|
||||
$normalized = ['value' => $value];
|
||||
|
||||
$timestamp_item = $this->createTimestampItemProphecy();
|
||||
// The field item should be set with the expected timestamp.
|
||||
$timestamp_item->setValue(['value' => $expected])
|
||||
->shouldBeCalled();
|
||||
|
||||
$context = ['target_instance' => $timestamp_item->reveal()];
|
||||
|
||||
$denormalized = $this->normalizer->denormalize($normalized, TimestampItem::class, NULL, $context);
|
||||
$this->assertTrue($denormalized instanceof TimestampItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testDenormalizeValidFormats.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestDenormalizeValidFormats() {
|
||||
$expected_stamp = 1478422920;
|
||||
|
||||
$data = [];
|
||||
|
||||
$data['U'] = [$expected_stamp, $expected_stamp];
|
||||
$data['RFC3339'] = ['2016-11-06T09:02:00+00:00', $expected_stamp];
|
||||
$data['RFC3339 +0100'] = ['2016-11-06T09:02:00+01:00', $expected_stamp - 1 * 3600];
|
||||
$data['RFC3339 -0600'] = ['2016-11-06T09:02:00-06:00', $expected_stamp + 6 * 3600];
|
||||
|
||||
$data['ISO8601'] = ['2016-11-06T09:02:00+0000', $expected_stamp];
|
||||
$data['ISO8601 +0100'] = ['2016-11-06T09:02:00+0100', $expected_stamp - 1 * 3600];
|
||||
$data['ISO8601 -0600'] = ['2016-11-06T09:02:00-0600', $expected_stamp + 6 * 3600];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the denormalize function with bad data.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeException() {
|
||||
$this->setExpectedException(UnexpectedValueException::class, 'The specified date "2016/11/06 09:02am GMT" is not in an accepted format: "U" (UNIX timestamp), "Y-m-d\TH:i:sO" (ISO 8601), "Y-m-d\TH:i:sP" (RFC 3339).');
|
||||
|
||||
$context = ['target_instance' => $this->createTimestampItemProphecy()->reveal()];
|
||||
|
||||
$normalized = ['value' => '2016/11/06 09:02am GMT'];
|
||||
$this->normalizer->denormalize($normalized, TimestampItem::class, NULL, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TimestampItem prophecy.
|
||||
*
|
||||
* @return \Prophecy\Prophecy\ObjectProphecy|\Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem
|
||||
*/
|
||||
protected function createTimestampItemProphecy() {
|
||||
$timestamp_item = $this->prophesize(TimestampItem::class);
|
||||
$timestamp_item->getParent()
|
||||
->willReturn(TRUE);
|
||||
|
||||
return $timestamp_item;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user