upgrades core to 8.4.2

This commit is contained in:
Bachir Soussi Chiadmi
2017-11-14 16:09:54 +01:00
parent bd60eff9b3
commit c2b4e25be4
3504 changed files with 140306 additions and 38684 deletions
@@ -2,7 +2,7 @@
namespace Drupal\rest\Annotation;
use \Drupal\Component\Annotation\Plugin;
use Drupal\Component\Annotation\Plugin;
/**
* Defines a REST resource annotation object.
@@ -0,0 +1,74 @@
<?php
namespace Drupal\rest\EventSubscriber;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Core\Routing\RoutingEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Generates a 'create' route for an entity type if it has a REST POST route.
*/
class EntityResourcePostRouteSubscriber implements EventSubscriberInterface {
/**
* The REST resource config storage.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $resourceConfigStorage;
/**
* Constructs a new EntityResourcePostRouteSubscriber instance.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config');
}
/**
* Provides routes on route rebuild time.
*
* @param \Drupal\Core\Routing\RouteBuildEvent $event
* The route build event.
*/
public function onDynamicRouteEvent(RouteBuildEvent $event) {
$route_collection = $event->getRouteCollection();
$resource_configs = $this->resourceConfigStorage->loadMultiple();
// Iterate over all REST resource config entities.
foreach ($resource_configs as $resource_config) {
// We only care about REST resource config entities for the
// \Drupal\rest\Plugin\rest\resource\EntityResource plugin.
$plugin_id = $resource_config->toArray()['plugin_id'];
if (substr($plugin_id, 0, 6) !== 'entity') {
continue;
}
$entity_type_id = substr($plugin_id, 7);
$rest_post_route_name = "rest.entity.$entity_type_id.POST";
if ($rest_post_route = $route_collection->get($rest_post_route_name)) {
// Create a route for the 'create' link relation type for this entity
// type that uses the same route definition as the REST 'POST' route
// which use that entity type.
// @see \Drupal\Core\Entity\Entity::toUrl()
$entity_create_route_name = "entity.$entity_type_id.create";
$route_collection->add($entity_create_route_name, $rest_post_route);
}
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Priority -10, to run after \Drupal\rest\Routing\ResourceRoutes, which has
// priority 0.
$events[RoutingEvents::DYNAMIC][] = ['onDynamicRouteEvent', -10];
return $events;
}
}
@@ -96,7 +96,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
$route = $route_match->getRouteObject();
$acceptable_request_formats = $route->hasRequirement('_format') ? explode('|', $route->getRequirement('_format')) : [];
$acceptable_content_type_formats = $route->hasRequirement('_content_type_format') ? explode('|', $route->getRequirement('_content_type_format')) : [];
$acceptable_formats = $request->isMethodSafe() ? $acceptable_request_formats : $acceptable_content_type_formats;
$acceptable_formats = $request->isMethodCacheable() ? $acceptable_request_formats : $acceptable_content_type_formats;
$requested_format = $request->getRequestFormat();
$content_type_format = $request->getContentType();
@@ -196,8 +196,9 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Run shortly before \Drupal\Core\EventSubscriber\FinishResponseSubscriber.
$events[KernelEvents::RESPONSE][] = ['onResponse', 5];
// Run before \Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber
// (priority 100), so that Dynamic Page Cache can cache flattened responses.
$events[KernelEvents::RESPONSE][] = ['onResponse', 128];
return $events;
}
@@ -22,7 +22,7 @@ class RestConfigSubscriber implements EventSubscriberInterface {
/**
* Constructs the RestConfigSubscriber.
*
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
* @param \Drupal\Core\Routing\RouteBuilderInterface $router_builder
* The router builder service.
*/
public function __construct(RouteBuilderInterface $router_builder) {
@@ -0,0 +1,55 @@
<?php
namespace Drupal\rest\PathProcessor;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Path processor to maintain BC for entity REST resource URLs from Drupal 8.0.
*/
class PathProcessorEntityResourceBC implements InboundPathProcessorInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Creates a new PathProcessorEntityResourceBC instance.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public function processInbound($path, Request $request) {
if ($request->getMethod() === 'POST' && strpos($path, '/entity/') === 0) {
$parts = explode('/', $path);
$entity_type_id = array_pop($parts);
// Until Drupal 8.3, no entity types specified a link template for the
// 'create' link relation type. As of Drupal 8.3, all core content entity
// types provide this link relation type. This inbound path processor
// provides automatic backwards compatibility: it allows both the old
// default from \Drupal\rest\Plugin\rest\resource\EntityResource, i.e.
// "/entity/{entity_type}" and the link template specified in a particular
// entity type. The former is rewritten to the latter
// specific one if it exists.
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
if ($entity_type->hasLinkTemplate('create')) {
return $entity_type->getLinkTemplate('create');
}
}
return $path;
}
}
@@ -74,7 +74,7 @@ class EntityDeriver implements ContainerDeriverInterface {
$default_uris = [
'canonical' => "/entity/$entity_type_id/" . '{' . $entity_type_id . '}',
'https://www.drupal.org/link-relations/create' => "/entity/$entity_type_id",
'create' => "/entity/$entity_type_id",
];
foreach ($default_uris as $link_relation => $default_uri) {
@@ -100,7 +100,15 @@ abstract class ResourceBase extends PluginBase implements ContainerFactoryPlugin
$definition = $this->getPluginDefinition();
$canonical_path = isset($definition['uri_paths']['canonical']) ? $definition['uri_paths']['canonical'] : '/' . strtr($this->pluginId, ':', '/') . '/{id}';
$create_path = isset($definition['uri_paths']['https://www.drupal.org/link-relations/create']) ? $definition['uri_paths']['https://www.drupal.org/link-relations/create'] : '/' . strtr($this->pluginId, ':', '/');
$create_path = isset($definition['uri_paths']['create']) ? $definition['uri_paths']['create'] : '/' . strtr($this->pluginId, ':', '/');
// BC: the REST module originally created the POST URL for a resource by
// reading the 'https://www.drupal.org/link-relations/create' URI path from
// the plugin annotation. For consistency with entity type definitions, that
// then changed to reading the 'create' URI path. For any REST Resource
// plugins that were using the old mechanism, we continue to support that.
if (!isset($definition['uri_paths']['create']) && isset($definition['uri_paths']['https://www.drupal.org/link-relations/create'])) {
$create_path = $definition['uri_paths']['https://www.drupal.org/link-relations/create'];
}
$route_name = strtr($this->pluginId, ':', '.');
@@ -35,7 +35,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
* deriver = "Drupal\rest\Plugin\Deriver\EntityDeriver",
* uri_paths = {
* "canonical" = "/entity/{entity_type}/{entity}",
* "https://www.drupal.org/link-relations/create" = "/entity/{entity_type}"
* "create" = "/entity/{entity_type}"
* }
* )
*/
@@ -431,8 +431,11 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
* @see https://tools.ietf.org/html/rfc5988#section-5
*/
protected function addLinkHeaders(EntityInterface $entity, Response $response) {
foreach ($entity->getEntityType()->getLinkTemplates() as $relation_name => $link_template) {
if ($definition = $this->linkRelationTypeManager->getDefinition($relation_name, FALSE)) {
foreach ($entity->uriRelationships() as $relation_name) {
if ($this->linkRelationTypeManager->hasDefinition($relation_name)) {
/** @var \Drupal\Core\Http\LinkRelationTypeInterface $link_relation_type */
$link_relation_type = $this->linkRelationTypeManager->createInstance($relation_name);
$generator_url = $entity->toUrl($relation_name)
->setAbsolute(TRUE)
->toString(TRUE);
@@ -440,10 +443,10 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
$response->addCacheableDependency($generator_url);
}
$uri = $generator_url->getGeneratedUrl();
$relationship = $relation_name;
if (!empty($definition['uri'])) {
$relationship = $definition['uri'];
}
$relationship = $link_relation_type->isRegistered()
? $link_relation_type->getRegisteredName()
: $link_relation_type->getExtensionUri();
$link_header = '<' . $uri . '>; rel="' . $relationship . '"';
$response->headers->set('Link', $link_header, FALSE);
@@ -87,7 +87,23 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
protected $authenticationCollector;
/**
* The authentication providers, keyed by ID.
* The authentication providers, like 'cookie' and 'basic_auth'.
*
* @var string[]
*/
protected $authenticationProviderIds;
/**
* The authentication providers' modules, keyed by provider ID.
*
* Authentication providers like 'cookie' and 'basic_auth' are the array
* keys. The array values are the module names, e.g.:
* @code
* ['cookie' => 'user', 'basic_auth' => 'basic_auth']
* @endcode
*
* @deprecated as of 8.4.x, will be removed in before Drupal 9.0.0, see
* https://www.drupal.org/node/2825204.
*
* @var string[]
*/
@@ -115,6 +131,13 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state);
$this->renderer = $renderer;
// $authentication_providers as defined in
// \Drupal\Core\DependencyInjection\Compiler\AuthenticationProviderPass
// and as such it is an array, with authentication providers (cookie,
// basic_auth) as keys and modules providing those as values (user,
// basic_auth).
$this->authenticationProviderIds = array_keys($authentication_providers);
// For BC reasons we keep around authenticationProviders as before.
$this->authenticationProviders = $authentication_providers;
}
@@ -227,7 +250,7 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
* An array to use as value for "#options" in the form element.
*/
public function getAuthOptions() {
return array_combine($this->authenticationProviders, $this->authenticationProviders);
return array_combine($this->authenticationProviderIds, $this->authenticationProviderIds);
}
/**
@@ -407,7 +430,7 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
*/
public function render() {
$build = [];
$build['#markup'] = $this->renderer->executeInRenderContext(new RenderContext(), function() {
$build['#markup'] = $this->renderer->executeInRenderContext(new RenderContext(), function () {
return $this->view->style_plugin->render();
});
@@ -435,7 +458,7 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
$build['#markup'] = ViewsRenderPipelineMarkup::create($build['#markup']);
}
parent::applyDisplayCachablityMetadata($build);
parent::applyDisplayCacheabilityMetadata($build);
return $build;
}
@@ -457,10 +480,14 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
$dependencies = parent::calculateDependencies();
$dependencies += ['module' => []];
$modules = array_map(function ($authentication_provider) {
return $this->authenticationProviders[$authentication_provider];
}, $this->getOption('auth'));
$dependencies['module'] = array_merge($dependencies['module'], $modules);
$dependencies['module'] = array_merge($dependencies['module'], array_filter(array_map(function ($provider) {
// During the update path the provider options might be wrong. This can
// happen when any update function, like block_update_8300() triggers a
// view to be saved.
return isset($this->authenticationProviderIds[$provider])
? $this->authenticationProviderIds[$provider]
: NULL;
}, $this->getOption('auth'))));
return $dependencies;
}
@@ -184,7 +184,7 @@ class DataFieldRow extends RowPluginBase {
* A regular one dimensional array of values.
*/
protected static function extractFromOptionsArray($key, $options) {
return array_map(function($item) use ($key) {
return array_map(function ($item) use ($key) {
return isset($item[$key]) ? $item[$key] : NULL;
}, $options);
}
+31 -18
View File
@@ -11,7 +11,9 @@ use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
/**
* Acts as intermediate request forwarder for resource plugins.
@@ -58,22 +60,20 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
* The response object.
*/
public function handle(RouteMatchInterface $route_match, Request $request) {
$method = strtolower($request->getMethod());
// Symfony is built to transparently map HEAD requests to a GET request. In
// the case of the REST module's RequestHandler though, we essentially have
// our own light-weight routing system on top of the Drupal/symfony routing
// system. So, we have to do the same as what the UrlMatcher does: map HEAD
// requests to the logic for GET. This also guarantees response headers for
// HEAD requests are identical to those for GET requests, because we just
// return a GET response. Response::prepare() will transform it to a HEAD
// response at the very last moment.
// system. So, we have to respect the decision that the routing system made:
// we look not at the request method, but at the route's method. All REST
// routes are guaranteed to have _method set.
// Response::prepare() will transform it to a HEAD response at the very last
// moment.
// @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
// @see \Symfony\Component\Routing\Matcher\UrlMatcher::matchCollection()
// @see \Symfony\Component\HttpFoundation\Response::prepare()
if ($method === 'head') {
$method = 'get';
}
$method = strtolower($route_match->getRouteObject()->getMethods()[0]);
assert(count($route_match->getRouteObject()->getMethods()) === 1);
$resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config');
/** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
@@ -89,19 +89,32 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
$format = $request->getContentType();
$definition = $resource->getPluginDefinition();
// First decode the request data. We can then determine if the
// serialized data was malformed.
try {
if (!empty($definition['serialization_class'])) {
$unserialized = $serializer->deserialize($received, $definition['serialization_class'], $format, ['request_method' => $method]);
}
// If the plugin does not specify a serialization class just decode
// the received data.
else {
$unserialized = $serializer->decode($received, $format, ['request_method' => $method]);
}
$unserialized = $serializer->decode($received, $format, ['request_method' => $method]);
}
catch (UnexpectedValueException $e) {
// If an exception was thrown at this stage, there was a problem
// decoding the data. Throw a 400 http exception.
throw new BadRequestHttpException($e->getMessage());
}
// Then attempt to denormalize if there is a serialization class.
if (!empty($definition['serialization_class'])) {
try {
$unserialized = $serializer->denormalize($unserialized, $definition['serialization_class'], $format, ['request_method' => $method]);
}
// These two serialization exception types mean there was a problem
// with the structure of the decoded data and it's not valid.
catch (UnexpectedValueException $e) {
throw new UnprocessableEntityHttpException($e->getMessage());
}
catch (InvalidArgumentException $e) {
throw new UnprocessableEntityHttpException($e->getMessage());
}
}
}
// Determine the request parameters that should be passed to the resource
@@ -2,7 +2,6 @@
namespace Drupal\rest;
trait ResourceResponseTrait {
/**
@@ -3,16 +3,18 @@
namespace Drupal\rest\Routing;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\RouteSubscriberBase;
use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Core\Routing\RoutingEvents;
use Drupal\rest\Plugin\Type\ResourcePluginManager;
use Drupal\rest\RestResourceConfigInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\RouteCollection;
/**
* Subscriber for REST-style routes.
*/
class ResourceRoutes extends RouteSubscriberBase {
class ResourceRoutes implements EventSubscriberInterface {
/**
* The plugin manager for REST plugins.
@@ -54,18 +56,18 @@ class ResourceRoutes extends RouteSubscriberBase {
/**
* Alters existing routes for a specific collection.
*
* @param \Symfony\Component\Routing\RouteCollection $collection
* The route collection for adding routes.
* @param \Drupal\Core\Routing\RouteBuildEvent $event
* The route build event.
* @return array
*/
protected function alterRoutes(RouteCollection $collection) {
public function onDynamicRouteEvent(RouteBuildEvent $event) {
// Iterate over all enabled REST resource config entities.
/** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */
$resource_configs = $this->resourceConfigStorage->loadMultiple();
foreach ($resource_configs as $resource_config) {
if ($resource_config->status()) {
$resource_routes = $this->getRoutesForResourceConfig($resource_config);
$collection->addCollection($resource_routes);
$event->getRouteCollection()->addCollection($resource_routes);
}
}
}
@@ -131,4 +133,12 @@ class ResourceRoutes extends RouteSubscriberBase {
return $collection;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[RoutingEvents::DYNAMIC] = 'onDynamicRouteEvent';
return $events;
}
}
+6 -4
View File
@@ -306,10 +306,12 @@ abstract class RESTTestBase extends WebTestBase {
return [
'name' => $this->randomMachineName(),
'user_id' => 1,
'field_test_text' => [0 => [
'value' => $this->randomString(),
'format' => 'plain_text',
]],
'field_test_text' => [
0 => [
'value' => $this->randomString(),
'format' => 'plain_text',
],
],
];
case 'config_test':
return [
@@ -0,0 +1,36 @@
<?php
namespace Drupal\rest\Tests\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
/**
* Ensures that update hook is run properly for REST Export config.
*
* @group Update
*/
class RestExportAuthCorrectionUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
__DIR__ . '/../../../tests/fixtures/update/rest-export-with-authentication-correction.php',
];
}
/**
* Ensures that update hook is run for "rest" module.
*/
public function testUpdate() {
$this->runUpdates();
// Get particular view.
$view = \Drupal::entityTypeManager()->getStorage('view')->load('rest_export_with_authorization_correction');
$displays = $view->get('display');
$this->assertIdentical($displays['rest_export_1']['display_options']['auth'], ['cookie'], 'Cookie is used for authentication');
}
}