From e68662396df6c920a286a18c4509aaa112bf9bb8 Mon Sep 17 00:00:00 2001 From: effulgentsia <alex.bronstein@acquia.com> Date: Mon, 14 Oct 2019 12:49:15 -0700 Subject: [PATCH] Issue #3085035 by gabesullice, Wim Leers: Add a public API for aliasing and disabling JSON:API resource type fields --- .../ResourceType/ResourceTypeBuildEvent.php | 62 ++++++++++++++++++- .../src/ResourceType/ResourceTypeField.php | 10 +++ .../ResourceType/ResourceTypeRelationship.php | 10 +++ .../ResourceType/ResourceTypeRepository.php | 6 +- .../ResourceTypeBuildEventSubscriber.php | 44 ++++++++++++- .../ResourceTypeRepositoryTest.php | 40 ++++++++++++ 6 files changed, 166 insertions(+), 6 deletions(-) diff --git a/core/modules/jsonapi/src/ResourceType/ResourceTypeBuildEvent.php b/core/modules/jsonapi/src/ResourceType/ResourceTypeBuildEvent.php index cb9d6dbf1e23..55e8fe1b38c8 100644 --- a/core/modules/jsonapi/src/ResourceType/ResourceTypeBuildEvent.php +++ b/core/modules/jsonapi/src/ResourceType/ResourceTypeBuildEvent.php @@ -2,6 +2,7 @@ namespace Drupal\jsonapi\ResourceType; +use Drupal\Component\Assertion\Inspector; use Drupal\Core\Entity\EntityTypeInterface; use Symfony\Component\EventDispatcher\Event; @@ -20,6 +21,13 @@ class ResourceTypeBuildEvent extends Event { */ protected $resourceTypeName; + /** + * The fields of the resource type to be built. + * + * @var \Drupal\jsonapi\ResourceType\ResourceTypeField[] + */ + protected $fields; + /** * Whether the JSON:API resource type to be built should be disabled. * @@ -35,9 +43,13 @@ class ResourceTypeBuildEvent extends Event { * * @param string $resource_type_name * A JSON:API resource type name. + * @param \Drupal\jsonapi\ResourceType\ResourceTypeField[] $fields + * The fields of the resource type to be built. */ - protected function __construct($resource_type_name) { + protected function __construct($resource_type_name, array $fields) { + assert(Inspector::assertAllObjects($fields, ResourceTypeField::class)); $this->resourceTypeName = $resource_type_name; + $this->fields = $fields; } /** @@ -48,12 +60,14 @@ protected function __construct($resource_type_name) { * @param string $bundle * A bundle name for the resource type to be built. If the entity type does * not have bundles, the entity type ID. + * @param \Drupal\jsonapi\ResourceType\ResourceTypeField[] $fields + * The fields of the resource type to be built. * * @return \Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent * A new event. */ - public static function createFromEntityTypeAndBundle(EntityTypeInterface $entity_type, $bundle) { - return new static(sprintf('%s--%s', $entity_type->id(), $bundle)); + public static function createFromEntityTypeAndBundle(EntityTypeInterface $entity_type, $bundle, array $fields) { + return new static(sprintf('%s--%s', $entity_type->id(), $bundle), $fields); } /** @@ -83,4 +97,46 @@ public function resourceTypeShouldBeDisabled() { return $this->disabled; } + /** + * Gets the current fields of the resource type to be built. + * + * @return \Drupal\jsonapi\ResourceType\ResourceTypeField[] + * The current fields of the resource type to be built. + */ + public function getFields() { + return $this->fields; + } + + /** + * Sets the public name of the given field on the resource type to be built. + * + * @param \Drupal\jsonapi\ResourceType\ResourceTypeField $field + * The field for which to set a public name. + * @param string $public_field_name + * The public field name to set. + */ + public function setPublicFieldName(ResourceTypeField $field, $public_field_name) { + foreach ($this->fields as $index => $value) { + if ($field === $value) { + $this->fields[$index] = $value->withPublicName($public_field_name); + return; + } + } + } + + /** + * Disables the given field on the resource type to be built. + * + * @param \Drupal\jsonapi\ResourceType\ResourceTypeField $field + * The field for which to set a public name. + */ + public function disableField(ResourceTypeField $field) { + foreach ($this->fields as $index => $value) { + if ($field === $value) { + $this->fields[$index] = $value->disabled(); + return; + } + } + } + } diff --git a/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php b/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php index 76e35dbcc0c8..987f4963843e 100644 --- a/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php +++ b/core/modules/jsonapi/src/ResourceType/ResourceTypeField.php @@ -95,6 +95,16 @@ public function withPublicName($public_name) { return new static($this->internalName, $public_name, $this->enabled, $this->hasOne); } + /** + * Gets a new instance of the field that is disabled. + * + * @return static + * A new instance of the field that is disabled. + */ + public function disabled() { + return new static($this->internalName, $this->publicName, FALSE, $this->hasOne); + } + /** * Whether the field is enabled. * diff --git a/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php b/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php index e62203ca2fe7..8e782a527c4b 100644 --- a/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php +++ b/core/modules/jsonapi/src/ResourceType/ResourceTypeRelationship.php @@ -60,4 +60,14 @@ public function withPublicName($public_name) { : $relationship; } + /** + * {@inheritdoc} + */ + public function disabled() { + $relationship = parent::disabled(); + return isset($this->relatableResourceTypes) + ? $relationship->withRelatableResourceTypes($this->relatableResourceTypes) + : $relationship; + } + } diff --git a/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php b/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php index b12baeec54fc..724264732f4b 100644 --- a/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php +++ b/core/modules/jsonapi/src/ResourceType/ResourceTypeRepository.php @@ -151,10 +151,12 @@ public function all() { protected function createResourceType(EntityTypeInterface $entity_type, $bundle) { $raw_fields = $this->getAllFieldNames($entity_type, $bundle); $internalize_resource_type = $entity_type->isInternal(); + $fields = static::getFields($raw_fields, $entity_type, $bundle); if (!$internalize_resource_type) { - $event = ResourceTypeBuildEvent::createFromEntityTypeAndBundle($entity_type, $bundle); + $event = ResourceTypeBuildEvent::createFromEntityTypeAndBundle($entity_type, $bundle, $fields); $this->eventDispatcher->dispatch(ResourceTypeBuildEvents::BUILD, $event); $internalize_resource_type = $event->resourceTypeShouldBeDisabled(); + $fields = $event->getFields(); } return new ResourceType( $entity_type->id(), @@ -164,7 +166,7 @@ protected function createResourceType(EntityTypeInterface $entity_type, $bundle) static::isLocatableResourceType($entity_type, $bundle), static::isMutableResourceType($entity_type, $bundle), static::isVersionableResourceType($entity_type), - static::getFields($raw_fields, $entity_type, $bundle) + $fields ); } diff --git a/core/modules/jsonapi/tests/modules/jsonapi_test_resource_type_building/src/EventSubscriber/ResourceTypeBuildEventSubscriber.php b/core/modules/jsonapi/tests/modules/jsonapi_test_resource_type_building/src/EventSubscriber/ResourceTypeBuildEventSubscriber.php index 252461032c4a..af4f1a267a99 100644 --- a/core/modules/jsonapi/tests/modules/jsonapi_test_resource_type_building/src/EventSubscriber/ResourceTypeBuildEventSubscriber.php +++ b/core/modules/jsonapi/tests/modules/jsonapi_test_resource_type_building/src/EventSubscriber/ResourceTypeBuildEventSubscriber.php @@ -17,7 +17,13 @@ class ResourceTypeBuildEventSubscriber implements EventSubscriberInterface { * {@inheritdoc} */ public static function getSubscribedEvents() { - return [ResourceTypeBuildEvents::BUILD => 'disableResourceType']; + return [ + ResourceTypeBuildEvents::BUILD => [ + ['disableResourceType'], + ['aliasResourceTypeFields'], + ['disableResourceTypeFields'], + ], + ]; } /** @@ -33,4 +39,40 @@ public function disableResourceType(ResourceTypeBuildEvent $event) { } } + /** + * Aliases any resource type fields that have been aliased by a test. + * + * @param \Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent $event + * The build event. + */ + public function aliasResourceTypeFields(ResourceTypeBuildEvent $event) { + $aliases = \Drupal::state()->get('jsonapi_test_resource_type_builder.resource_type_field_aliases', []); + $resource_type_name = $event->getResourceTypeName(); + if (in_array($resource_type_name, array_keys($aliases), TRUE)) { + foreach ($event->getFields() as $field) { + if (isset($aliases[$resource_type_name][$field->getInternalName()])) { + $event->setPublicFieldName($field, $aliases[$resource_type_name][$field->getInternalName()]); + } + } + } + } + + /** + * Disables any resource type fields that have been aliased by a test. + * + * @param \Drupal\jsonapi\ResourceType\ResourceTypeBuildEvent $event + * The build event. + */ + public function disableResourceTypeFields(ResourceTypeBuildEvent $event) { + $aliases = \Drupal::state()->get('jsonapi_test_resource_type_builder.disabled_resource_type_fields', []); + $resource_type_name = $event->getResourceTypeName(); + if (in_array($resource_type_name, array_keys($aliases), TRUE)) { + foreach ($event->getFields() as $field) { + if (isset($aliases[$resource_type_name][$field->getInternalName()]) && $aliases[$resource_type_name][$field->getInternalName()] === TRUE) { + $event->disableField($field); + } + } + } + } + } diff --git a/core/modules/jsonapi/tests/src/Kernel/ResourceType/ResourceTypeRepositoryTest.php b/core/modules/jsonapi/tests/src/Kernel/ResourceType/ResourceTypeRepositoryTest.php index b7ecced323df..79081e9a35c0 100644 --- a/core/modules/jsonapi/tests/src/Kernel/ResourceType/ResourceTypeRepositoryTest.php +++ b/core/modules/jsonapi/tests/src/Kernel/ResourceType/ResourceTypeRepositoryTest.php @@ -167,4 +167,44 @@ public function testResourceTypeDisabling() { $this->assertTrue($this->resourceTypeRepository->getByTypeName('user--user')->isInternal()); } + /** + * Tests that resource type fields can be aliased per resource type. + */ + public function testResourceTypeFieldAliasing() { + $this->assertSame($this->resourceTypeRepository->getByTypeName('node--article')->getPublicName('uid'), 'uid'); + $this->assertSame($this->resourceTypeRepository->getByTypeName('node--page')->getPublicName('uid'), 'uid'); + $resource_type_field_aliases = [ + 'node--article' => [ + 'uid' => 'author', + ], + 'node--page' => [ + 'uid' => 'owner', + ], + ]; + \Drupal::state()->set('jsonapi_test_resource_type_builder.resource_type_field_aliases', $resource_type_field_aliases); + Cache::invalidateTags(['jsonapi_resource_types']); + $this->assertSame($this->resourceTypeRepository->getByTypeName('node--article')->getPublicName('uid'), 'author'); + $this->assertSame($this->resourceTypeRepository->getByTypeName('node--page')->getPublicName('uid'), 'owner'); + } + + /** + * Tests that resource type fields can be disabled per resource type. + */ + public function testResourceTypeFieldDisabling() { + $this->assertTrue($this->resourceTypeRepository->getByTypeName('node--article')->isFieldEnabled('uid')); + $this->assertTrue($this->resourceTypeRepository->getByTypeName('node--page')->isFieldEnabled('uid')); + $disabled_resource_type_fields = [ + 'node--article' => [ + 'uid' => TRUE, + ], + 'node--page' => [ + 'uid' => FALSE, + ], + ]; + \Drupal::state()->set('jsonapi_test_resource_type_builder.disabled_resource_type_fields', $disabled_resource_type_fields); + Cache::invalidateTags(['jsonapi_resource_types']); + $this->assertFalse($this->resourceTypeRepository->getByTypeName('node--article')->isFieldEnabled('uid')); + $this->assertTrue($this->resourceTypeRepository->getByTypeName('node--page')->isFieldEnabled('uid')); + } + } -- GitLab