Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -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.'
|
||||
|
|
|
@ -33,7 +33,8 @@ function serialization_requirements($phase) {
|
|||
/**
|
||||
* @see hal_update_8301()
|
||||
*/
|
||||
function serialization_update_8301() {}
|
||||
function serialization_update_8301() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add serialization.settings::bc_primitives_as_strings configuration.
|
||||
|
@ -46,3 +47,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']
|
||||
|
@ -78,7 +85,7 @@ services:
|
|||
class: Drupal\serialization\EntityResolver\UuidResolver
|
||||
tags:
|
||||
- { name: entity_resolver}
|
||||
arguments: ['@entity.manager']
|
||||
arguments: ['@entity.repository']
|
||||
serialization.entity_resolver.target_id:
|
||||
class: Drupal\serialization\EntityResolver\TargetIdResolver
|
||||
tags:
|
||||
|
|
|
@ -10,6 +10,10 @@ use Symfony\Component\Serializer\Encoder\JsonEncoder as BaseJsonEncoder;
|
|||
|
||||
/**
|
||||
* Adds 'ajax to the supported content types of the JSON encoder'
|
||||
*
|
||||
* @internal
|
||||
* This encoder should not be used directly. Rather, use the `serializer`
|
||||
* service.
|
||||
*/
|
||||
class JsonEncoder extends BaseJsonEncoder implements EncoderInterface, DecoderInterface {
|
||||
|
||||
|
|
|
@ -4,16 +4,23 @@ namespace Drupal\serialization\Encoder;
|
|||
|
||||
use Symfony\Component\Serializer\Encoder\EncoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\DecoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\SerializerAwareEncoder;
|
||||
use Symfony\Component\Serializer\Encoder\XmlEncoder as BaseXmlEncoder;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* Adds XML support for serializer.
|
||||
*
|
||||
* This acts as a wrapper class for Symfony's XmlEncoder so that it is not
|
||||
* implementing NormalizationAwareInterface, and can be normalized externally.
|
||||
*
|
||||
* @internal
|
||||
* This encoder should not be used directly. Rather, use the `serializer`
|
||||
* service.
|
||||
*/
|
||||
class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, DecoderInterface {
|
||||
class XmlEncoder implements SerializerAwareInterface, EncoderInterface, DecoderInterface {
|
||||
|
||||
use SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* The formats that this Encoder supports.
|
||||
|
@ -56,7 +63,7 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function encode($data, $format, array $context = []){
|
||||
public function encode($data, $format, array $context = []) {
|
||||
return $this->getBaseEncoder()->encode($data, $format, $context);
|
||||
}
|
||||
|
||||
|
@ -70,7 +77,7 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function decode($data, $format, array $context = []){
|
||||
public function decode($data, $format, array $context = []) {
|
||||
return $this->getBaseEncoder()->decode($data, $format, $context);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
|
@ -11,20 +11,20 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
|||
class UuidResolver implements EntityResolverInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
* The entity repository.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
protected $entityRepository;
|
||||
|
||||
/**
|
||||
* Constructs a UuidResolver object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
|
||||
* The entity repository.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
public function __construct(EntityRepositoryInterface $entity_repository) {
|
||||
$this->entityRepository = $entity_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ class UuidResolver implements EntityResolverInterface {
|
|||
// deserialized. If it can return a UUID from that data, and if there's an
|
||||
// entity with that UUID, then return its ID.
|
||||
if (($normalizer instanceof UuidReferenceInterface) && ($uuid = $normalizer->getUuid($data))) {
|
||||
if ($entity = $this->entityManager->loadEntityByUuid($entity_type, $uuid)) {
|
||||
if ($entity = $this->entityRepository->loadEntityByUuid($entity_type, $uuid)) {
|
||||
return $entity->id();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\serialization\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
|
@ -51,8 +53,12 @@ class DefaultExceptionSubscriber extends HttpExceptionSubscriberBase {
|
|||
*/
|
||||
protected static function getPriority() {
|
||||
// This will fire after the most common HTML handler, since HTML requests
|
||||
// are still more common than HTTP requests.
|
||||
return -75;
|
||||
// are still more common than HTTP requests. But it has a lower priority
|
||||
// than \Drupal\Core\EventSubscriber\ExceptionJsonSubscriber::on4xx(), so
|
||||
// that this also handles the 'json' format. Then all serialization formats
|
||||
// (::getHandledFormats()) are handled by this exception subscriber, which
|
||||
// results in better consistency.
|
||||
return -70;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,14 +73,22 @@ class DefaultExceptionSubscriber extends HttpExceptionSubscriberBase {
|
|||
$request = $event->getRequest();
|
||||
|
||||
$format = $request->getRequestFormat();
|
||||
$content = ['message' => $event->getException()->getMessage()];
|
||||
$content = ['message' => $exception->getMessage()];
|
||||
$encoded_content = $this->serializer->serialize($content, $format);
|
||||
$headers = $exception->getHeaders();
|
||||
|
||||
// Add the MIME type from the request to send back in the header.
|
||||
$headers['Content-Type'] = $request->getMimeType($format);
|
||||
|
||||
$response = new Response($encoded_content, $exception->getStatusCode(), $headers);
|
||||
// If the exception is cacheable, generate a cacheable response.
|
||||
if ($exception instanceof CacheableDependencyInterface) {
|
||||
$response = new CacheableResponse($encoded_content, $exception->getStatusCode(), $headers);
|
||||
$response->addCacheableDependency($exception);
|
||||
}
|
||||
else {
|
||||
$response = new Response($encoded_content, $exception->getStatusCode(), $headers);
|
||||
}
|
||||
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Defines the interface for normalizers producing cacheable normalizations.
|
||||
*
|
||||
* @see cache
|
||||
*/
|
||||
interface CacheableNormalizerInterface extends NormalizerInterface {
|
||||
|
||||
/**
|
||||
* Name of key for bubbling cacheability metadata via serialization context.
|
||||
*
|
||||
* @see \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
|
||||
* @see \Symfony\Component\Serializer\SerializerInterface::serialize()
|
||||
* @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::renderResponseBody()
|
||||
*/
|
||||
const SERIALIZATION_CONTEXT_CACHEABILITY = 'cacheability';
|
||||
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInternalPropertiesHelper;
|
||||
|
||||
/**
|
||||
* Converts the Drupal entity object structures to a normalized array.
|
||||
*
|
||||
|
@ -26,9 +29,19 @@ 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);
|
||||
// $object will not always match $supportedInterfaceOrClass.
|
||||
// @see \Drupal\serialization\Normalizer\EntityNormalizer
|
||||
// Other normalizers that extend this class may only provide $object that
|
||||
// implements \Traversable.
|
||||
if ($object instanceof ComplexDataInterface) {
|
||||
// If there are no properties to normalize, just normalize the value.
|
||||
$object = !empty($object->getProperties(TRUE))
|
||||
? TypedDataInternalPropertiesHelper::getNonInternalProperties($object)
|
||||
: $object->getValue();
|
||||
}
|
||||
/** @var \Drupal\Core\TypedData\TypedDataInterface $property */
|
||||
foreach ($object as $name => $property) {
|
||||
$attributes[$name] = $this->serializer->normalize($property, $format, $context);
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,33 @@ class ConfigEntityNormalizer extends EntityNormalizer {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->toArray();
|
||||
return static::getDataWithoutInternals($object->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
return parent::denormalize(static::getDataWithoutInternals($data), $class, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the given data without the internal implementation details.
|
||||
*
|
||||
* @param array $data
|
||||
* The data that is either currently or about to be stored in configuration.
|
||||
*
|
||||
* @return array
|
||||
* The same data, but without internals. Currently, that is only the '_core'
|
||||
* key, which is reserved by Drupal core to handle complex edge cases
|
||||
* correctly. Data in the '_core' key is irrelevant to clients reading
|
||||
* configuration, and is not allowed to be set by clients writing
|
||||
* configuration: it is for Drupal core only, and managed by Drupal core.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2653358
|
||||
*/
|
||||
protected static function getDataWithoutInternals(array $data) {
|
||||
return array_diff_key($data, ['_core' => TRUE]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\TypedDataInternalPropertiesHelper;
|
||||
|
||||
/**
|
||||
* Normalizes/denormalizes Drupal content entities into an array structure.
|
||||
*/
|
||||
|
@ -15,15 +17,16 @@ 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);
|
||||
/** @var \Drupal\Core\Entity\Entity $entity */
|
||||
foreach (TypedDataInternalPropertiesHelper::getNonInternalProperties($entity->getTypedData()) 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->entityClassImplements(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,17 @@
|
|||
|
||||
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 {
|
||||
|
||||
use EntityReferenceFieldItemNormalizerTrait;
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
|
@ -16,12 +21,31 @@ 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}
|
||||
*/
|
||||
public function normalize($field_item, $format = NULL, array $context = []) {
|
||||
$values = parent::normalize($field_item, $format, $context);
|
||||
|
||||
$this->normalizeRootReferenceValue($values, $field_item);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
if ($entity = $field_item->get('entity')->getValue()) {
|
||||
$values['target_type'] = $entity->getEntityTypeId();
|
||||
|
@ -39,4 +63,29 @@ class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
|
|||
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()] + array_intersect_key($data, $field_item->getProperties());
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
|
||||
/**
|
||||
* Converts empty reference values for entity reference items.
|
||||
*/
|
||||
trait EntityReferenceFieldItemNormalizerTrait {
|
||||
|
||||
protected function normalizeRootReferenceValue(&$values, EntityReferenceItem $field_item) {
|
||||
// @todo Generalize for all tree-structured entity types.
|
||||
if ($this->fieldItemReferencesTaxonomyTerm($field_item) && empty($values['target_id'])) {
|
||||
$values['target_id'] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a field item references a taxonomy term.
|
||||
*
|
||||
* @param \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $field_item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function fieldItemReferencesTaxonomyTerm(EntityReferenceItem $field_item) {
|
||||
return $field_item->getFieldDefinition()->getSetting('target_type') === 'taxonomy_term';
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,7 @@ class FieldNormalizer extends ListNormalizer implements DenormalizerInterface {
|
|||
throw new InvalidArgumentException('The field passed in via $context[\'target_instance\'] must have a parent set.');
|
||||
}
|
||||
|
||||
/** @var FieldItemListInterface $items */
|
||||
/** @var \Drupal\Core\Field\FieldItemListInterface $items */
|
||||
$items = $context['target_instance'];
|
||||
$item_class = $items->getItemDefinition()->getClass();
|
||||
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareInterface;
|
||||
use Symfony\Component\Serializer\SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* Base class for Normalizers.
|
||||
*/
|
||||
abstract class NormalizerBase extends SerializerAwareNormalizer implements NormalizerInterface {
|
||||
abstract class NormalizerBase implements SerializerAwareInterface, CacheableNormalizerInterface {
|
||||
|
||||
use SerializerAwareTrait;
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
|
@ -17,6 +20,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 +39,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 +59,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 +81,21 @@ abstract class NormalizerBase extends SerializerAwareNormalizer implements Norma
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
return in_array($format, (array) $this->format);
|
||||
return in_array($format, (array) $this->format, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds cacheability if applicable.
|
||||
*
|
||||
* @param array $context
|
||||
* Context options for the normalizer.
|
||||
* @param $data
|
||||
* The data that might have cacheability information.
|
||||
*/
|
||||
protected function addCacheableDependency(array $context, $data) {
|
||||
if ($data instanceof CacheableDependencyInterface && isset($context[static::SERIALIZATION_CONTEXT_CACHEABILITY])) {
|
||||
$context[static::SERIALIZATION_CONTEXT_CACHEABILITY]->addCacheableDependency($data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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/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);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,13 @@ class TypedDataNormalizer extends NormalizerBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->getValue();
|
||||
$this->addCacheableDependency($context, $object);
|
||||
$value = $object->getValue();
|
||||
// Support for stringable value objects: avoid numerous custom normalizers.
|
||||
if (is_object($value) && method_exists($value, '__toString')) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
|
||||
// Retrieve registered Normalizers and Encoders from the container.
|
||||
foreach ($container->findTaggedServiceIds('normalizer') as $id => $attributes) {
|
||||
// The 'serializer' service is the public API: mark normalizers private.
|
||||
$container->getDefinition($id)->setPublic(FALSE);
|
||||
|
||||
// If there is a BC key present, pass this to determine if the normalizer
|
||||
// should be skipped.
|
||||
if (isset($attributes[0]['bc']) && $this->normalizerBcSettingIsEnabled($attributes[0]['bc'], $attributes[0]['bc_config_name'])) {
|
||||
|
@ -33,6 +36,9 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
$normalizers[$priority][] = new Reference($id);
|
||||
}
|
||||
foreach ($container->findTaggedServiceIds('encoder') as $id => $attributes) {
|
||||
// The 'serializer' service is the public API: mark encoders private.
|
||||
$container->getDefinition($id)->setPublic(FALSE);
|
||||
|
||||
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
||||
$encoders[$priority][] = new Reference($id);
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -29,7 +29,7 @@ class TextItemSillyNormalizer extends FieldItemNormalizer {
|
|||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
$value = parent::constructValue($data, $context);
|
||||
$value['value'] = str_replace('::silly_suffix', '', $value['value']);
|
||||
$value['value'] = str_replace('::silly_suffix', '', $value['value']);
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* Tests that entities can be serialized to supported core formats.
|
||||
|
@ -12,6 +15,8 @@ use Drupal\entity_test\Entity\EntityTestMulRev;
|
|||
*/
|
||||
class EntitySerializationTest extends NormalizerTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
|
@ -43,7 +48,7 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer.
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
|
@ -60,6 +65,27 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
// User create needs sequence table.
|
||||
$this->installSchema('system', ['sequences']);
|
||||
|
||||
FilterFormat::create([
|
||||
'format' => 'my_text_format',
|
||||
'name' => 'My Text Format',
|
||||
'filters' => [
|
||||
'filter_html' => [
|
||||
'module' => 'filter',
|
||||
'status' => TRUE,
|
||||
'weight' => 10,
|
||||
'settings' => [
|
||||
'allowed_html' => '<p>',
|
||||
],
|
||||
],
|
||||
'filter_autop' => [
|
||||
'module' => 'filter',
|
||||
'status' => TRUE,
|
||||
'weight' => 10,
|
||||
'settings' => [],
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
|
||||
// Create a test user to use as the entity owner.
|
||||
$this->user = \Drupal::entityManager()->getStorage('user')->create([
|
||||
'name' => 'serialization_test_user',
|
||||
|
@ -69,12 +95,13 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
$this->user->save();
|
||||
|
||||
// Create a test entity to serialize.
|
||||
$test_text_value = $this->randomMachineName();
|
||||
$this->values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'user_id' => $this->user->id(),
|
||||
'field_test_text' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
'value' => $test_text_value,
|
||||
'format' => 'my_text_format',
|
||||
],
|
||||
];
|
||||
$this->entity = EntityTestMulRev::create($this->values);
|
||||
|
@ -106,7 +133,7 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
['value' => 'entity_test_mulrev'],
|
||||
],
|
||||
'created' => [
|
||||
['value' => $this->entity->created->value],
|
||||
$this->formatExpectedTimestampItemValues($this->entity->created->value),
|
||||
],
|
||||
'user_id' => [
|
||||
[
|
||||
|
@ -123,11 +150,16 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
'default_langcode' => [
|
||||
['value' => TRUE],
|
||||
],
|
||||
'revision_translation_affected' => [
|
||||
['value' => TRUE],
|
||||
],
|
||||
'non_rev_field' => [],
|
||||
'non_mul_field' => [],
|
||||
'field_test_text' => [
|
||||
[
|
||||
'value' => $this->values['field_test_text']['value'],
|
||||
'format' => $this->values['field_test_text']['format'],
|
||||
'processed' => "<p>{$this->values['field_test_text']['value']}</p>",
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@ -168,7 +200,7 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
// JsonEncoder. The output of ComplexDataNormalizer::normalize() is tested
|
||||
// elsewhere, so we can just assume that it works properly here.
|
||||
$normalized = $this->serializer->normalize($this->entity, 'json');
|
||||
$expected = json_encode($normalized);
|
||||
$expected = Json::encode($normalized);
|
||||
// Test 'json'.
|
||||
$actual = $this->serializer->serialize($this->entity, 'json');
|
||||
$this->assertIdentical($actual, $expected, 'Entity serializes to JSON when "json" is requested.');
|
||||
|
@ -182,18 +214,22 @@ 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_mul_field' => '<non_mul_field/>',
|
||||
'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>',
|
||||
'field_test_text' => '<field_test_text><value>' . $this->values['field_test_text']['value'] . '</value><format>' . $this->values['field_test_text']['format'] . '</format><processed><![CDATA[<p>' . $this->values['field_test_text']['value'] . '</p>]]></processed></field_test_text>',
|
||||
];
|
||||
// Sort it in the same order as normalised.
|
||||
$expected = array_merge($normalized, $expected);
|
||||
|
@ -217,7 +253,7 @@ class EntitySerializationTest extends NormalizerTestBase {
|
|||
|
||||
foreach (['json', 'xml'] as $type) {
|
||||
$denormalized = $this->serializer->denormalize($normalized, $this->entityClass, $type, ['entity_type' => 'entity_test_mulrev']);
|
||||
$this->assertTrue($denormalized instanceof $this->entityClass, SafeMarkup::format('Denormalized entity is an instance of @class', ['@class' => $this->entityClass]));
|
||||
$this->assertTrue($denormalized instanceof $this->entityClass, new FormattableMarkup('Denormalized entity is an instance of @class', ['@class' => $this->entityClass]));
|
||||
$this->assertIdentical($denormalized->getEntityTypeId(), $this->entity->getEntityTypeId(), 'Expected entity type found.');
|
||||
$this->assertIdentical($denormalized->bundle(), $this->entity->bundle(), 'Expected entity bundle found.');
|
||||
$this->assertIdentical($denormalized->uuid(), $this->entity->uuid(), 'Expected entity UUID found.');
|
||||
|
|
|
@ -43,7 +43,7 @@ class FieldItemSerializationTest extends NormalizerTestBase {
|
|||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer.
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\Core\TypedData\MapDataDefinition;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* @group typedData
|
||||
*/
|
||||
class MapDataNormalizerTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system', 'serialization'];
|
||||
|
||||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The typed data manager.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
|
||||
*/
|
||||
protected $typedDataManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->serializer = \Drupal::service('serializer');
|
||||
$this->typedDataManager = \Drupal::typedDataManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether map data can be normalized.
|
||||
*/
|
||||
public function testMapNormalize() {
|
||||
$typed_data = $this->buildExampleTypedData();
|
||||
$data = $this->serializer->normalize($typed_data, 'json');
|
||||
$expect_value = [
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 3,
|
||||
'key4' => [
|
||||
0 => TRUE,
|
||||
1 => 'value6',
|
||||
'key7' => 'value7',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expect_value, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether map data with properties can be normalized.
|
||||
*/
|
||||
public function testMapWithPropertiesNormalize() {
|
||||
$typed_data = $this->buildExampleTypedDataWithProperties();
|
||||
$data = $this->serializer->normalize($typed_data, 'json');
|
||||
$expect_value = [
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 3,
|
||||
'key4' => [
|
||||
0 => TRUE,
|
||||
1 => 'value6',
|
||||
'key7' => 'value7',
|
||||
],
|
||||
];
|
||||
$this->assertSame($expect_value, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds some example typed data object with no properties.
|
||||
*/
|
||||
protected function buildExampleTypedData() {
|
||||
$tree = [
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 3,
|
||||
'key4' => [
|
||||
0 => TRUE,
|
||||
1 => 'value6',
|
||||
'key7' => 'value7',
|
||||
],
|
||||
];
|
||||
$map_data_definition = MapDataDefinition::create();
|
||||
$typed_data = $this->typedDataManager->create(
|
||||
$map_data_definition,
|
||||
$tree,
|
||||
'test name'
|
||||
);
|
||||
return $typed_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds some example typed data object with properties.
|
||||
*/
|
||||
protected function buildExampleTypedDataWithProperties() {
|
||||
$tree = [
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'key3' => 3,
|
||||
'key4' => [
|
||||
0 => TRUE,
|
||||
1 => 'value6',
|
||||
'key7' => 'value7',
|
||||
],
|
||||
];
|
||||
$map_data_definition = MapDataDefinition::create()
|
||||
->setPropertyDefinition('key1', DataDefinition::create('string'))
|
||||
->setPropertyDefinition('key2', DataDefinition::create('string'))
|
||||
->setPropertyDefinition('key3', DataDefinition::create('integer'))
|
||||
->setPropertyDefinition('key4', MapDataDefinition::create()
|
||||
->setPropertyDefinition(0, DataDefinition::create('boolean'))
|
||||
->setPropertyDefinition(1, DataDefinition::create('string'))
|
||||
->setPropertyDefinition('key7', DataDefinition::create('string'))
|
||||
);
|
||||
|
||||
$typed_data = $this->typedDataManager->create(
|
||||
$map_data_definition,
|
||||
$tree,
|
||||
'test name'
|
||||
);
|
||||
|
||||
return $typed_data;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
@ -20,26 +21,38 @@ class RegisterSerializationClassesCompilerPassTest extends \PHPUnit_Framework_Te
|
|||
$container = new ContainerBuilder();
|
||||
$container->setDefinition('serializer', new Definition(Serializer::class, [[], []]));
|
||||
|
||||
$definition = new Definition('TestClass');
|
||||
$definition->addTag('encoder', ['format' => 'xml']);
|
||||
$definition->addTag('_provider', ['provider' => 'test_provider_a']);
|
||||
$container->setDefinition('encoder_1', $definition);
|
||||
$encoder_1_definition = new Definition('TestClass');
|
||||
$encoder_1_definition->addTag('encoder', ['format' => 'xml']);
|
||||
$encoder_1_definition->addTag('_provider', ['provider' => 'test_provider_a']);
|
||||
$container->setDefinition('encoder_1', $encoder_1_definition);
|
||||
|
||||
$definition = new Definition('TestClass');
|
||||
$definition->addTag('encoder', ['format' => 'json']);
|
||||
$definition->addTag('_provider', ['provider' => 'test_provider_a']);
|
||||
$container->setDefinition('encoder_2', $definition);
|
||||
$encoder_2_definition = new Definition('TestClass');
|
||||
$encoder_2_definition->addTag('encoder', ['format' => 'json']);
|
||||
$encoder_2_definition->addTag('_provider', ['provider' => 'test_provider_a']);
|
||||
$container->setDefinition('encoder_2', $encoder_2_definition);
|
||||
|
||||
$definition = new Definition('TestClass');
|
||||
$definition->addTag('encoder', ['format' => 'hal_json']);
|
||||
$definition->addTag('_provider', ['provider' => 'test_provider_b']);
|
||||
$container->setDefinition('encoder_3', $definition);
|
||||
$encoder_3_definition = new Definition('TestClass');
|
||||
$encoder_3_definition->addTag('encoder', ['format' => 'hal_json']);
|
||||
$encoder_3_definition->addTag('_provider', ['provider' => 'test_provider_b']);
|
||||
$container->setDefinition('encoder_3', $encoder_3_definition);
|
||||
|
||||
$normalizer_1_definition = new Definition('TestClass');
|
||||
$normalizer_1_definition->addTag('normalizer');
|
||||
$container->setDefinition('normalizer_1', $normalizer_1_definition);
|
||||
|
||||
$compiler_pass = new RegisterSerializationClassesCompilerPass();
|
||||
$compiler_pass->process($container);
|
||||
|
||||
// Check registration of formats and providers.
|
||||
$this->assertEquals(['xml', 'json', 'hal_json'], $container->getParameter('serializer.formats'));
|
||||
$this->assertEquals(['xml' => 'test_provider_a', 'json' => 'test_provider_a', 'hal_json' => 'test_provider_b'], $container->getParameter('serializer.format_providers'));
|
||||
|
||||
// Check all encoder and normalizer service definitions are marked private.
|
||||
$this->assertFalse($encoder_1_definition->isPublic());
|
||||
$this->assertFalse($encoder_2_definition->isPublic());
|
||||
$this->assertFalse($encoder_3_definition->isPublic());
|
||||
|
||||
$this->assertFalse($normalizer_1_definition->isPublic());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ class XmlEncoderTest extends UnitTestCase {
|
|||
}
|
||||
|
||||
class TestObject {
|
||||
|
||||
public function getA() {
|
||||
return 'A';
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\serialization\Unit\EntityResolver;
|
||||
|
||||
use Drupal\Core\Entity\EntityRepositoryInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\EntityResolver\UuidResolver;
|
||||
|
||||
|
@ -29,7 +30,7 @@ class UuidResolverTest extends UnitTestCase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityManager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
|
||||
$this->entityManager = $this->getMockBuilder(EntityRepositoryInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\TraversableTypedDataInterface;
|
||||
use Drupal\serialization\Normalizer\ComplexDataNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
@ -19,6 +18,8 @@ use Symfony\Component\Serializer\Serializer;
|
|||
*/
|
||||
class ComplexDataNormalizerTest extends UnitTestCase {
|
||||
|
||||
use InternalTypedDataTestTrait;
|
||||
|
||||
/**
|
||||
* Test format string.
|
||||
*
|
||||
|
@ -44,103 +45,77 @@ class ComplexDataNormalizerTest extends UnitTestCase {
|
|||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization(new TestComplexData()));
|
||||
$complex_data = $this->prophesize(ComplexDataInterface::class)->reveal();
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($complex_data));
|
||||
// Also test that an object not implementing ComplexDataInterface fails.
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test normalizing complex data.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$context = ['test' => 'test'];
|
||||
|
||||
public function testNormalizeComplexData() {
|
||||
$serializer_prophecy = $this->prophesize(Serializer::class);
|
||||
|
||||
$serializer_prophecy->normalize('A', static::TEST_FORMAT, $context)
|
||||
->shouldBeCalled();
|
||||
$serializer_prophecy->normalize('B', static::TEST_FORMAT, $context)
|
||||
$non_internal_property = $this->getTypedDataProperty(FALSE);
|
||||
|
||||
$serializer_prophecy->normalize($non_internal_property, static::TEST_FORMAT, [])
|
||||
->willReturn('A-normalized')
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->normalizer->setSerializer($serializer_prophecy->reveal());
|
||||
|
||||
$complex_data = new TestComplexData(['a' => 'A', 'b' => 'B']);
|
||||
$this->normalizer->normalize($complex_data, static::TEST_FORMAT, $context);
|
||||
$complex_data = $this->prophesize(ComplexDataInterface::class);
|
||||
$complex_data->getProperties(TRUE)
|
||||
->willReturn([
|
||||
'prop:a' => $non_internal_property,
|
||||
'prop:internal' => $this->getTypedDataProperty(TRUE),
|
||||
])
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($complex_data->reveal(), static::TEST_FORMAT);
|
||||
$this->assertEquals(['prop:a' => 'A-normalized'], $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test normalize() where $object does not implement ComplexDataInterface.
|
||||
*
|
||||
* Normalizers extending ComplexDataNormalizer may have a different supported
|
||||
* class.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalizeNonComplex() {
|
||||
$normalizer = new TestExtendedNormalizer();
|
||||
$serialization_context = ['test' => 'test'];
|
||||
|
||||
$serializer_prophecy = $this->prophesize(Serializer::class);
|
||||
$serializer_prophecy->normalize('A', static::TEST_FORMAT, $serialization_context)
|
||||
->willReturn('A-normalized')
|
||||
->shouldBeCalled();
|
||||
$serializer_prophecy->normalize('B', static::TEST_FORMAT, $serialization_context)
|
||||
->willReturn('B-normalized')
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalizer->setSerializer($serializer_prophecy->reveal());
|
||||
|
||||
$stdClass = new \stdClass();
|
||||
$stdClass->a = 'A';
|
||||
$stdClass->b = 'B';
|
||||
|
||||
$normalized = $normalizer->normalize($stdClass, static::TEST_FORMAT, $serialization_context);
|
||||
$this->assertEquals(['a' => 'A-normalized', 'b' => 'B-normalized'], $normalized);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test class implementing ComplexDataInterface and IteratorAggregate.
|
||||
* Test normalizer with a different supported class.
|
||||
*/
|
||||
class TestComplexData implements \IteratorAggregate, ComplexDataInterface {
|
||||
|
||||
private $values;
|
||||
|
||||
public function __construct(array $values = []) {
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function getIterator() {
|
||||
return new \ArrayIterator($this->values);
|
||||
}
|
||||
|
||||
public function applyDefaultValue($notify = TRUE) {
|
||||
}
|
||||
|
||||
public static function createInstance($definition, $name = NULL, TraversableTypedDataInterface $parent = NULL) {
|
||||
}
|
||||
|
||||
public function get($property_name) {
|
||||
}
|
||||
|
||||
public function getConstraints() {
|
||||
}
|
||||
|
||||
public function getDataDefinition() {
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
}
|
||||
|
||||
public function getParent() {
|
||||
}
|
||||
|
||||
public function getProperties($include_computed = FALSE) {
|
||||
}
|
||||
|
||||
public function getPropertyPath() {
|
||||
}
|
||||
|
||||
public function getRoot() {
|
||||
}
|
||||
|
||||
public function getString() {
|
||||
}
|
||||
|
||||
public function getValue() {
|
||||
}
|
||||
|
||||
public function isEmpty() {
|
||||
}
|
||||
|
||||
public function onChange($name) {
|
||||
}
|
||||
|
||||
public function set($property_name, $value, $notify = TRUE) {
|
||||
}
|
||||
|
||||
public function setContext($name = NULL, TraversableTypedDataInterface $parent = NULL) {
|
||||
}
|
||||
|
||||
public function setValue($value, $notify = TRUE) {
|
||||
}
|
||||
|
||||
public function toArray() {
|
||||
}
|
||||
|
||||
public function validate() {
|
||||
}
|
||||
class TestExtendedNormalizer extends ComplexDataNormalizer {
|
||||
protected $supportedInterfaceOrClass = \stdClass::class;
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\serialization\Normalizer\ConfigEntityNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -17,7 +20,13 @@ class ConfigEntityNormalizerTest extends UnitTestCase {
|
|||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$test_export_properties = ['test' => 'test'];
|
||||
$test_export_properties = [
|
||||
'test' => 'test',
|
||||
'_core' => [
|
||||
'default_config_hash' => $this->randomMachineName(),
|
||||
$this->randomMachineName() => 'some random key',
|
||||
],
|
||||
];
|
||||
|
||||
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$normalizer = new ConfigEntityNormalizer($entity_manager);
|
||||
|
@ -27,7 +36,61 @@ class ConfigEntityNormalizerTest extends UnitTestCase {
|
|||
->method('toArray')
|
||||
->will($this->returnValue($test_export_properties));
|
||||
|
||||
$this->assertSame($test_export_properties, $normalizer->normalize($config_entity));
|
||||
$this->assertSame(['test' => 'test'], $normalizer->normalize($config_entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalize() {
|
||||
$test_value = $this->randomMachineName();
|
||||
$data = [
|
||||
'test' => $test_value,
|
||||
'_core' => [
|
||||
'default_config_hash' => $this->randomMachineName(),
|
||||
$this->randomMachineName() => 'some random key',
|
||||
],
|
||||
];
|
||||
|
||||
$expected_storage_data = [
|
||||
'test' => $test_value,
|
||||
];
|
||||
|
||||
// Mock of the entity storage, to test our expectation that the '_core' key
|
||||
// never makes it to that point, thanks to the denormalizer omitting it.
|
||||
$entity_storage = $this->prophesize(EntityStorageInterface::class);
|
||||
$entity_storage->create($expected_storage_data)
|
||||
->shouldBeCalled()
|
||||
->will(function ($args) {
|
||||
$entity = new \stdClass();
|
||||
$entity->received_data = $args[0];
|
||||
return $entity;
|
||||
});
|
||||
|
||||
// Stubs for the denormalizer going from entity manager to entity storage.
|
||||
$entity_type_id = $this->randomMachineName();
|
||||
$entity_type_class = $this->randomMachineName();
|
||||
$entity_manager = $this->prophesize(EntityManagerInterface::class);
|
||||
$entity_manager->getEntityTypeFromClass($entity_type_class)
|
||||
->willReturn($entity_type_id);
|
||||
$entity_manager->getDefinition($entity_type_id, FALSE)
|
||||
->willReturn($this->prophesize(ConfigEntityTypeInterface::class)->reveal());
|
||||
$entity_manager->getStorage($entity_type_id)
|
||||
->willReturn($entity_storage->reveal());
|
||||
$normalizer = new ConfigEntityNormalizer($entity_manager->reveal());
|
||||
|
||||
// Verify the denormalizer still works correctly: the mock above creates an
|
||||
// artificial entity object containing exactly the data it received. It also
|
||||
// should still set _restSubmittedFields correctly.
|
||||
$expected_denormalization = (object) [
|
||||
'_restSubmittedFields' => [
|
||||
'test',
|
||||
],
|
||||
'received_data' => [
|
||||
'test' => $test_value,
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected_denormalization, $normalizer->denormalize($data, $entity_type_class, 'json'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
use Drupal\serialization\Normalizer\ContentEntityNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -67,16 +70,20 @@ class ContentEntityNormalizerTest extends UnitTestCase {
|
|||
->will($this->returnValue('test'));
|
||||
|
||||
$definitions = [
|
||||
'field_1' => $this->createMockFieldListItem(),
|
||||
'field_2' => $this->createMockFieldListItem(FALSE),
|
||||
'field_accessible_external' => $this->createMockFieldListItem(TRUE, FALSE),
|
||||
'field_non-accessible_external' => $this->createMockFieldListItem(FALSE, FALSE),
|
||||
'field_accessible_internal' => $this->createMockFieldListItem(TRUE, TRUE),
|
||||
'field_non-accessible_internal' => $this->createMockFieldListItem(FALSE, TRUE),
|
||||
];
|
||||
$content_entity_mock = $this->createMockForContentEntity($definitions);
|
||||
|
||||
$normalized = $this->contentEntityNormalizer->normalize($content_entity_mock, 'test_format');
|
||||
|
||||
$this->assertArrayHasKey('field_1', $normalized);
|
||||
$this->assertEquals('test', $normalized['field_1']);
|
||||
$this->assertArrayNotHasKey('field_2', $normalized);
|
||||
$this->assertArrayHasKey('field_accessible_external', $normalized);
|
||||
$this->assertEquals('test', $normalized['field_accessible_external']);
|
||||
$this->assertArrayNotHasKey('field_non-accessible_external', $normalized);
|
||||
$this->assertArrayNotHasKey('field_accessible_internal', $normalized);
|
||||
$this->assertArrayNotHasKey('field_non-accessible_internal', $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,8 +106,8 @@ class ContentEntityNormalizerTest extends UnitTestCase {
|
|||
// The mock account should get passed directly into the access() method on
|
||||
// field items from $context['account'].
|
||||
$definitions = [
|
||||
'field_1' => $this->createMockFieldListItem(TRUE, $mock_account),
|
||||
'field_2' => $this->createMockFieldListItem(FALSE, $mock_account),
|
||||
'field_1' => $this->createMockFieldListItem(TRUE, FALSE, $mock_account),
|
||||
'field_2' => $this->createMockFieldListItem(FALSE, FALSE, $mock_account),
|
||||
];
|
||||
$content_entity_mock = $this->createMockForContentEntity($definitions);
|
||||
|
||||
|
@ -121,11 +128,15 @@ class ContentEntityNormalizerTest extends UnitTestCase {
|
|||
public function createMockForContentEntity($definitions) {
|
||||
$content_entity_mock = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getFields'])
|
||||
->setMethods(['getTypedData'])
|
||||
->getMockForAbstractClass();
|
||||
$content_entity_mock->expects($this->once())
|
||||
->method('getFields')
|
||||
->will($this->returnValue($definitions));
|
||||
$typed_data = $this->prophesize(ComplexDataInterface::class);
|
||||
$typed_data->getProperties(TRUE)
|
||||
->willReturn($definitions)
|
||||
->shouldBeCalled();
|
||||
$content_entity_mock->expects($this->any())
|
||||
->method('getTypedData')
|
||||
->will($this->returnValue($typed_data->reveal()));
|
||||
|
||||
return $content_entity_mock;
|
||||
}
|
||||
|
@ -134,16 +145,26 @@ class ContentEntityNormalizerTest extends UnitTestCase {
|
|||
* Creates a mock field list item.
|
||||
*
|
||||
* @param bool $access
|
||||
* @param bool $internal
|
||||
* @param \Drupal\Core\Session\AccountInterface $user_context
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldItemListInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function createMockFieldListItem($access = TRUE, $user_context = NULL) {
|
||||
protected function createMockFieldListItem($access, $internal, AccountInterface $user_context = NULL) {
|
||||
$data_definition = $this->prophesize(DataDefinitionInterface::class);
|
||||
$mock = $this->getMock('Drupal\Core\Field\FieldItemListInterface');
|
||||
$mock->expects($this->once())
|
||||
->method('access')
|
||||
->with('view', $user_context)
|
||||
->will($this->returnValue($access));
|
||||
|
||||
->method('getDataDefinition')
|
||||
->will($this->returnValue($data_definition->reveal()));
|
||||
$data_definition->isInternal()
|
||||
->willReturn($internal)
|
||||
->shouldBeCalled();
|
||||
if (!$internal) {
|
||||
$mock->expects($this->once())
|
||||
->method('access')
|
||||
->with('view', $user_context)
|
||||
->will($this->returnValue($access));
|
||||
}
|
||||
return $mock;
|
||||
}
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ class EntityNormalizerTest extends UnitTestCase {
|
|||
->with('bundle')
|
||||
->will($this->returnValue('test_type'));
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->method('entityClassImplements')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(TRUE);
|
||||
|
||||
|
@ -240,7 +240,7 @@ class EntityNormalizerTest extends UnitTestCase {
|
|||
->with('bundle')
|
||||
->will($this->returnValue('test_type'));
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->method('entityClassImplements')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(TRUE);
|
||||
|
||||
|
@ -302,6 +302,10 @@ class EntityNormalizerTest extends UnitTestCase {
|
|||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->once())
|
||||
->method('entityClassImplements')
|
||||
->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('entityClassImplements')
|
||||
->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')
|
||||
|
|
|
@ -3,11 +3,20 @@
|
|||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\TypedData\Type\IntegerInterface;
|
||||
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\locale\StringInterface;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -16,6 +25,8 @@ use Symfony\Component\Serializer\Serializer;
|
|||
*/
|
||||
class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
|
||||
use InternalTypedDataTestTrait;
|
||||
|
||||
/**
|
||||
* The mock serializer.
|
||||
*
|
||||
|
@ -37,22 +48,40 @@ 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.
|
||||
$this->serializer->normalize(Argument::cetera())
|
||||
->willReturn(['value' => 'test']);
|
||||
->willReturn('test');
|
||||
|
||||
$this->normalizer->setSerializer($this->serializer->reveal());
|
||||
|
||||
$this->fieldItem = $this->prophesize(EntityReferenceItem::class);
|
||||
$this->fieldItem->getIterator()
|
||||
->willReturn(new \ArrayIterator(['target_id' => []]));
|
||||
|
||||
$this->fieldDefinition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,6 +92,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
|
||||
*/
|
||||
|
@ -85,14 +122,25 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
|||
->willReturn($entity->reveal())
|
||||
->shouldBeCalled();
|
||||
|
||||
$field_definition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
$field_definition->getSetting('target_type')
|
||||
->willReturn('test_type');
|
||||
|
||||
$this->fieldItem->getFieldDefinition()
|
||||
->willReturn($field_definition->reveal());
|
||||
|
||||
$this->fieldItem->get('entity')
|
||||
->willReturn($entity_reference)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->getProperties(TRUE)
|
||||
->willReturn(['target_id' => $this->getTypedDataProperty(FALSE)])
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->fieldItem->reveal());
|
||||
|
||||
$expected = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_id' => 'test',
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
'url' => $test_url,
|
||||
|
@ -100,6 +148,46 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
|||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalizeWithEmptyTaxonomyTermReference() {
|
||||
// Override the serializer prophecy from setUp() to return a zero value.
|
||||
$this->serializer = $this->prophesize(Serializer::class);
|
||||
// Set up the serializer to return an entity property.
|
||||
$this->serializer->normalize(Argument::cetera())
|
||||
->willReturn(0);
|
||||
|
||||
$this->normalizer->setSerializer($this->serializer->reveal());
|
||||
|
||||
$entity_reference = $this->prophesize(TypedDataInterface::class);
|
||||
$entity_reference->getValue()
|
||||
->willReturn(NULL)
|
||||
->shouldBeCalled();
|
||||
|
||||
$field_definition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
$field_definition->getSetting('target_type')
|
||||
->willReturn('taxonomy_term');
|
||||
|
||||
$this->fieldItem->getFieldDefinition()
|
||||
->willReturn($field_definition->reveal());
|
||||
|
||||
$this->fieldItem->get('entity')
|
||||
->willReturn($entity_reference)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->getProperties(TRUE)
|
||||
->willReturn(['target_id' => $this->getTypedDataProperty(FALSE)])
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->fieldItem->reveal());
|
||||
|
||||
$expected = [
|
||||
'target_id' => NULL,
|
||||
];
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
|
@ -109,16 +197,208 @@ class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
|||
->willReturn(NULL)
|
||||
->shouldBeCalled();
|
||||
|
||||
$field_definition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
$field_definition->getSetting('target_type')
|
||||
->willReturn('test_type');
|
||||
|
||||
$this->fieldItem->getFieldDefinition()
|
||||
->willReturn($field_definition->reveal());
|
||||
|
||||
$this->fieldItem->get('entity')
|
||||
->willReturn($entity_reference->reveal())
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->getProperties(TRUE)
|
||||
->willReturn(['target_id' => $this->getTypedDataProperty(FALSE)])
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->fieldItem->reveal());
|
||||
|
||||
$expected = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_id' => 'test',
|
||||
];
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithTypeAndUuid() {
|
||||
$data = [
|
||||
'target_id' => '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->getProperties()->willReturn([
|
||||
'target_id' => $this->prophesize(IntegerInterface::class),
|
||||
]);
|
||||
$this->fieldItem->setValue(['target_id' => 'test'])->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithUuidWithoutType() {
|
||||
$data = [
|
||||
'target_id' => '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->getProperties()->willReturn([
|
||||
'target_id' => $this->prophesize(IntegerInterface::class),
|
||||
]);
|
||||
$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' => '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' => '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' => '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' => '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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::constructValue
|
||||
*/
|
||||
public function testConstructValueProperties() {
|
||||
$data = [
|
||||
'target_id' => 'test',
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
'extra_property' => 'extra_value',
|
||||
];
|
||||
|
||||
$entity = $this->prophesize(FieldableEntityInterface::class);
|
||||
$entity->id()
|
||||
->willReturn('test')
|
||||
->shouldBeCalled();
|
||||
$this->entityRepository
|
||||
->loadEntityByUuid($data['target_type'], $data['target_uuid'])
|
||||
->willReturn($entity)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->getProperties()->willReturn([
|
||||
'target_id' => $this->prophesize(IntegerInterface::class),
|
||||
'extra_property' => $this->prophesize(StringInterface::class),
|
||||
]);
|
||||
$this->fieldItem->setValue([
|
||||
'target_id' => 'test',
|
||||
'extra_property' => 'extra_value',
|
||||
])->shouldBeCalled();
|
||||
|
||||
$this->assertDenormalize($data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinitionInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
|
||||
/**
|
||||
* Trait that provides mocked typed data objects.
|
||||
*/
|
||||
trait InternalTypedDataTestTrait {
|
||||
|
||||
/**
|
||||
* Gets a typed data property.
|
||||
*
|
||||
* @param bool $internal
|
||||
* Whether the typed data property is internal.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\TypedDataInterface
|
||||
* The typed data property.
|
||||
*/
|
||||
protected function getTypedDataProperty($internal = TRUE) {
|
||||
$definition = $this->prophesize(DataDefinitionInterface::class);
|
||||
$definition->isInternal()
|
||||
->willReturn($internal)
|
||||
->shouldBeCalled();
|
||||
$definition = $definition->reveal();
|
||||
|
||||
$property = $this->prophesize(TypedDataInterface::class);
|
||||
$property->getDataDefinition()
|
||||
->willReturn($definition)
|
||||
->shouldBeCalled();
|
||||
return $property->reveal();
|
||||
}
|
||||
|
||||
}
|
|
@ -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,168 @@
|
|||
<?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 {
|
||||
|
||||
use InternalTypedDataTestTrait;
|
||||
|
||||
/**
|
||||
* @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]));
|
||||
|
||||
$value_property = $this->getTypedDataProperty(FALSE);
|
||||
$timestamp_item->getProperties(TRUE)
|
||||
->willReturn(['value' => $value_property])
|
||||
->shouldBeCalled();
|
||||
|
||||
$serializer_prophecy = $this->prophesize(Serializer::class);
|
||||
|
||||
$serializer_prophecy->normalize($value_property, NULL, [])
|
||||
->willReturn(1478422920)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->normalizer->setSerializer($serializer_prophecy->reveal());
|
||||
|
||||
$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 a new issue