You are here

class DataDefinitionNormalizer in JSON:API Schema 8

Normalizer for DataDefinitionInterface instances.

DataDefinitionInterface is the ultimate parent to all data definitions. This service must always be low priority for data definitions, otherwise the simpler normalization process it supports will take precedence over all the complexities most entity properties contain before reaching this level.

DataDefinitionNormalizer produces scalar value definitions.

All the TypedData normalizers extend from this class.

Hierarchy

Expanded class hierarchy of DataDefinitionNormalizer

1 string reference to 'DataDefinitionNormalizer'
jsonapi_schema.services.yml in ./jsonapi_schema.services.yml
jsonapi_schema.services.yml
1 service uses DataDefinitionNormalizer
serializer.normalizer.data_definition.schema_json.fallback in ./jsonapi_schema.services.yml
Drupal\jsonapi_schema\Normalizer\DataDefinitionNormalizer

File

src/Normalizer/DataDefinitionNormalizer.php, line 21

Namespace

Drupal\jsonapi_schema\Normalizer
View source
class DataDefinitionNormalizer extends NormalizerBase {
  const JSON_TYPES = [
    'null',
    'boolean',
    'string',
    'number',
    'integer',
    'array',
    'object',
  ];

  /**
   * The formats that the Normalizer can handle.
   *
   * @var array
   */
  protected $format = 'schema_json';

  /**
   * The interface or class that this Normalizer supports.
   *
   * @var string
   */
  protected $supportedInterfaceOrClass = DataDefinitionInterface::class;

  /**
   * The supported data type.
   *
   * @var string[]
   */
  protected $supportedDataTypes = [];

  /**
   * {@inheritdoc}
   */
  public function normalize($entity, $format = NULL, array $context = []) {
    assert($entity instanceof DataDefinitionInterface);

    // `text source` and `date source` produce objects not supported in the API.
    // It is not clear how the API excludes them.
    // @todo properly identify and exclude this class of computed objects.
    if ($entity
      ->getSetting('text source') || $entity
      ->getSetting('date source')) {
      return [];
    }
    $property = $this
      ->extractPropertyData($entity, $context);
    if (!is_object($property) && !empty($context['parent']) && $context['name'] == 'value') {
      if ($maxLength = $context['parent']
        ->getSetting('max_length')) {
        $property['maxLength'] = $maxLength;
      }
      if (empty($context['parent']
        ->getSetting('allowed_values_function')) && !empty($context['parent']
        ->getSetting('allowed_values'))) {
        $allowed_values = $context['parent']
          ->getSetting('allowed_values');
        $property['enum'] = array_keys($allowed_values);
      }
    }
    if (!is_object($property) && !isset($property['title']) && isset($context['name'])) {
      $property['title'] = $context['name'];
    }
    $normalized = [
      'properties' => [],
    ];
    if (!is_object($property) && !in_array($property['type'], static::JSON_TYPES)) {

      // Unable to find the correct type.
      \Drupal::logger('jsonapi_schema')
        ->error('{type} is not a valid type for a JSON document.', [
        'type' => $property['type'],
      ]);
      $property = (object) [];
    }
    $normalized['properties'][$context['name']] = $property;
    if ($this
      ->requiredProperty($entity)) {
      $normalized['required'][] = $context['name'];
    }
    return $normalized;
  }

  /**
   * Extracts property details from a data definition.
   *
   * This method includes mapping primitive types in Drupal to JSON Schema
   * type and format descriptions. This method is invoked by several of the
   * normalizers.
   *
   * @param \Drupal\Core\TypedData\DataDefinitionInterface $property
   *   The data definition from which to extract values.
   * @param array $context
   *   Serializer context.
   *
   * @return array
   *   Discrete values of the property definition
   */
  protected function extractPropertyData(DataDefinitionInterface $property, array $context = []) {
    $value = [
      'type' => $property
        ->getDataType(),
    ];
    if ($item = $property
      ->getLabel()) {
      $value['title'] = $item;
    }
    if ($item = $property
      ->getDescription()) {
      $value['description'] = addslashes(strip_tags($item));
    }
    return $value;
  }

  /**
   * Normalize an array of data definitions.
   *
   * This normalization process gets an array of properties and an array of
   * properties that are required by name. This is needed by the
   * SchemataSchemaNormalizer, otherwise it would have been placed in
   * DataDefinitionNormalizer.
   *
   * @param \Drupal\Core\TypedData\DataDefinitionInterface[] $items
   *   An array of data definition properties to be normalized.
   * @param string $format
   *   Format identifier of the current serialization process.
   * @param array $context
   *   Operating context of the serializer.
   *
   * @return array
   *   Array containing one or two nested arrays.
   *   - properties: The array of all normalized properties.
   *   - required: The array of required properties by name.
   */
  protected function normalizeProperties(array $items, $format, array $context = []) {
    $normalized = [];
    foreach ($items as $name => $property) {
      $context['name'] = $name;
      $item = $this->serializer
        ->normalize($property, $format, $context);
      if (!empty($item)) {
        $normalized = NestedArray::mergeDeep($normalized, $item);
      }
    }
    return $normalized;
  }

  /**
   * Determine if the given property is a required element of the schema.
   *
   * @param \Drupal\Core\TypedData\DataDefinitionInterface $property
   *   The data property to be evaluated.
   *
   * @return bool
   *   Whether the property should be treated as required for schema
   *   purposes.
   */
  protected function requiredProperty(DataDefinitionInterface $property) {
    return $property
      ->isReadOnly() || $property
      ->isRequired();
  }

  /**
   * {@inheritdoc}
   */
  public function supportsNormalization($data, $format = NULL) {
    return parent::supportsNormalization($data, $format) && $data instanceof DataDefinitionInterface && (empty($this->supportedDataTypes) || in_array($data
      ->getDataType(), $this->supportedDataTypes));
  }

  /**
   * {@inheritdoc}
   */
  public function supportsDenormalization($data, $type, $format = NULL) {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function denormalize($data, $class, $format = NULL, array $context = []) {
    throw new \RuntimeException('Denormalization is not supported.');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY constant Name of key for bubbling cacheability metadata via serialization context.
DataDefinitionNormalizer::$format protected property The formats that the Normalizer can handle. Overrides NormalizerBase::$format
DataDefinitionNormalizer::$supportedDataTypes protected property The supported data type. 6
DataDefinitionNormalizer::$supportedInterfaceOrClass protected property The interface or class that this Normalizer supports. Overrides NormalizerBase::$supportedInterfaceOrClass 2
DataDefinitionNormalizer::denormalize public function
DataDefinitionNormalizer::extractPropertyData protected function Extracts property details from a data definition. 6
DataDefinitionNormalizer::JSON_TYPES constant
DataDefinitionNormalizer::normalize public function 2
DataDefinitionNormalizer::normalizeProperties protected function Normalize an array of data definitions.
DataDefinitionNormalizer::requiredProperty protected function Determine if the given property is a required element of the schema.
DataDefinitionNormalizer::supportsDenormalization public function Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() Overrides NormalizerBase::supportsDenormalization
DataDefinitionNormalizer::supportsNormalization public function Checks whether the given class is supported for normalization by this normalizer. Overrides NormalizerBase::supportsNormalization 1
NormalizerBase::addCacheableDependency protected function Adds cacheability if applicable.
NormalizerBase::checkFormat protected function Checks if the provided format is supported by this normalizer. 2