summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authore0ipso2017-05-22 22:06:48 (GMT)
committerMateu Aguiló Bosch2017-05-22 22:06:48 (GMT)
commit2bdaca652bcfdd9b41886294a1c4bc443427fd9a (patch)
treedfad1497f4678b774b4951b924187e844c20b8ee
parent0284cd95abda320075b4f6f0d00d4a09528ec534 (diff)
feat(Serialization): Apply enhancers for the data coming into the server (#2874309 by e0ipso)
-rw-r--r--jsonapi_extras.services.yml11
-rw-r--r--src/JsonapiExtrasServiceProvider.php4
-rw-r--r--src/Normalizer/ConfigEntityNormalizer.php14
-rw-r--r--src/Normalizer/ContentEntityNormalizer.php14
-rw-r--r--src/Normalizer/EntityNormalizerTrait.php83
-rw-r--r--src/Normalizer/FieldItemNormalizer.php99
-rw-r--r--src/ResourceType/ConfigurableResourceType.php100
-rw-r--r--src/ResourceType/ConfigurableResourceTypeRepository.php14
8 files changed, 223 insertions, 116 deletions
diff --git a/jsonapi_extras.services.yml b/jsonapi_extras.services.yml
index 44131f6..d8795bd 100644
--- a/jsonapi_extras.services.yml
+++ b/jsonapi_extras.services.yml
@@ -16,6 +16,17 @@ services:
tags:
- { name: normalizer, priority: 25 }
+ serializer.normalizer.entity.jsonapi_extras:
+ class: Drupal\jsonapi_extras\Normalizer\ContentEntityNormalizer
+ arguments: ['@jsonapi.link_manager', '@jsonapi.resource_type.repository', '@entity_type.manager']
+ tags:
+ - { name: normalizer, priority: 22 }
+ serializer.normalizer.config_entity.jsonapi_extras:
+ class: Drupal\jsonapi_extras\Normalizer\ConfigEntityNormalizer
+ arguments: ['@jsonapi.link_manager', '@jsonapi.resource_type.repository', '@entity_type.manager']
+ tags:
+ - { name: normalizer, priority: 22 }
+
plugin.manager.resource_field_enhancer:
class: Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager
parent: default_plugin_manager
diff --git a/src/JsonapiExtrasServiceProvider.php b/src/JsonapiExtrasServiceProvider.php
index ce81c4d..52c5518 100644
--- a/src/JsonapiExtrasServiceProvider.php
+++ b/src/JsonapiExtrasServiceProvider.php
@@ -20,8 +20,10 @@ class JsonapiExtrasServiceProvider implements ServiceModifierInterface {
// Override the class used for the configurable service.
$definition = $container->getDefinition('jsonapi.resource_type.repository');
$definition->setClass(ConfigurableResourceTypeRepository::class);
- // The configurable service expects the entity repository.
+ // The configurable service expects the entity repository and the enhancer
+ // plugin manager.
$definition->addArgument(new Reference('entity.repository'));
+ $definition->addArgument(new Reference('plugin.manager.resource_field_enhancer'));
}
}
diff --git a/src/Normalizer/ConfigEntityNormalizer.php b/src/Normalizer/ConfigEntityNormalizer.php
new file mode 100644
index 0000000..2bd398c
--- /dev/null
+++ b/src/Normalizer/ConfigEntityNormalizer.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\jsonapi_extras\Normalizer;
+
+use Drupal\jsonapi\Normalizer\ConfigEntityNormalizer as JsonapiConfigEntityNormalizer;
+
+/**
+ * Override ConfigEntityNormalizer to prepare input.
+ */
+class ConfigEntityNormalizer extends JsonapiConfigEntityNormalizer {
+
+ use EntityNormalizerTrait;
+
+}
diff --git a/src/Normalizer/ContentEntityNormalizer.php b/src/Normalizer/ContentEntityNormalizer.php
new file mode 100644
index 0000000..e5b1f01
--- /dev/null
+++ b/src/Normalizer/ContentEntityNormalizer.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\jsonapi_extras\Normalizer;
+
+use Drupal\jsonapi\Normalizer\ContentEntityNormalizer as JsonapiContentEntityNormalizer;
+
+/**
+ * Override ContentEntityNormalizer to prepare input.
+ */
+class ContentEntityNormalizer extends JsonapiContentEntityNormalizer {
+
+ use EntityNormalizerTrait;
+
+}
diff --git a/src/Normalizer/EntityNormalizerTrait.php b/src/Normalizer/EntityNormalizerTrait.php
new file mode 100644
index 0000000..1cd343d
--- /dev/null
+++ b/src/Normalizer/EntityNormalizerTrait.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Drupal\jsonapi_extras\Normalizer;
+
+use Drupal\jsonapi\ResourceType\ResourceType;
+
+/**
+ * Common code for entity normalizers.
+ */
+trait EntityNormalizerTrait {
+
+ /**
+ * Prepares the input data to create the entity.
+ *
+ * @param array $data
+ * The input data to modify.
+ * @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
+ * Contains the info about the resource type.
+ *
+ * @return array
+ * The modified input data.
+ */
+ protected function prepareInput(array $data, ResourceType $resource_type) {
+ $data_internal = [];
+ /** @var \Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType $resource_type */
+ // Translate the public fields into the entity fields.
+ foreach ($data as $public_field_name => $field_value) {
+ // Skip any disabled field.
+ if (!$resource_type->isFieldEnabled($public_field_name)) {
+ continue;
+ }
+ $internal_name = $resource_type->getInternalName($public_field_name);
+ $enhancer = $resource_type->getFieldEnhancer($public_field_name, 'publicName');
+ $field_value = $enhancer ? $enhancer->prepareForInput($field_value) : $field_value;
+ $data_internal[$internal_name] = $field_value;
+ }
+
+ return $data_internal;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function normalize($entity, $format = NULL, array $context = []) {
+ $output = parent::normalize($entity, $format, $context);
+
+ /** @var \Drupal\jsonapi\ResourceType\ResourceType $resource_type */
+ $resource_type = $context['resource_type'];
+ $entity_type_id = $resource_type->getEntityTypeId();
+ $bundle_id = $resource_type->getBundle();
+ // The output depends on the configuration entity for caching.
+ $context['cacheable_metadata']->addCacheableDependency(
+ $this->getResourceConfig($entity_type_id, $bundle_id)
+ );
+ $context['cacheable_metadata']->addCacheableDependency(
+ \Drupal::config('jsonapi_extras.settings')
+ );
+
+ return $output;
+ }
+
+ /**
+ * Get the configuration entity based on the entity type and bundle.
+ *
+ * @param string $entity_type_id
+ * The entity type ID.
+ * @param string $bundle_id
+ * The bundle ID.
+ *
+ * @return \Drupal\Core\Entity\EntityInterface|null
+ * The resource config entity or NULL.
+ */
+ protected function getResourceConfig($entity_type_id, $bundle_id) {
+ $id = sprintf('%s--%s', $entity_type_id, $bundle_id);
+ // TODO: Inject this service.
+ $resource_config = \Drupal::entityTypeManager()
+ ->getStorage('jsonapi_resource_config')
+ ->load($id);
+
+ return $resource_config;
+ }
+
+}
diff --git a/src/Normalizer/FieldItemNormalizer.php b/src/Normalizer/FieldItemNormalizer.php
index d4df120..b95e298 100644
--- a/src/Normalizer/FieldItemNormalizer.php
+++ b/src/Normalizer/FieldItemNormalizer.php
@@ -2,7 +2,6 @@
namespace Drupal\jsonapi_extras\Normalizer;
-use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\jsonapi\Normalizer\NormalizerBase;
@@ -66,103 +65,17 @@ class FieldItemNormalizer extends NormalizerBase {
// First get the regular output.
$normalized_output = $this->subject->normalize($object, $format, $context);
// Then detect if there is any enhancer to be applied here.
- /** @var \Drupal\jsonapi\ResourceType\ResourceType $resource_type */
+ /** @var \Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType $resource_type */
$resource_type = $context['resource_type'];
- $entity_type_id = $resource_type->getEntityTypeId();
- $bundle_id = $resource_type->getBundle();
- $resource_field_info = $this->getResourceFieldInfo(
- $entity_type_id,
- $bundle_id,
- $object->getParent()->getName()
- );
- if (empty($resource_field_info['enhancer']['id'])) {
+ $enhancer = $resource_type->getFieldEnhancer($object->getParent()->getName());
+ if (!$enhancer) {
return $normalized_output;
}
- try {
- $enhancer_info = $resource_field_info['enhancer'];
- // Ensure that the settings are in a suitable format.
- $settings = [];
- if (!empty($enhancer_info['settings']) && is_array($enhancer_info['settings'])) {
- $settings = $enhancer_info['settings'];
- }
- // Get the enhancer instance.
- /** @var \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerInterface $enhancer */
- $enhancer = $this->enhancerManager->createInstance(
- $enhancer_info['id'],
- $settings
- );
- // Apply any enhancements necessary.
- $processed = $enhancer->postProcess($normalized_output->rasterizeValue());
- $normalized_output = new FieldItemNormalizerValue([$processed]);
- }
- catch (PluginNotFoundException $exception) {
- watchdog_exception('jsonapi_extras', $exception);
- }
-
- // TODO: This should live in an Entity level normalizer. At this point we do
- // not have one, so the performance is best if we have it run multiple times
- // here. However we will introduce one when altering the incoming output for
- // things.
- // The output depends on the configuration entity for caching.
- $context['cacheable_metadata']->addCacheableDependency(
- $this->getResourceConfig($entity_type_id, $bundle_id)
- );
- $context['cacheable_metadata']->addCacheableDependency(
- \Drupal::config('jsonapi_extras.settings')
- );
+ // Apply any enhancements necessary.
+ $processed = $enhancer->postProcess($normalized_output->rasterizeValue());
+ $normalized_output = new FieldItemNormalizerValue([$processed]);
return $normalized_output;
}
- /**
- * Get information about the particular field, if it exists.
- *
- * @param string $entity_type_id
- * The entity type ID.
- * @param string $bundle_id
- * The bundle ID.
- * @param string $internal_field_name
- * The field name to get info about.
- *
- * @return array|null
- * The structured array with configuration or NULL if not found.
- */
- protected function getResourceFieldInfo($entity_type_id, $bundle_id, $internal_field_name) {
- /** @var \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig $resource_config */
- $resource_config = $this->getResourceConfig($entity_type_id, $bundle_id);
- if (!$resource_config) {
- return NULL;
- }
- $resource_fields = array_filter(
- $resource_config->get('resourceFields'),
- function (array $resource_field) use ($internal_field_name) {
- return $resource_field['fieldName'] === $internal_field_name;
- }
- );
- if (empty($resource_fields)) {
- return NULL;
- }
- return reset($resource_fields);
- }
-
- /**
- * Get the configuration entity based on the entity type and bundle.
- *
- * @param string $entity_type_id
- * The entity type ID.
- * @param string $bundle_id
- * The bundle ID.
- *
- * @return \Drupal\Core\Entity\EntityInterface|null
- * The resource config entity or NULL.
- */
- protected function getResourceConfig($entity_type_id, $bundle_id) {
- $id = sprintf('%s--%s', $entity_type_id, $bundle_id);
- $resource_config = $this->entityTypeManager
- ->getStorage('jsonapi_resource_config')
- ->load($id);
-
- return $resource_config;
- }
-
}
diff --git a/src/ResourceType/ConfigurableResourceType.php b/src/ResourceType/ConfigurableResourceType.php
index 0a295f9..3280f3b 100644
--- a/src/ResourceType/ConfigurableResourceType.php
+++ b/src/ResourceType/ConfigurableResourceType.php
@@ -2,8 +2,10 @@
namespace Drupal\jsonapi_extras\ResourceType;
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
+use Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager;
/**
* Defines a configurable resource type.
@@ -18,6 +20,13 @@ class ConfigurableResourceType extends ResourceType {
protected $jsonapiResourceConfig;
/**
+ * Plugin manager for enhancers.
+ *
+ * @var \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager
+ */
+ protected $enhancerManager;
+
+ /**
* Instantiates a ResourceType object.
*
* @param string $entity_type_id
@@ -28,11 +37,14 @@ class ConfigurableResourceType extends ResourceType {
* The deserialization target class.
* @param \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig $resource_config
* The configuration entity.
+ * @param \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager $enhancer_manager
+ * Plugin manager for enhancers.
*/
- public function __construct($entity_type_id, $bundle, $deserialization_target_class, JsonapiResourceConfig $resource_config) {
+ public function __construct($entity_type_id, $bundle, $deserialization_target_class, JsonapiResourceConfig $resource_config, ResourceFieldEnhancerManager $enhancer_manager) {
parent::__construct($entity_type_id, $bundle, $deserialization_target_class);
$this->jsonapiResourceConfig = $resource_config;
+ $this->enhancerManager = $enhancer_manager;
if ($resource_config->get('resourceType')) {
// Set the type name.
@@ -68,18 +80,73 @@ class ConfigurableResourceType extends ResourceType {
* {@inheritdoc}
*/
public function isFieldEnabled($field_name) {
+ $resource_field = $this->getResourceFieldConfiguration($field_name);
+ return $resource_field
+ ? empty($resource_field['disabled'])
+ : parent::isFieldEnabled($field_name);
+ }
+
+ /**
+ * Get the resource field configuration.
+ *
+ * @param string $field_name
+ * The internal field name.
+ * @param string $from
+ * The realm of the provided field name.
+ *
+ * @return array
+ * The resource field definition. NULL if none can be found.
+ */
+ public function getResourceFieldConfiguration($field_name, $from = 'fieldName') {
$resource_fields = $this->jsonapiResourceConfig->get('resourceFields');
- // Find the resource field in the config entity for the given public field
- // name.
- $found = array_filter($resource_fields, function ($resource_field) use ($field_name) {
- return !empty($resource_field['fieldName']) &&
- $field_name == $resource_field['fieldName'];
+ // Find the resource field in the config entity for the given field name.
+ $found = array_filter($resource_fields, function ($resource_field) use ($field_name, $from) {
+ return !empty($resource_field[$from]) &&
+ $field_name == $resource_field[$from];
});
if (empty($found)) {
- return parent::isFieldEnabled($field_name);
+ return NULL;
}
- $resource_field = reset($found);
- return empty($resource_field['disabled']);
+ return reset($found);
+ }
+
+ /**
+ * Get the field enhancer plugin.
+ *
+ * @param string $field_name
+ * The internal field name.
+ * @param string $from
+ * The realm of the provided field name.
+ *
+ * @return \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerInterface|null
+ * The enhancer plugin. NULL if not found.
+ */
+ public function getFieldEnhancer($field_name, $from = 'fieldName') {
+ if (!$resource_field = $this->getResourceFieldConfiguration($field_name, $from)) {
+ return NULL;
+ }
+ if (empty($resource_field['enhancer']['id'])) {
+ return NULL;
+ }
+ try {
+ $enhancer_info = $resource_field['enhancer'];
+ // Ensure that the settings are in a suitable format.
+ $settings = [];
+ if (!empty($enhancer_info['settings']) && is_array($enhancer_info['settings'])) {
+ $settings = $enhancer_info['settings'];
+ }
+ // Get the enhancer instance.
+ /** @var \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerInterface $enhancer */
+ $enhancer = $this->enhancerManager->createInstance(
+ $enhancer_info['id'],
+ $settings
+ );
+ return $enhancer;
+ }
+ catch (PluginNotFoundException $exception) {
+ return NULL;
+ }
+
}
/**
@@ -96,17 +163,10 @@ class ConfigurableResourceType extends ResourceType {
* The field name in the desired realm.
*/
private function translateFieldName($field_name, $from, $to) {
- $resource_fields = $this->jsonapiResourceConfig->get('resourceFields');
- // Find the resource field in the config entity for the given field name.
- $found = array_filter($resource_fields, function ($resource_field) use ($field_name, $from) {
- return !empty($resource_field[$from]) &&
- $field_name == $resource_field[$from];
- });
- if (empty($found)) {
- return $field_name;
- }
- $resource_field = reset($found);
- return $resource_field[$to];
+ $resource_field = $this->getResourceFieldConfiguration($field_name, $from);
+ return empty($resource_field[$to])
+ ? $field_name
+ : $resource_field[$to];
}
}
diff --git a/src/ResourceType/ConfigurableResourceTypeRepository.php b/src/ResourceType/ConfigurableResourceTypeRepository.php
index 66ca0a5..8d89549 100644
--- a/src/ResourceType/ConfigurableResourceTypeRepository.php
+++ b/src/ResourceType/ConfigurableResourceTypeRepository.php
@@ -6,6 +6,7 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\jsonapi\ResourceType\ResourceTypeRepository;
+use Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager;
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
/**
@@ -21,11 +22,19 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
protected $entityRepository;
/**
+ * Plugin manager for enhancers.
+ *
+ * @var \Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager
+ */
+ protected $enhancerManager;
+
+ /**
* {@inheritdoc}
*/
- public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager, EntityRepositoryInterface $entity_repository) {
+ public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager, EntityRepositoryInterface $entity_repository, ResourceFieldEnhancerManager $enhancer_manager) {
parent::__construct($entity_type_manager, $bundle_manager);
$this->entityRepository = $entity_repository;
+ $this->enhancerManager = $enhancer_manager;
}
/**
@@ -84,7 +93,8 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
$entity_type_id,
$bundle,
$this->entityTypeManager->getDefinition($entity_type_id)->getClass(),
- $resource_config
+ $resource_config,
+ $this->enhancerManager
);
}, $bundles);
$resource_types = array_merge($resource_types, $current_types);