class EntityNormalizer

Converts the Drupal entity object structure to a HAL array structure.

Hierarchy

Expanded class hierarchy of EntityNormalizer

1 file declares its use of EntityNormalizer
NormalizerTestBase.php in drupal/core/modules/hal/lib/Drupal/hal/Tests/NormalizerTestBase.php
Contains \Drupal\hal\Tests\NormalizerTestBase.
1 string reference to 'EntityNormalizer'
hal.services.yml in drupal/core/modules/hal/hal.services.yml
drupal/core/modules/hal/hal.services.yml
1 service uses EntityNormalizer

File

drupal/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php, line 18
Contains \Drupal\hal\Normalizer\EntityNormalizer.

Namespace

Drupal\hal\Normalizer
View source
class EntityNormalizer extends NormalizerBase {

  /**
   * The interface or class that this Normalizer supports.
   *
   * @var string
   */
  protected $supportedInterfaceOrClass = 'Drupal\\Core\\Entity\\EntityInterface';

  /**
   * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize()
   */
  public function normalize($entity, $format = NULL, array $context = array()) {

    // Create the array of normalized properties, starting with the URI.
    $normalized = array(
      '_links' => array(
        'self' => array(
          'href' => $this
            ->getEntityUri($entity),
        ),
        'type' => array(
          'href' => $this->linkManager
            ->getTypeUri($entity
            ->entityType(), $entity
            ->bundle()),
        ),
      ),
    );

    // If the properties to use were specified, only output those properties.
    // Otherwise, output all properties except internal ID.
    if (isset($context['included_fields'])) {
      foreach ($context['included_fields'] as $property_name) {
        $properties[] = $entity
          ->get($property_name);
      }
    }
    else {
      $properties = $entity
        ->getProperties();
    }
    foreach ($properties as $property) {

      // In some cases, Entity API will return NULL array items. Ensure this is
      // a real property and that it is not the internal id.
      if (!is_object($property) || $property
        ->getName() == 'id') {
        continue;
      }
      $normalized_property = $this->serializer
        ->normalize($property, $format, $context);
      $normalized = NestedArray::mergeDeep($normalized, $normalized_property);
    }
    return $normalized;
  }

  /**
   * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize().
   *
   * @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']);

    // Figure out the language to use.
    if (isset($data['langcode'])) {
      $langcode = $data['langcode'][0]['value'];
    }
    elseif (module_exists('language')) {
      $langcode = language_get_default_langcode($typed_data_ids['entity_type'], $typed_data_ids['bundle']);
    }
    else {
      $langcode = Language::LANGCODE_NOT_SPECIFIED;
    }
    $entity = entity_create($typed_data_ids['entity_type'], array(
      'langcode' => $langcode,
      'type' => $typed_data_ids['bundle'],
    ));

    // Get links and remove from data array.
    $links = $data['_links'];
    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;
      }
    }

    // Iterate through remaining items in data array. These should all
    // correspond to fields.
    foreach ($data as $field_name => $field_data) {

      // Remove any values that were set as a part of entity creation (e.g
      // uuid). If this field is set to an empty array in the data, this will
      // also have the effect of marking the field for deletion in REST module.
      $entity->{$field_name} = array();
      $field = $entity
        ->get($field_name);

      // Get the class of the field. This will generally be the default Field
      // class.
      $field_class = get_class($field);

      // Pass in the empty field object as a target instance. Since the context
      // is already prepared for the field, any data added to it is
      // automatically added to the entity.
      $context['target_instance'] = $field;
      $this->serializer
        ->denormalize($field_data, $field_class, $format, $context);
    }
    return $entity;
  }

  /**
   * Constructs the entity URI.
   *
   * @param $entity
   *   The entity.
   *
   * @return string
   *   The entity URI.
   */
  protected function getEntityUri($entity) {
    $uri_info = $entity
      ->uri();
    return url($uri_info['path'], array(
      'absolute' => TRUE,
    ));
  }

  /**
   * 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).
   *
   * @return array
   *   The typed data IDs.
   *
   * @throws \Symfony\Component\Serializer\Exception\UnexpectedValueException
   */
  protected function getTypedDataIds($types) {

    // 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'])) {
        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;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityNormalizer::$supportedInterfaceOrClass protected property The interface or class that this Normalizer supports. Overrides NormalizerBase::$supportedInterfaceOrClass
EntityNormalizer::denormalize public function Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize(). Overrides DenormalizerInterface::denormalize
EntityNormalizer::getEntityUri protected function Constructs the entity URI.
EntityNormalizer::getTypedDataIds protected function Gets the typed data IDs for a type URI.
EntityNormalizer::normalize public function Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() Overrides NormalizerInterface::normalize
NormalizerBase::$entityResolver protected property The entity resolver.
NormalizerBase::$formats protected property The formats that the Normalizer can handle.
NormalizerBase::$linkManager protected property The hypermedia link manager.
NormalizerBase::setEntityResolver public function Sets the entity resolver.
NormalizerBase::setLinkManager public function Sets the link manager.
NormalizerBase::supportsDenormalization public function Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() Overrides DenormalizerInterface::supportsDenormalization
NormalizerBase::supportsNormalization public function Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization(). Overrides NormalizerBase::supportsNormalization
SerializerAwareNormalizer::$serializer protected property
SerializerAwareNormalizer::setSerializer public function Sets the owning Serializer object Overrides SerializerAwareInterface::setSerializer