Update core 8.3.0
This commit is contained in:
parent
da7a7918f8
commit
cd7a898e66
6144 changed files with 132297 additions and 87747 deletions
|
@ -4,6 +4,8 @@ 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;
|
||||
|
||||
/**
|
||||
|
@ -16,7 +18,19 @@ class JsonEncoder extends BaseJsonEncoder implements EncoderInterface, DecoderIn
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $format = array('json', 'ajax');
|
||||
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}
|
||||
|
|
|
@ -19,7 +19,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
static protected $format = array('xml');
|
||||
static protected $format = ['xml'];
|
||||
|
||||
/**
|
||||
* An instance of the Symfony XmlEncoder to perform the actual encoding.
|
||||
|
@ -54,7 +54,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function encode($data, $format, array $context = array()){
|
||||
public function encode($data, $format, array $context = []){
|
||||
return $this->getBaseEncoder()->encode($data, $format, $context);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ class XmlEncoder implements EncoderInterface, DecoderInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function decode($data, $format, array $context = array()){
|
||||
public function decode($data, $format, array $context = []){
|
||||
return $this->getBaseEncoder()->decode($data, $format, $context);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class ChainEntityResolver implements ChainEntityResolverInterface {
|
|||
*
|
||||
* @var \Drupal\serialization\EntityResolver\EntityResolverInterface[]
|
||||
*/
|
||||
protected $resolvers = array();
|
||||
protected $resolvers = [];
|
||||
|
||||
/**
|
||||
* Constructs a ChainEntityResolver object.
|
||||
|
@ -22,7 +22,7 @@ class ChainEntityResolver implements ChainEntityResolverInterface {
|
|||
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface[] $resolvers
|
||||
* The array of concrete resolvers.
|
||||
*/
|
||||
public function __construct(array $resolvers = array()) {
|
||||
public function __construct(array $resolvers = []) {
|
||||
$this->resolvers = $resolvers;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -56,88 +56,25 @@ class DefaultExceptionSubscriber extends HttpExceptionSubscriberBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Handles a 400 error for HTTP.
|
||||
* Handles all 4xx errors for all serialization failures.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on400(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
public function on4xx(GetResponseForExceptionEvent $event) {
|
||||
/** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $exception */
|
||||
$exception = $event->getException();
|
||||
$request = $event->getRequest();
|
||||
|
||||
/**
|
||||
* Handles a 403 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on403(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 404 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on404(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 405 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on405(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_METHOD_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 406 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on406(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_NOT_ACCEPTABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 422 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on422(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a 429 error for HTTP.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function on429(GetResponseForExceptionEvent $event) {
|
||||
$this->setEventResponse($event, Response::HTTP_TOO_MANY_REQUESTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Response for the exception event.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The current exception event.
|
||||
* @param int $status
|
||||
* The HTTP status code to set for the response.
|
||||
*/
|
||||
protected function setEventResponse(GetResponseForExceptionEvent $event, $status) {
|
||||
$format = $event->getRequest()->getRequestFormat();
|
||||
$format = $request->getRequestFormat();
|
||||
$content = ['message' => $event->getException()->getMessage()];
|
||||
$encoded_content = $this->serializer->serialize($content, $format);
|
||||
$response = new Response($encoded_content, $status);
|
||||
$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);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,20 +5,12 @@ namespace Drupal\serialization\EventSubscriber;
|
|||
use Drupal\Core\Routing\RouteBuildEvent;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Alters user authentication routes to support additional serialization formats.
|
||||
*/
|
||||
class UserRouteAlterSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The available serialization formats.
|
||||
*
|
||||
|
@ -29,13 +21,10 @@ class UserRouteAlterSubscriber implements EventSubscriberInterface {
|
|||
/**
|
||||
* UserRouteAlterSubscriber constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer service.
|
||||
* @param array $serializer_formats
|
||||
* The available serializer formats.
|
||||
*/
|
||||
public function __construct(SerializerInterface $serializer, array $serializer_formats) {
|
||||
$this->serializer = $serializer;
|
||||
public function __construct(array $serializer_formats) {
|
||||
$this->serializerFormats = $serializer_formats;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ class ComplexDataNormalizer extends NormalizerBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
$attributes = array();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ class ConfigEntityNormalizer extends EntityNormalizer {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = array('Drupal\Core\Config\Entity\ConfigEntityInterface');
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Core\Config\Entity\ConfigEntityInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->toArray();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,19 +8,17 @@ namespace Drupal\serialization\Normalizer;
|
|||
class ContentEntityNormalizer extends EntityNormalizer {
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var array
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Core\Entity\ContentEntityInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
$context += array(
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$context += [
|
||||
'account' => NULL,
|
||||
);
|
||||
];
|
||||
|
||||
$attributes = [];
|
||||
foreach ($object as $name => $field) {
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
namespace Drupal\serialization\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
|
||||
/**
|
||||
|
@ -11,19 +12,14 @@ use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
|||
*/
|
||||
class EntityNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
|
||||
|
||||
use FieldableEntityNormalizerTrait;
|
||||
|
||||
/**
|
||||
* The interface or class that this Normalizer supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = array('Drupal\Core\Entity\EntityInterface');
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
protected $supportedInterfaceOrClass = [EntityInterface::class];
|
||||
|
||||
/**
|
||||
* Constructs an EntityNormalizer object.
|
||||
|
@ -39,49 +35,26 @@ class EntityNormalizer extends ComplexDataNormalizer implements DenormalizerInte
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function denormalize($data, $class, $format = NULL, array $context = []) {
|
||||
// Get the entity type ID while letting context override the $class param.
|
||||
$entity_type_id = !empty($context['entity_type']) ? $context['entity_type'] : $this->entityManager->getEntityTypeFromClass($class);
|
||||
$entity_type_id = $this->determineEntityTypeId($class, $context);
|
||||
$entity_type_definition = $this->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);
|
||||
// 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);
|
||||
|
||||
// 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 etnity type is required for denormalization', $entity_type_id));
|
||||
// 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);
|
||||
}
|
||||
|
||||
// The bundle property will be required to denormalize a bundleable entity.
|
||||
if ($entity_type_definition->hasKey('bundle')) {
|
||||
$bundle_key = $entity_type_definition->getKey('bundle');
|
||||
// Get the base field definitions for this entity type.
|
||||
$base_field_definitions = $this->entityManager->getBaseFieldDefinitions($entity_type_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.
|
||||
$data[$bundle_key] = isset($data[$bundle_key][0][$key_id]) ? $data[$bundle_key][0][$key_id] : (isset($data[$bundle_key]) ? $data[$bundle_key] : NULL);
|
||||
|
||||
// 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($data[$bundle_key])) {
|
||||
throw new UnexpectedValueException('A string must be provided as a bundle value.');
|
||||
}
|
||||
|
||||
// Make sure the submitted bundle is a valid bundle for the entity type.
|
||||
if ($bundle_types && !in_array($data[$bundle_key], $bundle_types)) {
|
||||
throw new UnexpectedValueException(sprintf('"%s" is not a valid bundle type for denormalization.', $data[$bundle_key]));
|
||||
}
|
||||
else {
|
||||
// Create the entity from all data.
|
||||
$entity = $this->entityManager->getStorage($entity_type_id)->create($data);
|
||||
}
|
||||
|
||||
// Create the entity from 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -23,8 +23,8 @@ class ListNormalizer extends NormalizerBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
$attributes = array();
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
$attributes = [];
|
||||
foreach ($object as $fieldItem) {
|
||||
$attributes[] = $this->serializer->normalize($fieldItem, $format, $context);
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ class MarkupNormalizer extends NormalizerBase {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedInterfaceOrClass = array('Drupal\Component\Render\MarkupInterface');
|
||||
protected $supportedInterfaceOrClass = ['Drupal\Component\Render\MarkupInterface'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return (string) $object;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class NullNormalizer extends NormalizerBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -17,7 +17,7 @@ class TypedDataNormalizer extends NormalizerBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = array()) {
|
||||
public function normalize($object, $format = NULL, array $context = []) {
|
||||
return $object->getValue();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
|
|||
*/
|
||||
public function process(ContainerBuilder $container) {
|
||||
$definition = $container->getDefinition('serializer.entity_resolver');
|
||||
$resolvers = array();
|
||||
$resolvers = [];
|
||||
|
||||
// Retrieve registered Normalizers and Encoders from the container.
|
||||
foreach ($container->findTaggedServiceIds('entity_resolver') as $id => $attributes) {
|
||||
|
@ -29,7 +29,7 @@ class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
|
|||
|
||||
// Add the registered concrete EntityResolvers to the ChainEntityResolver.
|
||||
foreach ($this->sort($resolvers) as $resolver) {
|
||||
$definition->addMethodCall('addResolver', array($resolver));
|
||||
$definition->addMethodCall('addResolver', [$resolver]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
|
|||
* to low priority.
|
||||
*/
|
||||
protected function sort($services) {
|
||||
$sorted = array();
|
||||
$sorted = [];
|
||||
krsort($services);
|
||||
|
||||
// Flatten the array.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\serialization;
|
||||
|
||||
use Drupal\Core\Config\BootstrapConfigStorageFactory;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
@ -22,6 +23,12 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
|
||||
// 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);
|
||||
}
|
||||
|
@ -39,7 +46,7 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
}
|
||||
|
||||
// Find all serialization formats known.
|
||||
$formats = array();
|
||||
$formats = [];
|
||||
$format_providers = [];
|
||||
foreach ($container->findTaggedServiceIds('encoder') as $service_id => $attributes) {
|
||||
$format = $attributes[0]['format'];
|
||||
|
@ -53,6 +60,18 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
$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.
|
||||
*
|
||||
|
@ -68,7 +87,7 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
|
|||
* to low priority.
|
||||
*/
|
||||
protected function sort($services) {
|
||||
$sorted = array();
|
||||
$sorted = [];
|
||||
krsort($services);
|
||||
|
||||
// Flatten the array.
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\serialization\Tests;
|
||||
|
||||
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'));
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue