diff --git a/jsonapi.services.yml b/jsonapi.services.yml index 5cdadc3..969008e 100644 --- a/jsonapi.services.yml +++ b/jsonapi.services.yml @@ -185,15 +185,30 @@ services: - { name: event_subscriber, priority: 1000 } # Revision management. - plugin.manager.version_negotiator: - class: Drupal\jsonapi\Revisions\VersionNegotiatorManager + jsonapi.version_negotiator: + class: Drupal\jsonapi\Revisions\VersionNegotiator public: false - parent: default_plugin_manager + tags: + - { name: service_collector, tag: jsonapi_version_negotiator, call: addVersionNegotiator } + jsonapi.version_negotiator.default: + arguments: ['@entity_type.manager'] + public: false + abstract: true + jsonapi.version_negotiator.id: + class: Drupal\jsonapi\Revisions\VersionById + parent: jsonapi.version_negotiator.default + tags: + - { name: jsonapi_version_negotiator, negotiator_name: 'id' } + jsonapi.version_negotiator.rel: + class: Drupal\jsonapi\Revisions\VersionByRel + parent: jsonapi.version_negotiator.default + tags: + - { name: jsonapi_version_negotiator, negotiator_name: 'rel' } jsonapi.resource_version.route_enhancer: class: Drupal\jsonapi\Revisions\ResourceVersionRouteEnhancer public: false arguments: - - '@plugin.manager.version_negotiator' + - '@jsonapi.version_negotiator' tags: - { name: route_enhancer } diff --git a/src/Plugin/VersionNegotiator/VersionById.php b/src/Plugin/VersionNegotiator/VersionById.php deleted file mode 100644 index 69904c7..0000000 --- a/src/Plugin/VersionNegotiator/VersionById.php +++ /dev/null @@ -1,40 +0,0 @@ -entityTypeManager = $entity_type_manager; } - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager')); - } - /** * Gets the revision ID. * diff --git a/src/Revisions/ResourceVersionRouteEnhancer.php b/src/Revisions/ResourceVersionRouteEnhancer.php index eade7e2..10c75d6 100644 --- a/src/Revisions/ResourceVersionRouteEnhancer.php +++ b/src/Revisions/ResourceVersionRouteEnhancer.php @@ -6,7 +6,6 @@ use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Http\Exception\CacheableBadRequestHttpException; use Drupal\Core\Routing\EnhancerInterface; -use Drupal\jsonapi\Plugin\VersionNegotiator\VersionByRel; use Drupal\jsonapi\Routing\Routes; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -53,26 +52,26 @@ final class ResourceVersionRouteEnhancer implements EnhancerInterface { * @var string */ const VERSION_IDENTIFIER_VALIDATOR = '/^[a-z]+[a-z_]*[a-z]+' - . VersionNegotiatorManager::SEPARATOR + . VersionNegotiator::SEPARATOR . '[a-zA-Z0-9\-]+(' - . VersionNegotiatorManager::SEPARATOR + . VersionNegotiator::SEPARATOR . '[a-zA-Z0-9\-]+)*$/'; /** - * The revision ID negotiator manager. + * The revision ID negotiator. * - * @var \Drupal\jsonapi\Revisions\VersionNegotiatorManager + * @var \Drupal\jsonapi\Revisions\VersionNegotiator */ - protected $versionNegotiatorManager; + protected $versionNegotiator; /** * ResourceVersionRouteEnhancer constructor. * - * @param \Drupal\jsonapi\Revisions\VersionNegotiatorManager $version_negotiator_manager + * @param \Drupal\jsonapi\Revisions\VersionNegotiator $version_negotiator_manager * The version negotiator. */ - public function __construct(VersionNegotiatorManager $version_negotiator_manager) { - $this->versionNegotiatorManager = $version_negotiator_manager; + public function __construct(VersionNegotiator $version_negotiator_manager) { + $this->versionNegotiator = $version_negotiator_manager; } /** @@ -122,9 +121,8 @@ final class ResourceVersionRouteEnhancer implements EnhancerInterface { // Determine if the request is for a collection resource. if ($defaults[RouteObjectInterface::CONTROLLER_NAME] === Routes::CONTROLLER_SERVICE_NAME . ':getCollection') { - // @todo: If VersionNegotiator plugins become a public API, then this logic will need to be moved into the relevant plugins. - $latest_version_identifier = VersionByRel::NEGOTIATOR_NAME . VersionNegotiatorManager::SEPARATOR . VersionByRel::LATEST_VERSION; - $working_copy_identifier = VersionByRel::NEGOTIATOR_NAME . VersionNegotiatorManager::SEPARATOR . VersionByRel::WORKING_COPY; + $latest_version_identifier = 'rel' . VersionNegotiator::SEPARATOR . VersionByRel::LATEST_VERSION; + $working_copy_identifier = 'rel' . VersionNegotiator::SEPARATOR . VersionByRel::WORKING_COPY; // 'latest-version' and 'working-copy' are the only acceptable version // identifiers for a collection resource. if (!in_array($resource_version_identifier, [$latest_version_identifier, $working_copy_identifier])) { @@ -144,7 +142,7 @@ final class ResourceVersionRouteEnhancer implements EnhancerInterface { $entity = $defaults['entity']; /** @var \Drupal\jsonapi\Revisions\VersionNegotiatorInterface $negotiator */ - $resolved_revision = $this->versionNegotiatorManager->getRevision($entity, $resource_version_identifier); + $resolved_revision = $this->versionNegotiator->getRevision($entity, $resource_version_identifier); // Ensure none of the original entity cacheability is lost, especially the // query argument's cache context. $resolved_revision->addCacheableDependency($entity); diff --git a/src/Revisions/VersionById.php b/src/Revisions/VersionById.php new file mode 100644 index 0000000..f3fcf6e --- /dev/null +++ b/src/Revisions/VersionById.php @@ -0,0 +1,24 @@ +setCacheBackend($cache_backend, 'revision_id_negotiator_info_plugins'); + protected $negotiators = []; + + /** + * Adds a version negotiator. + * + * @param \Drupal\jsonapi\Revisions\VersionNegotiatorInterface $version_negotiator + * The version negotiator. + * @param string $negotiator_name + * The name of the negotiation strategy used by the version negotiator. + */ + public function addVersionNegotiator(VersionNegotiatorInterface $version_negotiator, $negotiator_name) { + assert(strpos(get_class($version_negotiator), 'Drupal\jsonapi') === 0, 'Version negotiators are not a public API.'); + $this->negotiators[$negotiator_name] = $version_negotiator; } /** @@ -65,10 +62,11 @@ class VersionNegotiatorManager extends DefaultPluginManager { */ public function getRevision(EntityInterface $entity, $resource_version_identifier) { try { - list($version_negotiator, $version_argument) = explode(VersionNegotiatorManager::SEPARATOR, $resource_version_identifier, 2); - $negotiator = $this->createInstance($version_negotiator); - assert($negotiator instanceof VersionNegotiatorInterface); - return $negotiator->getRevision($entity, $version_argument); + list($version_negotiator_name, $version_argument) = explode(VersionNegotiator::SEPARATOR, $resource_version_identifier, 2); + if (!isset($this->negotiators[$version_negotiator_name])) { + static::throwBadRequestHttpException($resource_version_identifier); + } + return $this->negotiators[$version_negotiator_name]->getRevision($entity, $version_argument); } catch (VersionNotFoundException $exception) { static::throwNotFoundHttpException($entity, $resource_version_identifier); @@ -76,9 +74,6 @@ class VersionNegotiatorManager extends DefaultPluginManager { catch (InvalidVersionIdentifierException $exception) { static::throwBadRequestHttpException($resource_version_identifier); } - catch (PluginException $exception) { - static::throwBadRequestHttpException($resource_version_identifier); - } } /** diff --git a/src/Revisions/VersionNegotiatorInterface.php b/src/Revisions/VersionNegotiatorInterface.php index dc37817..fdc716c 100644 --- a/src/Revisions/VersionNegotiatorInterface.php +++ b/src/Revisions/VersionNegotiatorInterface.php @@ -5,11 +5,9 @@ namespace Drupal\jsonapi\Revisions; use Drupal\Core\Entity\EntityInterface; /** - * Defines the common interface for all version negotiator plugins. + * Defines the common interface for all version negotiators. * - * @see \Drupal\jsonapi\Revisions\Annotation\VersionNegotiator - * @see \Drupal\jsonapi\Revisions\VersionNegotiatorManager - * @see plugin_api + * @see \Drupal\jsonapi\Revisions\VersionNegotiator * @internal */ interface VersionNegotiatorInterface { @@ -25,8 +23,8 @@ interface VersionNegotiatorInterface { * the "latest version" regardless of its ID. It is possible to imagine other * scenarios as well, like fetching a revision based on a date or time. * - * Each VersionNegotiator plugin provides one of these strategies and is able - * to map a version argument to an existing revision. + * Each version negotiator provides one of these strategies and is able to map + * a version argument to an existing revision. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity for which a revision should be resolved. diff --git a/tests/src/Kernel/Plugin/VersionNegotiator/VersionNegotiatorTestBase.php b/tests/src/Kernel/Plugin/VersionNegotiator/VersionNegotiatorTestBase.php index 32dde6f..c3fa1a0 100644 --- a/tests/src/Kernel/Plugin/VersionNegotiator/VersionNegotiatorTestBase.php +++ b/tests/src/Kernel/Plugin/VersionNegotiator/VersionNegotiatorTestBase.php @@ -2,7 +2,7 @@ namespace Drupal\Tests\jsonapi\Kernel\Plugin\VersionNegotiator; -use Drupal\jsonapi\Revisions\VersionNegotiatorManager; +use Drupal\jsonapi\Revisions\VersionNegotiator; use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\Tests\jsonapi\Kernel\JsonapiKernelTestBase; @@ -97,7 +97,7 @@ abstract class VersionNegotiatorTestBase extends JsonapiKernelTestBase { ]); $this->node2->save(); - $this->pluginManager = new VersionNegotiatorManager( + $this->pluginManager = new VersionNegotiator( $this->container->get('container.namespaces'), $this->container->get('cache.discovery'), $this->container->get('module_handler')