View source
<?php
namespace Drupal\jsonapi_schema;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\ListDataDefinition;
use Drupal\Core\TypedData\ListDataDefinitionInterface;
use Drupal\Core\TypedData\MapDataDefinition;
use Drupal\Core\TypedData\TypedDataManagerInterface;
class StaticDataDefinitionExtractor {
const BOGUS_CONFIG_ENTITY_ID = 'ID';
private $typedDataManager;
private $typedConfigManager;
private $entityFieldManager;
private $definitions;
public function __construct(TypedDataManagerInterface $typed_data_manager, TypedConfigManagerInterface $typed_config_manager, EntityFieldManagerInterface $entity_field_manager) {
$this->typedDataManager = $typed_data_manager;
$this->typedConfigManager = $typed_config_manager;
$this->entityFieldManager = $entity_field_manager;
}
public function extract(EntityTypeInterface $entity_type, $bundle) {
$data_type = sprintf('entity:%s:%s', $entity_type
->id(), $bundle);
if (isset($this->definitions[$data_type])) {
return $this->definitions[$data_type];
}
if ($entity_type instanceof ContentEntityTypeInterface) {
$definition = $this
->extractContentEntityType($entity_type, $bundle);
}
else {
if ($entity_type instanceof ConfigEntityTypeInterface) {
$definition = $this
->extractConfigEntityType($entity_type, $bundle);
}
else {
throw new \LogicException('Only configuration and content entities are supported.');
}
}
$this->definitions[$data_type] = $definition;
return $definition;
}
public function extractField(EntityTypeInterface $entity_type, $bundle, $field_name) {
$definition = $this
->extract($entity_type, $bundle);
return $definition
->getPropertyDefinition($field_name) ?: DataDefinition::createFromDataType('undefined');
}
private function extractContentEntityType(ContentEntityTypeInterface $entity_type, $bundle) {
$data_type = sprintf('entity:%s', $entity_type
->id());
if ($entity_type
->getBundleEntityType()) {
$data_type .= ':' . $bundle;
}
return $this->typedDataManager
->createDataDefinition($data_type);
}
private function extractConfigEntityType(ConfigEntityTypeInterface $entity_type, $bundle) {
$data_type = sprintf('entity:%s', $entity_type
->id());
if ($entity_type
->hasKey('bundle')) {
$data_type .= ':' . $bundle;
}
$config_definition = $this->typedConfigManager
->getDefinition(sprintf('%s.%s', $entity_type
->getConfigPrefix(), static::BOGUS_CONFIG_ENTITY_ID), FALSE);
$definition = MapDataDefinition::createFromDataType($data_type);
foreach ($entity_type
->getPropertiesToExport(static::BOGUS_CONFIG_ENTITY_ID) as $field_name) {
$field_schema = NestedArray::getValue($config_definition, [
'mapping',
$field_name,
]) ?: [];
$definition
->setPropertyDefinition($field_name, $this
->createDataDefinition($field_schema));
}
return $definition;
}
private function createDataDefinition($field_schema) {
if (!isset($field_schema['type'])) {
return DataDefinition::createFromDataType('undefined');
}
$data_type = $field_schema['type'];
$field_schema += $this->typedConfigManager
->getDefinition($data_type, FALSE);
$definition_class = $field_schema['definition_class'];
if (is_subclass_of($definition_class, MapDataDefinition::class)) {
$definition = call_user_func([
$definition_class,
'createFromDataType',
], $data_type)
->setTypedDataManager($this->typedDataManager);
assert($definition instanceof MapDataDefinition);
foreach ($field_schema['mapping'] as $name => $item_definition) {
$item_definition = $this
->createDataDefinition($item_definition);
$definition
->setPropertyDefinition($name, $item_definition);
}
return $definition;
}
$is_sequence = FALSE;
if (is_subclass_of($definition_class, ListDataDefinitionInterface::class)) {
$is_sequence = TRUE;
$data_type = $field_schema['sequence']['type'];
}
if ($this->typedDataManager
->hasDefinition($data_type)) {
return $is_sequence ? $this->typedDataManager
->createListDataDefinition($data_type) : $this->typedDataManager
->createDataDefinition($data_type);
}
$data_definition = DataDefinition::createFromDataType('undefined')
->setTypedDataManager($this->typedDataManager);
if ($is_sequence) {
$data_definition = ListDataDefinition::createFromDataType('sequence')
->setTypedDataManager($this->typedDataManager)
->setItemDefinition($data_definition);
}
return $data_definition;
}
}