src/ResourceType/ResourceType.php | 16 ++++++++-------- src/ResourceType/ResourceTypeRepository.php | 8 ++++---- src/Routing/Routes.php | 15 +++++++-------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/ResourceType/ResourceType.php b/src/ResourceType/ResourceType.php index 355028a..1ea2a00 100644 --- a/src/ResourceType/ResourceType.php +++ b/src/ResourceType/ResourceType.php @@ -61,7 +61,7 @@ class ResourceType { * * @var bool */ - protected $isValidatable; + protected $isMutable; /** * Gets the entity type ID. @@ -203,16 +203,16 @@ class ResourceType { } /** - * Whether resources of this resource type are validatable. + * Whether resources of this resource type are mutable. * - * A resource type may not be modified (created, updated or deleted; POST, - * PATCH or DELETE) when it is not validatable. + * Indicates that resources of this type may not be created, updated or + * deleted (POST, PATCH or DELETE, respectively). * * @return bool - * TRUE if the resource type's resources are validatable. FALSE otherwise. + * TRUE if the resource type's resources are mutable. FALSE otherwise. */ - public function isValidatable() { - return $this->isValidatable; + public function isMutable() { + return $this->isMutable; } /** @@ -237,7 +237,7 @@ class ResourceType { $this->deserializationTargetClass = $deserialization_target_class; $this->internal = $internal; $this->isLocatable = $is_locatable; - $this->isValidatable = $is_validatable; + $this->isMutable = $is_validatable; $this->typeName = sprintf('%s--%s', $this->entityTypeId, $this->bundle); } diff --git a/src/ResourceType/ResourceTypeRepository.php b/src/ResourceType/ResourceTypeRepository.php index e61ab60..88d0ad0 100644 --- a/src/ResourceType/ResourceTypeRepository.php +++ b/src/ResourceType/ResourceTypeRepository.php @@ -106,7 +106,7 @@ class ResourceTypeRepository implements ResourceTypeRepositoryInterface { $entity_type->getClass(), static::shouldBeInternalResourceType($entity_type), static::isLocatableResourceType($entity_type), - static::isValidatableResourceType($entity_type) + static::isMutableResourceType($entity_type) ); }, array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id)))); } @@ -165,15 +165,15 @@ class ResourceTypeRepository implements ResourceTypeRepositoryInterface { } /** - * Whether an entity type is a validatable resource type. + * Whether an entity type is a mutable resource type. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * The entity type to assess. * * @return bool - * TRUE if the entity type is validatable, FALSE otherwise. + * TRUE if the entity type is mutable, FALSE otherwise. */ - protected static function isValidatableResourceType(EntityTypeInterface $entity_type) { + protected static function isMutableResourceType(EntityTypeInterface $entity_type) { return !$entity_type instanceof ConfigEntityTypeInterface; } diff --git a/src/Routing/Routes.php b/src/Routing/Routes.php index a4cfba0..34cef7b 100644 --- a/src/Routing/Routes.php +++ b/src/Routing/Routes.php @@ -140,7 +140,11 @@ class Routes implements ContainerInjectionInterface { // Collection route like `/jsonapi/node/article`. $collection_route = new Route('/' . $resource_type->getPath()); - $collection_route->setMethods($resource_type->isLocatable() ? ['GET', 'POST'] : ['POST']); + $methods = $resource_type->isLocatable() ? ['GET', 'POST'] : ['POST']; + if (!$resource_type->isMutable()) { + $methods = array_intersect($methods, ['GET']); + } + $collection_route->setMethods($methods); $collection_route->addDefaults(['serialization_class' => JsonApiDocumentTopLevel::class]); $collection_route->setRequirement('_csrf_request_header_token', 'TRUE'); $routes->add(static::getRouteName($resource_type, 'collection'), $collection_route); @@ -197,7 +201,7 @@ class Routes implements ContainerInjectionInterface { // Individual read, update and remove. $individual_route = new Route("/{$path}/{{$entity_type_id}}"); - $individual_route->setMethods(['GET', 'PATCH', 'DELETE']); + $individual_route->setMethods($resource_type->isMutable() ? ['GET', 'PATCH', 'DELETE'] : ['GET']); $individual_route->addDefaults(['serialization_class' => JsonApiDocumentTopLevel::class]); $individual_route->setRequirement('_csrf_request_header_token', 'TRUE'); $routes->add(static::getRouteName($resource_type, 'individual'), $individual_route); @@ -212,7 +216,7 @@ class Routes implements ContainerInjectionInterface { // Read, update, add, or remove an individual resources relationships to // other resources. $relationship_route = new Route("/{$path}/{{$entity_type_id}}/relationships/{related}"); - $relationship_route->setMethods(['GET', 'POST', 'PATCH', 'DELETE']); + $relationship_route->setMethods($resource_type->isMutable() ? ['GET', 'POST', 'PATCH', 'DELETE'] : ['GET']); // @todo: remove the _on_relationship default in https://www.drupal.org/project/jsonapi/issues/2953346. $relationship_route->addDefaults(['_on_relationship' => TRUE]); $relationship_route->addDefaults(['serialization_class' => EntityReferenceFieldItemList::class]); @@ -222,11 +226,6 @@ class Routes implements ContainerInjectionInterface { // Add entity parameter conversion to every route. $routes->addOptions(['parameters' => [$entity_type_id => ['type' => 'entity:' . $entity_type_id]]]); - // If a resource type is not validatable, make all its routes read-only. - if (!$resource_type->isValidatable()) { - $routes->setMethods(['GET']); - } - return $routes; }