first commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# Before Drupal 8.3, typed data primitive values were normalized as strings, as
|
||||
# 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
|
||||
@@ -0,0 +1,7 @@
|
||||
serialization.settings:
|
||||
type: config_object
|
||||
label: 'Serialization settings'
|
||||
mapping:
|
||||
bc_primitives_as_strings:
|
||||
type: boolean
|
||||
label: 'Whether to retain pre Drupal 8.3 behavior of serializing all primitive items as strings.'
|
||||
@@ -0,0 +1,12 @@
|
||||
name: Serialization
|
||||
type: module
|
||||
description: Provides a service for (de)serializing data to/from formats such as JSON and XML
|
||||
package: Web services
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-19
|
||||
version: '8.3.1'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1492622988
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Update functions for the Serialization module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function serialization_requirements($phase) {
|
||||
$requirements = [];
|
||||
|
||||
if ($phase == 'runtime') {
|
||||
$requirements['serialization_as_strings'] = [
|
||||
'title' => t('Serialized data types'),
|
||||
'severity' => REQUIREMENT_INFO,
|
||||
];
|
||||
|
||||
if (\Drupal::config('serialization.settings')->get('bc_primitives_as_strings')) {
|
||||
$requirements['serialization_as_strings']['value'] = t('Enabled');
|
||||
$requirements['serialization_as_strings']['description'] = t('The Serialization API is configured to output only string values for REST and other applications (instead of integers or Booleans when appropriate). <a href="https://www.drupal.org/node/2837696">Disabling this backwards compatibility mode</a> is recommended unless your sites or applications require string output.');
|
||||
}
|
||||
else {
|
||||
$requirements['serialization_as_strings']['value'] = t('Not enabled');
|
||||
$requirements['serialization_as_strings']['description'] = t('The Serialization API is configured with the recommended default and outputs typed values (integers, Booleans, or strings as appropriate) for REST and other applications. If your site or applications require string output, you can <a href="https://www.drupal.org/node/2837696">enable backwards compatibility mode</a>.');
|
||||
}
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see hal_update_8301()
|
||||
*/
|
||||
function serialization_update_8301() {}
|
||||
|
||||
/**
|
||||
* Add serialization.settings::bc_primitives_as_strings configuration.
|
||||
*/
|
||||
function serialization_update_8302() {
|
||||
$config_factory = \Drupal::configFactory();
|
||||
$config_factory->getEditable('serialization.settings')
|
||||
->set('bc_primitives_as_strings', FALSE)
|
||||
->save(TRUE);
|
||||
|
||||
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>');
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides a service for (de)serializing data to/from formats such as JSON and XML.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function serialization_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.serialization':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The Serialization module provides a service for serializing and deserializing data to and from formats such as JSON and XML.') . '</p>';
|
||||
$output .= '<p>' . t('Serialization is the process of converting data structures like arrays and objects into a string. This allows the data to be represented in a way that is easy to exchange and store (for example, for transmission over the Internet or for storage in a local file system). These representations can then be deserialized to get back to the original data structures.') . '</p>';
|
||||
$output .= '<p>' . t('The serializer splits this process into two parts. Normalization converts an object to a normalized array structure. Encoding takes that array and converts it to a string.') . '</p>';
|
||||
$output .= '<p>' . t('This module does not have a user interface. It is used by other modules which need to serialize data, such as <a href=":rest">REST</a>.', [':rest' => (\Drupal::moduleHandler()->moduleExists('rest')) ? \Drupal::url('help.page', ['name' => 'rest']) : '#']) . '</p>';
|
||||
$output .= '<p>' . t('For more information, see the <a href=":doc_url">online documentation for the Serialization module</a>.', [':doc_url' => 'https://www.drupal.org/documentation/modules/serialization']) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
services:
|
||||
serializer:
|
||||
class: Symfony\Component\Serializer\Serializer
|
||||
arguments: [{ }, { }]
|
||||
serializer.normalizer.config_entity:
|
||||
class: Drupal\serialization\Normalizer\ConfigEntityNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
arguments: ['@entity.manager']
|
||||
serializer.normalizer.content_entity:
|
||||
class: Drupal\serialization\Normalizer\ContentEntityNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
arguments: ['@entity.manager']
|
||||
serializer.normalizer.entity:
|
||||
class: Drupal\serialization\Normalizer\EntityNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
arguments: ['@entity.manager']
|
||||
serializer.normalizer.primitive_data:
|
||||
class: Drupal\serialization\Normalizer\PrimitiveDataNormalizer
|
||||
tags:
|
||||
- { name: normalizer, priority: 5, bc: bc_primitives_as_strings, bc_config_name: 'serialization.settings' }
|
||||
serializer.normalizer.complex_data:
|
||||
class: Drupal\serialization\Normalizer\ComplexDataNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
serializer.normalizer.entity_reference_field_item:
|
||||
class: Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
|
||||
tags:
|
||||
# Set the priority lower than the hal entity reference field item
|
||||
# normalizer, so that we do not replace that for hal_json but higher than
|
||||
# this modules generic field item normalizer.
|
||||
# @todo Find a better way for this in https://www.drupal.org/node/2575761.
|
||||
- { name: normalizer, priority: 8 }
|
||||
serialization.normalizer.field_item:
|
||||
class: Drupal\serialization\Normalizer\FieldItemNormalizer
|
||||
tags:
|
||||
# Priority must be lower than serializer.normalizer.field_item.hal and any
|
||||
# field type specific normalizer such as
|
||||
# serializer.normalizer.entity_reference_field_item.
|
||||
- { name: normalizer, priority: 6 }
|
||||
serialization.normalizer.field:
|
||||
class: Drupal\serialization\Normalizer\FieldNormalizer
|
||||
tags:
|
||||
# Priority must be lower than serializer.normalizer.field.hal.
|
||||
- { name: normalizer, priority: 6 }
|
||||
serializer.normalizer.list:
|
||||
class: Drupal\serialization\Normalizer\ListNormalizer
|
||||
tags:
|
||||
# Priority must be higher than serialization.normalizer.field but less
|
||||
# than hal field normalizer.
|
||||
- { name: normalizer, priority: 9 }
|
||||
serializer.normalizer.password_field_item:
|
||||
class: Drupal\serialization\Normalizer\NullNormalizer
|
||||
arguments: ['Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem']
|
||||
tags:
|
||||
- { name: normalizer, priority: 20 }
|
||||
serializer.normalizer.safe_string:
|
||||
class: Drupal\serialization\Normalizer\MarkupNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
serializer.normalizer.typed_data:
|
||||
class: Drupal\serialization\Normalizer\TypedDataNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
serializer.encoder.json:
|
||||
class: Drupal\serialization\Encoder\JsonEncoder
|
||||
tags:
|
||||
- { name: encoder, format: json }
|
||||
serializer.encoder.xml:
|
||||
class: Drupal\serialization\Encoder\XmlEncoder
|
||||
tags:
|
||||
- { name: encoder, format: xml }
|
||||
serializer.entity_resolver:
|
||||
class: Drupal\serialization\EntityResolver\ChainEntityResolver
|
||||
serializer.entity_resolver.uuid:
|
||||
class: Drupal\serialization\EntityResolver\UuidResolver
|
||||
tags:
|
||||
- { name: entity_resolver}
|
||||
arguments: ['@entity.manager']
|
||||
serialization.entity_resolver.target_id:
|
||||
class: Drupal\serialization\EntityResolver\TargetIdResolver
|
||||
tags:
|
||||
- { name: entity_resolver}
|
||||
serialization.exception.default:
|
||||
class: Drupal\serialization\EventSubscriber\DefaultExceptionSubscriber
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
arguments: ['@serializer', '%serializer.formats%']
|
||||
serialization.user_route_alter_subscriber:
|
||||
class: Drupal\serialization\EventSubscriber\UserRouteAlterSubscriber
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
arguments: ['%serializer.formats%']
|
||||
serialization.bc_config_subscriber:
|
||||
class: Drupal\serialization\EventSubscriber\BcConfigSubscriber
|
||||
tags:
|
||||
- { name: event_subscriber }
|
||||
arguments: ['@kernel']
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Encoder;
|
||||
|
||||
use Symfony\Component\Serializer\Encoder\DecoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\EncoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\JsonDecode;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncode;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder as BaseJsonEncoder;
|
||||
|
||||
/**
|
||||
* Adds 'ajax to the supported content types of the JSON encoder'
|
||||
*/
|
||||
class JsonEncoder extends BaseJsonEncoder implements EncoderInterface, DecoderInterface {
|
||||
|
||||
/**
|
||||
* The formats that this Encoder supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $format = ['json', 'ajax'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(JsonEncode $encodingImpl = NULL, JsonDecode $decodingImpl = NULL) {
|
||||
// Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be
|
||||
// embedded into HTML.
|
||||
// @see \Symfony\Component\HttpFoundation\JsonResponse
|
||||
$json_encoding_options = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT;
|
||||
$this->encodingImpl = $encodingImpl ?: new JsonEncode($json_encoding_options);
|
||||
$this->decodingImpl = $decodingImpl ?: new JsonDecode(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsEncoding($format) {
|
||||
return in_array($format, static::$format);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDecoding($format) {
|
||||
return in_array($format, static::$format);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Encoder;
|
||||
|
||||
use Symfony\Component\Serializer\Encoder\EncoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\DecoderInterface;
|
||||
use Symfony\Component\Serializer\Encoder\XmlEncoder as BaseXmlEncoder;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class XmlEncoder implements EncoderInterface, DecoderInterface {
|
||||
|
||||
/**
|
||||
* The formats that this Encoder supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $format = ['xml'];
|
||||
|
||||
/**
|
||||
* An instance of the Symfony XmlEncoder to perform the actual encoding.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Encoder\XmlEncoder
|
||||
*/
|
||||
protected $baseEncoder;
|
||||
|
||||
/**
|
||||
* Gets the base encoder instance.
|
||||
*
|
||||
* @return \Symfony\Component\Serializer\Encoder\XmlEncoder
|
||||
* The base encoder.
|
||||
*/
|
||||
public function getBaseEncoder() {
|
||||
if (!isset($this->baseEncoder)) {
|
||||
$this->baseEncoder = new BaseXmlEncoder();
|
||||
}
|
||||
|
||||
return $this->baseEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base encoder instance.
|
||||
*
|
||||
* @param \Symfony\Component\Serializer\Encoder\XmlEncoder $encoder
|
||||
*/
|
||||
public function setBaseEncoder($encoder) {
|
||||
$this->baseEncoder = $encoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function encode($data, $format, array $context = []){
|
||||
return $this->getBaseEncoder()->encode($data, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsEncoding($format) {
|
||||
return in_array($format, static::$format);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function decode($data, $format, array $context = []){
|
||||
return $this->getBaseEncoder()->decode($data, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsDecoding($format) {
|
||||
return in_array($format, static::$format);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Resolver delegating the entity resolution to a chain of resolvers.
|
||||
*/
|
||||
class ChainEntityResolver implements ChainEntityResolverInterface {
|
||||
|
||||
/**
|
||||
* The concrete resolvers.
|
||||
*
|
||||
* @var \Drupal\serialization\EntityResolver\EntityResolverInterface[]
|
||||
*/
|
||||
protected $resolvers = [];
|
||||
|
||||
/**
|
||||
* Constructs a ChainEntityResolver object.
|
||||
*
|
||||
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface[] $resolvers
|
||||
* The array of concrete resolvers.
|
||||
*/
|
||||
public function __construct(array $resolvers = []) {
|
||||
$this->resolvers = $resolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addResolver(EntityResolverInterface $resolver) {
|
||||
$this->resolvers[] = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(NormalizerInterface $normalizer, $data, $entity_type) {
|
||||
foreach ($this->resolvers as $resolver) {
|
||||
$resolved = $resolver->resolve($normalizer, $data, $entity_type);
|
||||
if (isset($resolved)) {
|
||||
return $resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
/**
|
||||
* An interface for delegating a entity resolution to a chain of resolvers.
|
||||
*/
|
||||
interface ChainEntityResolverInterface extends EntityResolverInterface {
|
||||
|
||||
/**
|
||||
* Adds an entity resolver.
|
||||
*
|
||||
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface $resolver
|
||||
* The entity resolver to add.
|
||||
*/
|
||||
public function addResolver(EntityResolverInterface $resolver);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
interface EntityResolverInterface {
|
||||
|
||||
/**
|
||||
* Returns the local ID of an entity referenced by serialized data.
|
||||
*
|
||||
* Drupal entities are loaded by and internally referenced by a local ID.
|
||||
* Because different websites can use the same local ID to refer to different
|
||||
* entities (e.g., node "1" can be a different node on foo.com and bar.com, or
|
||||
* on example.com and staging.example.com), it is generally unsuitable for use
|
||||
* in hypermedia data exchanges. Instead, UUIDs, URIs, or other globally
|
||||
* unique IDs are preferred.
|
||||
*
|
||||
* This function takes a $data array representing partially deserialized data
|
||||
* for an entity reference, and resolves it to a local entity ID. For example,
|
||||
* depending on the data specification being used, $data might contain a
|
||||
* 'uuid' key, a 'uri' key, a 'href' key, or some other data identifying the
|
||||
* entity, and it is up to the implementor of this interface to resolve that
|
||||
* appropriately for the specification being used.
|
||||
*
|
||||
* @param \Symfony\Component\Serializer\Normalizer\NormalizerInterface $normalizer
|
||||
* The Normalizer which is handling the data.
|
||||
* @param array $data
|
||||
* The data passed into the calling Normalizer.
|
||||
* @param string $entity_type
|
||||
* The type of entity being resolved; e.g., 'node' or 'user'.
|
||||
*
|
||||
* @return string|null
|
||||
* Returns the local entity ID, if found. Otherwise, returns NULL.
|
||||
*/
|
||||
public function resolve(NormalizerInterface $normalizer, $data, $entity_type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Resolves entities from data that contains an entity target ID.
|
||||
*/
|
||||
class TargetIdResolver implements EntityResolverInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(NormalizerInterface $normalizer, $data, $entity_type) {
|
||||
if (isset($data['target_id'])) {
|
||||
return $data['target_id'];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Interface for extracting UUID from entity reference data when denormalizing.
|
||||
*/
|
||||
interface UuidReferenceInterface extends NormalizerInterface {
|
||||
|
||||
/**
|
||||
* Get the uuid from the data array.
|
||||
*
|
||||
* @param array $data
|
||||
* The data, as was passed into the Normalizer.
|
||||
*
|
||||
* @return string
|
||||
* A UUID.
|
||||
*/
|
||||
public function getUuid($data);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EntityResolver;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Resolves entities from data that contains an entity UUID.
|
||||
*/
|
||||
class UuidResolver implements EntityResolverInterface {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a UuidResolver object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(NormalizerInterface $normalizer, $data, $entity_type) {
|
||||
// The normalizer is what knows the specification of the data being
|
||||
// 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)) {
|
||||
return $entity->id();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Config\ConfigCrudEvent;
|
||||
use Drupal\Core\Config\ConfigEvents;
|
||||
use Drupal\Core\DrupalKernelInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Config event subscriber to rebuild the container when BC config is saved.
|
||||
*/
|
||||
class BcConfigSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The Drupal Kernel.
|
||||
*
|
||||
* @var \Drupal\Core\DrupalKernelInterface
|
||||
*/
|
||||
protected $kernel;
|
||||
|
||||
/**
|
||||
* BcConfigSubscriber constructor.
|
||||
*
|
||||
* @param \Drupal\Core\DrupalKernelInterface $kernel
|
||||
* The Drupal Kernel.
|
||||
*/
|
||||
public function __construct(DrupalKernelInterface $kernel) {
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[ConfigEvents::SAVE][] = 'onConfigSave';
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the service container if serialization BC config gets updated.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigCrudEvent $event
|
||||
*/
|
||||
public function onConfigSave(ConfigCrudEvent $event) {
|
||||
$saved_config = $event->getConfig();
|
||||
|
||||
if ($saved_config->getName() === 'serialization.settings') {
|
||||
if ($event->isChanged('bc_primitives_as_strings')) {
|
||||
$this->kernel->invalidateContainer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EventSubscriber;
|
||||
|
||||
use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Handles default error responses in serialization formats.
|
||||
*/
|
||||
class DefaultExceptionSubscriber extends HttpExceptionSubscriberBase {
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The available serialization formats.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $serializerFormats = [];
|
||||
|
||||
/**
|
||||
* DefaultExceptionSubscriber constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer service.
|
||||
* @param array $serializer_formats
|
||||
* The available serialization formats.
|
||||
*/
|
||||
public function __construct(SerializerInterface $serializer, array $serializer_formats) {
|
||||
$this->serializer = $serializer;
|
||||
$this->serializerFormats = $serializer_formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getHandledFormats() {
|
||||
return $this->serializerFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all 4xx errors for all serialization failures.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on4xx(GetResponseForExceptionEvent $event) {
|
||||
/** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $exception */
|
||||
$exception = $event->getException();
|
||||
$request = $event->getRequest();
|
||||
|
||||
$format = $request->getRequestFormat();
|
||||
$content = ['message' => $event->getException()->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);
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Routing\RouteBuildEvent;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Alters user authentication routes to support additional serialization formats.
|
||||
*/
|
||||
class UserRouteAlterSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The available serialization formats.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $serializerFormats = [];
|
||||
|
||||
/**
|
||||
* UserRouteAlterSubscriber constructor.
|
||||
*
|
||||
* @param array $serializer_formats
|
||||
* The available serializer formats.
|
||||
*/
|
||||
public function __construct(array $serializer_formats) {
|
||||
$this->serializerFormats = $serializer_formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[RoutingEvents::ALTER][] = 'onRoutingAlterAddFormats';
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds supported formats to the user authentication HTTP routes.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteBuildEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function onRoutingAlterAddFormats(RouteBuildEvent $event) {
|
||||
$route_names = [
|
||||
'user.login_status.http',
|
||||
'user.login.http',
|
||||
'user.logout.http',
|
||||
];
|
||||
$routes = $event->getRouteCollection();
|
||||
foreach ($route_names as $route_name) {
|
||||
if ($route = $routes->get($route_name)) {
|
||||
$formats = explode('|', $route->getRequirement('_format'));
|
||||
$formats = array_unique(array_merge($formats, $this->serializerFormats));
|
||||
$route->setRequirement('_format', implode('|', $formats));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Converts the Drupal entity object structures to a normalized array.
|
||||
*
|
||||
* This is the default Normalizer for entities. All formats that have Encoders
|
||||
* registered with the Serializer in the DIC will be normalized with this
|
||||
* class unless another Normalizer is registered which supersedes it. If a
|
||||
* module wants to use format-specific or class-specific normalization, then
|
||||
* that module can register a new Normalizer and give it a higher priority than
|
||||
* this one.
|
||||
*/
|
||||
class ComplexDataNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = 'Drupal\Core\TypedData\ComplexDataInterface';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Normalizes/denormalizes Drupal config entity objects into an array structure.
|
||||
*/
|
||||
class ConfigEntityNormalizer extends EntityNormalizer {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Core\Config\Entity\ConfigEntityInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Normalizes/denormalizes Drupal content entities into an array structure.
|
||||
*/
|
||||
class ContentEntityNormalizer extends EntityNormalizer {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Core\Entity\ContentEntityInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $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);
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
/**
|
||||
* Normalizes/denormalizes Drupal entity objects into an array structure.
|
||||
*/
|
||||
class EntityNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
|
||||
|
||||
use FieldableEntityNormalizerTrait;
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = [EntityInterface::class];
|
||||
|
||||
/**
|
||||
* Constructs an EntityNormalizer object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager) {
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
$entity_type_id = $this->determineEntityTypeId($class, $context);
|
||||
$entity_type_definition = $this->getEntityTypeDefinition($entity_type_id);
|
||||
|
||||
// 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);
|
||||
|
||||
// Create the entity from bundle data only, then apply field values after.
|
||||
$entity = $this->entityManager->getStorage($entity_type_id)->create($bundle_data);
|
||||
|
||||
$this->denormalizeFieldData($data, $entity, $format, $context);
|
||||
}
|
||||
else {
|
||||
// Create the entity from all data.
|
||||
$entity = $this->entityManager->getStorage($entity_type_id)->create($data);
|
||||
}
|
||||
|
||||
// Pass the names of the fields whose values can be merged.
|
||||
// @todo https://www.drupal.org/node/2456257 remove this.
|
||||
$entity->_restSubmittedFields = array_keys($data);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
|
||||
/**
|
||||
* Adds the file URI to embedded file entities.
|
||||
*/
|
||||
class EntityReferenceFieldItemNormalizer extends ComplexDataNormalizer {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = EntityReferenceItem::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($field_item, $format = NULL, array $context = []) {
|
||||
$values = parent::normalize($field_item, $format, $context);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
if ($entity = $field_item->get('entity')->getValue()) {
|
||||
$values['target_type'] = $entity->getEntityTypeId();
|
||||
// Add the target entity UUID to the normalized output values.
|
||||
$values['target_uuid'] = $entity->uuid();
|
||||
|
||||
// Add a 'url' value if there is a reference and a canonical URL. Hard
|
||||
// code 'canonical' here as config entities override the default $rel
|
||||
// parameter value to 'edit-form.
|
||||
if ($url = $entity->url('canonical')) {
|
||||
$values['url'] = $url;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\FieldItemInterface;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
/**
|
||||
* Denormalizes field item object structure by updating the entity field values.
|
||||
*/
|
||||
class FieldItemNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = FieldItemInterface::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
if (!isset($context['target_instance'])) {
|
||||
throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the FieldItemNormalizer');
|
||||
}
|
||||
|
||||
if ($context['target_instance']->getParent() == NULL) {
|
||||
throw new InvalidArgumentException('The field item passed in via $context[\'target_instance\'] must have a parent set.');
|
||||
}
|
||||
|
||||
/** @var \Drupal\Core\Field\FieldItemInterface $field_item */
|
||||
$field_item = $context['target_instance'];
|
||||
|
||||
$field_item->setValue($this->constructValue($data, $context));
|
||||
return $field_item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the field item value using the incoming data.
|
||||
*
|
||||
* Most normalizers that extend this class can simply use this method to
|
||||
* construct the denormalized value without having to override denormalize()
|
||||
* and reimplementing its validation logic or its call to set the field value.
|
||||
*
|
||||
* @param mixed $data
|
||||
* The incoming data for this field item.
|
||||
* @param array $context
|
||||
* The context passed into the Normalizer.
|
||||
*
|
||||
* @return mixed
|
||||
* The value to use in Entity::setValue().
|
||||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
/**
|
||||
* Denormalizes data to Drupal field values.
|
||||
*
|
||||
* This class simply calls denormalize() on the individual FieldItems. The
|
||||
* FieldItem normalizers are responsible for setting the field values for each
|
||||
* item.
|
||||
*
|
||||
* @see \Drupal\serialization\Normalizer\FieldItemNormalizer.
|
||||
*/
|
||||
class FieldNormalizer extends ListNormalizer implements DenormalizerInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = FieldItemListInterface::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
if (!isset($context['target_instance'])) {
|
||||
throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the FieldNormalizer');
|
||||
}
|
||||
|
||||
if ($context['target_instance']->getParent() == NULL) {
|
||||
throw new InvalidArgumentException('The field passed in via $context[\'target_instance\'] must have a parent set.');
|
||||
}
|
||||
|
||||
/** @var FieldItemListInterface $items */
|
||||
$items = $context['target_instance'];
|
||||
$item_class = $items->getItemDefinition()->getClass();
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw new UnexpectedValueException(sprintf('Field values for "%s" must use an array structure', $items->getName()));
|
||||
}
|
||||
|
||||
foreach ($data as $item_data) {
|
||||
// Create a new item and pass it as the target for the unserialization of
|
||||
// $item_data. All items in field should have removed before this method
|
||||
// was called.
|
||||
// @see \Drupal\serialization\Normalizer\ContentEntityNormalizer::denormalize().
|
||||
$context['target_instance'] = $items->appendItem();
|
||||
$this->serializer->denormalize($item_data, $item_class, $format, $context);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* A trait for providing fieldable entity normalization/denormalization methods.
|
||||
*
|
||||
* @todo Move this into a FieldableEntityNormalizer in Drupal 9. This is a trait
|
||||
* used in \Drupal\serialization\Normalizer\EntityNormalizer to maintain BC.
|
||||
* @see https://www.drupal.org/node/2834734
|
||||
*/
|
||||
trait FieldableEntityNormalizerTrait {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Determines the entity type ID to denormalize as.
|
||||
*
|
||||
* @param string $class
|
||||
* The entity type class to be denormalized to.
|
||||
* @param array $context
|
||||
* The serialization context data.
|
||||
*
|
||||
* @return string
|
||||
* The entity type ID.
|
||||
*/
|
||||
protected function determineEntityTypeId($class, $context) {
|
||||
// Get the entity type ID while letting context override the $class param.
|
||||
return !empty($context['entity_type']) ? $context['entity_type'] : $this->entityManager->getEntityTypeFromClass($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity type definition.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type ID to load the definition for.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityTypeInterface
|
||||
* The loaded entity type definition.
|
||||
*
|
||||
* @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
|
||||
*/
|
||||
protected function getEntityTypeDefinition($entity_type_id) {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type_definition */
|
||||
// Get the entity type definition.
|
||||
$entity_type_definition = $this->entityManager->getDefinition($entity_type_id, FALSE);
|
||||
|
||||
// Don't try to create an entity without an entity type id.
|
||||
if (!$entity_type_definition) {
|
||||
throw new UnexpectedValueException(sprintf('The specified entity type "%s" does not exist. A valid entity type is required for denormalization', $entity_type_id));
|
||||
}
|
||||
|
||||
return $entity_type_definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denormalizes the bundle property so entity creation can use it.
|
||||
*
|
||||
* @param array $data
|
||||
* The data being denormalized.
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type_definition
|
||||
* The entity type definition.
|
||||
*
|
||||
* @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
|
||||
*
|
||||
* @return string
|
||||
* The valid bundle name.
|
||||
*/
|
||||
protected function extractBundleData(array &$data, EntityTypeInterface $entity_type_definition) {
|
||||
$bundle_key = $entity_type_definition->getKey('bundle');
|
||||
// Get the base field definitions for this entity type.
|
||||
$base_field_definitions = $this->entityManager->getBaseFieldDefinitions($entity_type_definition->id());
|
||||
|
||||
// Get the ID key from the base field definition for the bundle key or
|
||||
// default to 'value'.
|
||||
$key_id = isset($base_field_definitions[$bundle_key]) ? $base_field_definitions[$bundle_key]->getFieldStorageDefinition()->getMainPropertyName() : 'value';
|
||||
|
||||
// Normalize the bundle if it is not explicitly set.
|
||||
$bundle_value = isset($data[$bundle_key][0][$key_id]) ? $data[$bundle_key][0][$key_id] : (isset($data[$bundle_key]) ? $data[$bundle_key] : NULL);
|
||||
// Unset the bundle from the data.
|
||||
unset($data[$bundle_key]);
|
||||
|
||||
// Get the bundle entity type from the entity type definition.
|
||||
$bundle_type_id = $entity_type_definition->getBundleEntityType();
|
||||
$bundle_types = $bundle_type_id ? $this->entityManager->getStorage($bundle_type_id)->getQuery()->execute() : [];
|
||||
|
||||
// Make sure a bundle has been provided.
|
||||
if (!is_string($bundle_value)) {
|
||||
throw new UnexpectedValueException(sprintf('Could not determine entity type bundle: "%s" field is missing.', $bundle_key));
|
||||
}
|
||||
|
||||
// Make sure the submitted bundle is a valid bundle for the entity type.
|
||||
if ($bundle_types && !in_array($bundle_value, $bundle_types)) {
|
||||
throw new UnexpectedValueException(sprintf('"%s" is not a valid bundle type for denormalization.', $bundle_value));
|
||||
}
|
||||
|
||||
return [$bundle_key => $bundle_value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Denormalizes entity data by denormalizing each field individually.
|
||||
*
|
||||
* @param array $data
|
||||
* The data to denormalize.
|
||||
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
|
||||
* The fieldable entity to set field values for.
|
||||
* @param string $format
|
||||
* The serialization format.
|
||||
* @param array $context
|
||||
* The context data.
|
||||
*/
|
||||
protected function denormalizeFieldData(array $data, FieldableEntityInterface $entity, $format, array $context) {
|
||||
foreach ($data as $field_name => $field_data) {
|
||||
$field_item_list = $entity->get($field_name);
|
||||
|
||||
// Remove any values that were set as a part of entity creation (e.g
|
||||
// uuid). If the incoming field data is set to an empty array, this will
|
||||
// also have the effect of emptying the field in REST module.
|
||||
$field_item_list->setValue([]);
|
||||
$field_item_list_class = get_class($field_item_list);
|
||||
|
||||
if ($field_data) {
|
||||
// The field instance must be passed in the context so that the field
|
||||
// denormalizer can update field values for the parent entity.
|
||||
$context['target_instance'] = $field_item_list;
|
||||
$this->serializer->denormalize($field_data, $field_item_list_class, $format, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Converts list objects to arrays.
|
||||
*
|
||||
* Ordinarily, this would be handled automatically by Serializer, but since
|
||||
* there is a TypedDataNormalizer and the Field class extends TypedData, any
|
||||
* Field will be handled by that Normalizer instead of being traversed. This
|
||||
* class ensures that TypedData classes that also implement ListInterface are
|
||||
* traversed instead of simply returning getValue().
|
||||
*/
|
||||
class ListNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = 'Drupal\Core\TypedData\ListInterface';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$attributes = [];
|
||||
foreach ($object as $fieldItem) {
|
||||
$attributes[] = $this->serializer->normalize($fieldItem, $format, $context);
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Normalizes MarkupInterface objects into a string.
|
||||
*/
|
||||
class MarkupNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Component\Render\MarkupInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return (string) $object;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;
|
||||
|
||||
/**
|
||||
* Base class for Normalizers.
|
||||
*/
|
||||
abstract class NormalizerBase extends SerializerAwareNormalizer implements NormalizerInterface {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, $format = NULL) {
|
||||
// If we aren't dealing with an object or the format is not supported return
|
||||
// now.
|
||||
if (!is_object($data) || !$this->checkFormat($format)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$supported = (array) $this->supportedInterfaceOrClass;
|
||||
|
||||
return (bool) array_filter($supported, function($name) use ($data) {
|
||||
return $data instanceof $name;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization()
|
||||
*
|
||||
* This class doesn't implement DenormalizerInterface, but most of its child
|
||||
* classes do, so this method is implemented at this level to reduce code
|
||||
* duplication.
|
||||
*/
|
||||
public function supportsDenormalization($data, $type, $format = NULL) {
|
||||
// If the format is not supported return now.
|
||||
if (!$this->checkFormat($format)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$supported = (array) $this->supportedInterfaceOrClass;
|
||||
|
||||
$subclass_check = function($name) use ($type) {
|
||||
return (class_exists($name) || interface_exists($name)) && is_subclass_of($type, $name, TRUE);
|
||||
};
|
||||
|
||||
return in_array($type, $supported) || array_filter($supported, $subclass_check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided format is supported by this normalizer.
|
||||
*
|
||||
* @param string $format
|
||||
* The format to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the format is supported, FALSE otherwise. If no format is
|
||||
* specified this will return TRUE.
|
||||
*/
|
||||
protected function checkFormat($format = NULL) {
|
||||
if (!isset($format) || !isset($this->format)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return in_array($format, (array) $this->format);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Null normalizer.
|
||||
*/
|
||||
class NullNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* Constructs a NullNormalizer object.
|
||||
*
|
||||
* @param string|array $supported_interface_of_class
|
||||
* The supported interface(s) or class(es).
|
||||
*/
|
||||
public function __construct($supported_interface_of_class) {
|
||||
$this->supportedInterfaceOrClass = $supported_interface_of_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\PrimitiveInterface;
|
||||
|
||||
/**
|
||||
* Converts primitive data objects to their casted values.
|
||||
*/
|
||||
class PrimitiveDataNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = PrimitiveInterface::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
// Typed data casts NULL objects to their empty variants, so for example
|
||||
// the empty string ('') for string type data, or 0 for integer typed data.
|
||||
// In a better world with typed data implementing algebraic data types,
|
||||
// getCastedValue would return NULL, but as typed data is not aware of real
|
||||
// optional values on the primitive level, we implement our own optional
|
||||
// value normalization here.
|
||||
return $object->getValue() === NULL ? NULL : $object->getCastedValue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
/**
|
||||
* Converts typed data objects to arrays.
|
||||
*/
|
||||
class TypedDataNormalizer extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = 'Drupal\Core\TypedData\TypedDataInterface';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->getValue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
/**
|
||||
* Adds services tagged 'normalizer' and 'encoder' to the Serializer.
|
||||
*/
|
||||
class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
|
||||
|
||||
/**
|
||||
* Adds services to the Serializer.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* The container to process.
|
||||
*/
|
||||
public function process(ContainerBuilder $container) {
|
||||
$definition = $container->getDefinition('serializer.entity_resolver');
|
||||
$resolvers = [];
|
||||
|
||||
// Retrieve registered Normalizers and Encoders from the container.
|
||||
foreach ($container->findTaggedServiceIds('entity_resolver') as $id => $attributes) {
|
||||
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
||||
$resolvers[$priority][] = new Reference($id);
|
||||
}
|
||||
|
||||
// Add the registered concrete EntityResolvers to the ChainEntityResolver.
|
||||
foreach ($this->sort($resolvers) as $resolver) {
|
||||
$definition->addMethodCall('addResolver', [$resolver]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts by priority.
|
||||
*
|
||||
* Order services from highest priority number to lowest (reverse sorting).
|
||||
*
|
||||
* @param array $services
|
||||
* A nested array keyed on priority number. For each priority number, the
|
||||
* value is an array of Symfony\Component\DependencyInjection\Reference
|
||||
* objects, each a reference to a normalizer or encoder service.
|
||||
*
|
||||
* @return array
|
||||
* A flattened array of Reference objects from $services, ordered from high
|
||||
* to low priority.
|
||||
*/
|
||||
protected function sort($services) {
|
||||
$sorted = [];
|
||||
krsort($services);
|
||||
|
||||
// Flatten the array.
|
||||
foreach ($services as $a) {
|
||||
$sorted = array_merge($sorted, $a);
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization;
|
||||
|
||||
use Drupal\Core\Config\BootstrapConfigStorageFactory;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
/**
|
||||
* Adds services tagged 'normalizer' and 'encoder' to the Serializer.
|
||||
*/
|
||||
class RegisterSerializationClassesCompilerPass implements CompilerPassInterface {
|
||||
|
||||
/**
|
||||
* Adds services to the Serializer.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
|
||||
* The container to process.
|
||||
*/
|
||||
public function process(ContainerBuilder $container) {
|
||||
$definition = $container->getDefinition('serializer');
|
||||
|
||||
// Retrieve registered Normalizers and Encoders from the container.
|
||||
foreach ($container->findTaggedServiceIds('normalizer') as $id => $attributes) {
|
||||
// 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'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
||||
$normalizers[$priority][] = new Reference($id);
|
||||
}
|
||||
foreach ($container->findTaggedServiceIds('encoder') as $id => $attributes) {
|
||||
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
||||
$encoders[$priority][] = new Reference($id);
|
||||
}
|
||||
|
||||
// Add the registered Normalizers and Encoders to the Serializer.
|
||||
if (!empty($normalizers)) {
|
||||
$definition->replaceArgument(0, $this->sort($normalizers));
|
||||
}
|
||||
if (!empty($encoders)) {
|
||||
$definition->replaceArgument(1, $this->sort($encoders));
|
||||
}
|
||||
|
||||
// Find all serialization formats known.
|
||||
$formats = [];
|
||||
$format_providers = [];
|
||||
foreach ($container->findTaggedServiceIds('encoder') as $service_id => $attributes) {
|
||||
$format = $attributes[0]['format'];
|
||||
$formats[] = $format;
|
||||
|
||||
if ($provider_tag = $container->getDefinition($service_id)->getTag('_provider')) {
|
||||
$format_providers[$format] = $provider_tag[0]['provider'];
|
||||
}
|
||||
}
|
||||
$container->setParameter('serializer.formats', $formats);
|
||||
$container->setParameter('serializer.format_providers', $format_providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a normalizer BC setting is disabled or not.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function normalizerBcSettingIsEnabled($key, $config_name) {
|
||||
$settings = BootstrapConfigStorageFactory::get()->read($config_name);
|
||||
return !empty($settings[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts by priority.
|
||||
*
|
||||
* Order services from highest priority number to lowest (reverse sorting).
|
||||
*
|
||||
* @param array $services
|
||||
* A nested array keyed on priority number. For each priority number, the
|
||||
* value is an array of Symfony\Component\DependencyInjection\Reference
|
||||
* objects, each a reference to a normalizer or encoder service.
|
||||
*
|
||||
* @return array
|
||||
* A flattened array of Reference objects from $services, ordered from high
|
||||
* to low priority.
|
||||
*/
|
||||
protected function sort($services) {
|
||||
$sorted = [];
|
||||
krsort($services);
|
||||
|
||||
// Flatten the array.
|
||||
foreach ($services as $a) {
|
||||
$sorted = array_merge($sorted, $a);
|
||||
}
|
||||
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Serialization dependency injection container.
|
||||
*/
|
||||
class SerializationServiceProvider implements ServiceProviderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register(ContainerBuilder $container) {
|
||||
// Add a compiler pass for adding Normalizers and Encoders to Serializer.
|
||||
$container->addCompilerPass(new RegisterSerializationClassesCompilerPass());
|
||||
// Add a compiler pass for adding concrete Resolvers to chain Resolver.
|
||||
$container->addCompilerPass(new RegisterEntityResolversCompilerPass());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization\Tests;
|
||||
|
||||
use Drupal\Tests\serialization\Kernel\NormalizerTestBase as SerializationNormalizerTestBase;
|
||||
|
||||
/**
|
||||
* Helper base class to set up some test fields for serialization testing.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\serialization\Kernel\NormalizerTestBase instead.
|
||||
*/
|
||||
abstract class NormalizerTestBase extends SerializationNormalizerTestBase { }
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
name: 'Entity serialization test support'
|
||||
type: module
|
||||
description: 'Provides test support for entity serialization tests.'
|
||||
package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-19
|
||||
version: '8.3.1'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1492622988
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test support module for entity serialization tests.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access_alter().
|
||||
*
|
||||
* Overrides some default access control to support testing.
|
||||
*
|
||||
* @see Drupal\serialization\Tests\EntitySerializationTest::testUserNormalize()
|
||||
*/
|
||||
function entity_serialization_test_entity_field_access_alter(array &$grants, array $context) {
|
||||
// Override default access control from UserAccessControlHandler to allow
|
||||
// access to 'pass' field for the test user.
|
||||
if ($context['field_definition']->getName() == 'pass' && $context['account']->getUsername() == 'serialization_test_user') {
|
||||
$grants[':default'] = AccessResult::allowed()->inheritCacheability($grants[':default'])->addCacheableDependency($context['items']->getEntity());
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
name: 'FieldItem normalization test support'
|
||||
type: module
|
||||
description: 'Provides test support for fieldItem normalization test support.'
|
||||
package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-19
|
||||
version: '8.3.1'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1492622988
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
serializer.normalizer.silly_fielditem:
|
||||
class: Drupal\field_normalization_test\Normalization\TextItemSillyNormalizer
|
||||
tags:
|
||||
# The priority must be higher than serialization.normalizer.field_item.
|
||||
- { name: normalizer , priority: 9 }
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\field_normalization_test\Normalization;
|
||||
|
||||
use Drupal\serialization\Normalizer\FieldItemNormalizer;
|
||||
use Drupal\text\Plugin\Field\FieldType\TextItemBase;
|
||||
|
||||
/**
|
||||
* A test TextItem normalizer to test denormalization.
|
||||
*/
|
||||
class TextItemSillyNormalizer extends FieldItemNormalizer {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = TextItemBase::class;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$data = parent::normalize($object, $format, $context);
|
||||
$data['value'] .= '::silly_suffix';
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function constructValue($data, $context) {
|
||||
$value = parent::constructValue($data, $context);
|
||||
$value['value'] = str_replace('::silly_suffix', '', $value['value']);
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
name: Serialization test module
|
||||
type: module
|
||||
description: "Support module for serialization tests."
|
||||
package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-04-19
|
||||
version: '8.3.1'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1492622988
|
||||
@@ -0,0 +1,9 @@
|
||||
services:
|
||||
serializer.normalizer.serialization_test:
|
||||
class: Drupal\serialization_test\SerializationTestNormalizer
|
||||
tags:
|
||||
- { name: normalizer }
|
||||
serializer.encoder.serialization_test:
|
||||
class: Drupal\serialization_test\SerializationTestEncoder
|
||||
tags:
|
||||
- { name: encoder, format: serialization_test}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization_test;
|
||||
|
||||
use Symfony\Component\Serializer\Encoder\EncoderInterface;
|
||||
|
||||
class SerializationTestEncoder implements EncoderInterface {
|
||||
|
||||
/**
|
||||
* The format that this Encoder supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static protected $format = 'serialization_test';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function encode($data, $format, array $context = []) {
|
||||
// @see \Drupal\serialization_test\SerializationTestNormalizer::normalize().
|
||||
return 'Normalized by ' . $data['normalized_by'] . ', Encoded by SerializationTestEncoder';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsEncoding($format) {
|
||||
return static::$format === $format;
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\serialization_test;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
class SerializationTestNormalizer implements NormalizerInterface {
|
||||
|
||||
/**
|
||||
* The format that this Normalizer supports.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
static protected $format = 'serialization_test';
|
||||
|
||||
/**
|
||||
* Normalizes an object into a set of arrays/scalars.
|
||||
*
|
||||
* @param object $object
|
||||
* Object to normalize.
|
||||
* @param string $format
|
||||
* Format the normalization result will be encoded as.
|
||||
*
|
||||
* @return array
|
||||
* An array containing a normalized representation of $object, appropriate
|
||||
* for encoding to the requested format.
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$normalized = (array) $object;
|
||||
// Add identifying value that can be used to verify that the expected
|
||||
// normalizer was invoked.
|
||||
$normalized['normalized_by'] = 'SerializationTestNormalizer';
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether format is supported by this normalizer.
|
||||
*
|
||||
* @param mixed $data
|
||||
* Data to normalize.
|
||||
* @param string $format
|
||||
* Format the normalization result will be encoded as.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the normalizer can handle the request.
|
||||
*/
|
||||
public function supportsNormalization($data, $format = NULL) {
|
||||
return static::$format === $format;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests that entities references can be resolved.
|
||||
*
|
||||
* @group serialization
|
||||
*/
|
||||
class EntityResolverTest extends NormalizerTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['hal', 'rest'];
|
||||
|
||||
/**
|
||||
* The format being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $format = 'hal_json';
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// Create the test field storage.
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_entity_reference',
|
||||
'type' => 'entity_reference',
|
||||
'settings' => [
|
||||
'target_type' => 'entity_test_mulrev',
|
||||
],
|
||||
])->save();
|
||||
|
||||
// Create the test field.
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_entity_reference',
|
||||
'bundle' => 'entity_test_mulrev',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that fields referencing UUIDs can be denormalized.
|
||||
*/
|
||||
public function testUuidEntityResolver() {
|
||||
// Create an entity to get the UUID from.
|
||||
$entity = EntityTestMulRev::create(['type' => 'entity_test_mulrev']);
|
||||
$entity->set('name', 'foobar');
|
||||
$entity->set('field_test_entity_reference', [['target_id' => 1]]);
|
||||
$entity->save();
|
||||
|
||||
$field_uri = Url::fromUri('base:rest/relation/entity_test_mulrev/entity_test_mulrev/field_test_entity_reference', ['absolute' => TRUE])->toString();
|
||||
|
||||
$data = [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => Url::fromUri('base:rest/type/entity_test_mulrev/entity_test_mulrev', ['absolute' => TRUE])->toString(),
|
||||
],
|
||||
$field_uri => [
|
||||
[
|
||||
'href' => $entity->url(),
|
||||
],
|
||||
],
|
||||
],
|
||||
'_embedded' => [
|
||||
$field_uri => [
|
||||
[
|
||||
'_links' => [
|
||||
'self' => $entity->url(),
|
||||
],
|
||||
'uuid' => [
|
||||
[
|
||||
'value' => $entity->uuid(),
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$denormalized = $this->container->get('serializer')->denormalize($data, 'Drupal\entity_test\Entity\EntityTestMulRev', $this->format);
|
||||
$field_value = $denormalized->get('field_test_entity_reference')->getValue();
|
||||
$this->assertEqual($field_value[0]['target_id'], 1, 'Entity reference resolved using UUID.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
|
||||
/**
|
||||
* Tests that entities can be serialized to supported core formats.
|
||||
*
|
||||
* @group serialization
|
||||
*/
|
||||
class EntitySerializationTest extends NormalizerTestBase {
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['serialization', 'system', 'field', 'entity_test', 'text', 'filter', 'user', 'entity_serialization_test'];
|
||||
|
||||
/**
|
||||
* The test values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $values;
|
||||
|
||||
/**
|
||||
* The test entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The test user.
|
||||
*
|
||||
* @var \Drupal\user\Entity\User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer.
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The class name of the test class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityClass = 'Drupal\entity_test\Entity\EntityTest';
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// User create needs sequence table.
|
||||
$this->installSchema('system', ['sequences']);
|
||||
|
||||
// Create a test user to use as the entity owner.
|
||||
$this->user = \Drupal::entityManager()->getStorage('user')->create([
|
||||
'name' => 'serialization_test_user',
|
||||
'mail' => 'foo@example.com',
|
||||
'pass' => '123456',
|
||||
]);
|
||||
$this->user->save();
|
||||
|
||||
// Create a test entity to serialize.
|
||||
$this->values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'user_id' => $this->user->id(),
|
||||
'field_test_text' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
],
|
||||
];
|
||||
$this->entity = EntityTestMulRev::create($this->values);
|
||||
$this->entity->save();
|
||||
|
||||
$this->serializer = $this->container->get('serializer');
|
||||
|
||||
$this->installConfig(['field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the normalize function.
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$expected = [
|
||||
'id' => [
|
||||
['value' => 1],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
],
|
||||
'langcode' => [
|
||||
['value' => 'en'],
|
||||
],
|
||||
'name' => [
|
||||
['value' => $this->values['name']],
|
||||
],
|
||||
'type' => [
|
||||
['value' => 'entity_test_mulrev'],
|
||||
],
|
||||
'created' => [
|
||||
['value' => $this->entity->created->value],
|
||||
],
|
||||
'user_id' => [
|
||||
[
|
||||
// id() will return the string value as it comes from the database.
|
||||
'target_id' => (int) $this->user->id(),
|
||||
'target_type' => $this->user->getEntityTypeId(),
|
||||
'target_uuid' => $this->user->uuid(),
|
||||
'url' => $this->user->url(),
|
||||
],
|
||||
],
|
||||
'revision_id' => [
|
||||
['value' => 1],
|
||||
],
|
||||
'default_langcode' => [
|
||||
['value' => TRUE],
|
||||
],
|
||||
'non_rev_field' => [],
|
||||
'field_test_text' => [
|
||||
[
|
||||
'value' => $this->values['field_test_text']['value'],
|
||||
'format' => $this->values['field_test_text']['format'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$normalized = $this->serializer->normalize($this->entity);
|
||||
|
||||
foreach (array_keys($expected) as $fieldName) {
|
||||
$this->assertSame($expected[$fieldName], $normalized[$fieldName], "Normalization produces expected array for $fieldName.");
|
||||
}
|
||||
$this->assertEqual(array_diff_key($normalized, $expected), [], 'No unexpected data is added to the normalized array.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user normalization, using the entity_serialization_test module to
|
||||
* override some default access controls.
|
||||
*/
|
||||
public function testUserNormalize() {
|
||||
// Test password isn't available.
|
||||
$normalized = $this->serializer->normalize($this->user);
|
||||
|
||||
$this->assertFalse(array_key_exists('pass', $normalized), '"pass" key does not exist in normalized user');
|
||||
$this->assertFalse(array_key_exists('mail', $normalized), '"mail" key does not exist in normalized user');
|
||||
|
||||
// Test again using our test user, so that our access control override will
|
||||
// allow password viewing.
|
||||
$normalized = $this->serializer->normalize($this->user, NULL, ['account' => $this->user]);
|
||||
|
||||
// The key 'pass' will now exist, but the password value should be
|
||||
// normalized to NULL.
|
||||
$this->assertIdentical($normalized['pass'], [NULL], '"pass" value is normalized to [NULL]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registered Serializer's entity serialization for core's formats.
|
||||
*/
|
||||
public function testSerialize() {
|
||||
// Test that Serializer responds using the ComplexDataNormalizer and
|
||||
// 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);
|
||||
// Test 'json'.
|
||||
$actual = $this->serializer->serialize($this->entity, 'json');
|
||||
$this->assertIdentical($actual, $expected, 'Entity serializes to JSON when "json" is requested.');
|
||||
$actual = $this->serializer->serialize($normalized, 'json');
|
||||
$this->assertIdentical($actual, $expected, 'A normalized array serializes to JSON when "json" is requested');
|
||||
// Test 'ajax'.
|
||||
$actual = $this->serializer->serialize($this->entity, 'ajax');
|
||||
$this->assertIdentical($actual, $expected, 'Entity serializes to JSON when "ajax" is requested.');
|
||||
$actual = $this->serializer->serialize($normalized, 'ajax');
|
||||
$this->assertIdentical($actual, $expected, 'A normalized array serializes to JSON when "ajax" is requested');
|
||||
|
||||
// Generate the expected xml in a way that allows changes to entity property
|
||||
// order.
|
||||
$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>',
|
||||
'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>',
|
||||
'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>',
|
||||
];
|
||||
// Sort it in the same order as normalised.
|
||||
$expected = array_merge($normalized, $expected);
|
||||
// Add header and footer.
|
||||
array_unshift($expected, '<?xml version="1.0"?>' . PHP_EOL . '<response>');
|
||||
$expected[] = '</response>' . PHP_EOL;
|
||||
// Reduced the array to a string.
|
||||
$expected = implode('', $expected);
|
||||
// Test 'xml'. The output should match that of Symfony's XmlEncoder.
|
||||
$actual = $this->serializer->serialize($this->entity, 'xml');
|
||||
$this->assertIdentical($actual, $expected);
|
||||
$actual = $this->serializer->serialize($normalized, 'xml');
|
||||
$this->assertIdentical($actual, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests denormalization of an entity.
|
||||
*/
|
||||
public function testDenormalize() {
|
||||
$normalized = $this->serializer->normalize($this->entity);
|
||||
|
||||
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->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.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\entity_test\Entity\EntityTestMulRev;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Test field level normalization process.
|
||||
*
|
||||
* @group serialization
|
||||
*/
|
||||
class FieldItemSerializationTest extends NormalizerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['serialization', 'system', 'field', 'entity_test', 'text', 'filter', 'user', 'field_normalization_test'];
|
||||
|
||||
/**
|
||||
* The class name of the test class.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityClass = 'Drupal\entity_test\Entity\EntityTestMulRev';
|
||||
|
||||
/**
|
||||
* The test values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $values;
|
||||
|
||||
/**
|
||||
* The test entity.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\ContentEntityBase
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer.
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Auto-create a field for testing default field values.
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_text_default',
|
||||
'type' => 'text',
|
||||
'cardinality' => 1,
|
||||
'translatable' => FALSE,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_text_default',
|
||||
'bundle' => 'entity_test_mulrev',
|
||||
'label' => 'Test text-field with default',
|
||||
'default_value' => [
|
||||
[
|
||||
'value' => 'This is the default',
|
||||
'format' => 'full_html',
|
||||
],
|
||||
],
|
||||
'widget' => [
|
||||
'type' => 'text_textfield',
|
||||
'weight' => 0,
|
||||
],
|
||||
])->save();
|
||||
|
||||
// Create a test entity to serialize.
|
||||
$this->values = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'field_test_text' => [
|
||||
'value' => $this->randomMachineName(),
|
||||
'format' => 'full_html',
|
||||
],
|
||||
];
|
||||
$this->entity = EntityTestMulRev::create($this->values);
|
||||
$this->entity->save();
|
||||
|
||||
$this->serializer = $this->container->get('serializer');
|
||||
|
||||
$this->installConfig(['field']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests normalizing and denormalizing an entity with field item normalizer.
|
||||
*/
|
||||
public function testFieldNormalizeDenormalize() {
|
||||
$normalized = $this->serializer->normalize($this->entity, 'json');
|
||||
|
||||
$expected_field_value = $this->entity->field_test_text[0]->getValue()['value'] . '::silly_suffix';
|
||||
$this->assertEquals($expected_field_value, $normalized['field_test_text'][0]['value'], 'Text field item normalized');
|
||||
$denormalized = $this->serializer->denormalize($normalized, $this->entityClass, 'json');
|
||||
|
||||
$this->assertEquals($denormalized->field_test_text[0]->getValue(), $this->entity->field_test_text[0]->getValue(), 'Text field item denormalized.');
|
||||
$this->assertEquals($denormalized->field_test_text_default[0]->getValue(), $this->entity->field_test_text_default[0]->getValue(), 'Text field item with default denormalized.');
|
||||
|
||||
// Unset the values for text field that has a default value.
|
||||
unset($normalized['field_test_text_default']);
|
||||
$denormalized_without_all_fields = $this->serializer->denormalize($normalized, $this->entityClass, 'json');
|
||||
// Check that denormalized entity is still the same even if not all fields
|
||||
// are not provided.
|
||||
$this->assertEquals($denormalized_without_all_fields->field_test_text[0]->getValue(), $this->entity->field_test_text[0]->getValue(), 'Text field item denormalized.');
|
||||
// Even though field_test_text_default value was unset before
|
||||
// denormalization it should still have the default values for the field.
|
||||
$this->assertEquals($denormalized_without_all_fields->field_test_text_default[0]->getValue(), $this->entity->field_test_text_default[0]->getValue(), 'Text field item with default denormalized.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests denormalizing using a scalar field value.
|
||||
*/
|
||||
public function testFieldDenormalizeWithScalarValue() {
|
||||
$this->setExpectedException(UnexpectedValueException::class, 'Field values for "uuid" must use an array structure');
|
||||
|
||||
$normalized = $this->serializer->normalize($this->entity, 'json');
|
||||
|
||||
// Change the UUID value to use the UUID directly. No array structure.
|
||||
$normalized['uuid'] = $normalized['uuid'][0]['value'];
|
||||
|
||||
$this->serializer->denormalize($normalized, $this->entityClass, 'json');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Helper base class to set up some test fields for serialization testing.
|
||||
*/
|
||||
abstract class NormalizerTestBase extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['serialization', 'system', 'field', 'entity_test', 'text', 'filter', 'user'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('entity_test_mulrev');
|
||||
$this->installEntitySchema('user');
|
||||
$this->installConfig(['field']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
\Drupal::moduleHandler()->invoke('rest', 'install');
|
||||
|
||||
// Auto-create a field for testing.
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_text',
|
||||
'type' => 'text',
|
||||
'cardinality' => 1,
|
||||
'translatable' => FALSE,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test_mulrev',
|
||||
'field_name' => 'field_test_text',
|
||||
'bundle' => 'entity_test_mulrev',
|
||||
'label' => 'Test text-field',
|
||||
'widget' => [
|
||||
'type' => 'text_textfield',
|
||||
'weight' => 0,
|
||||
],
|
||||
])->save();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Kernel;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Functional tests for serialization system.
|
||||
*
|
||||
* @group serialization
|
||||
*/
|
||||
class SerializationTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['serialization', 'serialization_test'];
|
||||
|
||||
/**
|
||||
* The serializer service to test.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->serializer = $this->container->get('serializer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that modules can register normalizers and encoders.
|
||||
*/
|
||||
public function testSerializerComponentRegistration() {
|
||||
$object = new \stdClass();
|
||||
$format = 'serialization_test';
|
||||
$expected = 'Normalized by SerializationTestNormalizer, Encoded by SerializationTestEncoder';
|
||||
|
||||
// Ensure the serialization invokes the expected normalizer and encoder.
|
||||
$this->assertIdentical($this->serializer->serialize($object, $format), $expected);
|
||||
|
||||
// Ensure the serialization fails for an unsupported format.
|
||||
try {
|
||||
$this->serializer->serialize($object, 'unsupported_format');
|
||||
$this->fail('The serializer was expected to throw an exception for an unsupported format, but did not.');
|
||||
}
|
||||
catch (UnexpectedValueException $e) {
|
||||
$this->pass('The serializer threw an exception for an unsupported format.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\CompilerPass;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\serialization\RegisterSerializationClassesCompilerPass;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\RegisterSerializationClassesCompilerPass
|
||||
* @group serialization
|
||||
*/
|
||||
class RegisterSerializationClassesCompilerPassTest extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
*/
|
||||
public function testEncoders() {
|
||||
$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);
|
||||
|
||||
$definition = new Definition('TestClass');
|
||||
$definition->addTag('encoder', ['format' => 'json']);
|
||||
$definition->addTag('_provider', ['provider' => 'test_provider_a']);
|
||||
$container->setDefinition('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);
|
||||
|
||||
$compiler_pass = new RegisterSerializationClassesCompilerPass();
|
||||
$compiler_pass->process($container);
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Encoder;
|
||||
|
||||
use Drupal\serialization\Encoder\JsonEncoder;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Encoder\JsonEncoder
|
||||
* @group serialization
|
||||
*/
|
||||
class JsonEncoderTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests the supportsEncoding() method.
|
||||
*/
|
||||
public function testSupportsEncoding() {
|
||||
$encoder = new JsonEncoder();
|
||||
|
||||
$this->assertTrue($encoder->supportsEncoding('json'));
|
||||
$this->assertTrue($encoder->supportsEncoding('ajax'));
|
||||
$this->assertFalse($encoder->supportsEncoding('xml'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Encoder;
|
||||
|
||||
use Drupal\serialization\Encoder\XmlEncoder;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Encoder\XmlEncoder
|
||||
* @group serialization
|
||||
*/
|
||||
class XmlEncoderTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The XmlEncoder instance.
|
||||
*
|
||||
* @var \Drupal\serialization\Encoder\XmlEncoder
|
||||
*/
|
||||
protected $encoder;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Serializer\Encoder\XmlEncoder|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $baseEncoder;
|
||||
|
||||
/**
|
||||
* An array of test data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $testArray = ['test' => 'test'];
|
||||
|
||||
protected function setUp() {
|
||||
$this->baseEncoder = $this->getMock('Symfony\Component\Serializer\Encoder\XmlEncoder');
|
||||
$this->encoder = new XmlEncoder();
|
||||
$this->encoder->setBaseEncoder($this->baseEncoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the supportsEncoding() method.
|
||||
*/
|
||||
public function testSupportsEncoding() {
|
||||
$this->assertTrue($this->encoder->supportsEncoding('xml'));
|
||||
$this->assertFalse($this->encoder->supportsEncoding('json'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the supportsDecoding() method.
|
||||
*/
|
||||
public function testSupportsDecoding() {
|
||||
$this->assertTrue($this->encoder->supportsDecoding('xml'));
|
||||
$this->assertFalse($this->encoder->supportsDecoding('json'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the encode() method.
|
||||
*/
|
||||
public function testEncode() {
|
||||
$this->baseEncoder->expects($this->once())
|
||||
->method('encode')
|
||||
->with($this->testArray, 'test', [])
|
||||
->will($this->returnValue('test'));
|
||||
|
||||
$this->assertEquals('test', $this->encoder->encode($this->testArray, 'test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the decode() method.
|
||||
*/
|
||||
public function testDecode() {
|
||||
$this->baseEncoder->expects($this->once())
|
||||
->method('decode')
|
||||
->with('test', 'test', [])
|
||||
->will($this->returnValue($this->testArray));
|
||||
|
||||
$this->assertEquals($this->testArray, $this->encoder->decode('test', 'test'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\EntityResolver;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\EntityResolver\ChainEntityResolver;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\EntityResolver\ChainEntityResolver
|
||||
* @group serialization
|
||||
*/
|
||||
class ChainEntityResolverTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* A mocked normalizer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Normalizer\NormalizerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $testNormalizer;
|
||||
|
||||
/**
|
||||
* Test data passed to the resolve method.
|
||||
*
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $testData;
|
||||
|
||||
/**
|
||||
* A test entity type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $testEntityType = 'test_type';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->testNormalizer = $this->getMock('Symfony\Component\Serializer\Normalizer\NormalizerInterface');
|
||||
$this->testData = new \stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the resolve method with no matching resolvers.
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::resolve
|
||||
*/
|
||||
public function testResolverWithNoneResolved() {
|
||||
$resolvers = [
|
||||
$this->createEntityResolverMock(),
|
||||
$this->createEntityResolverMock(),
|
||||
];
|
||||
|
||||
$resolver = new ChainEntityResolver($resolvers);
|
||||
|
||||
$this->assertNull($resolver->resolve($this->testNormalizer, $this->testData, $this->testEntityType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the resolve method with no matching resolvers, using addResolver.
|
||||
*
|
||||
* @covers ::addResolver
|
||||
* @covers ::resolve
|
||||
*/
|
||||
public function testResolverWithNoneResolvedUsingAddResolver() {
|
||||
$resolver = new ChainEntityResolver();
|
||||
$resolver->addResolver($this->createEntityResolverMock());
|
||||
$resolver->addResolver($this->createEntityResolverMock());
|
||||
|
||||
$this->assertNull($resolver->resolve($this->testNormalizer, $this->testData, $this->testEntityType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the resolve method with a matching resolver first.
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::resolve
|
||||
*/
|
||||
public function testResolverWithFirstResolved() {
|
||||
$resolvers = [
|
||||
$this->createEntityResolverMock(10),
|
||||
$this->createEntityResolverMock(NULL, FALSE),
|
||||
];
|
||||
|
||||
$resolver = new ChainEntityResolver($resolvers);
|
||||
|
||||
$this->assertSame(10, $resolver->resolve($this->testNormalizer, $this->testData, $this->testEntityType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the resolve method with a matching resolver last.
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::resolve
|
||||
*/
|
||||
public function testResolverWithLastResolved() {
|
||||
$resolvers = [
|
||||
$this->createEntityResolverMock(),
|
||||
$this->createEntityResolverMock(10),
|
||||
];
|
||||
|
||||
$resolver = new ChainEntityResolver($resolvers);
|
||||
|
||||
$this->assertSame(10, $resolver->resolve($this->testNormalizer, $this->testData, $this->testEntityType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the resolve method where one resolver returns 0.
|
||||
*
|
||||
* @covers ::__construct
|
||||
* @covers ::resolve
|
||||
*/
|
||||
public function testResolverWithResolvedToZero() {
|
||||
$resolvers = [
|
||||
$this->createEntityResolverMock(0),
|
||||
$this->createEntityResolverMock(NULL, FALSE),
|
||||
];
|
||||
|
||||
$resolver = new ChainEntityResolver($resolvers);
|
||||
|
||||
$this->assertSame(0, $resolver->resolve($this->testNormalizer, $this->testData, $this->testEntityType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock entity resolver.
|
||||
*
|
||||
* @param null|int $return
|
||||
* Whether the mocked resolve method should return TRUE or FALSE.
|
||||
* @param bool $called
|
||||
* Whether or not the resolve method is expected to be called.
|
||||
*
|
||||
* @return \Drupal\serialization\EntityResolver\EntityResolverInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
* The mocked entity resolver.
|
||||
*/
|
||||
protected function createEntityResolverMock($return = NULL, $called = TRUE) {
|
||||
$mock = $this->getMock('Drupal\serialization\EntityResolver\EntityResolverInterface');
|
||||
|
||||
if ($called) {
|
||||
$mock->expects($this->once())
|
||||
->method('resolve')
|
||||
->with($this->testNormalizer, $this->testData, $this->testEntityType)
|
||||
->will($this->returnValue($return));
|
||||
}
|
||||
else {
|
||||
$mock->expects($this->never())
|
||||
->method('resolve');
|
||||
}
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\EntityResolver;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\EntityResolver\UuidResolver;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\EntityResolver\UuidResolver
|
||||
* @group serialization
|
||||
*/
|
||||
class UuidResolverTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The UuidResolver instance.
|
||||
*
|
||||
* @var \Drupal\serialization\EntityResolver\UuidResolver
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* The mock EntityManager instance.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManager|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityManager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->resolver = new UuidResolver($this->entityManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test resolve() with a class using the incorrect interface.
|
||||
*/
|
||||
public function testResolveNotInInterface() {
|
||||
$this->entityManager->expects($this->never())
|
||||
->method('loadEntityByUuid');
|
||||
|
||||
$normalizer = $this->getMock('Symfony\Component\Serializer\Normalizer\NormalizerInterface');
|
||||
$this->assertNull($this->resolver->resolve($normalizer, [], 'test_type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test resolve() with a class using the correct interface but no UUID.
|
||||
*/
|
||||
public function testResolveNoUuid() {
|
||||
$this->entityManager->expects($this->never())
|
||||
->method('loadEntityByUuid');
|
||||
|
||||
$normalizer = $this->getMock('Drupal\serialization\EntityResolver\UuidReferenceInterface');
|
||||
$normalizer->expects($this->once())
|
||||
->method('getUuid')
|
||||
->with([])
|
||||
->will($this->returnValue(NULL));
|
||||
$this->assertNull($this->resolver->resolve($normalizer, [], 'test_type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test resolve() with correct interface but no matching entity for the UUID.
|
||||
*/
|
||||
public function testResolveNoEntity() {
|
||||
$uuid = '392eab92-35c2-4625-872d-a9dab4da008e';
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('loadEntityByUuid')
|
||||
->with('test_type')
|
||||
->will($this->returnValue(NULL));
|
||||
|
||||
$normalizer = $this->getMock('Drupal\serialization\EntityResolver\UuidReferenceInterface');
|
||||
$normalizer->expects($this->once())
|
||||
->method('getUuid')
|
||||
->with([])
|
||||
->will($this->returnValue($uuid));
|
||||
|
||||
$this->assertNull($this->resolver->resolve($normalizer, [], 'test_type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test resolve() when a UUID corresponds to an entity.
|
||||
*/
|
||||
public function testResolveWithEntity() {
|
||||
$uuid = '392eab92-35c2-4625-872d-a9dab4da008e';
|
||||
|
||||
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
|
||||
$entity->expects($this->once())
|
||||
->method('id')
|
||||
->will($this->returnValue(1));
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('loadEntityByUuid')
|
||||
->with('test_type', $uuid)
|
||||
->will($this->returnValue($entity));
|
||||
|
||||
$normalizer = $this->getMock('Drupal\serialization\EntityResolver\UuidReferenceInterface');
|
||||
$normalizer->expects($this->once())
|
||||
->method('getUuid')
|
||||
->with([])
|
||||
->will($this->returnValue($uuid));
|
||||
$this->assertSame(1, $this->resolver->resolve($normalizer, [], 'test_type'));
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\EventSubscriber;
|
||||
|
||||
use Drupal\serialization\Encoder\JsonEncoder;
|
||||
use Drupal\serialization\EventSubscriber\DefaultExceptionSubscriber;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\EventSubscriber\DefaultExceptionSubscriber
|
||||
* @group serialization
|
||||
*/
|
||||
class DefaultExceptionSubscriberTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::on4xx
|
||||
*/
|
||||
public function testOn4xx() {
|
||||
$kernel = $this->prophesize(HttpKernelInterface::class);
|
||||
$request = Request::create('/test');
|
||||
$request->setRequestFormat('json');
|
||||
|
||||
$e = new MethodNotAllowedHttpException(['POST', 'PUT'], 'test message');
|
||||
$event = new GetResponseForExceptionEvent($kernel->reveal(), $request, 'GET', $e);
|
||||
$subscriber = new DefaultExceptionSubscriber(new Serializer([], [new JsonEncoder()]), []);
|
||||
$subscriber->on4xx($event);
|
||||
$response = $event->getResponse();
|
||||
|
||||
$this->assertInstanceOf(Response::class, $response);
|
||||
$this->assertEquals('{"message":"test message"}', $response->getContent());
|
||||
$this->assertEquals(405, $response->getStatusCode());
|
||||
$this->assertEquals('POST, PUT', $response->headers->get('Allow'));
|
||||
$this->assertEquals('application/json', $response->headers->get('Content-Type'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\serialization\Unit\Normalizer\ComplexDataNormalizerTest.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\ComplexDataNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class ComplexDataNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Test format string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TEST_FORMAT = 'test_format';
|
||||
|
||||
/**
|
||||
* The Complex data normalizer under test.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\ComplexDataNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->normalizer = new ComplexDataNormalizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization(new TestComplexData()));
|
||||
// Also test that an object not implementing ComplexDataInterface fails.
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$context = ['test' => 'test'];
|
||||
|
||||
$serializer_prophecy = $this->prophesize(Serializer::class);
|
||||
|
||||
$serializer_prophecy->normalize('A', static::TEST_FORMAT, $context)
|
||||
->shouldBeCalled();
|
||||
$serializer_prophecy->normalize('B', static::TEST_FORMAT, $context)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->normalizer->setSerializer($serializer_prophecy->reveal());
|
||||
|
||||
$complex_data = new TestComplexData(['a' => 'A', 'b' => 'B']);
|
||||
$this->normalizer->normalize($complex_data, static::TEST_FORMAT, $context);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test class implementing ComplexDataInterface and IteratorAggregate.
|
||||
*/
|
||||
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() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\serialization\Normalizer\ConfigEntityNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\ConfigEntityNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class ConfigEntityNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests the normalize() method.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$test_export_properties = ['test' => 'test'];
|
||||
|
||||
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$normalizer = new ConfigEntityNormalizer($entity_manager);
|
||||
|
||||
$config_entity = $this->getMock('Drupal\Core\Config\Entity\ConfigEntityInterface');
|
||||
$config_entity->expects($this->once())
|
||||
->method('toArray')
|
||||
->will($this->returnValue($test_export_properties));
|
||||
|
||||
$this->assertSame($test_export_properties, $normalizer->normalize($config_entity));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\serialization\Normalizer\ContentEntityNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\ContentEntityNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class ContentEntityNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The mock entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The mock serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The normalizer under test.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\ContentEntityNormalizer
|
||||
*/
|
||||
protected $contentEntityNormalizer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$this->contentEntityNormalizer = new ContentEntityNormalizer($this->entityManager);
|
||||
$this->serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['normalize'])
|
||||
->getMock();
|
||||
$this->contentEntityNormalizer->setSerializer($this->serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$content_mock = $this->getMock('Drupal\Core\Entity\ContentEntityInterface');
|
||||
$config_mock = $this->getMock('Drupal\Core\Entity\ConfigEntityInterface');
|
||||
$this->assertTrue($this->contentEntityNormalizer->supportsNormalization($content_mock));
|
||||
$this->assertFalse($this->contentEntityNormalizer->supportsNormalization($config_mock));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize() method.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$this->serializer->expects($this->any())
|
||||
->method('normalize')
|
||||
->with($this->containsOnlyInstancesOf('Drupal\Core\Field\FieldItemListInterface'), 'test_format', ['account' => NULL])
|
||||
->will($this->returnValue('test'));
|
||||
|
||||
$definitions = [
|
||||
'field_1' => $this->createMockFieldListItem(),
|
||||
'field_2' => $this->createMockFieldListItem(FALSE),
|
||||
];
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize() method with account context passed.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalizeWithAccountContext() {
|
||||
$mock_account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||
|
||||
$context = [
|
||||
'account' => $mock_account,
|
||||
];
|
||||
|
||||
$this->serializer->expects($this->any())
|
||||
->method('normalize')
|
||||
->with($this->containsOnlyInstancesOf('Drupal\Core\Field\FieldItemListInterface'), 'test_format', $context)
|
||||
->will($this->returnValue('test'));
|
||||
|
||||
// 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),
|
||||
];
|
||||
$content_entity_mock = $this->createMockForContentEntity($definitions);
|
||||
|
||||
$normalized = $this->contentEntityNormalizer->normalize($content_entity_mock, 'test_format', $context);
|
||||
|
||||
$this->assertArrayHasKey('field_1', $normalized);
|
||||
$this->assertEquals('test', $normalized['field_1']);
|
||||
$this->assertArrayNotHasKey('field_2', $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock content entity.
|
||||
*
|
||||
* @param $definitions
|
||||
*
|
||||
* @return \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
public function createMockForContentEntity($definitions) {
|
||||
$content_entity_mock = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getFields'])
|
||||
->getMockForAbstractClass();
|
||||
$content_entity_mock->expects($this->once())
|
||||
->method('getFields')
|
||||
->will($this->returnValue($definitions));
|
||||
|
||||
return $content_entity_mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock field list item.
|
||||
*
|
||||
* @param bool $access
|
||||
*
|
||||
* @return \Drupal\Core\Field\FieldItemListInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected function createMockFieldListItem($access = TRUE, $user_context = NULL) {
|
||||
$mock = $this->getMock('Drupal\Core\Field\FieldItemListInterface');
|
||||
$mock->expects($this->once())
|
||||
->method('access')
|
||||
->with('view', $user_context)
|
||||
->will($this->returnValue($access));
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\serialization\Normalizer\EntityNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\EntityNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class EntityNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The mock entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The mock serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The entity normalizer.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\EntityNormalizer
|
||||
*/
|
||||
protected $entityNormalizer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
|
||||
$this->entityNormalizer = new EntityNormalizer($this->entityManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize() method.
|
||||
*
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$list_item_1 = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
$list_item_2 = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
|
||||
$definitions = [
|
||||
'field_1' => $list_item_1,
|
||||
'field_2' => $list_item_2,
|
||||
];
|
||||
|
||||
$content_entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['getFields'])
|
||||
->getMockForAbstractClass();
|
||||
$content_entity->expects($this->once())
|
||||
->method('getFields')
|
||||
->will($this->returnValue($definitions));
|
||||
|
||||
$serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['normalize'])
|
||||
->getMock();
|
||||
$serializer->expects($this->at(0))
|
||||
->method('normalize')
|
||||
->with($list_item_1, 'test_format');
|
||||
$serializer->expects($this->at(1))
|
||||
->method('normalize')
|
||||
->with($list_item_2, 'test_format');
|
||||
|
||||
$this->entityNormalizer->setSerializer($serializer);
|
||||
|
||||
$this->entityNormalizer->normalize($content_entity, 'test_format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the denormalize() method with no entity type provided in context.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithNoEntityType() {
|
||||
$this->setExpectedException(UnexpectedValueException::class);
|
||||
$this->entityNormalizer->denormalize([], 'Drupal\Core\Entity\ContentEntityBase');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the denormalize method with a bundle property.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithValidBundle() {
|
||||
$test_data = [
|
||||
'key_1' => 'value_1',
|
||||
'key_2' => 'value_2',
|
||||
'test_type' => [
|
||||
['name' => 'test_bundle'],
|
||||
],
|
||||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
|
||||
$entity_type->expects($this->once())
|
||||
->method('id')
|
||||
->willReturn('test');
|
||||
$entity_type->expects($this->once())
|
||||
->method('hasKey')
|
||||
->with('bundle')
|
||||
->will($this->returnValue(TRUE));
|
||||
$entity_type->expects($this->once())
|
||||
->method('getKey')
|
||||
->with('bundle')
|
||||
->will($this->returnValue('test_type'));
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(TRUE);
|
||||
|
||||
$entity_type->expects($this->once())
|
||||
->method('getBundleEntityType')
|
||||
->will($this->returnValue('test_bundle'));
|
||||
|
||||
$entity_type_storage_definition = $this->getmock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$entity_type_storage_definition->expects($this->once())
|
||||
->method('getMainPropertyName')
|
||||
->will($this->returnValue('name'));
|
||||
|
||||
$entity_type_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface');
|
||||
$entity_type_definition->expects($this->once())
|
||||
->method('getFieldStorageDefinition')
|
||||
->will($this->returnValue($entity_type_storage_definition));
|
||||
|
||||
$base_definitions = [
|
||||
'test_type' => $entity_type_definition,
|
||||
];
|
||||
|
||||
$this->entityManager->expects($this->at(0))
|
||||
->method('getDefinition')
|
||||
->with('test')
|
||||
->will($this->returnValue($entity_type));
|
||||
$this->entityManager->expects($this->at(1))
|
||||
->method('getBaseFieldDefinitions')
|
||||
->with('test')
|
||||
->will($this->returnValue($base_definitions));
|
||||
|
||||
$entity_query_mock = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
|
||||
$entity_query_mock->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(['test_bundle' => 'test_bundle']));
|
||||
|
||||
$entity_type_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
$entity_type_storage->expects($this->once())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($entity_query_mock));
|
||||
|
||||
$this->entityManager->expects($this->at(2))
|
||||
->method('getStorage')
|
||||
->with('test_bundle')
|
||||
->will($this->returnValue($entity_type_storage));
|
||||
|
||||
$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');
|
||||
// Create should only be called with the bundle property at first.
|
||||
$expected_test_data = [
|
||||
'test_type' => 'test_bundle',
|
||||
];
|
||||
|
||||
$storage->expects($this->once())
|
||||
->method('create')
|
||||
->with($expected_test_data)
|
||||
->will($this->returnValue($entity));
|
||||
|
||||
$this->entityManager->expects($this->at(3))
|
||||
->method('getStorage')
|
||||
->with('test')
|
||||
->will($this->returnValue($storage));
|
||||
|
||||
// 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 a bundle property.
|
||||
*
|
||||
* @covers ::denormalize
|
||||
*/
|
||||
public function testDenormalizeWithInvalidBundle() {
|
||||
$test_data = [
|
||||
'key_1' => 'value_1',
|
||||
'key_2' => 'value_2',
|
||||
'test_type' => [
|
||||
['name' => 'test_bundle'],
|
||||
],
|
||||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
|
||||
$entity_type->expects($this->once())
|
||||
->method('id')
|
||||
->willReturn('test');
|
||||
$entity_type->expects($this->once())
|
||||
->method('hasKey')
|
||||
->with('bundle')
|
||||
->will($this->returnValue(TRUE));
|
||||
$entity_type->expects($this->once())
|
||||
->method('getKey')
|
||||
->with('bundle')
|
||||
->will($this->returnValue('test_type'));
|
||||
$entity_type->expects($this->once())
|
||||
->method('isSubClassOf')
|
||||
->with(FieldableEntityInterface::class)
|
||||
->willReturn(TRUE);
|
||||
|
||||
$entity_type->expects($this->once())
|
||||
->method('getBundleEntityType')
|
||||
->will($this->returnValue('test_bundle'));
|
||||
|
||||
$entity_type_storage_definition = $this->getmock('Drupal\Core\Field\FieldStorageDefinitionInterface');
|
||||
$entity_type_storage_definition->expects($this->once())
|
||||
->method('getMainPropertyName')
|
||||
->will($this->returnValue('name'));
|
||||
|
||||
$entity_type_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface');
|
||||
$entity_type_definition->expects($this->once())
|
||||
->method('getFieldStorageDefinition')
|
||||
->will($this->returnValue($entity_type_storage_definition));
|
||||
|
||||
$base_definitions = [
|
||||
'test_type' => $entity_type_definition,
|
||||
];
|
||||
|
||||
$this->entityManager->expects($this->at(0))
|
||||
->method('getDefinition')
|
||||
->with('test')
|
||||
->will($this->returnValue($entity_type));
|
||||
$this->entityManager->expects($this->at(1))
|
||||
->method('getBaseFieldDefinitions')
|
||||
->with('test')
|
||||
->will($this->returnValue($base_definitions));
|
||||
|
||||
$entity_query_mock = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
|
||||
$entity_query_mock->expects($this->once())
|
||||
->method('execute')
|
||||
->will($this->returnValue(['test_bundle_other' => 'test_bundle_other']));
|
||||
|
||||
$entity_type_storage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
|
||||
$entity_type_storage->expects($this->once())
|
||||
->method('getQuery')
|
||||
->will($this->returnValue($entity_query_mock));
|
||||
|
||||
$this->entityManager->expects($this->at(2))
|
||||
->method('getStorage')
|
||||
->with('test_bundle')
|
||||
->will($this->returnValue($entity_type_storage));
|
||||
|
||||
$this->setExpectedException(UnexpectedValueException::class);
|
||||
$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 testDenormalizeWithNoBundle() {
|
||||
$test_data = [
|
||||
'key_1' => 'value_1',
|
||||
'key_2' => 'value_2',
|
||||
];
|
||||
|
||||
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
|
||||
$entity_type->expects($this->once())
|
||||
->method('hasKey')
|
||||
->with('bundle')
|
||||
->will($this->returnValue(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')
|
||||
->with($test_data)
|
||||
->will($this->returnValue($this->getMock('Drupal\Core\Entity\EntityInterface')));
|
||||
|
||||
$this->entityManager->expects($this->once())
|
||||
->method('getStorage')
|
||||
->with('test')
|
||||
->will($this->returnValue($storage));
|
||||
|
||||
$this->entityManager->expects($this->never())
|
||||
->method('getBaseFieldDefinitions');
|
||||
|
||||
$this->assertNotNull($this->entityNormalizer->denormalize($test_data, 'Drupal\Core\Entity\ContentEntityBase', NULL, ['entity_type' => 'test']));
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class EntityReferenceFieldItemNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The mock serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The normalizer under test.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* The mock field item.
|
||||
*
|
||||
* @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem|\Prophecy\Prophecy\ObjectProphecy
|
||||
*/
|
||||
protected $fieldItem;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->normalizer = new EntityReferenceFieldItemNormalizer();
|
||||
|
||||
$this->serializer = $this->prophesize(Serializer::class);
|
||||
// Set up the serializer to return an entity property.
|
||||
$this->serializer->normalize(Argument::cetera())
|
||||
->willReturn(['value' => 'test']);
|
||||
|
||||
$this->normalizer->setSerializer($this->serializer->reveal());
|
||||
|
||||
$this->fieldItem = $this->prophesize(EntityReferenceItem::class);
|
||||
$this->fieldItem->getIterator()
|
||||
->willReturn(new \ArrayIterator(['target_id' => []]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($this->fieldItem->reveal()));
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$test_url = '/test/100';
|
||||
|
||||
$entity = $this->prophesize(EntityInterface::class);
|
||||
$entity->url('canonical')
|
||||
->willReturn($test_url)
|
||||
->shouldBeCalled();
|
||||
$entity->uuid()
|
||||
->willReturn('080e3add-f9d5-41ac-9821-eea55b7b42fb')
|
||||
->shouldBeCalled();
|
||||
$entity->getEntityTypeId()
|
||||
->willReturn('test_type')
|
||||
->shouldBeCalled();
|
||||
|
||||
$entity_reference = $this->prophesize(TypedDataInterface::class);
|
||||
$entity_reference->getValue()
|
||||
->willReturn($entity->reveal())
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->get('entity')
|
||||
->willReturn($entity_reference)
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->fieldItem->reveal());
|
||||
|
||||
$expected = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
'target_type' => 'test_type',
|
||||
'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
|
||||
'url' => $test_url,
|
||||
];
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalizeWithNoEntity() {
|
||||
$entity_reference = $this->prophesize(TypedDataInterface::class);
|
||||
$entity_reference->getValue()
|
||||
->willReturn(NULL)
|
||||
->shouldBeCalled();
|
||||
|
||||
$this->fieldItem->get('entity')
|
||||
->willReturn($entity_reference->reveal())
|
||||
->shouldBeCalled();
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->fieldItem->reveal());
|
||||
|
||||
$expected = [
|
||||
'target_id' => ['value' => 'test'],
|
||||
];
|
||||
$this->assertSame($expected, $normalized);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\Normalizer\ListNormalizer;
|
||||
use Drupal\Core\TypedData\Plugin\DataType\ItemList;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\ListNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class ListNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The ListNormalizer instance.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\ListNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* The mock list instance.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\ListInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $list;
|
||||
|
||||
/**
|
||||
* The expected list values to use for testing.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $expectedListValues = ['test', 'test', 'test'];
|
||||
|
||||
/**
|
||||
* The mocked typed data.
|
||||
*
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\TypedData\TypedDataInterface
|
||||
*/
|
||||
protected $typedData;
|
||||
|
||||
protected function setUp() {
|
||||
// Mock the TypedDataManager to return a TypedDataInterface mock.
|
||||
$this->typedData = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
$typed_data_manager = $this->getMock(TypedDataManagerInterface::class);
|
||||
$typed_data_manager->expects($this->any())
|
||||
->method('getPropertyInstance')
|
||||
->will($this->returnValue($this->typedData));
|
||||
|
||||
// Set up a mock container as ItemList() will call for the 'typed_data_manager'
|
||||
// service.
|
||||
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')
|
||||
->setMethods(['get'])
|
||||
->getMock();
|
||||
$container->expects($this->any())
|
||||
->method('get')
|
||||
->with($this->equalTo('typed_data_manager'))
|
||||
->will($this->returnValue($typed_data_manager));
|
||||
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$this->normalizer = new ListNormalizer();
|
||||
|
||||
$this->list = new ItemList(new DataDefinition());
|
||||
$this->list->setValue($this->expectedListValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the supportsNormalization() method.
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($this->list));
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize() method.
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$serializer = $this->prophesize(Serializer::class);
|
||||
$serializer->normalize($this->typedData, 'json', ['mu' => 'nu'])
|
||||
->shouldBeCalledTimes(3)
|
||||
->willReturn('test');
|
||||
|
||||
$this->normalizer->setSerializer($serializer->reveal());
|
||||
|
||||
$normalized = $this->normalizer->normalize($this->list, 'json', ['mu' => 'nu']);
|
||||
|
||||
$this->assertEquals($this->expectedListValues, $normalized);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\serialization\Unit\Normalizer\NormalizerBaseTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\Normalizer\NormalizerBase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\NormalizerBase
|
||||
* @group serialization
|
||||
*/
|
||||
class NormalizerBaseTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests the supportsNormalization method.
|
||||
*
|
||||
* @dataProvider providerTestSupportsNormalization
|
||||
*
|
||||
* @param bool $expected_return
|
||||
* The expected boolean return value from supportNormalization.
|
||||
* @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.
|
||||
*/
|
||||
public function testSupportsNormalization($expected_return, $data, $supported_interface_or_class = NULL) {
|
||||
$normalizer_base = $this->getMockForAbstractClass('Drupal\Tests\serialization\Unit\Normalizer\TestNormalizerBase');
|
||||
|
||||
if (isset($supported_interface_or_class)) {
|
||||
$normalizer_base->setSupportedInterfaceOrClass($supported_interface_or_class);
|
||||
}
|
||||
|
||||
$this->assertSame($expected_return, $normalizer_base->supportsNormalization($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testSupportsNormalization.
|
||||
*
|
||||
* @return array
|
||||
* An array of provider data for testSupportsNormalization.
|
||||
*/
|
||||
public function providerTestSupportsNormalization() {
|
||||
return [
|
||||
// Something that is not an object should return FALSE immediately.
|
||||
[FALSE, []],
|
||||
// An object with no class set should return FALSE.
|
||||
[FALSE, new \stdClass()],
|
||||
// Set a supported Class.
|
||||
[TRUE, new \stdClass(), 'stdClass'],
|
||||
// Set a supported interface.
|
||||
[TRUE, new \RecursiveArrayIterator(), 'RecursiveIterator'],
|
||||
// Set a different class.
|
||||
[FALSE, new \stdClass(), 'ArrayIterator'],
|
||||
// Set a different interface.
|
||||
[FALSE, new \stdClass(), 'RecursiveIterator'],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test class for NormalizerBase.
|
||||
*/
|
||||
abstract class TestNormalizerBase extends NormalizerBase {
|
||||
|
||||
/**
|
||||
* Sets the protected supportedInterfaceOrClass property.
|
||||
*
|
||||
* @param string $supported_interface_or_class
|
||||
* The class name to set.
|
||||
*/
|
||||
public function setSupportedInterfaceOrClass($supported_interface_or_class) {
|
||||
$this->supportedInterfaceOrClass = $supported_interface_or_class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\serialization\Normalizer\NullNormalizer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\NullNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class NullNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The NullNormalizer instance.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\NullNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* The interface to use in testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $interface = 'Drupal\Core\TypedData\TypedDataInterface';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->normalizer = new NullNormalizer($this->interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__construct
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$mock = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($mock));
|
||||
// Also test that an object not implementing TypedDataInterface fails.
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$mock = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
$this->assertNull($this->normalizer->normalize($mock));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\Core\TypedData\Plugin\DataType\BooleanData;
|
||||
use Drupal\Core\TypedData\Plugin\DataType\IntegerData;
|
||||
use Drupal\Core\TypedData\Plugin\DataType\StringData;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\Normalizer\PrimitiveDataNormalizer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\PrimitiveDataNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class PrimitiveDataNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The TypedDataNormalizer instance.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\TypedDataNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->normalizer = new PrimitiveDataNormalizer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
* @dataProvider dataProviderPrimitiveData
|
||||
*/
|
||||
public function testSupportsNormalization($primitive_data, $expected) {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($primitive_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::supportsNormalization
|
||||
*/
|
||||
public function testSupportsNormalizationFail() {
|
||||
// Test that an object not implementing PrimitiveInterface fails.
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::normalize
|
||||
* @dataProvider dataProviderPrimitiveData
|
||||
*/
|
||||
public function testNormalize($primitive_data, $expected) {
|
||||
$this->assertSame($expected, $this->normalizer->normalize($primitive_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testNormalize().
|
||||
*/
|
||||
public function dataProviderPrimitiveData() {
|
||||
$data = [];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('string');
|
||||
$string = new StringData($definition, 'string');
|
||||
$string->setValue('test');
|
||||
|
||||
$data['string'] = [$string, 'test'];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('string');
|
||||
$string = new StringData($definition, 'string');
|
||||
$string->setValue(NULL);
|
||||
|
||||
$data['string-null'] = [$string, NULL];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('integer');
|
||||
$integer = new IntegerData($definition, 'integer');
|
||||
$integer->setValue(5);
|
||||
|
||||
$data['integer'] = [$integer, 5];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('integer');
|
||||
$integer = new IntegerData($definition, 'integer');
|
||||
$integer->setValue(NULL);
|
||||
|
||||
$data['integer-null'] = [$integer, NULL];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('boolean');
|
||||
$boolean = new BooleanData($definition, 'boolean');
|
||||
$boolean->setValue(TRUE);
|
||||
|
||||
$data['boolean'] = [$boolean, TRUE];
|
||||
|
||||
$definition = DataDefinition::createFromDataType('boolean');
|
||||
$boolean = new BooleanData($definition, 'boolean');
|
||||
$boolean->setValue(NULL);
|
||||
|
||||
$data['boolean-null'] = [$boolean, NULL];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\serialization\Unit\Normalizer;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\serialization\Normalizer\TypedDataNormalizer;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\serialization\Normalizer\TypedDataNormalizer
|
||||
* @group serialization
|
||||
*/
|
||||
class TypedDataNormalizerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The TypedDataNormalizer instance.
|
||||
*
|
||||
* @var \Drupal\serialization\Normalizer\TypedDataNormalizer
|
||||
*/
|
||||
protected $normalizer;
|
||||
|
||||
/**
|
||||
* The mock typed data instance.
|
||||
*
|
||||
* @var \Drupal\Core\TypedData\TypedDataInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $typedData;
|
||||
|
||||
protected function setUp() {
|
||||
$this->normalizer = new TypedDataNormalizer();
|
||||
$this->typedData = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the supportsNormalization() method.
|
||||
*/
|
||||
public function testSupportsNormalization() {
|
||||
$this->assertTrue($this->normalizer->supportsNormalization($this->typedData));
|
||||
// Also test that an object not implementing TypedDataInterface fails.
|
||||
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the normalize() method.
|
||||
*/
|
||||
public function testNormalize() {
|
||||
$this->typedData->expects($this->once())
|
||||
->method('getValue')
|
||||
->will($this->returnValue('test'));
|
||||
|
||||
$this->assertEquals('test', $this->normalizer->normalize($this->typedData));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user