Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 101 |
ContentEntityNormalizer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 5 |
650 | |
0.00% |
0 / 101 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
normalize | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 33 |
|||
denormalize | |
0.00% |
0 / 1 |
90 | |
0.00% |
0 / 41 |
|||
getEntityUri | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
getTypedDataIds | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 17 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\hal\Normalizer\ContentEntityNormalizer. | |
*/ | |
namespace Drupal\hal\Normalizer; | |
use Drupal\Component\Utility\NestedArray; | |
use Drupal\Core\Entity\EntityInterface; | |
use Drupal\Core\Entity\EntityManagerInterface; | |
use Drupal\Core\Extension\ModuleHandlerInterface; | |
use Drupal\rest\LinkManager\LinkManagerInterface; | |
use Symfony\Component\Serializer\Exception\UnexpectedValueException; | |
/** | |
* Converts the Drupal entity object structure to a HAL array structure. | |
*/ | |
class ContentEntityNormalizer extends NormalizerBase { | |
/** | |
* The interface or class that this Normalizer supports. | |
* | |
* @var string | |
*/ | |
protected $supportedInterfaceOrClass = 'Drupal\Core\Entity\ContentEntityInterface'; | |
/** | |
* The hypermedia link manager. | |
* | |
* @var \Drupal\rest\LinkManager\LinkManagerInterface | |
*/ | |
protected $linkManager; | |
/** | |
* The entity manager. | |
* | |
* @var \Drupal\Core\Entity\EntityManagerInterface | |
*/ | |
protected $entityManager; | |
/** | |
* The module handler. | |
* | |
* @var \Drupal\Core\Extension\ModuleHandlerInterface | |
*/ | |
protected $moduleHandler; | |
/** | |
* Constructs an ContentEntityNormalizer object. | |
* | |
* @param \Drupal\rest\LinkManager\LinkManagerInterface $link_manager | |
* The hypermedia link manager. | |
*/ | |
public function __construct(LinkManagerInterface $link_manager, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler) { | |
$this->linkManager = $link_manager; | |
$this->entityManager = $entity_manager; | |
$this->moduleHandler = $module_handler; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function normalize($entity, $format = NULL, array $context = array()) { | |
$context += array( | |
'account' => NULL, | |
'included_fields' => NULL, | |
); | |
// Create the array of normalized fields, starting with the URI. | |
/** @var $entity \Drupal\Core\Entity\ContentEntityInterface */ | |
$normalized = array( | |
'_links' => array( | |
'self' => array( | |
'href' => $this->getEntityUri($entity), | |
), | |
'type' => array( | |
'href' => $this->linkManager->getTypeUri($entity->getEntityTypeId(), $entity->bundle(), $context), | |
), | |
), | |
); | |
// If the fields to use were specified, only output those field values. | |
// Otherwise, output all field values except internal ID. | |
if (isset($context['included_fields'])) { | |
$fields = array(); | |
foreach ($context['included_fields'] as $field_name) { | |
$fields[] = $entity->get($field_name); | |
} | |
} | |
else { | |
$fields = $entity->getFields(); | |
} | |
// Ignore the entity ID and revision ID. | |
$exclude = array($entity->getEntityType()->getKey('id'), $entity->getEntityType()->getKey('revision')); | |
foreach ($fields as $field) { | |
// Continue if this is an excluded field or the current user does not have | |
// access to view it. | |
if (in_array($field->getFieldDefinition()->getName(), $exclude) || !$field->access('view', $context['account'])) { | |
continue; | |
} | |
$normalized_property = $this->serializer->normalize($field, $format, $context); | |
$normalized = NestedArray::mergeDeep($normalized, $normalized_property); | |
} | |
return $normalized; | |
} | |
/** | |
* Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize(). | |
* | |
* @param array $data | |
* Entity data to restore. | |
* @param string $class | |
* Unused, entity_create() is used to instantiate entity objects. | |
* @param string $format | |
* Format the given data was extracted from. | |
* @param array $context | |
* Options available to the denormalizer. Keys that can be used: | |
* - request_method: if set to "patch" the denormalization will clear out | |
* all default values for entity fields before applying $data to the | |
* entity. | |
* | |
* @return \Drupal\Core\Entity\EntityInterface | |
* An unserialized entity object containing the data in $data. | |
* | |
* @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException | |
*/ | |
public function denormalize($data, $class, $format = NULL, array $context = array()) { | |
// Get type, necessary for determining which bundle to create. | |
if (!isset($data['_links']['type'])) { | |
throw new UnexpectedValueException('The type link relation must be specified.'); | |
} | |
// Create the entity. | |
$typed_data_ids = $this->getTypedDataIds($data['_links']['type'], $context); | |
$entity_type = $this->entityManager->getDefinition($typed_data_ids['entity_type']); | |
$langcode_key = $entity_type->getKey('langcode'); | |
$values = array(); | |
// Figure out the language to use. | |
if (isset($data[$langcode_key])) { | |
$values[$langcode_key] = $data[$langcode_key][0]['value']; | |
// Remove the langcode so it does not get iterated over below. | |
unset($data[$langcode_key]); | |
} | |
if ($entity_type->hasKey('bundle')) { | |
$bundle_key = $entity_type->getKey('bundle'); | |
$values[$bundle_key] = $typed_data_ids['bundle']; | |
// Unset the bundle key from data, if it's there. | |
unset($data[$bundle_key]); | |
} | |
$entity = $this->entityManager->getStorage($typed_data_ids['entity_type'])->create($values); | |
// Remove links from data array. | |
unset($data['_links']); | |
// Get embedded resources and remove from data array. | |
$embedded = array(); | |
if (isset($data['_embedded'])) { | |
$embedded = $data['_embedded']; | |
unset($data['_embedded']); | |
} | |
// Flatten the embedded values. | |
foreach ($embedded as $relation => $field) { | |
$field_ids = $this->linkManager->getRelationInternalIds($relation); | |
if (!empty($field_ids)) { | |
$field_name = $field_ids['field_name']; | |
$data[$field_name] = $field; | |
} | |
} | |
// Pass the names of the fields whose values can be merged. | |
$entity->_restSubmittedFields = array_keys($data); | |
// Iterate through remaining items in data array. These should all | |
// correspond to fields. | |
foreach ($data as $field_name => $field_data) { | |
$items = $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. | |
$items->setValue(array()); | |
if ($field_data) { | |
// Denormalize the field data into the FieldItemList object. | |
$context['target_instance'] = $items; | |
$this->serializer->denormalize($field_data, get_class($items), $format, $context); | |
} | |
} | |
return $entity; | |
} | |
/** | |
* Constructs the entity URI. | |
* | |
* @param \Drupal\Core\Entity\EntityInterface | |
* The entity. | |
* @return string | |
* The entity URI. | |
*/ | |
protected function getEntityUri(EntityInterface $entity) { | |
// Some entity types don't provide a canonical link template, at least call | |
// out to ->url(). | |
if ($entity->isNew() || !$entity->hasLinkTemplate('canonical')) { | |
return $entity->url('canonical', []); | |
} | |
$url = $entity->urlInfo('canonical', ['absolute' => TRUE]); | |
return $url->setRouteParameter('_format', 'hal_json')->toString(); | |
} | |
/** | |
* Gets the typed data IDs for a type URI. | |
* | |
* @param array $types | |
* The type array(s) (value of the 'type' attribute of the incoming data). | |
* @param array $context | |
* Context from the normalizer/serializer operation. | |
* | |
* @return array | |
* The typed data IDs. | |
* | |
*/ | |
protected function getTypedDataIds($types, $context = array()) { | |
// The 'type' can potentially contain an array of type objects. By default, | |
// Drupal only uses a single type in serializing, but allows for multiple | |
// types when deserializing. | |
if (isset($types['href'])) { | |
$types = array($types); | |
} | |
foreach ($types as $type) { | |
if (!isset($type['href'])) { | |
throw new UnexpectedValueException('Type must contain an \'href\' attribute.'); | |
} | |
$type_uri = $type['href']; | |
// Check whether the URI corresponds to a known type on this site. Break | |
// once one does. | |
if ($typed_data_ids = $this->linkManager->getTypeInternalIds($type['href'], $context)) { | |
break; | |
} | |
} | |
// If none of the URIs correspond to an entity type on this site, no entity | |
// can be created. Throw an exception. | |
if (empty($typed_data_ids)) { | |
throw new UnexpectedValueException(sprintf('Type %s does not correspond to an entity on this site.', $type_uri)); | |
} | |
return $typed_data_ids; | |
} | |
} |