config/install/jsonapi.resource_info.yml | 1 - config/schema/jsonapi.schema.yml | 3 - jsonapi.services.yml | 22 +-- ...JsonApiResource.php => JsonApiResourceType.php} | 36 ++-- src/Configuration/ResourceConfig.php | 196 --------------------- src/Configuration/ResourceConfigInterface.php | 127 ------------- src/Configuration/ResourceManagerInterface.php | 56 ------ src/Context/CurrentContext.php | 25 ++- src/Context/CurrentContextInterface.php | 4 +- src/Context/FieldResolver.php | 3 +- src/EntityCollection.php | 4 +- src/EntityCollectionInterface.php | 5 +- src/LinkManager/LinkManager.php | 17 +- src/LinkManager/LinkManagerInterface.php | 21 ++- src/Normalizer/DocumentRootNormalizer.php | 9 +- src/Normalizer/EntityNormalizer.php | 37 ++-- src/Normalizer/EntityReferenceFieldNormalizer.php | 15 +- src/Normalizer/RelationshipItemNormalizer.php | 12 +- src/Normalizer/RelationshipNormalizer.php | 21 +-- src/Normalizer/Value/EntityNormalizerValue.php | 9 +- .../Value/RelationshipItemNormalizerValue.php | 2 +- .../Value/RelationshipNormalizerValue.php | 8 +- .../Deriver/EntityDeriver.php} | 152 +++++++--------- src/Plugin/Deriver/ResourceDeriver.php | 82 --------- src/Plugin/JsonApiResourceInterface.php | 14 -- .../JsonApiResourceTypeInterface.php} | 83 +++++---- ...eManager.php => JsonApiResourceTypeManager.php} | 49 ++++-- src/Plugin/jsonapi/BundleJsonApiResource.php | 24 --- .../resource_type/EntityJsonApiResourceType.php} | 140 ++++++++------- src/Query/QueryBuilder.php | 4 +- src/Relationship.php | 14 +- src/RelationshipItem.php | 25 +-- src/RelationshipItemInterface.php | 8 - src/RequestHandler.php | 55 ++---- src/Routing/Routes.php | 118 ++++++------- tests/src/Functional/JsonApiFunctionalTest.php | 12 +- .../Kernel/Configuration/ResourceManagerTest.php | 2 +- tests/src/Unit/Routing/RoutesTest.php | 2 +- 38 files changed, 435 insertions(+), 982 deletions(-) diff --git a/config/install/jsonapi.resource_info.yml b/config/install/jsonapi.resource_info.yml index b17ff5a..54fbb44 100644 --- a/config/install/jsonapi.resource_info.yml +++ b/config/install/jsonapi.resource_info.yml @@ -1,2 +1 @@ -prefix: api id_field: uuid diff --git a/config/schema/jsonapi.schema.yml b/config/schema/jsonapi.schema.yml index e7ddc88..3238540 100644 --- a/config/schema/jsonapi.schema.yml +++ b/config/schema/jsonapi.schema.yml @@ -1,9 +1,6 @@ jsonapi.resource_info: type: config_object mapping: - prefix: - type: string - label: 'Prefix' id_field: type: string label: 'API field' diff --git a/jsonapi.services.yml b/jsonapi.services.yml index 99f5075..b4328f3 100644 --- a/jsonapi.services.yml +++ b/jsonapi.services.yml @@ -1,7 +1,8 @@ services: + # Serialization. serializer.normalizer.entity_reference_item.jsonapi: class: Drupal\jsonapi\Normalizer\RelationshipItemNormalizer - arguments: ['@jsonapi.resource.manager', '@serializer.normalizer.document_root.jsonapi',] + arguments: ['@plugin.manager.jsonapi.resource_type', '@serializer.normalizer.document_root.jsonapi'] tags: - { name: normalizer, priority: 21 } serializer.normalizer.field_item.jsonapi: @@ -18,12 +19,12 @@ services: - { name: normalizer, priority: 21 } serializer.normalizer.entity_reference_field.jsonapi: class: Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer - arguments: ['@jsonapi.link_manager', '@entity_field.manager', '@plugin.manager.field.field_type', '@jsonapi.resource.manager'] + arguments: ['@jsonapi.link_manager', '@entity_field.manager', '@plugin.manager.field.field_type'] tags: - { name: normalizer, priority: 31 } serializer.normalizer.relationship.jsonapi: class: Drupal\jsonapi\Normalizer\RelationshipNormalizer - arguments: ['@jsonapi.resource.manager', '@serializer.normalizer.document_root.jsonapi', '@jsonapi.link_manager'] + arguments: ['@plugin.manager.jsonapi.resource_type', '@serializer.normalizer.document_root.jsonapi', '@jsonapi.link_manager'] tags: - { name: normalizer, priority: 21 } serializer.normalizer.entity.jsonapi: @@ -50,9 +51,8 @@ services: class: Drupal\jsonapi\Encoder\JsonEncoder tags: - { name: encoder, priority: 21, format: 'api_json' } - jsonapi.resource.manager: - class: Drupal\jsonapi\Configuration\ResourceManager - arguments: ['@entity_type.manager', '@entity_type.bundle.info', '@config.factory', '@module_handler'] + + # Routing. jsonapi.route_enhancer: class: Drupal\jsonapi\Routing\RouteEnhancer tags: @@ -62,15 +62,17 @@ services: arguments: ['@entity_field.manager'] tags: - { name: route_enhancer } + + # Other. jsonapi.query_builder: class: Drupal\jsonapi\Query\QueryBuilder arguments: ['@entity_type.manager', '@jsonapi.current_context', '@jsonapi.field_resolver'] jsonapi.link_manager: class: Drupal\jsonapi\LinkManager\LinkManager - arguments: ['@router.no_access_checks', '@url_generator'] + arguments: ['@router.no_access_checks', '@url_generator', '@plugin.manager.jsonapi.resource_type'] jsonapi.current_context: class: Drupal\jsonapi\Context\CurrentContext - arguments: ['@jsonapi.resource.manager', '@request_stack'] + arguments: ['@plugin.manager.jsonapi.resource_type', '@request_stack'] jsonapi.field_resolver: class: Drupal\jsonapi\Context\FieldResolver arguments: ['@jsonapi.current_context', '@entity_field.manager'] @@ -85,8 +87,8 @@ services: arguments: ['@entity.manager'] jsonapi.error_handler: class: Drupal\jsonapi\Error\ErrorHandler - plugin.manager.resource.processor: - class: Drupal\jsonapi\Plugin\JsonApiResourceManager + plugin.manager.jsonapi.resource_type: + class: Drupal\jsonapi\Plugin\JsonApiResourceTypeManager parent: default_plugin_manager jsonapi.exception_subscriber: class: Drupal\jsonapi\EventSubscriber\DefaultExceptionSubscriber diff --git a/src/Annotation/JsonApiResource.php b/src/Annotation/JsonApiResourceType.php similarity index 33% rename from src/Annotation/JsonApiResource.php rename to src/Annotation/JsonApiResourceType.php index 277de71..2bec66e 100644 --- a/src/Annotation/JsonApiResource.php +++ b/src/Annotation/JsonApiResourceType.php @@ -5,14 +5,19 @@ namespace Drupal\jsonapi\Annotation; use Drupal\Component\Annotation\Plugin; /** - * Defines a JSON API Resource item annotation object. + * Defines a JSON API resource 'type' annotation object. * - * @see \Drupal\jsonapi\Plugin\JsonApiResourceManager + * Plugin Namespace: Plugin\jsonapi\resource_type + * + * @see \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager + * @see \Drupal\jsonapi\Plugin\JsonApiResourceTypeInterface * @see plugin_api * + * @see http://jsonapi.org/format/#document-resource-identifier-objects — 'type' + * * @Annotation */ -class JsonApiResource extends Plugin { +class JsonApiResourceType extends Plugin { /** * The plugin ID. @@ -31,31 +36,36 @@ class JsonApiResource extends Plugin { public $label; /** - * The entity type ID. + * The JSON API resource type. * * @var string */ - public $entityType; + public $type; /** - * The bundle ID. + * The serialization class to deserialize serialized data into. * - * @var string + * @var string (optional) */ - public $bundle; + public $serialization_class; /** - * Information about the data resources. + * The requirements to add to every JSON API route for this resource type. + * + * @see \Symfony\Component\Routing\Route * * @var array */ - public $data; + public $route_requirements; /** - * TRUE if the plugin is enabled. + * The options to add to every JSON API route for this resource type. + * + * @see \Symfony\Component\Routing\Route * - * @var bool + * @var array */ - public $enabled; + public $route_options; + public $route_path_part_for_individual_resource; } diff --git a/src/Configuration/ResourceConfig.php b/src/Configuration/ResourceConfig.php deleted file mode 100644 index d3b9f55..0000000 --- a/src/Configuration/ResourceConfig.php +++ /dev/null @@ -1,196 +0,0 @@ -globalConfig; - } - - /** - * {@inheritdoc} - */ - public function getEntityTypeId() { - return $this->entityTypeId; - } - - /** - * {@inheritdoc} - */ - public function setEntityTypeId($entity_type_id) { - $this->entityTypeId = $entity_type_id; - $this->deserializationTargetClass = $this->entityTypeManager - ->getDefinition($entity_type_id) - ->getClass(); - } - - /** - * {@inheritdoc} - */ - public function getTypeName() { - return $this->typeName; - } - - /** - * {@inheritdoc} - */ - public function setTypeName($type_name) { - $this->typeName = $type_name; - } - - /** - * {@inheritdoc} - */ - public function getPath() { - return $this->path; - } - - /** - * {@inheritdoc} - */ - public function setPath($path) { - $this->path = $path; - } - - /** - * {@inheritdoc} - */ - public function getBundleId() { - return $this->bundleId; - } - - /** - * {@inheritdoc} - */ - public function setBundleId($bundle_id) { - $this->bundleId = $bundle_id; - } - - /** - * {@inheritdoc} - */ - public function getStorage() { - return $this->entityTypeManager->getStorage($this->entityTypeId); - } - - /** - * {@inheritdoc} - */ - public function getDeserializationTargetClass() { - return $this->deserializationTargetClass; - } - - /** - * {@inheritdoc} - */ - public function getIdKey() { - return $this->getGlobalConfig()->get('id_field'); - } - - /** - * {@inheritdoc} - */ - public function isEnabled() { - return $this->isEnabled; - } - - /** - * {@inheritdoc} - */ - public function enable() { - $this->isEnabled = TRUE; - } - - /** - * {@inheritdoc} - */ - public function disable() { - $this->isEnabled = FALSE; - } - - /** - * Instantiates a ResourceConfig object. - * - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The configuration factory. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - */ - public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager) { - $this->globalConfig = $config_factory->get('jsonapi.resource_info'); - $this->entityTypeManager = $entity_type_manager; - } - -} diff --git a/src/Configuration/ResourceConfigInterface.php b/src/Configuration/ResourceConfigInterface.php deleted file mode 100644 index 95af84c..0000000 --- a/src/Configuration/ResourceConfigInterface.php +++ /dev/null @@ -1,127 +0,0 @@ -resourceManager = $resource_manager; + public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, RequestStack $request_stack) { + $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager; $this->currentRequest = $request_stack->getCurrentRequest(); if ($route = $this->currentRequest->get(RouteObjectInterface::ROUTE_OBJECT)) { $this->setCurrentRoute($route); @@ -70,13 +69,13 @@ class CurrentContext implements CurrentContextInterface { /** * {@inheritdoc} + * + * todo rename */ public function getResourceConfig() { if (!isset($this->resourceConfig)) { - $entity_type_id = $this->getCurrentRoute()->getRequirement('_entity_type'); - $bundle_id = $this->getCurrentRoute()->getRequirement('_bundle'); - $this->resourceConfig = $this->resourceManager - ->get($entity_type_id, $bundle_id); + $plugin_id = $this->getCurrentRoute()->getOption('_jsonapi_plugin_id'); + $this->resourceConfig = $this->jsonApiResourceTypeManager->getDefinition($plugin_id); } return $this->resourceConfig; @@ -99,8 +98,8 @@ class CurrentContext implements CurrentContextInterface { /** * {@inheritdoc} */ - public function getResourceManager() { - return $this->resourceManager; + public function getJsonApiResourceTypeManager() { + return $this->jsonApiResourceTypeManager; } /** diff --git a/src/Context/CurrentContextInterface.php b/src/Context/CurrentContextInterface.php index fda80a1..122959f 100644 --- a/src/Context/CurrentContextInterface.php +++ b/src/Context/CurrentContextInterface.php @@ -43,9 +43,9 @@ interface CurrentContextInterface { /** * Returns the resource manager. * - * @return \Drupal\jsonapi\Configuration\ResourceManagerInterface + * @return \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager */ - public function getResourceManager(); + public function getJsonApiResourceTypeManager(); /** * Get a value by key from the _json_api_params route parameter. diff --git a/src/Context/FieldResolver.php b/src/Context/FieldResolver.php index e9e17d6..93c97fe 100644 --- a/src/Context/FieldResolver.php +++ b/src/Context/FieldResolver.php @@ -4,6 +4,7 @@ namespace Drupal\jsonapi\Context; use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\jsonapi\Error\SerializableHttpException; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; /** * Contains FieldResolver. @@ -65,7 +66,7 @@ class FieldResolver implements FieldResolverInterface { $parts = explode('.', $external_field_name); // The last part of the chain is the referenced field, not a relationship. $leave_field = array_pop($parts); - $entity_type_id = $this->currentContext->getResourceConfig()->getEntityTypeId(); + $entity_type_id = EntityJsonApiResourceType::getEntityTypeIdForJsonApiResourceType($this->currentContext->getResourceConfig()['type']); foreach ($parts as $field_name) { if (!$definitions = $this->fieldManager->getFieldStorageDefinitions($entity_type_id)) { throw new SerializableHttpException(400, sprintf('Invalid nested filtering. There is no entity type "%s".', $entity_type_id)); diff --git a/src/EntityCollection.php b/src/EntityCollection.php index 88223fa..917a300 100644 --- a/src/EntityCollection.php +++ b/src/EntityCollection.php @@ -3,9 +3,7 @@ namespace Drupal\jsonapi; /** - * Class EntityCollection. - * - * @package Drupal\jsonapi + * @internal */ class EntityCollection implements EntityCollectionInterface { diff --git a/src/EntityCollectionInterface.php b/src/EntityCollectionInterface.php index 2069cc7..d7b1a8f 100644 --- a/src/EntityCollectionInterface.php +++ b/src/EntityCollectionInterface.php @@ -4,9 +4,8 @@ namespace Drupal\jsonapi; /** - * Class EntityCollectionInterface. - * - * @package Drupal\jsonapi + * @internal + * @todo Make this non-entity specific. */ interface EntityCollectionInterface extends \IteratorAggregate, \Countable { diff --git a/src/LinkManager/LinkManager.php b/src/LinkManager/LinkManager.php index 3d79bf8..a147dee 100644 --- a/src/LinkManager/LinkManager.php +++ b/src/LinkManager/LinkManager.php @@ -5,6 +5,8 @@ namespace Drupal\jsonapi\LinkManager; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\jsonapi\Configuration\ResourceConfigInterface; use Drupal\jsonapi\Error\SerializableHttpException; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\Routing\Param\OffsetPage; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -35,22 +37,24 @@ class LinkManager implements LinkManagerInterface { * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator * The Url generator. */ - public function __construct(RequestMatcherInterface $router, UrlGeneratorInterface $url_generator) { + public function __construct(RequestMatcherInterface $router, UrlGeneratorInterface $url_generator, JsonApiResourceTypeManager $jsonapi_resource_type_manager) { $this->router = $router; $this->urlGenerator = $url_generator; + $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager; } /** * {@inheritdoc} */ - public function getEntityLink($entity_id, ResourceConfigInterface $resource_config, array $route_parameters, $key) { + public function getResourceLink($type, $id, array $route_parameters, $key) { + assert("in_array($key, ['individual', 'collection', 'related', 'relationship'])"); + $definition = $this->jsonApiResourceTypeManager->getDefinition($type); $route_parameters += [ - $resource_config->getEntityTypeId() => $entity_id, + $definition['route_path_part_for_individual_resource'] => $id, '_format' => 'api_json', ]; - $prefix = $resource_config->getGlobalConfig()->get('prefix'); - $route_key = sprintf('%s.dynamic.%s.%s', $prefix, $resource_config->getTypeName(), $key); - return $this->urlGenerator->generateFromRoute($route_key, $route_parameters, ['absolute' => TRUE]); + $route_name = 'jsonapi.' . $type . '.' . $key; + return $this->urlGenerator->generateFromRoute($route_name, $route_parameters, ['absolute' => TRUE]); } /** @@ -58,6 +62,7 @@ class LinkManager implements LinkManagerInterface { */ public function getRequestLink(Request $request, $query = NULL) { $query = $query ?: (array) $request->query->getIterator(); + // @todo use the "current route match" service instead. $result = $this->router->matchRequest($request); $route_name = $result[RouteObjectInterface::ROUTE_NAME]; /* @var \Symfony\Component\HttpFoundation\ParameterBag $raw_variables */ diff --git a/src/LinkManager/LinkManagerInterface.php b/src/LinkManager/LinkManagerInterface.php index ec43d84..6f9169e 100644 --- a/src/LinkManager/LinkManagerInterface.php +++ b/src/LinkManager/LinkManagerInterface.php @@ -7,29 +7,28 @@ use Drupal\jsonapi\Configuration\ResourceConfigInterface; use Symfony\Component\HttpFoundation\Request; /** - * Class LinkManagerInterface. - * - * @package Drupal\jsonapi + * @internal */ interface LinkManagerInterface { /** - * Gets a link for the entity. + * Gets a link for a JSON API resource. * - * @param int $entity_id - * The entity ID to generate the link for. Note: Depending on the - * configuration this might be the UUID as well. - * @param \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource_config - * The resource configuration. + * @param string $jsonapi_resource_type + * The JSON API resource type to generate the link for. + * @see \Drupal\jsonapi\Annotation\JsonApiResourceType::$type + * @param string $id + * The JSON API resource ID to generate the link for. * @param array $route_parameters * Parameters for the route generation. * @param string $key - * A key to build the route identifier. + * Which JSON API route to generate for this resource type: 'collection', + * 'individual', 'related' or 'relationship'. * * @return string * The URL string. */ - public function getEntityLink($entity_id, ResourceConfigInterface $resource_config, array $route_parameters, $key); + public function getResourceLink($type, $uuid, array $route_parameters, $key); /** * Get the full URL for a given request object. diff --git a/src/Normalizer/DocumentRootNormalizer.php b/src/Normalizer/DocumentRootNormalizer.php index 11f6603..53c3b89 100644 --- a/src/Normalizer/DocumentRootNormalizer.php +++ b/src/Normalizer/DocumentRootNormalizer.php @@ -75,7 +75,8 @@ class DocumentRootNormalizer extends NormalizerBase implements DenormalizerInter } }, $data['data']['relationships']); - $id_key = $this->currentContext->getResourceConfig()->getIdKey(); + // @todo fix in https://www.drupal.org/node/2831134 + $id_key = 'uuid'; // Get an array of ids for every relationship. $relationships = array_map(function ($relationship) use ($id_key) { @@ -84,8 +85,8 @@ class DocumentRootNormalizer extends NormalizerBase implements DenormalizerInter return $id_list; } list($entity_type_id,) = explode('--', $relationship['data'][0]['type']); - $entity_storage = $this->currentContext->getResourceManager() - ->getEntityTypeManager() + $entity_storage = \Drupal::getContainer() + ->get('entity_type.manager') ->getStorage($entity_type_id); // In order to maintain the order ($delta) of the relationships, we need // to load the entities and explore the $id_key value. @@ -107,7 +108,7 @@ class DocumentRootNormalizer extends NormalizerBase implements DenormalizerInter } // Overwrite the serialization target class with the one in the resource // config. - $class = $context['resource_config']->getDeserializationTargetClass(); + $class = $context['resource_config']['serialization_class']; return $this->serializer ->denormalize($normalized, $class, $format, $context); diff --git a/src/Normalizer/EntityNormalizer.php b/src/Normalizer/EntityNormalizer.php index eefd8f7..24bb7d5 100644 --- a/src/Normalizer/EntityNormalizer.php +++ b/src/Normalizer/EntityNormalizer.php @@ -11,6 +11,7 @@ use Drupal\jsonapi\Context\CurrentContextInterface; use Drupal\jsonapi\Error\SerializableHttpException; use Drupal\jsonapi\LinkManager\LinkManagerInterface; use Drupal\jsonapi\Normalizer\Value\NullFieldNormalizerValue; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; use Drupal\jsonapi\RelationshipInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; @@ -41,13 +42,6 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface, protected $linkManager; /** - * The resource manager. - * - * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface - */ - protected $resourceManager; - - /** * The current JSON API request context. * * @var \Drupal\jsonapi\Context\CurrentContextInterface @@ -65,7 +59,6 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface, public function __construct(LinkManagerInterface $link_manager, CurrentContextInterface $current_context) { $this->linkManager = $link_manager; $this->currentContext = $current_context; - $this->resourceManager = $current_context->getResourceManager(); } /** @@ -73,14 +66,11 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface, */ public function normalize($entity, $format = NULL, array $context = array()) { // If the fields to use were specified, only output those field values. - $context['resource_config'] = $this->resourceManager->get( - $entity->getEntityTypeId(), - $entity->bundle() - ); - $resource_type = $context['resource_config']->getTypeName(); + $resource_type = EntityJsonApiResourceType::getJsonApiResourceTypeForEntity($entity); + $context['resource_config'] = $this->currentContext->getJsonApiResourceTypeManager()->getDefinition($resource_type); // Get the bundle ID of the requested resource. This is used to determine if // this is a bundle level resource or an entity level resource. - $bundle_id = $context['resource_config']->getBundleId(); + $bundle_id = $entity->bundle(); if (!empty($context['sparse_fieldset'][$resource_type])) { $field_names = $context['sparse_fieldset'][$resource_type]; } @@ -129,21 +119,24 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface, * {@inheritdoc} */ public function denormalize($data, $class, $format = NULL, array $context = array()) { - if (empty($context['resource_config']) || !$context['resource_config'] instanceof ResourceConfigInterface) { + if (empty($context['resource_config']) || !is_array($context['resource_config'])) { throw new SerializableHttpException(412, 'Missing context during denormalization.'); } - /* @var \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource_config */ - $resource_config = $context['resource_config']; - $bundle_id = $resource_config->getBundleId(); - $bundle_key = $this->resourceManager - ->getEntityTypeManager() - ->getDefinition($resource_config->getEntityTypeId()) + + /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ + $entity_type_manager = \Drupal::service('entity_type.manager'); + + $type = $context['resource_config']['type']; + $entity_type_id = EntityJsonApiResourceType::getEntityTypeIdForJsonApiResourceType($type); + $bundle_id = EntityJsonApiResourceType::getBundleForJsonApiResourceType($type); + $bundle_key = $entity_type_manager + ->getDefinition($entity_type_id) ->getKey('bundle'); if ($bundle_key && $bundle_id) { $data[$bundle_key] = $bundle_id; } - return $resource_config->getStorage()->create($data); + return $entity_type_manager->getStorage($entity_type_id)->create($data); } /** diff --git a/src/Normalizer/EntityReferenceFieldNormalizer.php b/src/Normalizer/EntityReferenceFieldNormalizer.php index 855ac04..95b44e6 100644 --- a/src/Normalizer/EntityReferenceFieldNormalizer.php +++ b/src/Normalizer/EntityReferenceFieldNormalizer.php @@ -56,14 +56,11 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal * The entity field manager. * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $plugin_manager * The plugin manager for fields. - * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager - * The resource manager. */ - public function __construct(LinkManagerInterface $link_manager, EntityFieldManagerInterface $field_manager, FieldTypePluginManagerInterface $plugin_manager, ResourceManagerInterface $resource_manager) { + public function __construct(LinkManagerInterface $link_manager, EntityFieldManagerInterface $field_manager, FieldTypePluginManagerInterface $plugin_manager) { $this->linkManager = $link_manager; $this->fieldManager = $field_manager; $this->pluginManager = $plugin_manager; - $this->resourceManager = $resource_manager; } /** @@ -81,7 +78,7 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal $entity_collection = new EntityCollection(array_map(function ($item) { return $item->get('entity')->getValue(); }, (array) $field->getIterator())); - $relationship = new Relationship($this->resourceManager, $field->getName(), $cardinality, $entity_collection, $field->getEntity(), $main_property); + $relationship = new Relationship($field->getName(), $cardinality, $entity_collection, $field->getEntity(), $main_property); return $this->serializer->normalize($relationship, $format, $context); } @@ -170,12 +167,10 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal */ protected function getAllowedResourceTypes(FieldItemDataDefinition $item_definition) { // Build the list of allowed resources. - $target_entity_id = $item_definition->getSetting('target_type'); + $target_entity_type_id = $item_definition->getSetting('target_type'); $handler_settings = $item_definition->getSetting('handler_settings'); - return array_map(function ($target_bundle_id) use ($target_entity_id) { - return $this->resourceManager - ->get($target_entity_id, $target_bundle_id) - ->getTypeName(); + return array_map(function ($target_bundle) use ($target_entity_type_id) { + return sprintf('%s--%s', $target_entity_type_id, $target_bundle); }, $handler_settings['target_bundles']); } diff --git a/src/Normalizer/RelationshipItemNormalizer.php b/src/Normalizer/RelationshipItemNormalizer.php index d1e32b1..e70b49d 100644 --- a/src/Normalizer/RelationshipItemNormalizer.php +++ b/src/Normalizer/RelationshipItemNormalizer.php @@ -6,6 +6,8 @@ use Drupal\Core\Cache\RefinableCacheableDependencyInterface; use Drupal\Core\Cache\RefinableCacheableDependencyTrait; use Drupal\Core\Entity\EntityInterface; use Drupal\jsonapi\Configuration\ResourceManagerInterface; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\RelationshipItemInterface; use Drupal\serialization\EntityResolver\UuidReferenceInterface; @@ -28,7 +30,7 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe * * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface */ - protected $resourceManager; + protected $jsonApiResourceTypeManager; /** * The document normalizer. @@ -45,8 +47,8 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe * @param \Drupal\jsonapi\Normalizer\DocumentRootNormalizerInterface $document_root_normalizer * The document root normalizer for the include. */ - public function __construct(ResourceManagerInterface $resource_manager, DocumentRootNormalizerInterface $document_root_normalizer) { - $this->resourceManager = $resource_manager; + public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, DocumentRootNormalizerInterface $document_root_normalizer) { + $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager; $this->documentRootNormalizer = $document_root_normalizer; } @@ -102,8 +104,8 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe */ protected function buildSubContext($context, EntityInterface $entity, $host_field_name) { // Swap out the context for the context of the referenced resource. - $context['resource_config'] = $this->resourceManager - ->get($entity->getEntityTypeId(), $entity->bundle()); + $type = EntityJsonApiResourceType::getJsonApiResourceTypeForEntity($entity); + $context['resource_config'] = $this->jsonApiResourceTypeManager->getDefinition($type); // Since we're going one level down the only includes we need are the ones // that apply to this level as well. $include_candidates = array_filter($context['include'], function ($include) use ($host_field_name) { diff --git a/src/Normalizer/RelationshipNormalizer.php b/src/Normalizer/RelationshipNormalizer.php index 41e8c7f..fd4dc03 100644 --- a/src/Normalizer/RelationshipNormalizer.php +++ b/src/Normalizer/RelationshipNormalizer.php @@ -5,6 +5,8 @@ namespace Drupal\jsonapi\Normalizer; use Drupal\Core\Entity\EntityInterface; use Drupal\jsonapi\Configuration\ResourceManagerInterface; use Drupal\jsonapi\LinkManager\LinkManagerInterface; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\Relationship; use Symfony\Component\Serializer\Exception\UnexpectedValueException; @@ -29,7 +31,7 @@ class RelationshipNormalizer extends NormalizerBase { * * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface */ - protected $resourceManager; + protected $jsonApiResourceTypeManager; /** * The link manager. @@ -48,15 +50,13 @@ class RelationshipNormalizer extends NormalizerBase { /** * RelationshipNormalizer constructor. * - * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager - * The resource manager. * @param \Drupal\jsonapi\Normalizer\DocumentRootNormalizerInterface $document_root_normalizer * The document root normalizer for the include. * @param \Drupal\jsonapi\LinkManager\LinkManagerInterface $link_manager * The link manager. */ - public function __construct(ResourceManagerInterface $resource_manager, DocumentRootNormalizerInterface $document_root_normalizer, LinkManagerInterface $link_manager) { - $this->resourceManager = $resource_manager; + public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, DocumentRootNormalizerInterface $document_root_normalizer, LinkManagerInterface $link_manager) { + $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager; $this->documentRootNormalizer = $document_root_normalizer; $this->linkManager = $link_manager; } @@ -85,15 +85,12 @@ class RelationshipNormalizer extends NormalizerBase { /* @var \Drupal\jsonapi\RelationshipInterface $relationship */ $normalizer_items = array(); foreach ($relationship->getItems() as $relationship_item) { - /* @var \Drupal\jsonapi\RelationshipItemInterface $relationship_item */ - if (!$relationship_item->resourceIsEnabled()) { - continue; - } $normalizer_items[] = $this->serializer->normalize($relationship_item, $format, $context); } $cardinality = $relationship->getCardinality(); $link_context = [ - 'host_entity_id' => $context['resource_config']->getIdKey() == 'uuid' ? $relationship->getHostEntity()->uuid() : $relationship->getHostEntity()->id(), + // @Todo + 'host_entity_id' => $relationship->getHostEntity()->uuid(), 'field_name' => $relationship->getPropertyName(), 'link_manager' => $this->linkManager, 'resource_config' => $context['resource_config'], @@ -120,8 +117,8 @@ class RelationshipNormalizer extends NormalizerBase { */ protected function buildSubContext($context, EntityInterface $entity, $host_field_name) { // Swap out the context for the context of the referenced resource. - $context['resource_config'] = $this->resourceManager - ->get($entity->getEntityTypeId(), $entity->bundle()); + $type = EntityJsonApiResourceType::getJsonApiResourceTypeForEntity($entity); + $context['resource_config'] = $this->jsonApiResourceTypeManager->getDefinition($type); // Since we're going one level down the only includes we need are the ones // that apply to this level as well. $include_candidates = array_filter($context['include'], function ($include) use ($host_field_name) { diff --git a/src/Normalizer/Value/EntityNormalizerValue.php b/src/Normalizer/Value/EntityNormalizerValue.php index 29bf5ec..84f9092 100644 --- a/src/Normalizer/Value/EntityNormalizerValue.php +++ b/src/Normalizer/Value/EntityNormalizerValue.php @@ -86,18 +86,17 @@ class EntityNormalizerValue implements EntityNormalizerValueInterface { * {@inheritdoc} */ public function rasterizeValue() { - $id_key = $this->context['resource_config']->getIdKey(); // Create the array of normalized fields, starting with the URI. $rasterized = [ - 'type' => $this->context['resource_config']->getTypeName(), - 'id' => $id_key == 'uuid' ? $this->entity->uuid() : $this->entity->id(), + 'type' => $this->context['resource_config']['type'], + 'id' => $this->entity->uuid(), 'attributes' => [], 'relationships' => [], ]; $rasterized['links'] = [ - 'self' => $this->linkManager->getEntityLink( + 'self' => $this->linkManager->getResourceLink( + $this->context['resource_config']['type'], $rasterized['id'], - $this->context['resource_config'], [], 'individual' ), diff --git a/src/Normalizer/Value/RelationshipItemNormalizerValue.php b/src/Normalizer/Value/RelationshipItemNormalizerValue.php index c00af71..b143426 100644 --- a/src/Normalizer/Value/RelationshipItemNormalizerValue.php +++ b/src/Normalizer/Value/RelationshipItemNormalizerValue.php @@ -40,7 +40,7 @@ class RelationshipItemNormalizerValue extends FieldItemNormalizerValue implement return $value; } return [ - 'type' => $this->resource->getTypeName(), + 'type' => $this->resource['type'], 'id' => $value, ]; } diff --git a/src/Normalizer/Value/RelationshipNormalizerValue.php b/src/Normalizer/Value/RelationshipNormalizerValue.php index 88e8ffa..170d451 100644 --- a/src/Normalizer/Value/RelationshipNormalizerValue.php +++ b/src/Normalizer/Value/RelationshipNormalizerValue.php @@ -75,15 +75,15 @@ class RelationshipNormalizerValue extends FieldNormalizerValue implements Relati return [ 'data' => $value, 'links' => [ - 'self' => $this->linkManager->getEntityLink( + 'self' => $this->linkManager->getResourceLink( + $this->resourceConfig['type'], $this->hostEntityId, - $this->resourceConfig, $route_parameters, 'relationship' ), - 'related' => $this->linkManager->getEntityLink( + 'related' => $this->linkManager->getResourceLink( + $this->resourceConfig['type'], $this->hostEntityId, - $this->resourceConfig, $route_parameters, 'related' ), diff --git a/src/Configuration/ResourceManager.php b/src/Plugin/Deriver/EntityDeriver.php similarity index 22% rename from src/Configuration/ResourceManager.php rename to src/Plugin/Deriver/EntityDeriver.php index 106efc1..a55546d 100644 --- a/src/Configuration/ResourceManager.php +++ b/src/Plugin/Deriver/EntityDeriver.php @@ -1,33 +1,34 @@ entityTypeManager = $entity_type_manager; $this->bundleManager = $bundle_manager; - $this->configFactory = $config_factory; - $this->moduleHandler = $module_handler; } /** * {@inheritdoc} */ - public function all($include_disabled = FALSE) { - if (!$this->all) { - $entity_type_ids = array_keys($this->entityTypeManager->getDefinitions()); - foreach ($entity_type_ids as $entity_type_id) { - // Add a ResourceConfig per bundle. - $this->all = array_merge($this->all, array_map(function ($bundle) use ($entity_type_id) { - $resource_config = new ResourceConfig($this->configFactory, $this->entityTypeManager); - $resource_config->setEntityTypeId($entity_type_id); - $resource_config->setBundleId($bundle); - $resource_config->setPath(sprintf('/%s/%s', $entity_type_id, $bundle)); - $resource_config->setTypeName(sprintf('%s--%s', $entity_type_id, $bundle)); - return $resource_config; - }, array_keys($this->bundleManager->getBundleInfo($entity_type_id)))); - } - // Allow altering the resource configuration. This is used, among other, to - // disable resources. - $this->moduleHandler->alter('jsonapi_resources', $this->all); - } - // Filter out the disabled resources if necessary. - return $include_disabled ? - $this->all : - array_filter($this->all, function ($resource) { - /* @var \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource */ - return $resource->isEnabled(); - }); + public static function create(ContainerInterface $container, $base_plugin_id) { + return new static( + $container->get('entity_type.manager'), + $container->get('entity_type.bundle.info') + ); } /** * {@inheritdoc} */ - public function get($entity_type_id, $bundle_id) { - if (empty($entity_type_id)) { - throw new PreconditionFailedHttpException('Server error. The current route is malformed.'); - } - foreach ($this->all(TRUE) as $resource) { - if ($resource->getEntityTypeId() == $entity_type_id && $resource->getBundleId() == $bundle_id) { - return $resource; - } + public function getDerivativeDefinitions($base_plugin_definition) { + if (isset($this->derivatives)) { + return $this->derivatives; } - return NULL; - } + $this->derivatives = []; - /** - * {@inheritdoc} - */ - public function getEntityTypeManager() { - return $this->entityTypeManager; - } + $entity_types = $this->entityTypeManager->getDefinitions(); + foreach ($entity_types as $entity_type_id => $entity_type) { + $plugin_definition = [ + 'serialization_class' => $entity_type->getClass(), + 'route_options' => [ + 'parameters' => [ + $entity_type_id => [ + 'type' => 'entity:' . $entity_type_id, + ], + ], + ], + 'route_path_part_for_individual_resource' => $entity_type_id, + ] + $base_plugin_definition; - /** - * {@inheritdoc} - */ - public function hasBundle($entity_type_id) { - return (bool) $this->getEntityTypeManager() - ->getDefinition($entity_type_id) - ->getBundleEntityType(); - } + // First derive a JSON API Resource Type for this entity type (this covers + // all bundles). + $jsonapi_resource_type = sprintf('%s', $entity_type_id); + $this->derivatives[$jsonapi_resource_type] = [ + 'id' => $jsonapi_resource_type, + 'type' => $entity_type_id , + 'route_requirements' => [ + '_entity_type' => $entity_type_id, + ], + ] + $plugin_definition; + // Now derive an additional JSON API Resource Type for every bundle that + // exists for this entity type. + // @todo ensure new bundles are picked up immediately, see \Drupal\Core\Entity\EntityTypeBundleInfo::clearCachedBundles(). + if ($entity_type->hasKey('bundle')) { + $bundles = array_keys($this->bundleManager->getBundleInfo($entity_type_id)); + foreach ($bundles as $bundle) { + $jsonapi_resource_type = sprintf('%s--%s', $entity_type_id, $bundle); + $this->derivatives[$jsonapi_resource_type] = [ + 'id' => $jsonapi_resource_type, + 'type' => sprintf('%s--%s', $entity_type_id, $bundle), + 'route_requirements' => [ + '_entity_type' => $entity_type_id, + '_bundle' => $bundle, + ], + ] + $plugin_definition; + } + } + } + return $this->derivatives; + } } diff --git a/src/Plugin/Deriver/ResourceDeriver.php b/src/Plugin/Deriver/ResourceDeriver.php deleted file mode 100644 index 3048b62..0000000 --- a/src/Plugin/Deriver/ResourceDeriver.php +++ /dev/null @@ -1,82 +0,0 @@ -resourceManager = $resource_manager; - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, $base_plugin_id) { - /* @var \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager */ - $resource_manager = $container->get('jsonapi.resource.manager'); - return new static($resource_manager); - } - - /** - * {@inheritdoc} - */ - public function getDerivativeDefinitions($base_definition) { - if (isset($this->derivatives)) { - return $this->derivatives; - } - $this->derivatives = []; - // Add in the default plugin configuration and the resource type. - /* @var \Drupal\jsonapi\Configuration\ResourceConfigInterface[] $resource_configs */ - $resource_configs = $this->resourceManager->all(); - foreach ($resource_configs as $resource) { - $global_config = $resource->getGlobalConfig(); - $prefix = $global_config->get('prefix'); - $id = sprintf('%s.dynamic.%s', $prefix, $resource->getTypeName()); - $this->derivatives[$id] = [ - 'id' => $id, - 'entityType' => $resource->getEntityTypeId(), - 'bundle' => $resource->getBundleId(), - 'hasBundle' => $this->resourceManager->hasBundle($resource->getEntityTypeId()), - 'type' => $resource->getTypeName(), - 'data' => [ - 'prefix' => $prefix, - 'partialPath' => '/' . $prefix . $resource->getPath() - ] - ]; - - $this->derivatives[$id] += $base_definition; - } - return $this->derivatives; - } - -} diff --git a/src/Plugin/JsonApiResourceInterface.php b/src/Plugin/JsonApiResourceInterface.php deleted file mode 100644 index 560b703..0000000 --- a/src/Plugin/JsonApiResourceInterface.php +++ /dev/null @@ -1,14 +0,0 @@ - 'access content', - 'controller' => Routes::FRONT_CONTROLLER, - 'enabled' => TRUE, - ]; - - /** - * Constructor for JsonApiResourceManager objects. + * Constructor for JsonApiResourceTypeManager objects. * * @param \Traversable $namespaces * An object that implements \Traversable which contains the root paths @@ -36,10 +24,33 @@ class JsonApiResourceManager extends DefaultPluginManager { * The module handler to invoke the alter hook with. */ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { - parent::__construct('Plugin/jsonapi', $namespaces, $module_handler, 'Drupal\jsonapi\Plugin\JsonApiResourceInterface', 'Drupal\jsonapi\Annotation\JsonApiResource'); + // For now, only allow the JSON API module to provide JSON API Resource Type + // plugins. The API is not yet finalized, and it's not yet clear whether it + // would make sense to allow additional types beyond entity types and entity + // type bundles. + $limited_namespaces = new \ArrayObject(['\Drupal\jsonapi' => $namespaces['Drupal\jsonapi']]); - $this->alterInfo('jsonapi_resource_info'); - $this->setCacheBackend($cache_backend, 'jsonapi_resource_plugins'); + parent::__construct('Plugin/jsonapi', $limited_namespaces, $module_handler, 'Drupal\jsonapi\Plugin\JsonApiResourceTypeInterface', 'Drupal\jsonapi\Annotation\JsonApiResourceType'); + $this->setCacheBackend($cache_backend, 'jsonapi_resource_type_plugins'); + } + + /** + * {@inheritdoc} + * + * @todo \Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator::encodePluginId() + * gets in the way; we specifically want all derived plugins to not be + * prefixed by their base plugin ID, because that helps ensure that across all + * JSON API Resource Type plugins, each type is specified only once. + */ + public function getDefinition($plugin_id, $exception_on_invalid = TRUE) { + try { + return parent::getDefinition($plugin_id, $exception_on_invalid); + } + catch (PluginNotFoundException $e) { + // This work-around will work as long as EntityJsonApiResourceType is the + // only plugin. + return parent::getDefinition('entity:' . $plugin_id, $exception_on_invalid); + } } } diff --git a/src/Plugin/jsonapi/BundleJsonApiResource.php b/src/Plugin/jsonapi/BundleJsonApiResource.php deleted file mode 100644 index bf97da3..0000000 --- a/src/Plugin/jsonapi/BundleJsonApiResource.php +++ /dev/null @@ -1,24 +0,0 @@ -entityTypeManager = \Drupal::getContainer()->get('entity_type.manager'); + $this->queryBuilder = \Drupal::getContainer()->get('jsonapi.query_builder'); + $this->currentContext = \Drupal::getContainer()->get('jsonapi.current_context'); + } /** - * Instantiates a EntityResource object. + * @param \Drupal\Core\Entity\EntityInterface $entity + * An entity. + * + * @return string + * The JSON API Resource Type. * - * @param \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource_config - * The configuration for the resource. - * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager - * The entity type manager. - * @param \Drupal\jsonapi\Query\QueryBuilderInterface $query_builder - * The query builder. - * @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager - * The entity type field manager. - * @param \Drupal\jsonapi\Context\CurrentContextInterface $current_context - * The current context. - * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $plugin_manager - * The plugin manager for fields. + * @see \Drupal\jsonapi\Annotation\JsonApiResourceType::$type */ - public function __construct(ResourceConfigInterface $resource_config, EntityTypeManagerInterface $entity_type_manager, QueryBuilderInterface $query_builder, EntityFieldManagerInterface $field_manager, CurrentContextInterface $current_context, FieldTypePluginManagerInterface $plugin_manager) { - $this->resourceConfig = $resource_config; - $this->entityTypeManager = $entity_type_manager; - $this->queryBuilder = $query_builder; - $this->fieldManager = $field_manager; - $this->currentContext = $current_context; - $this->pluginManager = $plugin_manager; + public static function getJsonApiResourceTypeForEntity(EntityInterface $entity) { + return $entity->getEntityType()->getBundleEntityType() === NULL + ? $entity->getEntityTypeId() + : sprintf('%s--%s', $entity->getEntityTypeId(), $entity->bundle()); + } + + public static function getEntityTypeIdForJsonApiResourceType($type) { + list($entity_type_id, $bundle) = explode('--', $type); + return $entity_type_id; + } + + public static function getBundleForJsonApiResourceType($type) { + list($entity_type_id, $bundle) = explode('--', $type); + return $bundle; + } + + + protected function getEntityTypeId() { + return static::getEntityTypeIdForJsonApiResourceType($this->getPluginDefinition()['type']); + } + + protected function getBundle() { + return static::getBundleForJsonApiResourceType($this->getPluginDefinition()['type']); } /** * {@inheritdoc} */ - public function getIndividual(EntityInterface $entity, Request $request, $response_code = 200) { + public function getIndividual($entity, Request $request, $response_code = 200) { + assert($entity instanceof EntityInterface); $entity_access = $entity->access('view', NULL, TRUE); if (!$entity_access->isAllowed()) { throw new SerializableHttpException(403, 'The current user is not allowed to GET the selected resource.'); @@ -121,7 +123,8 @@ class EntityResource implements EntityResourceInterface { * @throws \Drupal\jsonapi\Error\SerializableHttpException * If validation errors are found. */ - protected function validate(EntityInterface $entity) { + protected function validate($entity) { + assert($entity instanceof EntityInterface); if (!$entity instanceof FieldableEntityInterface) { return; } @@ -148,7 +151,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function createIndividual(EntityInterface $entity, Request $request) { + public function createIndividual($entity, Request $request) { + assert($entity instanceof EntityInterface); $entity_access = $entity->access('create', NULL, TRUE); if (!$entity_access->isAllowed()) { @@ -162,18 +166,18 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function patchIndividual(EntityInterface $entity, EntityInterface $parsed_entity, Request $request) { + public function patchIndividual($entity, $parsed_entity, Request $request) { + assert($entity instanceof EntityInterface); $entity_access = $entity->access('update', NULL, TRUE); if (!$entity_access->isAllowed()) { throw new SerializableHttpException(403, 'The current user is not allowed to GET the selected resource.'); } $body = Json::decode($request->getContent()); $data = $body['data']; - $id_key = $this->resourceConfig->getIdKey(); - if (!method_exists($entity, $id_key) || $data['id'] != $entity->{$id_key}()) { + if ($data['id'] !== $entity->uuid()) { throw new SerializableHttpException(400, sprintf( 'The selected entity (%s) does not match the ID in the payload (%s).', - $entity->{$id_key}(), + $entity->uuid(), $data['id'] )); } @@ -192,7 +196,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function deleteIndividual(EntityInterface $entity, Request $request) { + public function deleteIndividual($entity, Request $request) { + assert($entity instanceof EntityInterface); $entity_access = $entity->access('delete', NULL, TRUE); if (!$entity_access->isAllowed()) { throw new SerializableHttpException(403, 'The current user is not allowed to DELETE the selected resource.'); @@ -206,7 +211,7 @@ class EntityResource implements EntityResourceInterface { */ public function getCollection(Request $request) { // Instantiate the query for the filtering. - $entity_type_id = $this->resourceConfig->getEntityTypeId(); + $entity_type_id = $this->getEntityTypeId(); // Set the current context from the request. $this->currentContext->fromRequest($request); @@ -242,7 +247,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function getRelated(EntityInterface $entity, $related_field, Request $request) { + public function getRelated($entity, $related_field, Request $request) { + assert($entity instanceof EntityInterface); /* @var $field_list \Drupal\Core\Field\FieldItemListInterface */ if (!($field_list = $entity->get($related_field)) || !$this->isRelationshipField($field_list)) { throw new SerializableHttpException(404, sprintf('The relationship %s is not present in this resource.', $related_field)); @@ -266,7 +272,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function getRelationship(EntityInterface $entity, $related_field, Request $request, $response_code = 200) { + public function getRelationship($entity, $related_field, Request $request, $response_code = 200) { + assert($entity instanceof EntityInterface); if (!($field_list = $entity->get($related_field)) || !$this->isRelationshipField($field_list)) { throw new SerializableHttpException(404, sprintf('The relationship %s is not present in this resource.', $related_field)); } @@ -277,7 +284,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function createRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) { + public function createRelationship($entity, $related_field, $parsed_field_list, Request $request) { + assert($entity instanceof EntityInterface); if ($parsed_field_list instanceof Response) { // This usually means that there was an error, so there is no point on // processing further. @@ -312,7 +320,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function patchRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) { + public function patchRelationship($entity, $related_field, $parsed_field_list, Request $request) { + assert($entity instanceof EntityInterface); if ($parsed_field_list instanceof Response) { // This usually means that there was an error, so there is no point on // processing further. @@ -371,7 +380,8 @@ class EntityResource implements EntityResourceInterface { /** * {@inheritdoc} */ - public function deleteRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) { + public function deleteRelationship($entity, $related_field, $parsed_field_list, Request $request) { + assert($entity instanceof EntityInterface); if ($parsed_field_list instanceof Response) { // This usually means that there was an error, so there is no point on // processing further. @@ -420,10 +430,10 @@ class EntityResource implements EntityResourceInterface { $query = $this->queryBuilder->newQuery($entity_type, $params); // Limit this query to the bundle type for this resource. - $bundle_id = $this->resourceConfig->getBundleId(); - if ($bundle_id && ($bundle_key = $entity_type->getKey('bundle'))) { + $bundle = $this->getBundle(); + if ($bundle && ($bundle_key = $entity_type->getKey('bundle'))) { $query->condition( - $bundle_key, $bundle_id + $bundle_key, $bundle ); } diff --git a/src/Query/QueryBuilder.php b/src/Query/QueryBuilder.php index f9e90de..deac432 100644 --- a/src/Query/QueryBuilder.php +++ b/src/Query/QueryBuilder.php @@ -5,6 +5,7 @@ namespace Drupal\jsonapi\Query; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\jsonapi\Error\SerializableHttpException; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; use Drupal\jsonapi\Routing\Param\OffsetPage; use Drupal\jsonapi\Routing\Param\Filter; use Drupal\jsonapi\Routing\Param\JsonApiParamInterface; @@ -347,8 +348,7 @@ class QueryBuilder implements QueryBuilderInterface { * The key. */ protected function getLangcodeKey() { - $entity_type_id = $this->currentContext->getResourceConfig() - ->getEntityTypeId(); + $entity_type_id = EntityJsonApiResourceType::getEntityTypeIdForJsonApiResourceType($this->currentContext->getResourceConfig()['type']); return $this->entityTypeManager ->getDefinition($entity_type_id) ->getKey('langcode'); diff --git a/src/Relationship.php b/src/Relationship.php index c8350d5..42f4b95 100644 --- a/src/Relationship.php +++ b/src/Relationship.php @@ -39,13 +39,6 @@ class Relationship implements RelationshipInterface, AccessibleInterface { protected $propertyName; /** - * The resource manager. - * - * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface - */ - protected $resourceManager; - - /** * The relationship items. * * @var array @@ -55,8 +48,6 @@ class Relationship implements RelationshipInterface, AccessibleInterface { /** * Relationship constructor. * - * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager - * The resource manager. * @param string $field_name * The name of the relationship. * @param int $cardinality @@ -68,15 +59,14 @@ class Relationship implements RelationshipInterface, AccessibleInterface { * @param string $target_key * The property name of the relationship id. */ - public function __construct(ResourceManagerInterface $resource_manager, $field_name, $cardinality = FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, EntityCollectionInterface $entities, EntityInterface $host_entity, $target_key = 'target_id') { - $this->resourceManager = $resource_manager; + public function __construct($field_name, $cardinality = FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, EntityCollectionInterface $entities, EntityInterface $host_entity, $target_key = 'target_id') { $this->propertyName = $field_name; $this->cardinality = $cardinality; $this->hostEntity = $host_entity; $this->items = []; foreach ($entities as $entity) { $this->items[] = new RelationshipItem( - $resource_manager, + \Drupal::getContainer()->get('plugin.manager.jsonapi.resource_type'), $entity, $this, $target_key diff --git a/src/RelationshipItem.php b/src/RelationshipItem.php index a303205..ee01f6e 100644 --- a/src/RelationshipItem.php +++ b/src/RelationshipItem.php @@ -4,6 +4,8 @@ namespace Drupal\jsonapi; use Drupal\Core\Entity\EntityInterface; use Drupal\jsonapi\Configuration\ResourceManagerInterface; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; class RelationshipItem implements RelationshipItemInterface { @@ -38,8 +40,8 @@ class RelationshipItem implements RelationshipItemInterface { /** * Relationship item constructor. * - * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager - * The resource manager. + * @param \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager + * The JSON API Resource Type plugin manager. * @param \Drupal\Core\Entity\EntityInterface $target_entity * The entity this relationship points to. * @param RelationshipInterface @@ -47,11 +49,8 @@ class RelationshipItem implements RelationshipItemInterface { * @param string $target_key * The key name of the target relationship. */ - public function __construct(ResourceManagerInterface $resource_manager, EntityInterface $target_entity, RelationshipInterface $parent, $target_key = 'target_id') { - $this->targetResourceConfig = $resource_manager->get( - $target_entity->getEntityTypeId(), - $target_entity->bundle() - ); + public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, EntityInterface $target_entity, RelationshipInterface $parent, $target_key = 'target_id') { + $this->targetResourceConfig = $jsonapi_resource_type_manager->getDefinition(EntityJsonApiResourceType::getJsonApiResourceTypeForEntity($target_entity)); $this->targetKey = $target_key; $this->targetEntity = $target_entity; $this->parent = $parent; @@ -75,10 +74,7 @@ class RelationshipItem implements RelationshipItemInterface { * {@inheritdoc} */ public function getValue() { - $method = $this->getTargetResourceConfig()->getIdKey() == 'uuid' ? - 'uuid' : - 'id'; - return [$this->targetKey => $this->getTargetEntity()->{$method}()]; + return [$this->targetKey => $this->getTargetEntity()->uuid()]; } /** @@ -88,11 +84,4 @@ class RelationshipItem implements RelationshipItemInterface { return $this->parent; } - /** - * {@inheritdoc} - */ - public function resourceIsEnabled() { - return $this->getTargetResourceConfig()->isEnabled(); - } - } diff --git a/src/RelationshipItemInterface.php b/src/RelationshipItemInterface.php index 2f87206..c996e01 100644 --- a/src/RelationshipItemInterface.php +++ b/src/RelationshipItemInterface.php @@ -34,12 +34,4 @@ interface RelationshipItemInterface { */ public function getParent(); - /** - * Is the target resource enabled? - * - * @return bool - * TRUE if the resource is enabled. FALSE otherwise. - */ - public function resourceIsEnabled(); - } diff --git a/src/RequestHandler.php b/src/RequestHandler.php index bef31ab..493ed24 100644 --- a/src/RequestHandler.php +++ b/src/RequestHandler.php @@ -8,6 +8,8 @@ use Drupal\Core\Routing\RouteMatchInterface; use Drupal\jsonapi\Context\CurrentContextInterface; use Drupal\jsonapi\Error\ErrorHandlerInterface; use Drupal\jsonapi\Error\SerializableHttpException; +use Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\Resource\EntityResource; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; @@ -31,10 +33,22 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static($container->get('entity_type.manager')->getStorage('rest_resource_config')); + return new static( + $container->get('plugin.manager.jsonapi.resource_type') + ); } /** + * @var \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager + */ + protected $jsonApiResourceTypeManager; + + public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager) { + $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager; + } + + + /** * Handles a web API request. * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match @@ -77,7 +91,9 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter // parsing it out of the Accept headers again, we can simply retrieve the // format requirement. If there is no format associated, just pick JSON. $action = $this->action($route_match, $method); - $resource = $this->resourceFactory($route, $current_context); + + $jsonapi_plugin_id = $route->getOption('_jsonapi_plugin_id'); + $resource = $this->jsonApiResourceTypeManager->createInstance($jsonapi_plugin_id); // Only add the unserialized data if there is something there. $extra_parameters = $unserialized ? [$unserialized, $request] : [$request]; @@ -181,7 +197,7 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter return $serializer->deserialize($received, $serialization_class, $format, [ 'request_method' => $method, 'related' => $request->get('related'), - 'target_entity' => $request->get($current_context->getResourceConfig()->getEntityTypeId()), + 'target_entity' => $request->get(EntityJsonApiResourceType::getEntityTypeIdForJsonApiResourceType($current_context->getResourceConfig()['type'])), 'resource_config' => $current_context->getResourceConfig(), ]); } @@ -242,37 +258,4 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter return $route_match->getParameter($route->getRequirement('_entity_type')); } - /** - * Get the resource. - * - * @param \Symfony\Component\Routing\Route $route - * The matched route. - * @param \Drupal\jsonapi\Context\CurrentContextInterface $current_context - * The current context. - * - * @return \Drupal\jsonapi\Resource\EntityResourceInterface - * The instantiated resource. - */ - protected function resourceFactory(Route $route, CurrentContextInterface $current_context) { - /** @var \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager */ - $resource_manager = $this->container->get('jsonapi.resource.manager'); - /* @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */ - $entity_type_manager = $this->container->get('entity_type.manager'); - /* @var \Drupal\jsonapi\Query\QueryBuilderInterface $query_builder */ - $query_builder = $this->container->get('jsonapi.query_builder'); - /* @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */ - $field_manager = $this->container->get('entity_field.manager'); - /* @var \Drupal\Core\Field\FieldTypePluginManagerInterface $plugin_manager */ - $plugin_manager = $this->container->get('plugin.manager.field.field_type'); - $resource = new EntityResource( - $resource_manager->get($route->getRequirement('_entity_type'), $route->getRequirement('_bundle')), - $entity_type_manager, - $query_builder, - $field_manager, - $current_context, - $plugin_manager - ); - return $resource; - } - } diff --git a/src/Routing/Routes.php b/src/Routing/Routes.php index 2cd1413..4958c14 100644 --- a/src/Routing/Routes.php +++ b/src/Routing/Routes.php @@ -4,8 +4,10 @@ namespace Drupal\jsonapi\Routing; use Drupal\Core\Authentication\AuthenticationCollectorInterface; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\EntityReferenceFieldItemList; -use Drupal\jsonapi\Plugin\JsonApiResourceManager; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\Resource\DocumentWrapperInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -27,11 +29,23 @@ class Routes implements ContainerInjectionInterface { const FRONT_CONTROLLER = '\Drupal\jsonapi\RequestHandler::handle'; /** - * The resource manager interface. + * @var \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager + */ + protected $jsonApiResourceTypeManager; + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * The bundle manager. * - * @var \Drupal\jsonapi\Plugin\JsonApiResourceManager + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface */ - protected $resourcePluginManager; + protected $bundleManager; /** * The authentication collector. @@ -41,7 +55,7 @@ class Routes implements ContainerInjectionInterface { protected $authCollector; /** - * List of providers. + * List of authentication provider IDs. * * @var string[] */ @@ -50,13 +64,17 @@ class Routes implements ContainerInjectionInterface { /** * Instantiates a Routes object. * - * @param \Drupal\jsonapi\Plugin\JsonApiResourceManager $resource_plugin_manager - * The resource manager. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_manager + * The bundle manager. * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector - * The resource manager. + * The authentication collector. */ - public function __construct(JsonApiResourceManager $resource_plugin_manager, AuthenticationCollectorInterface $auth_collector) { - $this->resourcePluginManager = $resource_plugin_manager; + public function __construct(JsonApiResourceTypeManager $json_api_resource_type_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager, AuthenticationCollectorInterface $auth_collector) { + $this->jsonApiResourceTypeManager = $json_api_resource_type_manager; + $this->entityTypeManager = $entity_type_manager; + $this->bundleManager = $bundle_manager; $this->authCollector = $auth_collector; } @@ -64,12 +82,12 @@ class Routes implements ContainerInjectionInterface { * {@inheritdoc} */ public static function create(ContainerInterface $container) { - /* @var \Drupal\jsonapi\Plugin\JsonApiResourceManager $resource_plugin_manager */ - $resource_plugin_manager = $container->get('plugin.manager.resource.processor'); - /* @var \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector */ - $auth_collector = $container->get('authentication_collector'); - - return new static($resource_plugin_manager, $auth_collector); + return new static( + $container->get('plugin.manager.jsonapi.resource_type'), + $container->get('entity_type.manager'), + $container->get('entity_type.bundle.info'), + $container->get('authentication_collector') + ); } /** @@ -77,19 +95,14 @@ class Routes implements ContainerInjectionInterface { */ public function routes() { $collection = new RouteCollection(); - foreach ($this->resourcePluginManager->getDefinitions() as $plugin_id => $plugin_definition) { - if (empty($plugin_definition['enabled'])) { - continue; - } - $entity_type = $plugin_definition['entityType']; - // For the entity type resources the bundle is NULL. - $bundle = $plugin_definition['bundle']; - $partial_path = $plugin_definition['data']['partialPath']; - $route_keys = explode(':', $plugin_id); - $route_key = end($route_keys) . '.'; + + foreach ($this->jsonApiResourceTypeManager->getDefinitions() as $id => $definition) { + $route_name_prefix = 'jsonapi.' . $definition['type']; + $path_prefix = '/api/' . implode('/', explode('--', $definition['type'])); + // Add the collection route. $defaults = [ - RouteObjectInterface::CONTROLLER_NAME => $plugin_definition['controller'], + RouteObjectInterface::CONTROLLER_NAME => static::FRONT_CONTROLLER, ]; // Options that apply to all routes. $options = [ @@ -98,70 +111,57 @@ class Routes implements ContainerInjectionInterface { ]; // Collection endpoint, like /api/file/photo. - $route_collection = (new Route($partial_path)) + $route_collection = (new Route($path_prefix)) ->addDefaults($defaults) - ->setRequirement('_entity_type', $entity_type) - ->setRequirement('_permission', $plugin_definition['permission']) + ->addRequirements($definition['route_requirements']) ->setRequirement('_format', 'api_json') ->setRequirement('_custom_parameter_names', 'TRUE') + ->setOption('_jsonapi_plugin_id', $id) ->setOption('serialization_class', DocumentWrapperInterface::class) ->setMethods(['GET', 'POST']); - if ($bundle) { - $route_collection->setRequirement('_bundle', $bundle); - } $route_collection->addOptions($options); - $collection->add($route_key . 'collection', $route_collection); + $collection->add($route_name_prefix . '.collection', $route_collection); // Individual endpoint, like /api/file/photo/123. - $parameters = [$entity_type => ['type' => 'entity:' . $entity_type]]; - $route_individual = (new Route(sprintf('%s/{%s}', $partial_path, $entity_type))) + $route_individual = (new Route(sprintf('%s/{%s}', $path_prefix, $definition['route_path_part_for_individual_resource']))) ->addDefaults($defaults) - ->setRequirement('_entity_type', $entity_type) - ->setRequirement('_permission', $plugin_definition['permission']) + ->addRequirements($definition['route_requirements']) ->setRequirement('_format', 'api_json') ->setRequirement('_custom_parameter_names', 'TRUE') - ->setOption('parameters', $parameters) + ->addOptions($definition['route_options']) + ->setOption('_jsonapi_plugin_id', $id) ->setOption('_auth', $this->authProviderList()) ->setOption('serialization_class', DocumentWrapperInterface::class) ->setMethods(['GET', 'PATCH', 'DELETE']); - if ($bundle) { - $route_individual->setRequirement('_bundle', $bundle); - } $route_individual->addOptions($options); - $collection->add($route_key . 'individual', $route_individual); + $collection->add($route_name_prefix . '.individual', $route_individual); // Related resource, like /api/file/photo/123/comments. - $route_related = (new Route(sprintf('%s/{%s}/{related}', $partial_path, $entity_type))) + $route_related = (new Route(sprintf('%s/{%s}/{related}', $path_prefix, $definition['route_path_part_for_individual_resource']))) ->addDefaults($defaults) - ->setRequirement('_entity_type', $entity_type) - ->setRequirement('_permission', $plugin_definition['permission']) + ->addRequirements($definition['route_requirements']) ->setRequirement('_format', 'api_json') ->setRequirement('_custom_parameter_names', 'TRUE') - ->setOption('parameters', $parameters) + ->addOptions($definition['route_options']) + ->setOption('_jsonapi_plugin_id', $id) ->setOption('_auth', $this->authProviderList()) ->setMethods(['GET']); - if ($bundle) { - $route_related->setRequirement('_bundle', $bundle); - } $route_related->addOptions($options); - $collection->add($route_key . 'related', $route_related); + $collection->add($route_name_prefix . '.related', $route_related); // Related endpoint, like /api/file/photo/123/relationships/comments. - $route_relationship = (new Route(sprintf('%s/{%s}/relationships/{related}', $partial_path, $entity_type))) + $route_relationship = (new Route(sprintf('%s/{%s}/relationships/{related}', $path_prefix, $definition['route_path_part_for_individual_resource']))) ->addDefaults($defaults + ['_on_relationship' => TRUE]) - ->setRequirement('_entity_type', $entity_type) - ->setRequirement('_permission', $plugin_definition['permission']) + ->addRequirements($definition['route_requirements']) ->setRequirement('_format', 'api_json') ->setRequirement('_custom_parameter_names', 'TRUE') - ->setOption('parameters', $parameters) + ->addOptions($definition['route_options']) + ->setOption('_jsonapi_plugin_id', $id) ->setOption('_auth', $this->authProviderList()) ->setOption('serialization_class', EntityReferenceFieldItemList::class) ->setMethods(['GET', 'POST', 'PATCH', 'DELETE']); - if ($bundle) { - $route_relationship->setRequirement('_bundle', $bundle); - } $route_relationship->addOptions($options); - $collection->add($route_key . 'relationship', $route_relationship); + $collection->add($route_name_prefix . '.relationship', $route_relationship); } return $collection; diff --git a/tests/src/Functional/JsonApiFunctionalTest.php b/tests/src/Functional/JsonApiFunctionalTest.php index 5f62015..a2817db 100644 --- a/tests/src/Functional/JsonApiFunctionalTest.php +++ b/tests/src/Functional/JsonApiFunctionalTest.php @@ -225,7 +225,7 @@ class JsonApiFunctionalTest extends BrowserTestBase { $single_output['data'][0]['links']['self'] ); $this->assertEquals( - 'taxonomy_vocabulary--taxonomy_vocabulary', + 'taxonomy_vocabulary', $single_output['included'][0]['type'] ); // 10. Single article with includes. @@ -236,7 +236,7 @@ class JsonApiFunctionalTest extends BrowserTestBase { $this->assertEquals('node--article', $single_output['data']['type']); $first_include = reset($single_output['included']); $this->assertEquals( - 'user--user', + 'user', $first_include['type'] ); $last_include = end($single_output['included']); @@ -249,11 +249,11 @@ class JsonApiFunctionalTest extends BrowserTestBase { 'query' => ['include' => 'uid'], ])); $this->assertSession()->statusCodeEquals(200); - $this->assertEquals('user--user', $single_output['data']['type']); + $this->assertEquals('user', $single_output['data']['type']); $this->assertArrayHasKey('related', $single_output['links']); $first_include = reset($single_output['included']); $this->assertEquals( - 'user--user', + 'user', $first_include['data']['type'] ); // 12. Collection with one access denied @@ -350,7 +350,7 @@ class JsonApiFunctionalTest extends BrowserTestBase { public function testWrite() { $this->createDefaultContent(0, 2, FALSE); // 1. Successful post. - $collection_url = Url::fromRoute('api.dynamic.node--article.collection'); + $collection_url = Url::fromRoute('jsonapi.node--article.collection'); $body = [ 'data' => [ 'type' => 'node--article', @@ -465,7 +465,7 @@ class JsonApiFunctionalTest extends BrowserTestBase { 'attributes' => ['title' => 'My updated title'], ], ]; - $individual_url = Url::fromRoute('api.dynamic.node--article.individual', [ + $individual_url = Url::fromRoute('jsonapi.node--article.individual', [ 'node' => $uuid, ]); $response = $this->request('PATCH', $individual_url, [ diff --git a/tests/src/Kernel/Configuration/ResourceManagerTest.php b/tests/src/Kernel/Configuration/ResourceManagerTest.php index 0d3e1ee..d25b195 100644 --- a/tests/src/Kernel/Configuration/ResourceManagerTest.php +++ b/tests/src/Kernel/Configuration/ResourceManagerTest.php @@ -3,7 +3,7 @@ namespace Drupal\Tests\jsonapi\Kernel\Configuration; use Drupal\jsonapi\Configuration\ResourceConfigInterface; -use Drupal\jsonapi\Configuration\ResourceManager; +use Drupal\jsonapi\Configuration\JsonApiResourceRepository; use Drupal\KernelTests\KernelTestBase; use Drupal\node\Entity\NodeType; diff --git a/tests/src/Unit/Routing/RoutesTest.php b/tests/src/Unit/Routing/RoutesTest.php index b2e5d1b..5c0996c 100644 --- a/tests/src/Unit/Routing/RoutesTest.php +++ b/tests/src/Unit/Routing/RoutesTest.php @@ -3,7 +3,7 @@ namespace Drupal\Tests\jsonapi\Unit\Routing; use Drupal\Core\Authentication\AuthenticationCollectorInterface; -use Drupal\jsonapi\Plugin\JsonApiResourceManager; +use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager; use Drupal\jsonapi\Routing\Routes; use Drupal\Tests\UnitTestCase; use Symfony\Cmf\Component\Routing\RouteObjectInterface;