View source
<?php
namespace Drupal\jsonapi\Routing;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Field\EntityReferenceFieldItemList;
use Drupal\jsonapi\Controller\EntryPoint;
use Drupal\jsonapi\ParamConverter\ResourceTypeConverter;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
use Drupal\jsonapi\Resource\JsonApiDocumentTopLevel;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class Routes implements ContainerInjectionInterface {
const FRONT_CONTROLLER = 'jsonapi.request_handler:handle';
const JSON_API_ROUTE_FLAG_KEY = '_is_jsonapi';
const RESOURCE_TYPE_KEY = 'resource_type';
protected $resourceTypeRepository;
protected $providerIds;
protected $jsonApiBasePath;
public function __construct(ResourceTypeRepositoryInterface $resource_type_repository, array $authentication_providers, $jsonapi_base_path) {
$this->resourceTypeRepository = $resource_type_repository;
$this->providerIds = array_keys($authentication_providers);
$this->jsonApiBasePath = $jsonapi_base_path;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('jsonapi.resource_type.repository'), $container
->getParameter('authentication_providers'), $container
->getParameter('jsonapi.base_path'));
}
public function routes() {
$routes = new RouteCollection();
foreach ($this->resourceTypeRepository
->all() as $resource_type) {
$routes
->addCollection(static::getRoutesForResourceType($resource_type, $this->jsonApiBasePath));
}
$routes
->add('jsonapi.resource_list', static::getEntryPointRoute($this->jsonApiBasePath));
$routes
->addOptions([
'_auth' => $this->providerIds,
]);
$routes
->addDefaults([
static::JSON_API_ROUTE_FLAG_KEY => TRUE,
]);
return $routes;
}
protected static function getRoutesForResourceType(ResourceType $resource_type, $path_prefix) {
if ($resource_type
->isInternal()) {
return new RouteCollection();
}
$routes = new RouteCollection();
$collection_route = new Route('/' . $resource_type
->getPath());
$collection_route
->setMethods($resource_type
->isLocatable() ? [
'GET',
'POST',
] : [
'POST',
]);
$collection_route
->addDefaults([
'serialization_class' => JsonApiDocumentTopLevel::class,
]);
$collection_route
->setRequirement('_csrf_request_header_token', 'TRUE');
$routes
->add(static::getRouteName($resource_type, 'collection'), $collection_route);
$routes
->addCollection(static::getIndividualRoutesForResourceType($resource_type));
foreach ($routes as $route) {
static::addRouteParameter($route, static::RESOURCE_TYPE_KEY, [
'type' => ResourceTypeConverter::PARAM_TYPE_ID,
]);
$route
->addDefaults([
static::RESOURCE_TYPE_KEY => $resource_type
->getTypeName(),
]);
}
$routes
->addDefaults([
RouteObjectInterface::CONTROLLER_NAME => static::FRONT_CONTROLLER,
]);
$routes
->addRequirements([
'_jsonapi_custom_query_parameter_names' => 'TRUE',
]);
$routes
->addPrefix($path_prefix);
return $routes;
}
protected static function getIndividualRoutesForResourceType(ResourceType $resource_type) {
if (!$resource_type
->isLocatable()) {
return new RouteCollection();
}
$routes = new RouteCollection();
$path = $resource_type
->getPath();
$entity_type_id = $resource_type
->getEntityTypeId();
$individual_route = new Route("/{$path}/{{$entity_type_id}}");
$individual_route
->setMethods([
'GET',
'PATCH',
'DELETE',
]);
$individual_route
->addDefaults([
'serialization_class' => JsonApiDocumentTopLevel::class,
]);
$individual_route
->setRequirement('_csrf_request_header_token', 'TRUE');
$routes
->add(static::getRouteName($resource_type, 'individual'), $individual_route);
$related_route = new Route("/{$path}/{{$entity_type_id}}/{related}");
$related_route
->setMethods([
'GET',
]);
$routes
->add(static::getRouteName($resource_type, 'related'), $related_route);
$relationship_route = new Route("/{$path}/{{$entity_type_id}}/relationships/{related}");
$relationship_route
->setMethods([
'GET',
'POST',
'PATCH',
'DELETE',
]);
$relationship_route
->addDefaults([
'_on_relationship' => TRUE,
]);
$relationship_route
->addDefaults([
'serialization_class' => EntityReferenceFieldItemList::class,
]);
$relationship_route
->setRequirement('_csrf_request_header_token', 'TRUE');
$routes
->add(static::getRouteName($resource_type, 'relationship'), $relationship_route);
$routes
->addOptions([
'parameters' => [
$entity_type_id => [
'type' => 'entity:' . $entity_type_id,
],
],
]);
return $routes;
}
protected function getEntryPointRoute($path_prefix) {
$entry_point = new Route("/{$path_prefix}");
$entry_point
->addDefaults([
RouteObjectInterface::CONTROLLER_NAME => EntryPoint::class . '::index',
]);
$entry_point
->setRequirement('_permission', 'access jsonapi resource list');
$entry_point
->setMethods([
'GET',
]);
return $entry_point;
}
protected static function addRouteParameter(Route $route, $name, $parameter) {
$parameters = $route
->getOption('parameters') ?: [];
$parameters[$name] = $parameter;
$route
->setOption('parameters', $parameters);
}
protected static function getRouteName(ResourceType $resource_type, $route_type) {
return sprintf('jsonapi.%s.%s', $resource_type
->getTypeName(), $route_type);
}
public static function getResourceTypeNameFromParameters(array $parameters) {
if (isset($parameters[static::JSON_API_ROUTE_FLAG_KEY]) && $parameters[static::JSON_API_ROUTE_FLAG_KEY]) {
return isset($parameters[static::RESOURCE_TYPE_KEY]) ? $parameters[static::RESOURCE_TYPE_KEY] : NULL;
}
return NULL;
}
}