r.patch | 224 +++++++++++++++++++++++ tests/src/Functional/ExternalNormalizersTest.php | 2 +- yar | 130 +++++++++++++ 3 files changed, 355 insertions(+), 1 deletion(-) diff --git a/r.patch b/r.patch new file mode 100644 index 0000000..08744d7 --- /dev/null +++ b/r.patch @@ -0,0 +1,224 @@ +diff --git a/src/Normalizer/FieldItemNormalizer.php b/src/Normalizer/FieldItemNormalizer.php +index abc59da..2bde162 100644 +--- a/src/Normalizer/FieldItemNormalizer.php ++++ b/src/Normalizer/FieldItemNormalizer.php +@@ -2,6 +2,7 @@ + + namespace Drupal\jsonapi\Normalizer; + ++use Drupal\Core\Cache\CacheableMetadata; + use Drupal\Core\Field\FieldItemInterface; + use Drupal\Core\TypedData\TypedDataInternalPropertiesHelper; + use Drupal\jsonapi\Normalizer\Value\FieldItemNormalizerValue; +@@ -40,6 +41,10 @@ class FieldItemNormalizer extends NormalizerBase { + if (floatval(\Drupal::VERSION) >= 8.5) { + $field_item = TypedDataInternalPropertiesHelper::getNonInternalProperties($field_item); + } ++ ++ // @todo Use the constant \Drupal\serialization\Normalizer\CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY instead of the 'cacheability' string when JSON API requires Drupal 8.5 or newer. ++ $context['cacheability'] = new CacheableMetadata(); ++ + foreach ($field_item as $property_name => $property) { + $values[$property_name] = $this->serializer->normalize($property, $format, $context); + } +@@ -47,7 +52,10 @@ class FieldItemNormalizer extends NormalizerBase { + if (isset($context['langcode'])) { + $values['lang'] = $context['langcode']; + } +- return new FieldItemNormalizerValue($values); ++ // @todo Use the constant \Drupal\serialization\Normalizer\CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY instead of the 'cacheability' string when JSON API requires Drupal 8.5 or newer. ++ $value = new FieldItemNormalizerValue($values, $context['cacheability']); ++ unset($context['cacheability']); ++ return $value; + } + + /** +diff --git a/src/Normalizer/FieldNormalizer.php b/src/Normalizer/FieldNormalizer.php +index bf5eaa6..097ddc8 100644 +--- a/src/Normalizer/FieldNormalizer.php ++++ b/src/Normalizer/FieldNormalizer.php +@@ -75,12 +75,15 @@ class FieldNormalizer extends NormalizerBase { + + $normalized_field = new FieldNormalizerValue($normalizer_items, $cardinality); + +- // @todo Remove this when JSON API requires Drupal 8.5 or newer. +- if (floatval(\Drupal::VERSION) >= 8.5) { +- // @todo Use the constant \Drupal\serialization\Normalizer\CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY instead of the 'cacheability' string when JSON API requires Drupal 8.5 or newer. +- $normalized_field->addCacheableDependency($context['cacheability']); +- unset($context['cacheability']); +- } ++// // @todo Remove this when JSON API requires Drupal 8.5 or newer. ++// if (floatval(\Drupal::VERSION) >= 8.5) { ++// // @todo Use the constant \Drupal\serialization\Normalizer\CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY instead of the 'cacheability' string when JSON API requires Drupal 8.5 or newer. ++// $normalized_field->addCacheableDependency($context['cacheability']); ++// unset($context['cacheability']); ++// } ++// else { ++// $normalized_field = new FieldNormalizerValue($normalizer_items, $cardinality); ++// } + + return $normalized_field; + } +diff --git a/src/Normalizer/RelationshipItemNormalizer.php b/src/Normalizer/RelationshipItemNormalizer.php +index 93bc6af..f14fc8d 100644 +--- a/src/Normalizer/RelationshipItemNormalizer.php ++++ b/src/Normalizer/RelationshipItemNormalizer.php +@@ -2,6 +2,7 @@ + + namespace Drupal\jsonapi\Normalizer; + ++use Drupal\Core\Cache\CacheableMetadata; + use Drupal\Core\Entity\EntityInterface; + use Drupal\jsonapi\Normalizer\Value\RelationshipItemNormalizerValue; + use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface; +@@ -67,6 +68,7 @@ class RelationshipItemNormalizer extends FieldItemNormalizer { + } + $normalizer_value = new RelationshipItemNormalizerValue( + $values, ++ new CacheableMetadata(), + $relationship_item->getTargetResourceType() + ); + +@@ -83,8 +85,8 @@ class RelationshipItemNormalizer extends FieldItemNormalizer { + // Add the cacheable dependency of the included item directly to the + // response cacheable metadata. This is similar to the flatten include + // data structure, instead of a content graph. +- if (!empty($context['cacheable_metadata'])) { +- $context['cacheable_metadata']->addCacheableDependency($normalizer_value); ++ if (!empty($context['cacheable_metadata'])) { ++ $context['cacheable_metadata']->addCacheableDependency($normalizer_value); + } + } + return $normalizer_value; +diff --git a/src/Normalizer/Value/FieldItemNormalizerValue.php b/src/Normalizer/Value/FieldItemNormalizerValue.php +index e242eac..fa6aec5 100644 +--- a/src/Normalizer/Value/FieldItemNormalizerValue.php ++++ b/src/Normalizer/Value/FieldItemNormalizerValue.php +@@ -1,13 +1,17 @@ + raw = $values; ++ $this->setCacheability($values_cacheability); + } + + /** +diff --git a/src/Normalizer/Value/FieldNormalizerValue.php b/src/Normalizer/Value/FieldNormalizerValue.php +index e43e4f2..0e79e9e 100644 +--- a/src/Normalizer/Value/FieldNormalizerValue.php ++++ b/src/Normalizer/Value/FieldNormalizerValue.php +@@ -2,6 +2,9 @@ + + namespace Drupal\jsonapi\Normalizer\Value; + ++use Drupal\Core\Cache\CacheableDependencyInterface; ++use Drupal\Core\Cache\CacheableDependencyTrait; ++use Drupal\Core\Cache\CacheableMetadata; + use Drupal\Core\Cache\RefinableCacheableDependencyTrait; + + /** +@@ -11,7 +14,8 @@ use Drupal\Core\Cache\RefinableCacheableDependencyTrait; + */ + class FieldNormalizerValue implements FieldNormalizerValueInterface { + +- use RefinableCacheableDependencyTrait; ++// use RefinableCacheableDependencyTrait; ++ use CacheableDependencyTrait; + + /** + * The values. +@@ -51,6 +55,11 @@ class FieldNormalizerValue implements FieldNormalizerValueInterface { + */ + public function __construct(array $values, $cardinality) { + $this->values = $values; ++ $values_cacheability = new CacheableMetadata(); ++ array_walk($this->values, function ($value) use ($values_cacheability) { ++ $values_cacheability->addCacheableDependency($value); ++ }); ++ $this->setCacheability($values_cacheability); + $this->includes = array_map(function ($value) { + if (!$value instanceof FieldItemNormalizerValue) { + return new NullFieldNormalizerValue(); +diff --git a/src/Normalizer/Value/FieldNormalizerValueInterface.php b/src/Normalizer/Value/FieldNormalizerValueInterface.php +index c7ad5d9..1f8b7b9 100644 +--- a/src/Normalizer/Value/FieldNormalizerValueInterface.php ++++ b/src/Normalizer/Value/FieldNormalizerValueInterface.php +@@ -2,6 +2,7 @@ + + namespace Drupal\jsonapi\Normalizer\Value; + ++use Drupal\Core\Cache\CacheableDependencyInterface; + use Drupal\Core\Cache\RefinableCacheableDependencyInterface; + + /** +@@ -9,7 +10,7 @@ use Drupal\Core\Cache\RefinableCacheableDependencyInterface; + * + * @internal + */ +-interface FieldNormalizerValueInterface extends ValueExtractorInterface, RefinableCacheableDependencyInterface { ++interface FieldNormalizerValueInterface extends ValueExtractorInterface, CacheableDependencyInterface { + + /** + * Gets the includes. +diff --git a/src/Normalizer/Value/RelationshipItemNormalizerValue.php b/src/Normalizer/Value/RelationshipItemNormalizerValue.php +index a1dbe9d..9271d1a 100644 +--- a/src/Normalizer/Value/RelationshipItemNormalizerValue.php ++++ b/src/Normalizer/Value/RelationshipItemNormalizerValue.php +@@ -2,6 +2,8 @@ + + namespace Drupal\jsonapi\Normalizer\Value; + ++use Drupal\Core\Cache\CacheableDependencyInterface; ++use Drupal\Core\Cache\CacheableDependencyTrait; + use Drupal\Core\Cache\RefinableCacheableDependencyInterface; + use Drupal\Core\Cache\RefinableCacheableDependencyTrait; + +@@ -10,9 +12,11 @@ use Drupal\Core\Cache\RefinableCacheableDependencyTrait; + * + * @internal + */ +-class RelationshipItemNormalizerValue extends FieldItemNormalizerValue implements RefinableCacheableDependencyInterface { ++class RelationshipItemNormalizerValue extends FieldItemNormalizerValue implements CacheableDependencyInterface { + +- use RefinableCacheableDependencyTrait; ++// use RefinableCacheableDependencyTrait; ++ ++// use CacheableDependencyTrait; + + /** + * Resource path. +@@ -29,8 +33,8 @@ class RelationshipItemNormalizerValue extends FieldItemNormalizerValue implement + * @param string $resource + * The resource type of the target entity. + */ +- public function __construct(array $values, $resource) { +- parent::__construct($values); ++ public function __construct(array $values, CacheableDependencyInterface $values_cacheability, $resource) { ++ parent::__construct($values, $values_cacheability); + $this->resource = $resource; + } + diff --git a/tests/src/Functional/ExternalNormalizersTest.php b/tests/src/Functional/ExternalNormalizersTest.php index dcd99c1..8f4f21a 100644 --- a/tests/src/Functional/ExternalNormalizersTest.php +++ b/tests/src/Functional/ExternalNormalizersTest.php @@ -139,7 +139,7 @@ class ExternalNormalizersTest extends BrowserTestBase { static::VALUE_ORIGINAL, ], 'Format-agnostic @DataType-level normalizers SHOULD be able to affect the JSON API normalization' => [ - // \Drupal\jsonapi_test_field_type\Normalizer\StringNormalizer::normalize() + // \Drupal\jsonapi_test_data_type\Normalizer\StringNormalizer::normalize() 'jsonapi_test_data_type', static::VALUE_OVERRIDDEN, ], diff --git a/yar b/yar new file mode 100644 index 0000000..9adf766 --- /dev/null +++ b/yar @@ -0,0 +1,130 @@ + src/EntityToJsonApi.php | 6 +++--- + src/ResourceType/ResourceType.php | 10 ++++++---- + src/ResourceType/ResourceTypeRepository.php | 4 ++-- + src/ResourceType/ResourceTypeRepositoryInterface.php | 8 +++++--- + src/Routing/Routes.php | 10 +++++----- + tests/src/Unit/Routing/RoutesTest.php | 2 +- + 6 files changed, 22 insertions(+), 18 deletions(-) + +diff --git a/src/EntityToJsonApi.php b/src/EntityToJsonApi.php +index 30bcd3f..99ba536 100644 +--- a/src/EntityToJsonApi.php ++++ b/src/EntityToJsonApi.php +@@ -98,13 +98,13 @@ class EntityToJsonApi { + */ + protected function calculateContext(EntityInterface $entity) { + // TODO: Supporting includes requires adding the 'include' query string. +- $path_prefix = $this->resourceTypeRepository->getPathPrefix(); ++ $path_prefix = $this->resourceTypeRepository->getPrefixPathSegment(); + $resource_type = $this->resourceTypeRepository->get( + $entity->getEntityTypeId(), + $entity->bundle() + ); +- $resource_path = $resource_type->getPath(); +- $path = sprintf('/%s/%s/%s', $path_prefix, $resource_path, $entity->uuid()); ++ $resource_path = $resource_type->getPathSegments(); ++ $path = sprintf('%s%s/%s', $path_prefix, $resource_path, $entity->uuid()); + $request = Request::create($path, 'GET'); + return [ + 'account' => $this->currentUser, +diff --git a/src/ResourceType/ResourceType.php b/src/ResourceType/ResourceType.php +index f2257dd..ff06954 100644 +--- a/src/ResourceType/ResourceType.php ++++ b/src/ResourceType/ResourceType.php +@@ -244,13 +244,15 @@ class ResourceType { + } + + /** +- * Get the resource path. ++ * Gets the resource type path segments. + * + * @return string +- * The path to access this resource type. Defaults to entity_type_id/bundle. ++ * The path segments to access this resource type, without path prefix. ++ * ++ * @see \Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface::getPrefixPathSegment() + */ +- public function getPath() { +- return sprintf('%s/%s', $this->getEntityTypeId(), $this->getBundle()); ++ public function getPathSegments() { ++ return sprintf('/%s/%s', $this->getEntityTypeId(), $this->getBundle()); + } + + } +diff --git a/src/ResourceType/ResourceTypeRepository.php b/src/ResourceType/ResourceTypeRepository.php +index c536925..7ead907 100644 +--- a/src/ResourceType/ResourceTypeRepository.php ++++ b/src/ResourceType/ResourceTypeRepository.php +@@ -76,8 +76,8 @@ class ResourceTypeRepository implements ResourceTypeRepositoryInterface { + /** + * {@inheritdoc} + */ +- public function getPathPrefix() { +- return 'jsonapi'; ++ public function getPrefixPathSegment() { ++ return '/jsonapi'; + } + + // @codingStandardsIgnoreStart +diff --git a/src/ResourceType/ResourceTypeRepositoryInterface.php b/src/ResourceType/ResourceTypeRepositoryInterface.php +index b44f3d6..7d33016 100644 +--- a/src/ResourceType/ResourceTypeRepositoryInterface.php ++++ b/src/ResourceType/ResourceTypeRepositoryInterface.php +@@ -42,11 +42,13 @@ interface ResourceTypeRepositoryInterface { + public function getByTypeName($type_name); + + /** +- * Gets the path prefix for routes managed by JSON API. ++ * Gets the JSON API route prefix path segment. + * + * @return string +- * The route prefix in the JSON API route paths. ++ * The prefix path segment in the JSON API route paths. ++ * ++ * @see \Drupal\jsonapi\ResourceType\ResourceType::getPathSegments() + */ +- public function getPathPrefix(); ++ public function getPrefixPathSegment(); + + } +diff --git a/src/Routing/Routes.php b/src/Routing/Routes.php +index 66d7537..7c3c5f7 100644 +--- a/src/Routing/Routes.php ++++ b/src/Routing/Routes.php +@@ -80,8 +80,8 @@ class Routes implements ContainerInjectionInterface { + public function entryPoint() { + $collection = new RouteCollection(); + +- $path_prefix = $this->resourceTypeRepository->getPathPrefix(); +- $route_collection = (new Route('/' . $path_prefix, [ ++ $path_prefix = $this->resourceTypeRepository->getPrefixPathSegment(); ++ $route_collection = (new Route($path_prefix, [ + RouteObjectInterface::CONTROLLER_NAME => '\Drupal\jsonapi\Controller\EntryPoint::index', + ])) + ->setRequirement('_permission', 'access jsonapi resource list') +@@ -105,9 +105,9 @@ class Routes implements ContainerInjectionInterface { + continue; + } + +- $path_prefix = $this->resourceTypeRepository->getPathPrefix(); +- $resource_path = $resource_type->getPath(); +- $route_base_path = sprintf('/%s/%s', $path_prefix, $resource_path); ++ $path_prefix = $this->resourceTypeRepository->getPrefixPathSegment(); ++ $resource_path = $resource_type->getPathSegments(); ++ $route_base_path = sprintf('%s%s', $path_prefix, $resource_path); + $build_route_name = function ($key) use ($resource_type) { + return sprintf('jsonapi.%s.%s', $resource_type->getTypeName(), $key); + }; +diff --git a/tests/src/Unit/Routing/RoutesTest.php b/tests/src/Unit/Routing/RoutesTest.php +index 67f3c1a..de3c6ed 100644 +--- a/tests/src/Unit/Routing/RoutesTest.php ++++ b/tests/src/Unit/Routing/RoutesTest.php +@@ -47,7 +47,7 @@ class RoutesTest extends UnitTestCase { + $type_3->setRelatableResourceTypes([]); + $resource_type_repository = $this->prophesize(ResourceTypeRepository::class); + $resource_type_repository->all()->willReturn([$type_1, $type_2, $type_3]); +- $resource_type_repository->getPathPrefix()->willReturn('jsonapi'); ++ $resource_type_repository->getPrefixPathSegment()->willReturn('/jsonapi'); + $container = $this->prophesize(ContainerInterface::class); + $container->get('jsonapi.resource_type.repository')->willReturn($resource_type_repository->reveal()); + $auth_collector = $this->prophesize(AuthenticationCollectorInterface::class);