3 namespace Drupal\hal\Normalizer;
5 use Drupal\Core\Field\FieldItemInterface;
6 use Symfony\Component\Serializer\Exception\InvalidArgumentException;
9 * Converts the Drupal field item object structure to HAL array structure.
11 class FieldItemNormalizer extends NormalizerBase {
14 * The interface or class that this Normalizer supports.
18 protected $supportedInterfaceOrClass = 'Drupal\Core\Field\FieldItemInterface';
23 public function normalize($field_item, $format = NULL, array $context = []) {
24 // The values are wrapped in an array, and then wrapped in another array
25 // keyed by field name so that field items can be merged by the
26 // FieldNormalizer. This is necessary for the EntityReferenceItemNormalizer
27 // to be able to place values in the '_links' array.
28 $field = $field_item->getParent();
30 $field->getName() => [$this->normalizedFieldValues($field_item, $format, $context)],
37 public function denormalize($data, $class, $format = NULL, array $context = []) {
38 if (!isset($context['target_instance'])) {
39 throw new InvalidArgumentException('$context[\'target_instance\'] must be set to denormalize with the FieldItemNormalizer');
41 if ($context['target_instance']->getParent() == NULL) {
42 throw new InvalidArgumentException('The field item passed in via $context[\'target_instance\'] must have a parent set.');
45 $field_item = $context['target_instance'];
47 // If this field is translatable, we need to create a translated instance.
48 if (isset($data['lang'])) {
49 $langcode = $data['lang'];
51 $field_definition = $field_item->getFieldDefinition();
52 if ($field_definition->isTranslatable()) {
53 $field_item = $this->createTranslatedInstance($field_item, $langcode);
57 $field_item->setValue($this->constructValue($data, $context));
62 * Build the field item value using the incoming data.
65 * The incoming data for this field item.
67 * The context passed into the Normalizer.
70 * The value to use in Entity::setValue().
72 protected function constructValue($data, $context) {
77 * Normalizes field values for an item.
79 * @param \Drupal\Core\Field\FieldItemInterface $field_item
80 * The field item instance.
81 * @param string|null $format
82 * The normalization format.
83 * @param array $context
84 * The context passed into the normalizer.
87 * An array of field item values, keyed by property name.
89 protected function normalizedFieldValues(FieldItemInterface $field_item, $format, array $context) {
91 // We normalize each individual property, so each can do their own casting,
93 /** @var \Drupal\Core\TypedData\TypedDataInterface $property */
94 foreach ($field_item as $property_name => $property) {
95 $normalized[$property_name] = $this->serializer->normalize($property, $format, $context);
98 if (isset($context['langcode'])) {
99 $normalized['lang'] = $context['langcode'];
106 * Get a translated version of the field item instance.
108 * To indicate that a field item applies to one translation of an entity and
109 * not another, the property path must originate with a translation of the
110 * entity. This is the reason for using target_instances, from which the
111 * property path can be traversed up to the root.
113 * @param \Drupal\Core\Field\FieldItemInterface $item
114 * The untranslated field item instance.
118 * @return \Drupal\Core\Field\FieldItemInterface
119 * The translated field item instance.
121 protected function createTranslatedInstance(FieldItemInterface $item, $langcode) {
122 // Remove the untranslated item that was created for the default language
123 // by FieldNormalizer::denormalize().
124 $items = $item->getParent();
125 $delta = $item->getName();
126 unset($items[$delta]);
128 // Instead, create a new item for the entity in the requested language.
129 $entity = $item->getEntity();
130 $entity_translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode);
131 $field_name = $item->getFieldDefinition()->getName();
132 return $entity_translation->get($field_name)->appendItem();