caore d8 files

This commit is contained in:
Bachir Soussi Chiadmi
2016-09-06 12:44:15 +02:00
commit 58f46e4e8f
12831 changed files with 1451591 additions and 0 deletions
@@ -0,0 +1,35 @@
<?php
namespace Drupal\serialization\Encoder;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
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 = array('json', 'ajax');
/**
* {@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 = array('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 = array()){
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 = array()){
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 = array();
/**
* Constructs a ChainEntityResolver object.
*
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface[] $resolvers
* The array of concrete resolvers.
*/
public function __construct(array $resolvers = array()) {
$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,35 @@
<?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 = array()) {
$attributes = array();
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 = array('Drupal\Core\Config\Entity\ConfigEntityInterface');
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = array()) {
return $object->toArray();
}
}
@@ -0,0 +1,35 @@
<?php
namespace Drupal\serialization\Normalizer;
/**
* Normalizes/denormalizes Drupal content entities into an array structure.
*/
class ContentEntityNormalizer extends EntityNormalizer {
/**
* The interface or class that this Normalizer supports.
*
* @var array
*/
protected $supportedInterfaceOrClass = ['Drupal\Core\Entity\ContentEntityInterface'];
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = array()) {
$context += array(
'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,92 @@
<?php
namespace Drupal\serialization\Normalizer;
use Drupal\Core\Entity\EntityManagerInterface;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
/**
* Normalizes/denormalizes Drupal entity objects into an array structure.
*/
class EntityNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
/**
* 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;
/**
* 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 = []) {
// 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);
/** @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 etnity type is required for denormalization', $entity_type_id));
}
// 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]));
}
}
// 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);
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,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 = array()) {
$attributes = array();
foreach ($object as $fieldItem) {
$attributes[] = $this->serializer->normalize($fieldItem, $format);
}
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 = array('Drupal\Component\Render\MarkupInterface');
/**
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = array()) {
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 = array()) {
return NULL;
}
}
@@ -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 = array()) {
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 = array();
// 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', array($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 = array();
krsort($services);
// Flatten the array.
foreach ($services as $a) {
$sorted = array_merge($sorted, $a);
}
return $sorted;
}
}
@@ -0,0 +1,75 @@
<?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 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) {
$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 = array();
foreach ($container->findTaggedServiceIds('encoder') as $attributes) {
$formats[] = $attributes[0]['format'];
}
$container->setParameter('serializer.formats', $formats);
}
/**
* 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 = array();
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,98 @@
<?php
namespace Drupal\serialization\Tests;
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(array(
'entity_type' => 'entity_test_mulrev',
'field_name' => 'field_test_entity_reference',
'type' => 'entity_reference',
'settings' => array(
'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.
*/
function testUuidEntityResolver() {
// Create an entity to get the UUID from.
$entity = EntityTestMulRev::create(array('type' => 'entity_test_mulrev'));
$entity->set('name', 'foobar');
$entity->set('field_test_entity_reference', array(array('target_id' => 1)));
$entity->save();
$field_uri = Url::fromUri('base:rest/relation/entity_test_mulrev/entity_test_mulrev/field_test_entity_reference', array('absolute' => TRUE))->toString();
$data = array(
'_links' => array(
'type' => array(
'href' => Url::fromUri('base:rest/type/entity_test_mulrev/entity_test_mulrev', array('absolute' => TRUE))->toString(),
),
$field_uri => array(
array(
'href' => $entity->url(),
),
),
),
'_embedded' => array(
$field_uri => array(
array(
'_links' => array(
'self' => $entity->url(),
),
'uuid' => array(
array(
'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,226 @@
<?php
namespace Drupal\serialization\Tests;
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 = array('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\ContentEntityBase
*/
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', array('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 = array(
'name' => $this->randomMachineName(),
'user_id' => $this->user->id(),
'field_test_text' => array(
'value' => $this->randomMachineName(),
'format' => 'full_html',
),
);
$this->entity = EntityTestMulRev::create($this->values);
$this->entity->save();
$this->serializer = $this->container->get('serializer');
$this->installConfig(array('field'));
}
/**
* Test the normalize function.
*/
public function testNormalize() {
$expected = array(
'id' => array(
array('value' => 1),
),
'uuid' => array(
array('value' => $this->entity->uuid()),
),
'langcode' => array(
array('value' => 'en'),
),
'name' => array(
array('value' => $this->values['name']),
),
'type' => array(
array('value' => 'entity_test_mulrev'),
),
'created' => array(
array('value' => $this->entity->created->value),
),
'user_id' => array(
array(
'target_id' => $this->user->id(),
'target_type' => $this->user->getEntityTypeId(),
'target_uuid' => $this->user->uuid(),
'url' => $this->user->url(),
),
),
'revision_id' => array(
array('value' => 1),
),
'default_langcode' => array(
array('value' => TRUE),
),
'non_rev_field' => array(),
'field_test_text' => array(
array(
'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->assertEqual($expected[$fieldName], $normalized[$fieldName], "ComplexDataNormalizer produces expected array for $fieldName.");
}
$this->assertEqual(array_diff_key($normalized, $expected), array(), '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 = array(
'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 (array('json', 'xml') as $type) {
$denormalized = $this->serializer->denormalize($normalized, $this->entityClass, $type, array('entity_type' => 'entity_test_mulrev'));
$this->assertTrue($denormalized instanceof $this->entityClass, SafeMarkup::format('Denormalized entity is an instance of @class', array('@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,47 @@
<?php
namespace Drupal\serialization\Tests;
use Drupal\KernelTests\KernelTestBase;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
abstract class NormalizerTestBase extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('serialization', 'system', 'field', 'entity_test', 'text', 'filter', 'user');
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_mulrev');
$this->installEntitySchema('user');
$this->installConfig(array('field'));
\Drupal::service('router.builder')->rebuild();
\Drupal::moduleHandler()->invoke('rest', 'install');
// Auto-create a field for testing.
FieldStorageConfig::create(array(
'entity_type' => 'entity_test_mulrev',
'field_name' => 'field_test_text',
'type' => 'text',
'cardinality' => 1,
'translatable' => FALSE,
))->save();
FieldConfig::create(array(
'entity_type' => 'entity_test_mulrev',
'field_name' => 'field_test_text',
'bundle' => 'entity_test_mulrev',
'label' => 'Test text-field',
'widget' => array(
'type' => 'text_textfield',
'weight' => 0,
),
))->save();
}
}