Update to Drupal 8.0.5. For more information, see https://www.drupal.org/node/2679347
This commit is contained in:
parent
2a9f1f148d
commit
fd3b12cf27
251 changed files with 5439 additions and 957 deletions
|
@ -45,19 +45,24 @@ class EntityResource extends ResourceBase {
|
|||
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
||||
*/
|
||||
public function get(EntityInterface $entity) {
|
||||
if (!$entity->access('view')) {
|
||||
$entity_access = $entity->access('view', NULL, TRUE);
|
||||
if (!$entity_access->isAllowed()) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
foreach ($entity as $field_name => $field) {
|
||||
if (!$field->access('view')) {
|
||||
unset($entity->{$field_name});
|
||||
}
|
||||
}
|
||||
|
||||
$response = new ResourceResponse($entity, 200);
|
||||
// Make the response use the entity's cacheability metadata.
|
||||
// @todo include access cacheability metadata, for the access checks above.
|
||||
$response->addCacheableDependency($entity);
|
||||
$response->addCacheableDependency($entity_access);
|
||||
foreach ($entity as $field_name => $field) {
|
||||
/** @var \Drupal\Core\Field\FieldItemListInterface $field */
|
||||
$field_access = $field->access('view', NULL, TRUE);
|
||||
$response->addCacheableDependency($field_access);
|
||||
|
||||
if (!$field_access->isAllowed()) {
|
||||
$entity->set($field_name, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
@ -110,7 +115,8 @@ class EntityResource extends ResourceBase {
|
|||
// 201 Created responses have an empty body.
|
||||
$url = $entity->urlInfo('canonical', ['absolute' => TRUE])->toString(TRUE);
|
||||
$response = new ResourceResponse(NULL, 201, ['Location' => $url->getGeneratedUrl()]);
|
||||
$response->addCacheableDependency($url);
|
||||
// Responses after creating an entity are not cacheable, so we add no
|
||||
// cacheability metadata here.
|
||||
return $response;
|
||||
}
|
||||
catch (EntityStorageException $e) {
|
||||
|
|
|
@ -135,7 +135,7 @@ class Serializer extends StylePluginBase implements CacheableDependencyInterface
|
|||
else {
|
||||
$content_type = !empty($this->options['formats']) ? reset($this->options['formats']) : 'json';
|
||||
}
|
||||
return $this->serializer->serialize($rows, $content_type);
|
||||
return $this->serializer->serialize($rows, $content_type, ['views_style_plugin' => $this]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,8 +102,8 @@ class RequestHandler implements ContainerAwareInterface {
|
|||
return new Response($content, $e->getStatusCode(), $headers);
|
||||
}
|
||||
|
||||
// Serialize the outgoing data for the response, if available.
|
||||
if ($response instanceof ResourceResponse && $data = $response->getResponseData()) {
|
||||
if ($response instanceof ResourceResponse) {
|
||||
$data = $response->getResponseData();
|
||||
// Serialization can invoke rendering (e.g., generating URLs), but the
|
||||
// serialization API does not provide a mechanism to collect the
|
||||
// bubbleable metadata associated with that (e.g., language and other
|
||||
|
|
|
@ -64,7 +64,17 @@ class ResourceRoutes extends RouteSubscriberBase {
|
|||
*/
|
||||
protected function alterRoutes(RouteCollection $collection) {
|
||||
$routes = array();
|
||||
$enabled_resources = $this->config->get('rest.settings')->get('resources') ?: array();
|
||||
|
||||
// Silently ignore resources that are in the settings but are not defined on
|
||||
// the plugin manager currently. That avoids exceptions when REST module is
|
||||
// enabled before another module that provides the resource plugin specified
|
||||
// in the settings.
|
||||
// @todo Remove in https://www.drupal.org/node/2308745
|
||||
$resources = $this->config->get('rest.settings')->get('resources') ?: array();
|
||||
$enabled_resources = array_intersect_key($resources, $this->manager->getDefinitions());
|
||||
if (count($resources) != count($enabled_resources)) {
|
||||
trigger_error('rest.settings lists resources relying on the following missing plugins: ' . implode(', ', array_keys(array_diff_key($resources, $enabled_resources))));
|
||||
}
|
||||
|
||||
// Iterate over all enabled resource plugins.
|
||||
foreach ($enabled_resources as $id => $enabled_methods) {
|
||||
|
|
|
@ -74,7 +74,7 @@ class AuthTest extends RESTTestBase {
|
|||
* set curl settings for basic authentication.
|
||||
*
|
||||
* @param \Drupal\Core\Url $url
|
||||
* An Url object.
|
||||
* A Url object.
|
||||
* @param string $username
|
||||
* The user name to authenticate with.
|
||||
* @param string $password
|
||||
|
|
|
@ -199,8 +199,8 @@ class CreateTest extends RESTTestBase {
|
|||
}
|
||||
else {
|
||||
// Changed and revision_timestamp fields can never be added.
|
||||
unset($entity->changed);
|
||||
unset($entity->revision_timestamp);
|
||||
$entity->set('changed', NULL);
|
||||
$entity->set('revision_timestamp', NULL);
|
||||
}
|
||||
|
||||
$serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]);
|
||||
|
@ -299,7 +299,7 @@ class CreateTest extends RESTTestBase {
|
|||
}
|
||||
|
||||
// Changed field can never be added.
|
||||
unset($entity->changed);
|
||||
$entity->set('changed', NULL);
|
||||
|
||||
$serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class PageCacheTest extends RESTTestBase {
|
|||
|
||||
// Create an entity programmatically.
|
||||
$entity = $this->entityCreate('entity_test');
|
||||
$entity->set('field_test_text', 'custom cache tag value');
|
||||
$entity->save();
|
||||
// Read it over the REST API.
|
||||
$this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
|
||||
|
@ -40,6 +41,7 @@ class PageCacheTest extends RESTTestBase {
|
|||
$this->assertHeader('x-drupal-cache', 'MISS');
|
||||
$this->assertCacheTag('config:rest.settings');
|
||||
$this->assertCacheTag('entity_test:1');
|
||||
$this->assertCacheTag('entity_test_access:field_test_text');
|
||||
|
||||
// Read it again, should be page-cached now.
|
||||
$this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
|
||||
|
@ -47,6 +49,7 @@ class PageCacheTest extends RESTTestBase {
|
|||
$this->assertHeader('x-drupal-cache', 'HIT');
|
||||
$this->assertCacheTag('config:rest.settings');
|
||||
$this->assertCacheTag('entity_test:1');
|
||||
$this->assertCacheTag('entity_test_access:field_test_text');
|
||||
|
||||
// Trigger a config save which should clear the page cache, so we should get
|
||||
// a cache miss now for the same request.
|
||||
|
@ -56,6 +59,7 @@ class PageCacheTest extends RESTTestBase {
|
|||
$this->assertHeader('x-drupal-cache', 'MISS');
|
||||
$this->assertCacheTag('config:rest.settings');
|
||||
$this->assertCacheTag('entity_test:1');
|
||||
$this->assertCacheTag('entity_test_access:field_test_text');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
namespace Drupal\rest\Tests;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
|
@ -121,4 +123,30 @@ class ResourceTest extends RESTTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a resource with a missing plugin does not cause an exception.
|
||||
*/
|
||||
public function testMissingPlugin() {
|
||||
$settings = array(
|
||||
'entity:nonexisting' => array(
|
||||
'GET' => array(
|
||||
'supported_formats' => array(
|
||||
'hal_json',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
// Attempt to enable the resource.
|
||||
$this->config->set('resources', $settings);
|
||||
$this->config->save();
|
||||
$this->rebuildCache();
|
||||
$this->pass('rest.settings referencing a missing REST resource plugin does not cause an exception.');
|
||||
}
|
||||
catch (PluginNotFoundException $e) {
|
||||
$this->fail('rest.settings referencing a missing REST resource plugin caused an exception.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class UpdateTest extends RESTTestBase {
|
|||
));
|
||||
$patch_entity = entity_create($entity_type, $patch_values);
|
||||
// We don't want to overwrite the UUID.
|
||||
unset($patch_entity->uuid);
|
||||
$patch_entity->set('uuid', NULL);
|
||||
$serialized = $serializer->serialize($patch_entity, $this->defaultFormat, $context);
|
||||
|
||||
// Update the entity over the REST API.
|
||||
|
|
135
core/modules/rest/tests/src/Kernel/RequestHandlerTest.php
Normal file
135
core/modules/rest/tests/src/Kernel/RequestHandlerTest.php
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\rest\Kernel\RequestHandlerTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\rest\Kernel;
|
||||
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\rest\Plugin\ResourceBase;
|
||||
use Drupal\rest\Plugin\Type\ResourcePluginManager;
|
||||
use Drupal\rest\RequestHandler;
|
||||
use Drupal\rest\ResourceResponse;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Test REST RequestHandler controller logic.
|
||||
*
|
||||
* @group rest
|
||||
* @coversDefaultClass \Drupal\rest\RequestHandler
|
||||
*/
|
||||
class RequestHandlerTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\rest\RequestHandler
|
||||
*/
|
||||
protected $requestHandler;
|
||||
|
||||
public static $modules = ['serialization', 'rest'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->requestHandler = new RequestHandler();
|
||||
$this->requestHandler->setContainer($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert some basic handler method logic.
|
||||
*
|
||||
* @covers ::handle
|
||||
*/
|
||||
public function testBaseHandler() {
|
||||
$request = new Request();
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_plugin' => 'restplugin', '_format' => 'json']));
|
||||
|
||||
$resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
|
||||
$resource->get(NULL, $request)
|
||||
->shouldBeCalled();
|
||||
|
||||
// Setup stub plugin manager that will return our plugin.
|
||||
$stub = $this->prophesize(ResourcePluginManager::class);
|
||||
$stub->getInstance(['id' => 'restplugin'])
|
||||
->willReturn($resource->reveal());
|
||||
$this->container->set('plugin.manager.rest', $stub->reveal());
|
||||
|
||||
// Response returns NULL this time because response from plugin is not
|
||||
// a ResourceResponse so it is passed through directly.
|
||||
$response = $this->requestHandler->handle($route_match, $request);
|
||||
$this->assertEquals(NULL, $response);
|
||||
|
||||
// Response will return a ResourceResponse this time.
|
||||
$response = new ResourceResponse([]);
|
||||
$resource->get(NULL, $request)
|
||||
->willReturn($response);
|
||||
$handler_response = $this->requestHandler->handle($route_match, $request);
|
||||
$this->assertEquals($response, $handler_response);
|
||||
|
||||
// We will call the patch method this time.
|
||||
$request->setMethod('PATCH');
|
||||
$response = new ResourceResponse([]);
|
||||
$resource->patch(NULL, $request)
|
||||
->shouldBeCalledTimes(1)
|
||||
->willReturn($response);
|
||||
$handler_response = $this->requestHandler->handle($route_match, $request);
|
||||
$this->assertEquals($response, $handler_response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that given structured data, the request handler will serialize it.
|
||||
*
|
||||
* @dataProvider providerTestSerialization
|
||||
* @covers ::handle
|
||||
*/
|
||||
public function testSerialization($data) {
|
||||
$request = new Request();
|
||||
$route_match = new RouteMatch('test', new Route('/rest/test', ['_plugin' => 'restplugin', '_format' => 'json']));
|
||||
|
||||
$resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
|
||||
|
||||
// Setup stub plugin manager that will return our plugin.
|
||||
$stub = $this->prophesize(ResourcePluginManager::class);
|
||||
$stub->getInstance(['id' => 'restplugin'])
|
||||
->willReturn($resource->reveal());
|
||||
$this->container->set('plugin.manager.rest', $stub->reveal());
|
||||
|
||||
$response = new ResourceResponse($data);
|
||||
$resource->get(NULL, $request)
|
||||
->willReturn($response);
|
||||
$handler_response = $this->requestHandler->handle($route_match, $request);
|
||||
// Content is a serialized version of the data we provided.
|
||||
$this->assertEquals(json_encode($data), $handler_response->getContent());
|
||||
}
|
||||
|
||||
public function providerTestSerialization() {
|
||||
return [
|
||||
[NULL],
|
||||
[''],
|
||||
['string'],
|
||||
['Complex \ string $%^&@ with unicode ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ'],
|
||||
[[]],
|
||||
[['test']],
|
||||
[['test' => 'foobar']],
|
||||
[TRUE],
|
||||
[FALSE],
|
||||
// @todo Not supported. https://www.drupal.org/node/2427811
|
||||
// [new \stdClass()],
|
||||
// [(object) ['test' => 'foobar']],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StubRequestHandlerResourcePlugin extends ResourceBase {
|
||||
|
||||
/** stub methods so they can be prophesied. */
|
||||
function get() {}
|
||||
function patch() {}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\rest\Unit\Plugin\views\style\SerializerTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\rest\Unit\Plugin\views\style;
|
||||
|
||||
use Drupal\rest\Plugin\views\display\RestExport;
|
||||
use Drupal\rest\Plugin\views\style\Serializer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\rest\Plugin\views\style\Serializer
|
||||
* @group rest
|
||||
*/
|
||||
class SerializerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The View instance.
|
||||
*
|
||||
* @var \Drupal\views\ViewExecutable|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* The RestExport display handler.
|
||||
*
|
||||
* @var \Drupal\rest\Plugin\views\display\RestExport|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $displayHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->view = $this->getMockBuilder(ViewExecutable::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
// Make the view result empty so we don't have to mock the row plugin render
|
||||
// call.
|
||||
$this->view->result = [];
|
||||
|
||||
$this->displayHandler = $this->getMockBuilder(RestExport::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->displayHandler->expects($this->any())
|
||||
->method('getContentType')
|
||||
->willReturn('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the symfony serializer receives style plugin from the render() method.
|
||||
*
|
||||
* @covers ::render
|
||||
*/
|
||||
public function testSerializerReceivesOptions() {
|
||||
$mock_serializer = $this->prophesize(SerializerInterface::class);
|
||||
|
||||
// This is the main expectation of the test. We want to make sure the
|
||||
// serializer options are passed to the SerializerInterface object.
|
||||
$mock_serializer->serialize([], 'json', Argument::that(function ($argument) {
|
||||
return isset($argument['views_style_plugin']) && $argument['views_style_plugin'] instanceof Serializer;
|
||||
}))
|
||||
->willReturn()
|
||||
->shouldBeCalled();
|
||||
|
||||
$view_serializer_style = new Serializer([], 'dummy_serializer', [], $mock_serializer->reveal(), ['json', 'xml']);
|
||||
$view_serializer_style->options = ['formats' => ['xml', 'json']];
|
||||
$view_serializer_style->view = $this->view;
|
||||
$view_serializer_style->displayHandler = $this->displayHandler;
|
||||
$view_serializer_style->render();
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue