updated core from 8.4 to 8.5 : bug with login_destination
This commit is contained in:
@@ -7,8 +7,8 @@ package: Web services
|
||||
dependencies:
|
||||
- serialization
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-01-03
|
||||
version: '8.4.4'
|
||||
# Information added by Drupal.org packaging script on 2018-03-07
|
||||
version: '8.5.0'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1515021228
|
||||
datestamp: 1520457825
|
||||
|
||||
@@ -14,7 +14,7 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
function rest_requirements($phase) {
|
||||
$requirements = [];
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.6.0', '>=') && version_compare(PHP_VERSION, '7', '<') && ini_get('always_populate_raw_post_data') != -1) {
|
||||
if ($phase == 'runtime' && PHP_SAPI !== 'cli' && version_compare(PHP_VERSION, '5.6.0', '>=') && version_compare(PHP_VERSION, '7', '<') && ini_get('always_populate_raw_post_data') != -1) {
|
||||
$requirements['always_populate_raw_post_data'] = [
|
||||
'title' => t('always_populate_raw_post_data PHP setting'),
|
||||
'value' => t('Not set to -1.'),
|
||||
|
||||
@@ -43,3 +43,8 @@ services:
|
||||
arguments: ['@entity_type.manager']
|
||||
tags:
|
||||
- { name: path_processor_inbound }
|
||||
rest.route_processor_get_bc:
|
||||
class: \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC
|
||||
arguments: ['%serializer.formats%', '@router.route_provider']
|
||||
tags:
|
||||
- { name: route_processor_outbound }
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
namespace Drupal\rest\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\CacheableResponse;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\rest\ResourceResponseInterface;
|
||||
use Drupal\serialization\Normalizer\CacheableNormalizerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
@@ -79,7 +81,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
||||
* Determines the format to respond in.
|
||||
*
|
||||
* Respects the requested format if one is specified. However, it is common to
|
||||
* forget to specify a request format in case of a POST or PATCH. Rather than
|
||||
* forget to specify a response format in case of a POST or PATCH. Rather than
|
||||
* simply throwing an error, we apply the robustness principle: when POSTing
|
||||
* or PATCHing using a certain format, you probably expect a response in that
|
||||
* same format.
|
||||
@@ -94,43 +96,53 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
||||
*/
|
||||
public function getResponseFormat(RouteMatchInterface $route_match, Request $request) {
|
||||
$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->isMethodCacheable() ? $acceptable_request_formats : $acceptable_content_type_formats;
|
||||
$acceptable_response_formats = $route->hasRequirement('_format') ? explode('|', $route->getRequirement('_format')) : [];
|
||||
$acceptable_request_formats = $route->hasRequirement('_content_type_format') ? explode('|', $route->getRequirement('_content_type_format')) : [];
|
||||
$acceptable_formats = $request->isMethodCacheable() ? $acceptable_response_formats : $acceptable_request_formats;
|
||||
|
||||
$requested_format = $request->getRequestFormat();
|
||||
$content_type_format = $request->getContentType();
|
||||
|
||||
// If an acceptable format is requested, then use that. Otherwise, including
|
||||
// and particularly when the client forgot to specify a format, then use
|
||||
// heuristics to select the format that is most likely expected.
|
||||
if (in_array($requested_format, $acceptable_formats)) {
|
||||
// If an acceptable response format is requested, then use that. Otherwise,
|
||||
// including and particularly when the client forgot to specify a response
|
||||
// format, then use heuristics to select the format that is most likely
|
||||
// expected.
|
||||
if (in_array($requested_format, $acceptable_response_formats, TRUE)) {
|
||||
return $requested_format;
|
||||
}
|
||||
|
||||
// If a request body is present, then use the format corresponding to the
|
||||
// request body's Content-Type for the response, if it's an acceptable
|
||||
// format for the request.
|
||||
elseif (!empty($request->getContent()) && in_array($content_type_format, $acceptable_content_type_formats)) {
|
||||
if (!empty($request->getContent()) && in_array($content_type_format, $acceptable_request_formats, TRUE)) {
|
||||
return $content_type_format;
|
||||
}
|
||||
|
||||
// Otherwise, use the first acceptable format.
|
||||
elseif (!empty($acceptable_formats)) {
|
||||
if (!empty($acceptable_formats)) {
|
||||
return $acceptable_formats[0];
|
||||
}
|
||||
|
||||
// Sometimes, there are no acceptable formats, e.g. DELETE routes.
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a resource response body.
|
||||
*
|
||||
* 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
|
||||
* contexts), so instead, allow those to "leak" and collect them here in
|
||||
* a render context.
|
||||
* During serialization, encoders and normalizers are able to explicitly
|
||||
* bubble cacheability metadata via the 'cacheability' key-value pair in the
|
||||
* received context. This bubbled cacheability metadata will be applied to the
|
||||
* the response.
|
||||
*
|
||||
* In versions of Drupal prior to 8.5, implicit bubbling of cacheability
|
||||
* metadata was allowed because there was no explicit cacheability metadata
|
||||
* bubbling API. To maintain backwards compatibility, we continue to support
|
||||
* this, but support for this will be dropped in Drupal 9.0.0. This is
|
||||
* especially useful when interacting with APIs that implicitly invoke
|
||||
* rendering (for example: generating URLs): this allows those to "leak", and
|
||||
* we collect their bubbled cacheability metadata automatically in a render
|
||||
* context.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
@@ -150,14 +162,25 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
|
||||
|
||||
// If there is data to send, serialize and set it as the response body.
|
||||
if ($data !== NULL) {
|
||||
$serialization_context = [
|
||||
'request' => $request,
|
||||
CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY => new CacheableMetadata(),
|
||||
];
|
||||
|
||||
// @deprecated In Drupal 8.5.0, will be removed before Drupal 9.0.0. Use
|
||||
// explicit cacheability metadata bubbling instead. (The wrapping call to
|
||||
// executeInRenderContext() will be removed before Drupal 9.0.0.)
|
||||
$context = new RenderContext();
|
||||
$output = $this->renderer
|
||||
->executeInRenderContext($context, function () use ($serializer, $data, $format) {
|
||||
return $serializer->serialize($data, $format);
|
||||
->executeInRenderContext($context, function () use ($serializer, $data, $format, $serialization_context) {
|
||||
return $serializer->serialize($data, $format, $serialization_context);
|
||||
});
|
||||
|
||||
if ($response instanceof CacheableResponseInterface && !$context->isEmpty()) {
|
||||
$response->addCacheableDependency($context->pop());
|
||||
if ($response instanceof CacheableResponseInterface) {
|
||||
if (!$context->isEmpty()) {
|
||||
@trigger_error('Implicit cacheability metadata bubbling (onto the global render context) in normalizers is deprecated since Drupal 8.5.0 and will be removed in Drupal 9.0.0. Use the "cacheability" serialization context instead, for explicit cacheability metadata bubbling. See https://www.drupal.org/node/2918937', E_USER_DEPRECATED);
|
||||
$response->addCacheableDependency($context->pop());
|
||||
}
|
||||
$response->addCacheableDependency($serialization_context[CacheableNormalizerInterface::SERIALIZATION_CONTEXT_CACHEABILITY]);
|
||||
}
|
||||
|
||||
$response->setContent($output);
|
||||
|
||||
@@ -37,6 +37,7 @@ class RestConfigSubscriber implements EventSubscriberInterface {
|
||||
*/
|
||||
public function onSave(ConfigCrudEvent $event) {
|
||||
$saved_config = $event->getConfig();
|
||||
// @see \Drupal\rest\Plugin\rest\resource\EntityResource::permissions()
|
||||
if ($saved_config->getName() === 'rest.settings' && $event->isChanged('bc_entity_resource_permissions')) {
|
||||
$this->routerBuilder->setRebuildNeeded();
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ class EntityDeriver implements ContainerDeriverInterface {
|
||||
if (!isset($this->derivatives)) {
|
||||
// Add in the default plugin configuration and the resource type.
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
if ($entity_type->isInternal()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->derivatives[$entity_type_id] = [
|
||||
'id' => 'entity:' . $entity_type_id,
|
||||
'entity_type' => $entity_type_id,
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Drupal\rest\Plugin;
|
||||
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\PluginBase;
|
||||
use Drupal\Core\Routing\BcRoute;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
@@ -114,29 +115,24 @@ abstract class ResourceBase extends PluginBase implements ContainerFactoryPlugin
|
||||
|
||||
$methods = $this->availableMethods();
|
||||
foreach ($methods as $method) {
|
||||
$route = $this->getBaseRoute($canonical_path, $method);
|
||||
$path = $method === 'POST'
|
||||
? $create_path
|
||||
: $canonical_path;
|
||||
$route = $this->getBaseRoute($path, $method);
|
||||
|
||||
switch ($method) {
|
||||
case 'POST':
|
||||
$route->setPath($create_path);
|
||||
$collection->add("$route_name.$method", $route);
|
||||
break;
|
||||
// Note that '_format' and '_content_type_format' route requirements are
|
||||
// added in ResourceRoutes::getRoutesForResourceConfig().
|
||||
$collection->add("$route_name.$method", $route);
|
||||
|
||||
case 'GET':
|
||||
case 'HEAD':
|
||||
// Restrict GET and HEAD requests to the media type specified in the
|
||||
// HTTP Accept headers.
|
||||
foreach ($this->serializerFormats as $format_name) {
|
||||
// Expose one route per available format.
|
||||
$format_route = clone $route;
|
||||
$format_route->addRequirements(['_format' => $format_name]);
|
||||
$collection->add("$route_name.$method.$format_name", $format_route);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$collection->add("$route_name.$method", $route);
|
||||
break;
|
||||
// BC: the REST module originally created per-format GET routes, instead
|
||||
// of a single route. To minimize the surface of this BC layer, this uses
|
||||
// route definitions that are as empty as possible, plus an outbound route
|
||||
// processor.
|
||||
// @see \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC
|
||||
if ($method === 'GET' || $method === 'HEAD') {
|
||||
foreach ($this->serializerFormats as $format_name) {
|
||||
$collection->add("$route_name.$method.$format_name", (new BcRoute())->setRequirement('_format', $format_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\TypedData\PrimitiveInterface;
|
||||
use Drupal\Core\Http\Exception\CacheableAccessDeniedHttpException;
|
||||
use Drupal\rest\Plugin\ResourceBase;
|
||||
use Drupal\rest\ResourceResponse;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -122,7 +122,7 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
|
||||
public function get(EntityInterface $entity) {
|
||||
$entity_access = $entity->access('view', NULL, TRUE);
|
||||
if (!$entity_access->isAllowed()) {
|
||||
throw new AccessDeniedHttpException($entity_access->getReason() ?: $this->generateFallbackAccessDeniedMessage($entity, 'view'));
|
||||
throw new CacheableAccessDeniedHttpException($entity_access, $entity_access->getReason() ?: $this->generateFallbackAccessDeniedMessage($entity, 'view'));
|
||||
}
|
||||
|
||||
$response = new ResourceResponse($entity, 200);
|
||||
@@ -201,41 +201,6 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values from the field item list casted to the correct type.
|
||||
*
|
||||
* Values are casted to the correct type so we can determine whether or not
|
||||
* something has changed. REST formats such as JSON support typed data but
|
||||
* Drupal's database API will return values as strings. Currently, only
|
||||
* primitive data types know how to cast their values to the correct type.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldItemListInterface $field_item_list
|
||||
* The field item list to retrieve its data from.
|
||||
*
|
||||
* @return mixed[][]
|
||||
* The values from the field item list casted to the correct type. The array
|
||||
* of values returned is a multidimensional array keyed by delta and the
|
||||
* property name.
|
||||
*/
|
||||
protected function getCastedValueFromFieldItemList(FieldItemListInterface $field_item_list) {
|
||||
$value = $field_item_list->getValue();
|
||||
|
||||
foreach ($value as $delta => $field_item_value) {
|
||||
/** @var \Drupal\Core\Field\FieldItemInterface $field_item */
|
||||
$field_item = $field_item_list->get($delta);
|
||||
$properties = $field_item->getProperties(TRUE);
|
||||
// Foreach field value we check whether we know the underlying property.
|
||||
// If we exists we try to cast the value.
|
||||
foreach ($field_item_value as $property_name => $property_value) {
|
||||
if (isset($properties[$property_name]) && ($property = $field_item->get($property_name)) && $property instanceof PrimitiveInterface) {
|
||||
$value[$delta][$property_name] = $property->getCastedValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to entity PATCH requests.
|
||||
*
|
||||
@@ -262,38 +227,18 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
|
||||
throw new AccessDeniedHttpException($entity_access->getReason() ?: $this->generateFallbackAccessDeniedMessage($entity, 'update'));
|
||||
}
|
||||
|
||||
// Overwrite the received properties.
|
||||
$entity_keys = $entity->getEntityType()->getKeys();
|
||||
// Overwrite the received fields.
|
||||
foreach ($entity->_restSubmittedFields as $field_name) {
|
||||
$field = $entity->get($field_name);
|
||||
|
||||
// Entity key fields need special treatment: together they uniquely
|
||||
// identify the entity. Therefore it does not make sense to modify any of
|
||||
// them. However, rather than throwing an error, we just ignore them as
|
||||
// long as their specified values match their current values.
|
||||
if (in_array($field_name, $entity_keys, TRUE)) {
|
||||
// @todo Work around the wrong assumption that entity keys need special
|
||||
// treatment, when only read-only fields need it.
|
||||
// This will be fixed in https://www.drupal.org/node/2824851.
|
||||
if ($entity->getEntityTypeId() == 'comment' && $field_name == 'status' && !$original_entity->get($field_name)->access('edit')) {
|
||||
throw new AccessDeniedHttpException("Access denied on updating field '$field_name'.");
|
||||
}
|
||||
|
||||
// Unchanged values for entity keys don't need access checking.
|
||||
if ($this->getCastedValueFromFieldItemList($original_entity->get($field_name)) === $this->getCastedValueFromFieldItemList($entity->get($field_name))) {
|
||||
continue;
|
||||
}
|
||||
// It is not possible to set the language to NULL as it is automatically
|
||||
// re-initialized. As it must not be empty, skip it if it is.
|
||||
elseif (isset($entity_keys['langcode']) && $field_name === $entity_keys['langcode'] && $field->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// It is not possible to set the language to NULL as it is automatically
|
||||
// re-initialized. As it must not be empty, skip it if it is.
|
||||
// @todo Remove in https://www.drupal.org/project/drupal/issues/2933408.
|
||||
if ($entity->getEntityType()->hasKey('langcode') && $field_name === $entity->getEntityType()->getKey('langcode') && $field->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$original_entity->get($field_name)->access('edit')) {
|
||||
throw new AccessDeniedHttpException("Access denied on updating field '$field_name'.");
|
||||
if ($this->checkPatchFieldAccess($original_entity->get($field_name), $field)) {
|
||||
$original_entity->set($field_name, $field->getValue());
|
||||
}
|
||||
$original_entity->set($field_name, $field->getValue());
|
||||
}
|
||||
|
||||
// Validate the received data before saving.
|
||||
@@ -310,6 +255,49 @@ class EntityResource extends ResourceBase implements DependentPluginInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given field should be PATCHed.
|
||||
*
|
||||
* @param \Drupal\Core\Field\FieldItemListInterface $original_field
|
||||
* The original (stored) value for the field.
|
||||
* @param \Drupal\Core\Field\FieldItemListInterface $received_field
|
||||
* The received value for the field.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the field should be PATCHed or not.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown when the user sending the request is not allowed to update the
|
||||
* field. Only thrown when the user could not abuse this information to
|
||||
* determine the stored value.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function checkPatchFieldAccess(FieldItemListInterface $original_field, FieldItemListInterface $received_field) {
|
||||
// If the user is allowed to edit the field, it is always safe to set the
|
||||
// received value. We may be setting an unchanged value, but that is ok.
|
||||
if ($original_field->access('edit')) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The user might not have access to edit the field, but still needs to
|
||||
// submit the current field value as part of the PATCH request. For
|
||||
// example, the entity keys required by denormalizers. Therefore, if the
|
||||
// received value equals the stored value, return FALSE without throwing an
|
||||
// exception. But only for fields that the user has access to view, because
|
||||
// the user has no legitimate way of knowing the current value of fields
|
||||
// that they are not allowed to view, and we must not make the presence or
|
||||
// absence of a 403 response a way to find that out.
|
||||
if ($original_field->access('view') && $original_field->equals($received_field)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// It's helpful and safe to let the user know when they are not allowed to
|
||||
// update a field.
|
||||
$field_name = $received_field->getName();
|
||||
throw new AccessDeniedHttpException("Access denied on updating field '$field_name'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to entity DELETE requests.
|
||||
*
|
||||
|
||||
@@ -70,7 +70,7 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $mimeType;
|
||||
protected $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
@@ -109,6 +109,13 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
*/
|
||||
protected $authenticationProviders;
|
||||
|
||||
/**
|
||||
* The serialization format providers, keyed by format.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $formatProviders;
|
||||
|
||||
/**
|
||||
* Constructs a RestExport object.
|
||||
*
|
||||
@@ -126,8 +133,10 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
* The renderer.
|
||||
* @param string[] $authentication_providers
|
||||
* The authentication providers, keyed by ID.
|
||||
* @param string[] $serializer_format_providers
|
||||
* The serialization format providers, keyed by format.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer, array $authentication_providers) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteProviderInterface $route_provider, StateInterface $state, RendererInterface $renderer, array $authentication_providers, array $serializer_format_providers) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $route_provider, $state);
|
||||
|
||||
$this->renderer = $renderer;
|
||||
@@ -139,6 +148,7 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
$this->authenticationProviderIds = array_keys($authentication_providers);
|
||||
// For BC reasons we keep around authenticationProviders as before.
|
||||
$this->authenticationProviders = $authentication_providers;
|
||||
$this->formatProviders = $serializer_format_providers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,8 +162,8 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('state'),
|
||||
$container->get('renderer'),
|
||||
$container->getParameter('authentication_providers')
|
||||
|
||||
$container->getParameter('authentication_providers'),
|
||||
$container->getParameter('serializer.format_providers')
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -162,21 +172,22 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
public function initDisplay(ViewExecutable $view, array &$display, array &$options = NULL) {
|
||||
parent::initDisplay($view, $display, $options);
|
||||
|
||||
$request_content_type = $this->view->getRequest()->getRequestFormat();
|
||||
// Only use the requested content type if it's not 'html'. If it is then
|
||||
// default to 'json' to aid debugging.
|
||||
// @todo Remove the need for this when we have better content negotiation.
|
||||
if ($request_content_type != 'html') {
|
||||
$this->setContentType($request_content_type);
|
||||
}
|
||||
// If the requested content type is 'html' and the default 'json' is not
|
||||
// selected as a format option in the view display, fallback to the first
|
||||
// format in the array.
|
||||
elseif (!empty($options['style']['options']['formats']) && !isset($options['style']['options']['formats'][$this->getContentType()])) {
|
||||
$this->setContentType(reset($options['style']['options']['formats']));
|
||||
// If the default 'json' format is not selected as a format option in the
|
||||
// view display, fallback to the first format available for the default.
|
||||
if (!empty($options['style']['options']['formats']) && !isset($options['style']['options']['formats'][$this->getContentType()])) {
|
||||
$default_format = reset($options['style']['options']['formats']);
|
||||
$this->setContentType($default_format);
|
||||
}
|
||||
|
||||
$this->setMimeType($this->view->getRequest()->getMimeType($this->contentType));
|
||||
// Only use the requested content type if it's not 'html'. This allows
|
||||
// still falling back to the default for things like views preview.
|
||||
$request_content_type = $this->view->getRequest()->getRequestFormat();
|
||||
|
||||
if ($request_content_type !== 'html') {
|
||||
$this->setContentType($request_content_type);
|
||||
}
|
||||
|
||||
$this->setMimeType($this->view->getRequest()->getMimeType($this->getContentType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,17 +361,21 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
|
||||
if ($route = $collection->get("view.$view_id.$display_id")) {
|
||||
$style_plugin = $this->getPlugin('style');
|
||||
// REST exports should only respond to get methods.
|
||||
|
||||
// REST exports should only respond to GET methods.
|
||||
$route->setMethods(['GET']);
|
||||
|
||||
// Format as a string using pipes as a delimiter.
|
||||
if ($formats = $style_plugin->getFormats()) {
|
||||
// Allow a REST Export View to be returned with an HTML-only accept
|
||||
// format. That allows browsers or other non-compliant systems to access
|
||||
// the view, as it is unlikely to have a conflicting HTML representation
|
||||
// anyway.
|
||||
$route->setRequirement('_format', implode('|', $formats + ['html']));
|
||||
$formats = $style_plugin->getFormats();
|
||||
|
||||
// If there are no configured formats, add all formats that serialization
|
||||
// is known to support.
|
||||
if (!$formats) {
|
||||
$formats = $this->getFormatOptions();
|
||||
}
|
||||
|
||||
// Format as a string using pipes as a delimiter.
|
||||
$route->setRequirement('_format', implode('|', $formats));
|
||||
|
||||
// Add authentication to the route if it was set. If no authentication was
|
||||
// set, the default authentication will be used, which is cookie based by
|
||||
// default.
|
||||
@@ -444,15 +459,15 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
$build['#suffix'] = '</pre>';
|
||||
unset($build['#markup']);
|
||||
}
|
||||
elseif ($this->view->getRequest()->getFormat($this->view->element['#content_type']) !== 'html') {
|
||||
// This display plugin is primarily for returning non-HTML formats.
|
||||
// However, we still invoke the renderer to collect cacheability metadata.
|
||||
// Because the renderer is designed for HTML rendering, it filters
|
||||
// #markup for XSS unless it is already known to be safe, but that filter
|
||||
// only works for HTML. Therefore, we mark the contents as safe to bypass
|
||||
// the filter. So long as we are returning this in a non-HTML response
|
||||
// (checked above), this is safe, because an XSS attack only works when
|
||||
// executed by an HTML agent.
|
||||
else {
|
||||
// This display plugin is for returning non-HTML formats. However, we
|
||||
// still invoke the renderer to collect cacheability metadata. Because the
|
||||
// renderer is designed for HTML rendering, it filters #markup for XSS
|
||||
// unless it is already known to be safe, but that filter only works for
|
||||
// HTML. Therefore, we mark the contents as safe to bypass the filter. So
|
||||
// long as we are returning this in a non-HTML response,
|
||||
// this is safe, because an XSS attack only works when executed by an HTML
|
||||
// agent.
|
||||
// @todo Decide how to support non-HTML in the render API in
|
||||
// https://www.drupal.org/node/2501313.
|
||||
$build['#markup'] = ViewsRenderPipelineMarkup::create($build['#markup']);
|
||||
@@ -492,4 +507,15 @@ class RestExport extends PathPluginBase implements ResponseDisplayPluginInterfac
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of format options.
|
||||
*
|
||||
* @return string[]
|
||||
* An array of format options. Both key and value are the same.
|
||||
*/
|
||||
protected function getFormatOptions() {
|
||||
$formats = array_keys($this->formatProviders);
|
||||
return array_combine($formats, $formats);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,64 +2,103 @@
|
||||
|
||||
namespace Drupal\rest;
|
||||
|
||||
use Drupal\Component\Utility\ArgumentsResolver;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||
use Drupal\rest\Plugin\ResourceInterface;
|
||||
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;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Acts as intermediate request forwarder for resource plugins.
|
||||
*
|
||||
* @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber
|
||||
*/
|
||||
class RequestHandler implements ContainerAwareInterface, ContainerInjectionInterface {
|
||||
|
||||
use ContainerAwareTrait;
|
||||
class RequestHandler implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The resource configuration storage.
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $resourceStorage;
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface|\Symfony\Component\Serializer\Encoder\DecoderInterface
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* Creates a new RequestHandler instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
|
||||
* The resource configuration storage.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface|\Symfony\Component\Serializer\Encoder\DecoderInterface $serializer
|
||||
* The serializer.
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $entity_storage) {
|
||||
$this->resourceStorage = $entity_storage;
|
||||
public function __construct(ConfigFactoryInterface $config_factory, SerializerInterface $serializer) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('entity_type.manager')->getStorage('rest_resource_config'));
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('serializer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a web API request.
|
||||
* Handles a REST API request.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The HTTP request object.
|
||||
* @param \Drupal\rest\RestResourceConfigInterface $_rest_resource_config
|
||||
* REST resource config entity ID.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* The response object.
|
||||
* @return \Drupal\rest\ResourceResponseInterface|\Symfony\Component\HttpFoundation\Response
|
||||
* The REST resource response.
|
||||
*/
|
||||
public function handle(RouteMatchInterface $route_match, Request $request) {
|
||||
public function handle(RouteMatchInterface $route_match, Request $request, RestResourceConfigInterface $_rest_resource_config) {
|
||||
$response = $this->delegateToRestResourcePlugin($route_match, $request, $_rest_resource_config->getResourcePlugin());
|
||||
|
||||
if ($response instanceof CacheableResponseInterface) {
|
||||
$response->addCacheableDependency($_rest_resource_config);
|
||||
// Add global rest settings config's cache tag, for BC flags.
|
||||
// @see \Drupal\rest\Plugin\rest\resource\EntityResource::permissions()
|
||||
// @see \Drupal\rest\EventSubscriber\RestConfigSubscriber
|
||||
// @todo Remove in https://www.drupal.org/node/2893804
|
||||
$response->addCacheableDependency($this->configFactory->get('rest.settings'));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the normalized HTTP request method of the matched route.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
*
|
||||
* @return string
|
||||
* The normalized HTTP request method.
|
||||
*/
|
||||
protected static function getNormalizedRequestMethod(RouteMatchInterface $route_match) {
|
||||
// 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
|
||||
@@ -73,18 +112,34 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
|
||||
// @see \Symfony\Component\HttpFoundation\Response::prepare()
|
||||
$method = strtolower($route_match->getRouteObject()->getMethods()[0]);
|
||||
assert(count($route_match->getRouteObject()->getMethods()) === 1);
|
||||
return $method;
|
||||
}
|
||||
|
||||
$resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config');
|
||||
/** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
|
||||
$resource_config = $this->resourceStorage->load($resource_config_id);
|
||||
$resource = $resource_config->getResourcePlugin();
|
||||
|
||||
/**
|
||||
* Deserializes request body, if any.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The HTTP request object.
|
||||
* @param \Drupal\rest\Plugin\ResourceInterface $resource
|
||||
* The REST resource plugin.
|
||||
*
|
||||
* @return array|null
|
||||
* An object normalization, ikf there is a valid request body. NULL if there
|
||||
* is no request body.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
|
||||
* Thrown if the request body cannot be decoded.
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException
|
||||
* Thrown if the request body cannot be denormalized.
|
||||
*/
|
||||
protected function deserialize(RouteMatchInterface $route_match, Request $request, ResourceInterface $resource) {
|
||||
// Deserialize incoming data if available.
|
||||
/** @var \Symfony\Component\Serializer\SerializerInterface $serializer */
|
||||
$serializer = $this->container->get('serializer');
|
||||
$received = $request->getContent();
|
||||
$unserialized = NULL;
|
||||
if (!empty($received)) {
|
||||
$method = static::getNormalizedRequestMethod($route_match);
|
||||
$format = $request->getContentType();
|
||||
|
||||
$definition = $resource->getPluginDefinition();
|
||||
@@ -92,7 +147,7 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
|
||||
// First decode the request data. We can then determine if the
|
||||
// serialized data was malformed.
|
||||
try {
|
||||
$unserialized = $serializer->decode($received, $format, ['request_method' => $method]);
|
||||
$unserialized = $this->serializer->decode($received, $format, ['request_method' => $method]);
|
||||
}
|
||||
catch (UnexpectedValueException $e) {
|
||||
// If an exception was thrown at this stage, there was a problem
|
||||
@@ -103,7 +158,7 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
|
||||
// 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]);
|
||||
$unserialized = $this->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.
|
||||
@@ -116,8 +171,125 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
|
||||
}
|
||||
}
|
||||
|
||||
return $unserialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates an incoming request to the appropriate REST resource plugin.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The HTTP request object.
|
||||
* @param \Drupal\rest\Plugin\ResourceInterface $resource
|
||||
* The REST resource plugin.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response|\Drupal\rest\ResourceResponseInterface
|
||||
* The REST resource response.
|
||||
*/
|
||||
protected function delegateToRestResourcePlugin(RouteMatchInterface $route_match, Request $request, ResourceInterface $resource) {
|
||||
$unserialized = $this->deserialize($route_match, $request, $resource);
|
||||
$method = static::getNormalizedRequestMethod($route_match);
|
||||
|
||||
// Determine the request parameters that should be passed to the resource
|
||||
// plugin.
|
||||
$argument_resolver = $this->createArgumentResolver($route_match, $unserialized, $request);
|
||||
try {
|
||||
$arguments = $argument_resolver->getArguments([$resource, $method]);
|
||||
}
|
||||
catch (\RuntimeException $exception) {
|
||||
@trigger_error('Passing in arguments the legacy way is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Provide the right parameter names in the method, similar to controllers. See https://www.drupal.org/node/2894819', E_USER_DEPRECATED);
|
||||
$arguments = $this->getLegacyParameters($route_match, $unserialized, $request);
|
||||
}
|
||||
|
||||
// Invoke the operation on the resource plugin.
|
||||
return call_user_func_array([$resource, $method], $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an argument resolver, containing all REST parameters.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
* @param mixed $unserialized
|
||||
* The unserialized data.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request.
|
||||
*
|
||||
* @return \Drupal\Component\Utility\ArgumentsResolver
|
||||
* An instance of the argument resolver containing information like the
|
||||
* 'entity' we process and the 'unserialized' content from the request body.
|
||||
*/
|
||||
protected function createArgumentResolver(RouteMatchInterface $route_match, $unserialized, Request $request) {
|
||||
$route = $route_match->getRouteObject();
|
||||
|
||||
// Defaults for the parameters defined on the route object need to be added
|
||||
// to the raw arguments.
|
||||
$raw_route_arguments = $route_match->getRawParameters()->all() + $route->getDefaults();
|
||||
|
||||
$route_arguments = $route_match->getParameters()->all();
|
||||
$upcasted_route_arguments = $route_arguments;
|
||||
|
||||
// For request methods that have request bodies, ResourceInterface plugin
|
||||
// methods historically receive the unserialized request body as the N+1th
|
||||
// method argument, where N is the number of route parameters specified on
|
||||
// the accompanying route. To be able to use the argument resolver, which is
|
||||
// not based on position but on name and typehint, specify commonly used
|
||||
// names here. Similarly, those methods receive the original stored object
|
||||
// as the first method argument.
|
||||
|
||||
$route_arguments_entity = NULL;
|
||||
// Try to find a parameter which is an entity.
|
||||
foreach ($route_arguments as $value) {
|
||||
if ($value instanceof EntityInterface) {
|
||||
$route_arguments_entity = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($request->getMethod(), ['PATCH', 'POST'], TRUE)) {
|
||||
$upcasted_route_arguments['entity'] = $unserialized;
|
||||
$upcasted_route_arguments['data'] = $unserialized;
|
||||
$upcasted_route_arguments['unserialized'] = $unserialized;
|
||||
$upcasted_route_arguments['original_entity'] = $route_arguments_entity;
|
||||
}
|
||||
else {
|
||||
$upcasted_route_arguments['entity'] = $route_arguments_entity;
|
||||
}
|
||||
|
||||
// Parameters which are not defined on the route object, but still are
|
||||
// essential for access checking are passed as wildcards to the argument
|
||||
// resolver.
|
||||
$wildcard_arguments = [$route, $route_match];
|
||||
$wildcard_arguments[] = $request;
|
||||
if (isset($unserialized)) {
|
||||
$wildcard_arguments[] = $unserialized;
|
||||
}
|
||||
|
||||
return new ArgumentsResolver($raw_route_arguments, $upcasted_route_arguments, $wildcard_arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the parameter usable without an argument resolver.
|
||||
*
|
||||
* This creates an list of parameters in a statically defined order.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match
|
||||
* @param mixed $unserialized
|
||||
* The unserialized data.
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request.
|
||||
*
|
||||
* @deprecated in Drupal 8.4.0, will be removed before Drupal 9.0.0. Use the
|
||||
* argument resolver method instead, see ::createArgumentResolver().
|
||||
*
|
||||
* @see https://www.drupal.org/node/2894819
|
||||
*
|
||||
* @return array
|
||||
* An array of parameters.
|
||||
*/
|
||||
protected function getLegacyParameters(RouteMatchInterface $route_match, $unserialized, Request $request) {
|
||||
$route_parameters = $route_match->getParameters();
|
||||
$parameters = [];
|
||||
// Filter out all internal parameters starting with "_".
|
||||
@@ -127,15 +299,7 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the operation on the resource plugin.
|
||||
$response = call_user_func_array([$resource, $method], array_merge($parameters, [$unserialized, $request]));
|
||||
|
||||
if ($response instanceof CacheableResponseInterface) {
|
||||
// Add rest config's cache tags.
|
||||
$response->addCacheableDependency($resource_config);
|
||||
}
|
||||
|
||||
return $response;
|
||||
return array_merge($parameters, [$unserialized, $request]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use Drupal\Core\DependencyInjection\ServiceProviderInterface;
|
||||
use Drupal\rest\LinkManager\LinkManager;
|
||||
use Drupal\rest\LinkManager\RelationLinkManager;
|
||||
use Drupal\rest\LinkManager\TypeLinkManager;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
@@ -28,21 +28,21 @@ class RestServiceProvider implements ServiceProviderInterface {
|
||||
// @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0.
|
||||
// Use hal.link_manager instead.
|
||||
// @see https://www.drupal.org/node/2830467
|
||||
$service_definition = new DefinitionDecorator(new Reference('hal.link_manager'));
|
||||
$service_definition = new ChildDefinition(new Reference('hal.link_manager'));
|
||||
$service_definition->setClass(LinkManager::class);
|
||||
$container->setDefinition('rest.link_manager', $service_definition);
|
||||
|
||||
// @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0.
|
||||
// Use hal.link_manager.type instead.
|
||||
// @see https://www.drupal.org/node/2830467
|
||||
$service_definition = new DefinitionDecorator(new Reference('hal.link_manager.type'));
|
||||
$service_definition = new ChildDefinition(new Reference('hal.link_manager.type'));
|
||||
$service_definition->setClass(TypeLinkManager::class);
|
||||
$container->setDefinition('rest.link_manager.type', $service_definition);
|
||||
|
||||
// @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0.
|
||||
// Use hal.link_manager.relation instead.
|
||||
// @see https://www.drupal.org/node/2830467
|
||||
$service_definition = new DefinitionDecorator(new Reference('hal.link_manager.relation'));
|
||||
$service_definition = new ChildDefinition(new Reference('hal.link_manager.relation'));
|
||||
$service_definition->setClass(RelationLinkManager::class);
|
||||
$container->setDefinition('rest.link_manager.relation', $service_definition);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\rest\RouteProcessor;
|
||||
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Processes the BC REST routes, to ensure old route names continue to work.
|
||||
*/
|
||||
class RestResourceGetRouteProcessorBC implements OutboundRouteProcessorInterface {
|
||||
|
||||
/**
|
||||
* The available serialization formats.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $serializerFormats = [];
|
||||
|
||||
/**
|
||||
* The route provider.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* Constructs a RestResourceGetRouteProcessorBC object.
|
||||
*
|
||||
* @param string[] $serializer_formats
|
||||
* The available serialization formats.
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider.
|
||||
*/
|
||||
public function __construct(array $serializer_formats, RouteProviderInterface $route_provider) {
|
||||
$this->serializerFormats = $serializer_formats;
|
||||
$this->routeProvider = $route_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processOutbound($route_name, Route $route, array &$parameters, BubbleableMetadata $bubbleable_metadata = NULL) {
|
||||
$route_name_parts = explode('.', $route_name);
|
||||
// BC: the REST module originally created per-format GET routes, instead
|
||||
// of a single route. To minimize the surface of this BC layer, this uses
|
||||
// route definitions that are as empty as possible, plus an outbound route
|
||||
// processor.
|
||||
// @see \Drupal\rest\Plugin\ResourceBase::routes()
|
||||
if ($route_name_parts[0] === 'rest' && $route_name_parts[count($route_name_parts) - 2] === 'GET' && in_array($route_name_parts[count($route_name_parts) - 1], $this->serializerFormats, TRUE)) {
|
||||
array_pop($route_name_parts);
|
||||
$redirected_route_name = implode('.', $route_name_parts);
|
||||
@trigger_error(sprintf("The '%s' route is deprecated since version 8.5.x and will be removed in 9.0.0. Use the '%s' route instead.", $route_name, $redirected_route_name), E_USER_DEPRECATED);
|
||||
static::overwriteRoute($route, $this->routeProvider->getRouteByName($redirected_route_name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites one route's metadata with the other's.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $target_route
|
||||
* The route whose metadata to overwrite.
|
||||
* @param \Symfony\Component\Routing\Route $source_route
|
||||
* The route whose metadata to read from.
|
||||
*
|
||||
* @see \Symfony\Component\Routing\Route
|
||||
*/
|
||||
protected static function overwriteRoute(Route $target_route, Route $source_route) {
|
||||
$target_route->setPath($source_route->getPath());
|
||||
$target_route->setDefaults($source_route->getDefaults());
|
||||
$target_route->setRequirements($source_route->getRequirements());
|
||||
$target_route->setOptions($source_route->getOptions());
|
||||
$target_route->setHost($source_route->getHost());
|
||||
$target_route->setSchemes($source_route->getSchemes());
|
||||
$target_route->setMethods($source_route->getMethods());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -92,8 +92,11 @@ class ResourceRoutes implements EventSubscriberInterface {
|
||||
/** @var \Symfony\Component\Routing\Route $route */
|
||||
// @todo: Are multiple methods possible here?
|
||||
$methods = $route->getMethods();
|
||||
// Only expose routes where the method is enabled in the configuration.
|
||||
if ($methods && ($method = $methods[0]) && $supported_formats = $rest_resource_config->getFormats($method)) {
|
||||
// Only expose routes
|
||||
// - that have an explicit method and allow >=1 format for that method
|
||||
// - that exist for BC
|
||||
// @see \Drupal\rest\RouteProcessor\RestResourceGetRouteProcessorBC
|
||||
if (($methods && ($method = $methods[0]) && $supported_formats = $rest_resource_config->getFormats($method)) || $route->hasOption('bc_route')) {
|
||||
$route->setRequirement('_csrf_request_header_token', 'TRUE');
|
||||
|
||||
// Check that authentication providers are defined.
|
||||
@@ -108,24 +111,34 @@ class ResourceRoutes implements EventSubscriberInterface {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the route has a format requirement, then verify that the
|
||||
// resource has it.
|
||||
$format_requirement = $route->getRequirement('_format');
|
||||
if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) {
|
||||
continue;
|
||||
// Remove BC routes for unsupported formats.
|
||||
if ($route->getOption('bc_route') === TRUE) {
|
||||
$format_requirement = $route->getRequirement('_format');
|
||||
if ($format_requirement && !in_array($format_requirement, $rest_resource_config->getFormats($method))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// The configuration has been validated, so we update the route to:
|
||||
// - set the allowed response body content types/formats for methods
|
||||
// that may send response bodies
|
||||
// - set the allowed request body content types/formats for methods that
|
||||
// allow request bodies to be sent
|
||||
// - set the allowed authentication providers
|
||||
if (in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'PATCH'], TRUE)) {
|
||||
$route->addRequirements(['_format' => implode('|', $rest_resource_config->getFormats($method))]);
|
||||
}
|
||||
if (in_array($method, ['POST', 'PATCH', 'PUT'], TRUE)) {
|
||||
// Restrict the incoming HTTP Content-type header to the allowed
|
||||
// formats.
|
||||
$route->addRequirements(['_content_type_format' => implode('|', $rest_resource_config->getFormats($method))]);
|
||||
}
|
||||
$route->setOption('_auth', $rest_resource_config->getAuthenticationProviders($method));
|
||||
$route->setDefault('_rest_resource_config', $rest_resource_config->id());
|
||||
$parameters = $route->getOption('parameters') ?: [];
|
||||
$route->setOption('parameters', $parameters + [
|
||||
'_rest_resource_config' => [
|
||||
'type' => 'entity:' . $rest_resource_config->getEntityTypeId(),
|
||||
],
|
||||
]);
|
||||
$collection->add("rest.$name", $route);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ package: Testing
|
||||
dependencies:
|
||||
- config_test
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-01-03
|
||||
version: '8.4.4'
|
||||
# Information added by Drupal.org packaging script on 2018-03-07
|
||||
version: '8.5.0'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1515021228
|
||||
datestamp: 1520457825
|
||||
|
||||
@@ -7,8 +7,8 @@ package: Testing
|
||||
dependencies:
|
||||
- rest
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-01-03
|
||||
version: '8.4.4'
|
||||
# Information added by Drupal.org packaging script on 2018-03-07
|
||||
version: '8.5.0'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1515021228
|
||||
datestamp: 1520457825
|
||||
|
||||
@@ -14,19 +14,32 @@ use Drupal\Core\Access\AccessResult;
|
||||
* Implements hook_entity_field_access().
|
||||
*
|
||||
* @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::setUp()
|
||||
* @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPost()
|
||||
*/
|
||||
function rest_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
||||
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPost()
|
||||
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPatch()
|
||||
if ($field_definition->getName() === 'field_rest_test') {
|
||||
switch ($operation) {
|
||||
case 'view':
|
||||
// Never ever allow this field to be viewed: this lets EntityResourceTestBase::testGet() test in a "vanilla" way.
|
||||
// Never ever allow this field to be viewed: this lets
|
||||
// EntityResourceTestBase::testGet() test in a "vanilla" way.
|
||||
return AccessResult::forbidden();
|
||||
case 'edit':
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testGet()
|
||||
// @see \Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::testPatch()
|
||||
if ($field_definition->getName() === 'field_rest_test_multivalue') {
|
||||
switch ($operation) {
|
||||
case 'view':
|
||||
// Never ever allow this field to be viewed: this lets
|
||||
// EntityResourceTestBase::testGet() test in a "vanilla" way.
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
// No opinion.
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
@@ -7,3 +7,8 @@ services:
|
||||
class: Drupal\rest_test\Authentication\Provider\TestAuthGlobal
|
||||
tags:
|
||||
- { name: authentication_provider, provider_id: 'rest_test_auth_global', global: TRUE }
|
||||
rest_test.page_cache_request_policy.deny_test_auth_requests:
|
||||
class: Drupal\rest_test\PageCache\RequestPolicy\DenyTestAuthRequests
|
||||
public: false
|
||||
tags:
|
||||
- { name: page_cache_request_policy }
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\rest_test\PageCache\RequestPolicy;
|
||||
|
||||
use Drupal\Core\PageCache\RequestPolicyInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Cache policy for pages requested with REST Test Auth.
|
||||
*
|
||||
* This policy disallows caching of requests that use the REST Test Auth
|
||||
* authentication provider for security reasons (just like basic_auth).
|
||||
* Otherwise responses for authenticated requests can get into the page cache
|
||||
* and could be delivered to unprivileged users.
|
||||
*
|
||||
* @see \Drupal\rest_test\Authentication\Provider\TestAuth
|
||||
* @see \Drupal\rest_test\Authentication\Provider\TestAuthGlobal
|
||||
* @see \Drupal\basic_auth\PageCache\DisallowBasicAuthRequests
|
||||
*/
|
||||
class DenyTestAuthRequests implements RequestPolicyInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function check(Request $request) {
|
||||
if ($request->headers->has('REST-test-auth') || $request->headers->has('REST-test-auth-global')) {
|
||||
return self::DENY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ class NoSerializationClassTestResource extends ResourceBase {
|
||||
*
|
||||
* @return \Drupal\rest\ResourceResponse
|
||||
*/
|
||||
public function post(array $data = []) {
|
||||
public function post(array $data) {
|
||||
return new ResourceResponse($data);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ dependencies:
|
||||
- rest
|
||||
- views
|
||||
|
||||
# Information added by Drupal.org packaging script on 2018-01-03
|
||||
version: '8.4.4'
|
||||
# Information added by Drupal.org packaging script on 2018-03-07
|
||||
version: '8.5.0'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1515021228
|
||||
datestamp: 1520457825
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- rest
|
||||
- user
|
||||
id: test_serializer_shared_path
|
||||
label: 'Test serializer shared path'
|
||||
module: rest
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: entity_test
|
||||
base_field: id
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
style:
|
||||
type: serializer
|
||||
row:
|
||||
type: data_entity
|
||||
sorts:
|
||||
id:
|
||||
id: standard
|
||||
table: entity_test
|
||||
field: id
|
||||
order: DESC
|
||||
plugin_id: date
|
||||
entity_type: entity_test
|
||||
entity_field: id
|
||||
title: 'Test serialize'
|
||||
arguments: { }
|
||||
rest_export_1:
|
||||
display_plugin: rest_export
|
||||
id: rest_export_1
|
||||
display_title: serializer
|
||||
position: null
|
||||
display_options:
|
||||
defaults:
|
||||
access: false
|
||||
path: test/serialize/shared
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: page
|
||||
position: null
|
||||
display_options:
|
||||
defaults:
|
||||
access: false
|
||||
style: false
|
||||
row: false
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: entity:entity_test
|
||||
path: test/serialize/shared
|
||||
@@ -24,7 +24,7 @@ trait AnonResourceTestTrait {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
|
||||
throw new \LogicException('When testing for anonymous users, authentication cannot be missing.');
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ use Psr\Http\Message\ResponseInterface;
|
||||
* authenticated, a 401 response must be sent.
|
||||
* - Because every request must send an authorization, there is no danger of
|
||||
* CSRF attacks.
|
||||
*
|
||||
* @see \Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait
|
||||
*/
|
||||
trait BasicAuthResourceTestTrait {
|
||||
|
||||
@@ -31,8 +33,11 @@ trait BasicAuthResourceTestTrait {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
$this->assertResourceErrorResponse(401, 'No authentication credentials provided.', $response);
|
||||
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
|
||||
$expected_page_cache_header_value = $method === 'GET' ? 'MISS' : FALSE;
|
||||
// @see \Drupal\basic_auth\Authentication\Provider\BasicAuth::challengeException()
|
||||
$expected_dynamic_page_cache_header_value = $expected_page_cache_header_value;
|
||||
$this->assertResourceErrorResponse(401, 'No authentication credentials provided.', $response, ['4xx-response', 'config:system.site', 'config:user.role.anonymous', 'http_response'], ['user.roles:anonymous'], $expected_page_cache_header_value, $expected_dynamic_page_cache_header_value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Trait for ResourceTestBase subclasses testing $auth=basic_auth + 'language'.
|
||||
*
|
||||
* @see \Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait
|
||||
*/
|
||||
trait BasicAuthResourceWithInterfaceTranslationTestTrait {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
|
||||
// Because BasicAuth::challengeException() relies on the 'system.site'
|
||||
// configuration, and this test installs the 'language' module, all config
|
||||
// may be translated and therefore gets the 'languages:language_interface'
|
||||
// cache context.
|
||||
$expected_page_cache_header_value = $method === 'GET' ? 'MISS' : FALSE;
|
||||
$this->assertResourceErrorResponse(401, 'No authentication credentials provided.', $response, ['4xx-response', 'config:system.site', 'config:user.role.anonymous', 'http_response'], ['languages:language_interface', 'user.roles:anonymous'], $expected_page_cache_header_value, $expected_page_cache_header_value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,7 +61,7 @@ trait CookieResourceTestTrait {
|
||||
'pass' => $this->account->passRaw,
|
||||
];
|
||||
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, 'json');
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, static::$format);
|
||||
$request_options[RequestOptions::HEADERS] = [
|
||||
'Content-Type' => static::$mimeType,
|
||||
];
|
||||
@@ -91,11 +91,31 @@ trait CookieResourceTestTrait {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertResponseWhenMissingAuthentication(ResponseInterface $response) {
|
||||
protected function assertResponseWhenMissingAuthentication($method, ResponseInterface $response) {
|
||||
// Requests needing cookie authentication but missing it results in a 403
|
||||
// response. The cookie authentication mechanism sets no response message.
|
||||
// Hence, effectively, this is just the 403 response that one gets as the
|
||||
// anonymous user trying to access a certain REST resource.
|
||||
// @see \Drupal\user\Authentication\Provider\Cookie
|
||||
// @todo https://www.drupal.org/node/2847623
|
||||
$this->assertResourceErrorResponse(403, FALSE, $response);
|
||||
if ($method === 'GET') {
|
||||
$expected_cookie_403_cacheability = $this->getExpectedUnauthorizedAccessCacheability();
|
||||
// - \Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber applies
|
||||
// to cacheable anonymous responses: it updates their cacheability.
|
||||
// - A 403 response to a GET request is cacheable.
|
||||
// Therefore we must update our cacheability expectations accordingly.
|
||||
if (in_array('user.permissions', $expected_cookie_403_cacheability->getCacheContexts(), TRUE)) {
|
||||
$expected_cookie_403_cacheability->addCacheTags(['config:user.role.anonymous']);
|
||||
}
|
||||
// @todo Fix \Drupal\block\BlockAccessControlHandler::mergeCacheabilityFromConditions() in https://www.drupal.org/node/2867881
|
||||
if (static::$entityTypeId === 'block') {
|
||||
$expected_cookie_403_cacheability->setCacheTags(str_replace('user:2', 'user:0', $expected_cookie_403_cacheability->getCacheTags()));
|
||||
}
|
||||
$this->assertResourceErrorResponse(403, FALSE, $response, $expected_cookie_403_cacheability->getCacheTags(), $expected_cookie_403_cacheability->getCacheContexts(), 'MISS', 'MISS');
|
||||
}
|
||||
else {
|
||||
$this->assertResourceErrorResponse(403, FALSE, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionXmlAnonTest extends ActionResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionXmlBasicAuthTest extends ActionResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Action;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ActionXmlCookieTest extends ActionResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BaseFieldOverride;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BaseFieldOverrideXmlAnonTest extends BaseFieldOverrideResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BaseFieldOverride;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BaseFieldOverrideXmlBasicAuthTest extends BaseFieldOverrideResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BaseFieldOverride;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BaseFieldOverrideXmlCookieTest extends BaseFieldOverrideResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -141,4 +141,19 @@ abstract class BlockResourceTestBase extends EntityResourceTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\block\BlockAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->setCacheTags([
|
||||
'4xx-response',
|
||||
'config:block.block.llama',
|
||||
'http_response',
|
||||
static::$auth ? 'user:2' : 'user:0',
|
||||
])
|
||||
->setCacheContexts(['user.roles']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlAnonTest extends BlockResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlBasicAuthTest extends BlockResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Block;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockXmlCookieTest extends BlockResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentJsonAnonTest extends BlockContentResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentJsonBasicAuthTest extends BlockContentResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentJsonCookieTest extends BlockContentResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\block_content\Entity\BlockContent;
|
||||
use Drupal\block_content\Entity\BlockContentType;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
/**
|
||||
* ResourceTestBase for BlockContent entity.
|
||||
*/
|
||||
abstract class BlockContentResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['block_content'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'block_content';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\block_content\BlockContentInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer blocks']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
if (!BlockContentType::load('basic')) {
|
||||
$block_content_type = BlockContentType::create([
|
||||
'id' => 'basic',
|
||||
'label' => 'basic',
|
||||
'revision' => TRUE,
|
||||
]);
|
||||
$block_content_type->save();
|
||||
block_content_add_body_field($block_content_type->id());
|
||||
}
|
||||
|
||||
// Create a "Llama" custom block.
|
||||
$block_content = BlockContent::create([
|
||||
'info' => 'Llama',
|
||||
'type' => 'basic',
|
||||
'body' => [
|
||||
'value' => 'The name "llama" was adopted by European settlers from native Peruvians.',
|
||||
'format' => 'plain_text',
|
||||
],
|
||||
])
|
||||
->setPublished(FALSE);
|
||||
$block_content->save();
|
||||
return $block_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'id' => [
|
||||
[
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
'uuid' => [
|
||||
[
|
||||
'value' => $this->entity->uuid(),
|
||||
],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'type' => [
|
||||
[
|
||||
'target_id' => 'basic',
|
||||
'target_type' => 'block_content_type',
|
||||
'target_uuid' => BlockContentType::load('basic')->uuid(),
|
||||
],
|
||||
],
|
||||
'info' => [
|
||||
[
|
||||
'value' => 'Llama',
|
||||
],
|
||||
],
|
||||
'revision_log' => [],
|
||||
'changed' => [
|
||||
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
|
||||
],
|
||||
'revision_id' => [
|
||||
[
|
||||
'value' => 1,
|
||||
],
|
||||
],
|
||||
'revision_created' => [
|
||||
$this->formatExpectedTimestampItemValues((int) $this->entity->getRevisionCreationTime()),
|
||||
],
|
||||
'revision_user' => [],
|
||||
'revision_translation_affected' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
'body' => [
|
||||
[
|
||||
'value' => 'The name "llama" was adopted by European settlers from native Peruvians.',
|
||||
'format' => 'plain_text',
|
||||
'summary' => NULL,
|
||||
'processed' => "<p>The name "llama" was adopted by European settlers from native Peruvians.</p>\n",
|
||||
],
|
||||
],
|
||||
'status' => [
|
||||
[
|
||||
'value' => FALSE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'type' => [
|
||||
[
|
||||
'target_id' => 'basic',
|
||||
],
|
||||
],
|
||||
'info' => [
|
||||
[
|
||||
'value' => 'Dramallama',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\block_content\BlockContentAccessControlHandler()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->addCacheTags(['block_content:1']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentXmlAnonTest extends BlockContentResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentXmlBasicAuthTest extends BlockContentResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContent;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentXmlCookieTest extends BlockContentResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentTypeXmlAnonTest extends BlockContentTypeResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentTypeXmlBasicAuthTest extends BlockContentTypeResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\BlockContentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class BlockContentTypeXmlCookieTest extends BlockContentTypeResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+25
@@ -5,6 +5,7 @@ namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
use Drupal\comment\Entity\CommentType;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
@@ -197,6 +198,7 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
||||
[
|
||||
'value' => 'The name "llama" was adopted by European settlers from native Peruvians.',
|
||||
'format' => 'plain_text',
|
||||
'processed' => '<p>The name "llama" was adopted by European settlers from native Peruvians.</p>' . "\n",
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -248,6 +250,20 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
||||
return array_diff_key($this->getNormalizedPostEntity(), ['entity_type' => TRUE, 'entity_id' => TRUE, 'field_name' => TRUE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(['languages:language_interface', 'theme'], parent::getExpectedCacheContexts());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests POSTing a comment without critical base fields.
|
||||
*
|
||||
@@ -357,4 +373,13 @@ abstract class CommentResourceTestBase extends EntityResourceTestBase {
|
||||
$this->assertTrue($unserialized->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\comment\CommentAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->addCacheTags(['comment:1']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentXmlAnonTest extends CommentResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Anononymous users cannot edit their own comments.
|
||||
*
|
||||
* @see \Drupal\comment\CommentAccessControlHandler::checkAccess
|
||||
*
|
||||
* Therefore we grant them the 'administer comments' permission for the
|
||||
* purpose of this test.
|
||||
*
|
||||
* @see ::setUpAuthorization
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'pid',
|
||||
'entity_id',
|
||||
'changed',
|
||||
'thread',
|
||||
'entity_type',
|
||||
'field_name',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostDxWithoutCriticalBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostSkipCommentApproval() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentXmlBasicAuthTest extends CommentResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostDxWithoutCriticalBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostSkipCommentApproval() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentXmlCookieTest extends CommentResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostDxWithoutCriticalBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPostSkipCommentApproval() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeXmlAnonTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeXmlBasicAuthTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\CommentType;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class CommentTypeXmlCookieTest extends CommentTypeResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigTestXmlAnonTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigTestXmlBasicAuthTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigTestXmlCookieTest extends ConfigTestResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+2
-2
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageJsonBasicAuthTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
+18
@@ -3,6 +3,7 @@
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
@@ -74,4 +75,21 @@ abstract class ConfigurableLanguageResourceTestBase extends EntityResourceTestBa
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a GET request for a default config entity, which has a _core key.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2915414
|
||||
*/
|
||||
public function testGetDefaultConfig() {
|
||||
$this->initAuthentication();
|
||||
$url = Url::fromUri('base:/entity/configurable_language/en')->setOption('query', ['_format' => static::$format]);;
|
||||
$request_options = $this->getAuthenticationRequestOptions('GET');
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
|
||||
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
|
||||
$this->assertArrayNotHasKey('_core', $normalization);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlAnonTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlBasicAuthTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ConfigurableLanguage;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ConfigurableLanguageXmlCookieTest extends ConfigurableLanguageResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContactForm;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContactFormXmlAnonTest extends ContactFormResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContactForm;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContactFormXmlBasicAuthTest extends ContactFormResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContactForm;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContactFormXmlCookieTest extends ContactFormResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+2
-2
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContentLanguageSettings;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsJsonBasicAuthTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContentLanguageSettings;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlAnonTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContentLanguageSettings;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlBasicAuthTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use BasicAuthResourceWithInterfaceTranslationTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\ContentLanguageSettings;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class ContentLanguageSettingsXmlCookieTest extends ContentLanguageSettingsResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\DateFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class DateFormatXmlAnonTest extends DateFormatResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\DateFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class DateFormatXmlBasicAuthTest extends DateFormatResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\DateFormat;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class DateFormatXmlCookieTest extends DateFormatResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Editor;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EditorXmlAnonTest extends EditorResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Editor;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EditorXmlBasicAuthTest extends EditorResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\Editor;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EditorXmlCookieTest extends EditorResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayJsonAnonTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayJsonBasicAuthTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayJsonCookieTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
|
||||
abstract class EntityFormDisplayResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'entity_form_display';
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer node form display']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Camelids" node type.
|
||||
$camelids = NodeType::create([
|
||||
'name' => 'Camelids',
|
||||
'type' => 'camelids',
|
||||
]);
|
||||
|
||||
$camelids->save();
|
||||
|
||||
// Create a form display.
|
||||
$form_display = EntityFormDisplay::create([
|
||||
'targetEntityType' => 'node',
|
||||
'bundle' => 'camelids',
|
||||
'mode' => 'default',
|
||||
]);
|
||||
$form_display->save();
|
||||
|
||||
return $form_display;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'bundle' => 'camelids',
|
||||
'content' => [
|
||||
'created' => [
|
||||
'type' => 'datetime_timestamp',
|
||||
'weight' => 10,
|
||||
'region' => 'content',
|
||||
'settings' => [],
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
'promote' => [
|
||||
'type' => 'boolean_checkbox',
|
||||
'settings' => [
|
||||
'display_label' => TRUE,
|
||||
],
|
||||
'weight' => 15,
|
||||
'region' => 'content',
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'boolean_checkbox',
|
||||
'weight' => 120,
|
||||
'region' => 'content',
|
||||
'settings' => [
|
||||
'display_label' => TRUE,
|
||||
],
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
'sticky' => [
|
||||
'type' => 'boolean_checkbox',
|
||||
'settings' => [
|
||||
'display_label' => TRUE,
|
||||
],
|
||||
'weight' => 16,
|
||||
'region' => 'content',
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
'title' => [
|
||||
'type' => 'string_textfield',
|
||||
'weight' => -5,
|
||||
'region' => 'content',
|
||||
'settings' => [
|
||||
'size' => 60,
|
||||
'placeholder' => '',
|
||||
],
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
'uid' => [
|
||||
'type' => 'entity_reference_autocomplete',
|
||||
'weight' => 5,
|
||||
'settings' => [
|
||||
'match_operator' => 'CONTAINS',
|
||||
'size' => 60,
|
||||
'placeholder' => '',
|
||||
],
|
||||
'region' => 'content',
|
||||
'third_party_settings' => [],
|
||||
],
|
||||
],
|
||||
'dependencies' => [
|
||||
'config' => [
|
||||
'node.type.camelids',
|
||||
],
|
||||
],
|
||||
'hidden' => [],
|
||||
'id' => 'node.camelids.default',
|
||||
'langcode' => 'en',
|
||||
'mode' => 'default',
|
||||
'status' => NULL,
|
||||
'targetEntityType' => 'node',
|
||||
'uuid' => $this->entity->uuid(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return [
|
||||
'user.permissions',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
return "The 'administer node form display' permission is required.";
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayXmlAnonTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayXmlBasicAuthTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormDisplayXmlCookieTest extends EntityFormDisplayResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormMode;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormModeXmlAnonTest extends EntityFormModeResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormMode;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormModeXmlBasicAuthTest extends EntityFormModeResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityFormMode;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityFormModeXmlCookieTest extends EntityFormModeResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Checks that all core content/config entity types have REST test coverage.
|
||||
*
|
||||
* Every entity type must have test coverage for:
|
||||
* - every format in core (json + xml + hal_json)
|
||||
* - every authentication provider in core (anon, cookie, basic_auth)
|
||||
*
|
||||
* @group rest
|
||||
*/
|
||||
class EntityResourceRestTestCoverageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Entity definitions array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $definitions;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$all_modules = system_rebuild_module_data();
|
||||
$stable_core_modules = array_filter($all_modules, function ($module) {
|
||||
// Filter out contrib, hidden, testing, and experimental modules. We also
|
||||
// don't need to enable modules that are already enabled.
|
||||
return
|
||||
$module->origin === 'core' &&
|
||||
empty($module->info['hidden']) &&
|
||||
$module->status == FALSE &&
|
||||
$module->info['package'] !== 'Testing' &&
|
||||
$module->info['package'] !== 'Core (Experimental)';
|
||||
});
|
||||
|
||||
$this->container->get('module_installer')->install(array_keys($stable_core_modules));
|
||||
$this->rebuildContainer();
|
||||
|
||||
$this->definitions = $this->container->get('entity_type.manager')->getDefinitions();
|
||||
|
||||
// Entity types marked as "internal" are not exposed by the entity REST
|
||||
// resource plugin and hence also don't need test coverage.
|
||||
$this->definitions = array_filter($this->definitions, function (EntityTypeInterface $entity_type) {
|
||||
return !$entity_type->isInternal();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that all core content/config entity types have REST test coverage.
|
||||
*/
|
||||
public function testEntityTypeRestTestCoverage() {
|
||||
$default_test_locations = [
|
||||
// Test coverage for formats provided by the 'serialization' module.
|
||||
'serialization' => [
|
||||
'possible paths' => [
|
||||
'\Drupal\Tests\rest\Functional\EntityResource\CLASS\CLASS',
|
||||
],
|
||||
'class suffix' => [
|
||||
'JsonAnonTest',
|
||||
'JsonBasicAuthTest',
|
||||
'JsonCookieTest',
|
||||
'XmlAnonTest',
|
||||
'XmlBasicAuthTest',
|
||||
'XmlCookieTest',
|
||||
],
|
||||
],
|
||||
// Test coverage for formats provided by the 'hal' module.
|
||||
'hal' => [
|
||||
'possible paths' => [
|
||||
'\Drupal\Tests\hal\Functional\EntityResource\CLASS\CLASS',
|
||||
],
|
||||
'class suffix' => [
|
||||
'HalJsonAnonTest',
|
||||
'HalJsonBasicAuthTest',
|
||||
'HalJsonCookieTest',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$problems = [];
|
||||
foreach ($this->definitions as $entity_type_id => $info) {
|
||||
$class_name_full = $info->getClass();
|
||||
$parts = explode('\\', $class_name_full);
|
||||
$class_name = end($parts);
|
||||
$module_name = $parts[1];
|
||||
|
||||
// The test class can live either in the REST/HAL module, or in the module
|
||||
// providing the entity type.
|
||||
$tests = $default_test_locations;
|
||||
$tests['serialization']['possible paths'][] = '\Drupal\Tests\\' . $module_name . '\Functional\Rest\CLASS';
|
||||
$tests['hal']['possible paths'][] = '\Drupal\Tests\\' . $module_name . '\Functional\Hal\CLASS';
|
||||
|
||||
foreach ($tests as $module => $info) {
|
||||
$possible_paths = $info['possible paths'];
|
||||
$missing_tests = [];
|
||||
foreach ($info['class suffix'] as $postfix) {
|
||||
foreach ($possible_paths as $path) {
|
||||
$class = str_replace('CLASS', $class_name, $path . $postfix);
|
||||
if (class_exists($class)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$missing_tests[] = $postfix;
|
||||
}
|
||||
if (!empty($missing_tests)) {
|
||||
$missing_tests_list = implode(', ', array_map(function ($missing_test) use ($class_name) {
|
||||
return $class_name . $missing_test;
|
||||
}, $missing_tests));
|
||||
$which_normalization = $module === 'serialization' ? 'default' : $module;
|
||||
$problems[] = "$entity_type_id: $class_name ($class_name_full), $which_normalization normalization (expected tests: $missing_tests_list)";
|
||||
}
|
||||
}
|
||||
}
|
||||
$all = count($this->definitions);
|
||||
$good = $all - count($problems);
|
||||
$this->assertSame([], $problems, $this->getLlamaMessage($good, $all));
|
||||
}
|
||||
|
||||
/**
|
||||
* Message from Llama.
|
||||
*
|
||||
* @param int $g
|
||||
* A count of entities with test coverage.
|
||||
* @param int $a
|
||||
* A count of all entities.
|
||||
*
|
||||
* @return string
|
||||
* An information about progress of REST test coverage.
|
||||
*/
|
||||
protected function getLlamaMessage($g, $a) {
|
||||
return "
|
||||
☼
|
||||
________________________
|
||||
/ Hi! \\
|
||||
| It's llame to not have |
|
||||
| complete REST tests! |
|
||||
| |
|
||||
| Progress: $g/$a. |
|
||||
| ________________________/
|
||||
|/
|
||||
// o
|
||||
l'>
|
||||
ll
|
||||
llama
|
||||
|| ||
|
||||
'' ''
|
||||
";
|
||||
}
|
||||
|
||||
}
|
||||
+389
-163
@@ -3,13 +3,20 @@
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource;
|
||||
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Component\Utility\Random;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableResponseInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Entity\ContentEntityNullStorage;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\path\Plugin\Field\FieldType\PathItem;
|
||||
use Drupal\rest\ResourceResponseInterface;
|
||||
use Drupal\Tests\rest\Functional\ResourceTestBase;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
@@ -79,6 +86,14 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
*/
|
||||
protected static $patchProtectedFieldNames;
|
||||
|
||||
/**
|
||||
* The fields that need a different (random) value for each new entity created
|
||||
* by a POST request.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $uniqueFieldNames = [];
|
||||
|
||||
/**
|
||||
* Optionally specify which field is the 'label' field. Some entities specify
|
||||
* a 'label_callback', but not a 'label' entity key. For example: User.
|
||||
@@ -118,6 +133,13 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Another entity of the same type used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $anotherEntity;
|
||||
|
||||
/**
|
||||
* The entity storage.
|
||||
*
|
||||
@@ -175,12 +197,34 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
->setTranslatable(FALSE)
|
||||
->save();
|
||||
|
||||
// Reload entity so that it has the new field.
|
||||
$this->entity = $this->entityStorage->loadUnchanged($this->entity->id());
|
||||
// Add multi-value field.
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => static::$entityTypeId,
|
||||
'field_name' => 'field_rest_test_multivalue',
|
||||
'type' => 'string',
|
||||
])
|
||||
->setCardinality(3)
|
||||
->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => static::$entityTypeId,
|
||||
'field_name' => 'field_rest_test_multivalue',
|
||||
'bundle' => $this->entity->bundle(),
|
||||
])
|
||||
->setLabel('Test field: multi-value')
|
||||
->setTranslatable(FALSE)
|
||||
->save();
|
||||
|
||||
// Set a default value on the field.
|
||||
$this->entity->set('field_rest_test', ['value' => 'All the faith he had had had had no effect on the outcome of his life.']);
|
||||
$this->entity->save();
|
||||
// Reload entity so that it has the new field.
|
||||
$reloaded_entity = $this->entityStorage->loadUnchanged($this->entity->id());
|
||||
// Some entity types are not stored, hence they cannot be reloaded.
|
||||
if ($reloaded_entity !== NULL) {
|
||||
$this->entity = $reloaded_entity;
|
||||
|
||||
// Set a default value on the fields.
|
||||
$this->entity->set('field_rest_test', ['value' => 'All the faith he had had had had no effect on the outcome of his life.']);
|
||||
$this->entity->set('field_rest_test_multivalue', [['value' => 'One'], ['value' => 'Two']]);
|
||||
$this->entity->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +236,22 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
*/
|
||||
abstract protected function createEntity();
|
||||
|
||||
/**
|
||||
* Creates another entity to be tested.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* Another entity based on $this->entity.
|
||||
*/
|
||||
protected function createAnotherEntity() {
|
||||
$entity = $this->entity->createDuplicate();
|
||||
$label_key = $entity->getEntityType()->getKey('label');
|
||||
if ($label_key) {
|
||||
$entity->set($label_key, $entity->label() . '_dupe');
|
||||
}
|
||||
$entity->save();
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expected normalization of the entity.
|
||||
*
|
||||
@@ -224,6 +284,46 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
return $this->getNormalizedPostEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the second normalized POST entity.
|
||||
*
|
||||
* Entity types can have non-sequential IDs, and in that case the second
|
||||
* entity created for POST testing needs to be able to specify a different ID.
|
||||
*
|
||||
* @see ::testPost
|
||||
* @see ::getNormalizedPostEntity
|
||||
*
|
||||
* @return array
|
||||
* An array structure as returned by ::getNormalizedPostEntity().
|
||||
*/
|
||||
protected function getSecondNormalizedPostEntity() {
|
||||
// Return the values of the "parent" method by default.
|
||||
return $this->getNormalizedPostEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the normalized POST entity with random values for its unique fields.
|
||||
*
|
||||
* @see ::testPost
|
||||
* @see ::getNormalizedPostEntity
|
||||
*
|
||||
* @return array
|
||||
* An array structure as returned by ::getNormalizedPostEntity().
|
||||
*/
|
||||
protected function getModifiedEntityForPostTesting() {
|
||||
$normalized_entity = $this->getNormalizedPostEntity();
|
||||
|
||||
// Ensure that all the unique fields of the entity type get a new random
|
||||
// value.
|
||||
foreach (static::$uniqueFieldNames as $field_name) {
|
||||
$field_definition = $this->entity->getFieldDefinition($field_name);
|
||||
$field_type_class = $field_definition->getItemDefinition()->getClass();
|
||||
$normalized_entity[$field_name] = $field_type_class::generateSampleValue($field_definition);
|
||||
}
|
||||
|
||||
return $normalized_entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -254,6 +354,17 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
return "$message.";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
return (new CacheableMetadata())
|
||||
->setCacheTags(static::$auth
|
||||
? ['4xx-response', 'http_response']
|
||||
: ['4xx-response', 'config:user.role.anonymous', 'http_response'])
|
||||
->setCacheContexts(['user.permissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
* The expected cache tags for the GET/HEAD response of the test entity.
|
||||
*
|
||||
@@ -264,6 +375,9 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
protected function getExpectedCacheTags() {
|
||||
$expected_cache_tags = [
|
||||
'config:rest.resource.entity.' . static::$entityTypeId,
|
||||
// Necessary for 'bc_entity_resource_permissions'.
|
||||
// @see \Drupal\rest\Plugin\rest\resource\EntityResource::permissions()
|
||||
'config:rest.settings',
|
||||
];
|
||||
if (!static::$auth) {
|
||||
$expected_cache_tags[] = 'config:user.role.anonymous';
|
||||
@@ -339,7 +453,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// response.
|
||||
if (static::$auth) {
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResponseWhenMissingAuthentication($response);
|
||||
$this->assertResponseWhenMissingAuthentication('GET', $response);
|
||||
}
|
||||
|
||||
$request_options[RequestOptions::HEADERS]['REST-test-auth'] = '1';
|
||||
@@ -360,87 +474,55 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// DX: 403 when unauthorized.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response);
|
||||
$expected_403_cacheability = $this->getExpectedUnauthorizedAccessCacheability();
|
||||
$this->assertResourceErrorResponse(403, $this->getExpectedUnauthorizedAccessMessage('GET'), $response, $expected_403_cacheability->getCacheTags(), $expected_403_cacheability->getCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
$this->assertArrayNotHasKey('Link', $response->getHeaders());
|
||||
|
||||
$this->setUpAuthorization('GET');
|
||||
|
||||
// 200 for well-formed HEAD request.
|
||||
$response = $this->request('HEAD', $url, $request_options);
|
||||
$this->assertResourceResponse(200, '', $response);
|
||||
// @todo Entity resources with URLs that begin with '/admin/' are marked as
|
||||
// administrative (see https://www.drupal.org/node/2874938), which
|
||||
// excludes them from Dynamic Page Cache (see
|
||||
// https://www.drupal.org/node/2877528). When either of those issues is
|
||||
// fixed, remove the if-test and the 'else' block.
|
||||
if (strpos($this->entity->getEntityType()->getLinkTemplate('canonical'), '/admin/') !== 0) {
|
||||
$this->assertTrue($response->hasHeader('X-Drupal-Dynamic-Cache'));
|
||||
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Dynamic-Cache'));
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Dynamic-Cache'));
|
||||
}
|
||||
if (!$this->account) {
|
||||
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Cache'));
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
}
|
||||
$this->assertResourceResponse(200, '', $response, $this->getExpectedCacheTags(), $this->getExpectedCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
$head_headers = $response->getHeaders();
|
||||
|
||||
// 200 for well-formed GET request. Page Cache hit because of HEAD request.
|
||||
// Same for Dynamic Page Cache hit.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
// @todo Entity resources with URLs that begin with '/admin/' are marked as
|
||||
// administrative (see https://www.drupal.org/node/2874938), which
|
||||
// excludes them from Dynamic Page Cache (see
|
||||
// https://www.drupal.org/node/2877528). When either of those issues is
|
||||
// fixed, remove the if-test and the 'else' block.
|
||||
if (strpos($this->entity->getEntityType()->getLinkTemplate('canonical'), '/admin/') !== 0) {
|
||||
$this->assertTrue($response->hasHeader('X-Drupal-Dynamic-Cache'));
|
||||
if (!static::$auth) {
|
||||
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Cache'));
|
||||
$this->assertSame(['MISS'], $response->getHeader('X-Drupal-Dynamic-Cache'));
|
||||
$this->assertResourceResponse(200, FALSE, $response, $this->getExpectedCacheTags(), $this->getExpectedCacheContexts(), static::$auth ? FALSE : 'HIT', static::$auth ? 'HIT' : 'MISS');
|
||||
// Assert that Dynamic Page Cache did not store a ResourceResponse object,
|
||||
// which needs serialization after every cache hit. Instead, it should
|
||||
// contain a flattened response. Otherwise performance suffers.
|
||||
// @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::flattenResponse()
|
||||
$cache_items = $this->container->get('database')
|
||||
->query("SELECT cid, data FROM {cache_dynamic_page_cache} WHERE cid LIKE :pattern", [
|
||||
':pattern' => '%[route]=rest.%',
|
||||
])
|
||||
->fetchAllAssoc('cid');
|
||||
$this->assertTrue(count($cache_items) >= 2);
|
||||
$found_cache_redirect = FALSE;
|
||||
$found_cached_200_response = FALSE;
|
||||
$other_cached_responses_are_4xx = TRUE;
|
||||
foreach ($cache_items as $cid => $cache_item) {
|
||||
$cached_data = unserialize($cache_item->data);
|
||||
if (!isset($cached_data['#cache_redirect'])) {
|
||||
$cached_response = $cached_data['#response'];
|
||||
if ($cached_response->getStatusCode() === 200) {
|
||||
$found_cached_200_response = TRUE;
|
||||
}
|
||||
elseif (!$cached_response->isClientError()) {
|
||||
$other_cached_responses_are_4xx = FALSE;
|
||||
}
|
||||
$this->assertNotInstanceOf(ResourceResponseInterface::class, $cached_response);
|
||||
$this->assertInstanceOf(CacheableResponseInterface::class, $cached_response);
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
$this->assertSame(['HIT'], $response->getHeader('X-Drupal-Dynamic-Cache'));
|
||||
// Assert that Dynamic Page Cache did not store a ResourceResponse object,
|
||||
// which needs serialization after every cache hit. Instead, it should
|
||||
// contain a flattened response. Otherwise performance suffers.
|
||||
// @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::flattenResponse()
|
||||
$cache_items = $this->container->get('database')
|
||||
->query("SELECT cid, data FROM {cache_dynamic_page_cache} WHERE cid LIKE :pattern", [
|
||||
':pattern' => '%[route]=rest.%',
|
||||
])
|
||||
->fetchAllAssoc('cid');
|
||||
$this->assertCount(2, $cache_items);
|
||||
$found_cache_redirect = FALSE;
|
||||
$found_cached_response = FALSE;
|
||||
foreach ($cache_items as $cid => $cache_item) {
|
||||
$cached_data = unserialize($cache_item->data);
|
||||
if (!isset($cached_data['#cache_redirect'])) {
|
||||
$found_cached_response = TRUE;
|
||||
$cached_response = $cached_data['#response'];
|
||||
$this->assertNotInstanceOf(ResourceResponseInterface::class, $cached_response);
|
||||
$this->assertInstanceOf(CacheableResponseInterface::class, $cached_response);
|
||||
}
|
||||
else {
|
||||
$found_cache_redirect = TRUE;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found_cache_redirect);
|
||||
$this->assertTrue($found_cached_response);
|
||||
$found_cache_redirect = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Dynamic-Cache'));
|
||||
}
|
||||
$cache_tags_header_value = $response->getHeader('X-Drupal-Cache-Tags')[0];
|
||||
$this->assertEquals($this->getExpectedCacheTags(), empty($cache_tags_header_value) ? [] : explode(' ', $cache_tags_header_value));
|
||||
$cache_contexts_header_value = $response->getHeader('X-Drupal-Cache-Contexts')[0];
|
||||
$this->assertEquals($this->getExpectedCacheContexts(), empty($cache_contexts_header_value) ? [] : explode(' ', $cache_contexts_header_value));
|
||||
$this->assertTrue($found_cache_redirect);
|
||||
$this->assertTrue($found_cached_200_response);
|
||||
$this->assertTrue($other_cached_responses_are_4xx);
|
||||
|
||||
// Sort the serialization data first so we can do an identical comparison
|
||||
// for the keys with the array order the same (it needs to match with
|
||||
// identical comparison).
|
||||
@@ -452,8 +534,17 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// Not only assert the normalization, also assert deserialization of the
|
||||
// response results in the expected object.
|
||||
$unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
|
||||
$this->assertSame($unserialized->uuid(), $this->entity->uuid());
|
||||
// Note: deserialization of the XML format is not supported, so only test
|
||||
// this for other formats.
|
||||
if (static::$format !== 'xml') {
|
||||
// @todo Work-around for HAL's FileEntityNormalizer::denormalize() being
|
||||
// broken, being fixed in https://www.drupal.org/node/1927648, where this
|
||||
// if-test should be removed.
|
||||
if (!(static::$entityTypeId === 'file' && static::$format === 'hal_json')) {
|
||||
$unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
|
||||
$this->assertSame($unserialized->uuid(), $this->entity->uuid());
|
||||
}
|
||||
}
|
||||
// Finally, assert that the expected 'Link' headers are present.
|
||||
if ($this->entity->getEntityType()->getLinkTemplates()) {
|
||||
$this->assertArrayHasKey('Link', $response->getHeaders());
|
||||
@@ -476,15 +567,21 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$get_headers = $response->getHeaders();
|
||||
|
||||
// Verify that the GET and HEAD responses are the same. The only difference
|
||||
// is that there's no body. For this reason the 'Transfer-Encoding' header
|
||||
// is also added to the list of headers to ignore, as this could be added to
|
||||
// GET requests - depending on web server configuration. This would usually
|
||||
// be 'Transfer-Encoding: chunked'.
|
||||
$ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache', 'Transfer-Encoding'];
|
||||
foreach ($ignored_headers as $ignored_header) {
|
||||
unset($head_headers[$ignored_header]);
|
||||
unset($get_headers[$ignored_header]);
|
||||
}
|
||||
// is that there's no body. For this reason the 'Transfer-Encoding' and
|
||||
// 'Vary' headers are also added to the list of headers to ignore, as they
|
||||
// may be added to GET requests, depending on web server configuration. They
|
||||
// are usually 'Transfer-Encoding: chunked' and 'Vary: Accept-Encoding'.
|
||||
$ignored_headers = ['Date', 'Content-Length', 'X-Drupal-Cache', 'X-Drupal-Dynamic-Cache', 'Transfer-Encoding', 'Vary'];
|
||||
$header_cleaner = function ($headers) use ($ignored_headers) {
|
||||
foreach ($headers as $header => $value) {
|
||||
if (strpos($header, 'X-Drupal-Assertion-') === 0 || in_array($header, $ignored_headers)) {
|
||||
unset($headers[$header]);
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
};
|
||||
$get_headers = $header_cleaner($get_headers);
|
||||
$head_headers = $header_cleaner($head_headers);
|
||||
$this->assertSame($get_headers, $head_headers);
|
||||
|
||||
// BC: serialization_update_8302().
|
||||
@@ -499,7 +596,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$this->rebuildAll();
|
||||
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$this->assertResourceResponse(200, FALSE, $response, $this->getExpectedCacheTags(), $this->getExpectedCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
|
||||
// Again do an identical comparison, but this time transform the expected
|
||||
// normalized entity's values to strings. This ensures the BC layer for
|
||||
@@ -531,7 +628,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$this->rebuildAll();
|
||||
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$this->assertResourceResponse(200, FALSE, $response, $this->getExpectedCacheTags(), $this->getExpectedCacheContexts(), static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
|
||||
// This ensures the BC layer for bc_timestamp_normalizer_unix works as
|
||||
// expected. This method should be using
|
||||
@@ -562,7 +659,21 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$expected_cache_tags = $this->getExpectedCacheTags();
|
||||
$expected_cache_contexts = $this->getExpectedCacheContexts();
|
||||
// @todo Fix BlockAccessControlHandler::mergeCacheabilityFromConditions() in
|
||||
// https://www.drupal.org/node/2867881
|
||||
if (static::$entityTypeId === 'block') {
|
||||
$expected_cache_contexts = Cache::mergeContexts($expected_cache_contexts, ['user.permissions']);
|
||||
}
|
||||
// \Drupal\Core\EventSubscriber\AnonymousUserResponseSubscriber applies to
|
||||
// cacheable anonymous responses: it updates their cacheability. Therefore
|
||||
// we must update our cacheability expectations for anonymous responses
|
||||
// accordingly.
|
||||
if (!static::$auth && in_array('user.permissions', $expected_cache_contexts, TRUE)) {
|
||||
$expected_cache_tags = Cache::mergeTags($expected_cache_tags, ['config:user.role.anonymous']);
|
||||
}
|
||||
$this->assertResourceResponse(200, FALSE, $response, $expected_cache_tags, $expected_cache_contexts, static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
|
||||
$this->resourceConfigStorage->load(static::$resourceConfigId)->disable()->save();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
@@ -575,7 +686,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// DX: upon re-enabling a resource, immediate 200.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$this->assertResourceResponse(200, FALSE, $response, $expected_cache_tags, $expected_cache_contexts, static::$auth ? FALSE : 'MISS', 'MISS');
|
||||
|
||||
$this->resourceConfigStorage->load(static::$resourceConfigId)->delete();
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
@@ -599,14 +710,14 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$this->assert406Response($response);
|
||||
$this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type'));
|
||||
|
||||
$url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format);
|
||||
$url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET');
|
||||
$url->setRouteParameter(static::$entityTypeId, 987654321);
|
||||
$url->setOption('query', ['_format' => static::$format]);
|
||||
|
||||
// DX: 404 when GETting non-existing entity.
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$path = str_replace('987654321', '{' . static::$entityTypeId . '}', $url->setAbsolute()->setOptions(['base_url' => '', 'query' => []])->toString());
|
||||
$message = 'The "' . static::$entityTypeId . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . static::$entityTypeId . '.GET.' . static::$format . '")';
|
||||
$message = 'The "' . static::$entityTypeId . '" parameter was not converted for the path "' . $path . '" (route name: "rest.entity.' . static::$entityTypeId . '.GET")';
|
||||
$this->assertResourceErrorResponse(404, $message, $response);
|
||||
}
|
||||
|
||||
@@ -671,8 +782,8 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// Try with all of the following request bodies.
|
||||
$unparseable_request_body = '!{>}<';
|
||||
$parseable_valid_request_body = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
|
||||
$parseable_valid_request_body_2 = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
|
||||
$parseable_invalid_request_body = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPostEntity()), static::$format);
|
||||
$parseable_valid_request_body_2 = $this->serializer->encode($this->getSecondNormalizedPostEntity(), static::$format);
|
||||
$parseable_invalid_request_body = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPostEntity(), 'label'), static::$format);
|
||||
$parseable_invalid_request_body_2 = $this->serializer->encode($this->getNormalizedPostEntity() + ['uuid' => [$this->randomMachineName(129)]], static::$format);
|
||||
$parseable_invalid_request_body_3 = $this->serializer->encode($this->getNormalizedPostEntity() + ['field_rest_test' => [['value' => $this->randomString()]]], static::$format);
|
||||
|
||||
@@ -731,7 +842,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// DX: forgetting authentication: authentication provider-specific error
|
||||
// response.
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResponseWhenMissingAuthentication($response);
|
||||
$this->assertResponseWhenMissingAuthentication('POST', $response);
|
||||
}
|
||||
|
||||
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('POST'));
|
||||
@@ -789,23 +900,27 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$this->assertSame([], $response->getHeader('Location'));
|
||||
}
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
// Assert that the entity was indeed created, and that the response body
|
||||
// contains the serialized created entity.
|
||||
$created_entity = $this->entityStorage->loadUnchanged(static::$firstCreatedEntityId);
|
||||
$created_entity_normalization = $this->serializer->normalize($created_entity, static::$format, ['account' => $this->account]);
|
||||
// @todo Remove this if-test in https://www.drupal.org/node/2543726: execute
|
||||
// its body unconditionally.
|
||||
if (static::$entityTypeId !== 'taxonomy_term') {
|
||||
$this->assertSame($created_entity_normalization, $this->serializer->decode((string) $response->getBody(), static::$format));
|
||||
}
|
||||
// Assert that the entity was indeed created using the POSTed values.
|
||||
foreach ($this->getNormalizedPostEntity() as $field_name => $field_normalization) {
|
||||
// Some top-level keys in the normalization may not be fields on the
|
||||
// entity (for example '_links' and '_embedded' in the HAL normalization).
|
||||
if ($created_entity->hasField($field_name)) {
|
||||
// Subset, not same, because we can e.g. send just the target_id for the
|
||||
// bundle in a POST request; the response will include more properties.
|
||||
$this->assertArraySubset(static::castToString($field_normalization), $created_entity->get($field_name)->getValue(), TRUE);
|
||||
// If the entity is stored, perform extra checks.
|
||||
if (get_class($this->entityStorage) !== ContentEntityNullStorage::class) {
|
||||
// Assert that the entity was indeed created, and that the response body
|
||||
// contains the serialized created entity.
|
||||
$created_entity = $this->entityStorage->loadUnchanged(static::$firstCreatedEntityId);
|
||||
$created_entity_normalization = $this->serializer->normalize($created_entity, static::$format, ['account' => $this->account]);
|
||||
// @todo Remove this if-test in https://www.drupal.org/node/2543726: execute
|
||||
// its body unconditionally.
|
||||
if (static::$entityTypeId !== 'taxonomy_term') {
|
||||
$this->assertSame($created_entity_normalization, $this->serializer->decode((string) $response->getBody(), static::$format));
|
||||
}
|
||||
// Assert that the entity was indeed created using the POSTed values.
|
||||
foreach ($this->getNormalizedPostEntity() as $field_name => $field_normalization) {
|
||||
// Some top-level keys in the normalization may not be fields on the
|
||||
// entity (for example '_links' and '_embedded' in the HAL normalization).
|
||||
if ($created_entity->hasField($field_name)) {
|
||||
// Subset, not same, because we can e.g. send just the target_id for the
|
||||
// bundle in a POST request; the response will include more properties.
|
||||
$this->assertArraySubset(static::castToString($field_normalization), $created_entity->get($field_name)
|
||||
->getValue(), TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,12 +935,16 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$this->grantPermissionsToTestedRole(['restful post entity:' . static::$entityTypeId]);
|
||||
|
||||
// 201 for well-formed request.
|
||||
// Delete the first created entity in case there is a uniqueness constraint.
|
||||
$this->entityStorage->load(static::$firstCreatedEntityId)->delete();
|
||||
// If the entity is stored, delete the first created entity (in case there
|
||||
// is a uniqueness constraint).
|
||||
if (get_class($this->entityStorage) !== ContentEntityNullStorage::class) {
|
||||
$this->entityStorage->load(static::$firstCreatedEntityId)->delete();
|
||||
}
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResourceResponse(201, FALSE, $response);
|
||||
$created_entity = $this->entityStorage->load(static::$secondCreatedEntityId);
|
||||
if ($has_canonical_url) {
|
||||
$location = $this->entityStorage->load(static::$secondCreatedEntityId)->toUrl('canonical')->setAbsolute(TRUE)->toString();
|
||||
$location = $created_entity->toUrl('canonical')->setAbsolute(TRUE)->toString();
|
||||
$this->assertSame([$location], $response->getHeader('Location'));
|
||||
}
|
||||
else {
|
||||
@@ -833,6 +952,32 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
}
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
|
||||
if ($this->entity->getEntityType()->getStorageClass() !== ContentEntityNullStorage::class && $this->entity->getEntityType()->hasKey('uuid')) {
|
||||
// 500 when creating an entity with a duplicate UUID.
|
||||
$normalized_entity = $this->getModifiedEntityForPostTesting();
|
||||
$normalized_entity[$created_entity->getEntityType()->getKey('uuid')] = [['value' => $created_entity->uuid()]];
|
||||
$normalized_entity[$label_field] = [['value' => $this->randomMachineName()]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalized_entity, static::$format);
|
||||
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertSame(500, $response->getStatusCode());
|
||||
$this->assertContains('Internal Server Error', (string) $response->getBody());
|
||||
|
||||
// 201 when successfully creating an entity with a new UUID.
|
||||
$normalized_entity = $this->getModifiedEntityForPostTesting();
|
||||
$new_uuid = \Drupal::service('uuid')->generate();
|
||||
$normalized_entity[$created_entity->getEntityType()->getKey('uuid')] = [['value' => $new_uuid]];
|
||||
$normalized_entity[$label_field] = [['value' => $this->randomMachineName()]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalized_entity, static::$format);
|
||||
|
||||
$response = $this->request('POST', $url, $request_options);
|
||||
$this->assertResourceResponse(201, FALSE, $response);
|
||||
$entities = $this->entityStorage->loadByProperties([$created_entity->getEntityType()->getKey('uuid') => $new_uuid]);
|
||||
$new_entity = reset($entities);
|
||||
$this->assertNotNull($new_entity);
|
||||
$new_entity->delete();
|
||||
}
|
||||
|
||||
// BC: old default POST URLs have their path updated by the inbound path
|
||||
// processor \Drupal\rest\PathProcessor\PathProcessorEntityResourceBC to the
|
||||
// new URL, which is derived from the 'create' link template if an entity
|
||||
@@ -840,6 +985,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
if ($this->entity->getEntityType()->hasLinkTemplate('create')) {
|
||||
$this->entityStorage->load(static::$secondCreatedEntityId)->delete();
|
||||
$old_url = Url::fromUri('base:entity/' . static::$entityTypeId);
|
||||
$old_url->setOption('query', ['_format' => static::$format]);
|
||||
$response = $this->request('POST', $old_url, $request_options);
|
||||
$this->assertResourceResponse(201, FALSE, $response);
|
||||
}
|
||||
@@ -855,6 +1001,9 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch testing requires that another entity of the same type exists.
|
||||
$this->anotherEntity = $this->createAnotherEntity();
|
||||
|
||||
$this->initAuthentication();
|
||||
$has_canonical_url = $this->entity->hasLinkTemplate('canonical');
|
||||
|
||||
@@ -862,8 +1011,12 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$unparseable_request_body = '!{>}<';
|
||||
$parseable_valid_request_body = $this->serializer->encode($this->getNormalizedPatchEntity(), static::$format);
|
||||
$parseable_valid_request_body_2 = $this->serializer->encode($this->getNormalizedPatchEntity(), static::$format);
|
||||
$parseable_invalid_request_body = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPatchEntity()), static::$format);
|
||||
$parseable_invalid_request_body = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPatchEntity(), 'label'), static::$format);
|
||||
$parseable_invalid_request_body_2 = $this->serializer->encode($this->getNormalizedPatchEntity() + ['field_rest_test' => [['value' => $this->randomString()]]], static::$format);
|
||||
// The 'field_rest_test' field does not allow 'view' access, so does not end
|
||||
// up in the normalization. Even when we explicitly add it the normalization
|
||||
// that we send in the body of a PATCH request, it is considered invalid.
|
||||
$parseable_invalid_request_body_3 = $this->serializer->encode($this->getNormalizedPatchEntity() + ['field_rest_test' => $this->entity->get('field_rest_test')->getValue()], static::$format);
|
||||
|
||||
// The URL and Guzzle request options that will be used in this test. The
|
||||
// request options will be modified/expanded throughout this test:
|
||||
@@ -932,7 +1085,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// DX: forgetting authentication: authentication provider-specific error
|
||||
// response.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResponseWhenMissingAuthentication($response);
|
||||
$this->assertResponseWhenMissingAuthentication('PATCH', $response);
|
||||
}
|
||||
|
||||
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
@@ -955,22 +1108,43 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'field_rest_test'.", $response);
|
||||
|
||||
// DX: 403 when sending PATCH request with read-only fields.
|
||||
// First send all fields (the "maximum normalization"). Assert the expected
|
||||
// error message for the first PATCH-protected field. Remove that field from
|
||||
// the normalization, send another request, assert the next PATCH-protected
|
||||
// field error message. And so on.
|
||||
$max_normalization = $this->getNormalizedPatchEntity() + $this->serializer->normalize($this->entity, static::$format);
|
||||
for ($i = 0; $i < count(static::$patchProtectedFieldNames); $i++) {
|
||||
$max_normalization = $this->removeFieldsFromNormalization($max_normalization, array_slice(static::$patchProtectedFieldNames, 0, $i));
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->serialize($max_normalization, static::$format);
|
||||
// DX: 403 when entity trying to update an entity's ID field.
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPatchEntity(), 'id'), static::$format);;
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field '{$this->entity->getEntityType()->getKey('id')}'.", $response);
|
||||
|
||||
if ($this->entity->getEntityType()->hasKey('uuid')) {
|
||||
// DX: 403 when entity trying to update an entity's UUID field.
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($this->makeNormalizationInvalid($this->getNormalizedPatchEntity(), 'uuid'), static::$format);;
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field '" . static::$patchProtectedFieldNames[$i] . "'.", $response);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field '{$this->entity->getEntityType()->getKey('uuid')}'.", $response);
|
||||
}
|
||||
|
||||
// 200 for well-formed request that sends the maximum number of fields.
|
||||
$max_normalization = $this->removeFieldsFromNormalization($max_normalization, static::$patchProtectedFieldNames);
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->serialize($max_normalization, static::$format);
|
||||
$request_options[RequestOptions::BODY] = $parseable_invalid_request_body_3;
|
||||
|
||||
// DX: 403 when entity contains field without 'edit' nor 'view' access, even
|
||||
// when the value for that field matches the current value. This is allowed
|
||||
// in principle, but leads to information disclosure.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'field_rest_test'.", $response);
|
||||
|
||||
// DX: 403 when sending PATCH request with updated read-only fields.
|
||||
list($modified_entity, $original_values) = static::getModifiedEntityForPatchTesting($this->entity);
|
||||
// Send PATCH request by serializing the modified entity, assert the error
|
||||
// response, change the modified entity field that caused the error response
|
||||
// back to its original value, repeat.
|
||||
for ($i = 0; $i < count(static::$patchProtectedFieldNames); $i++) {
|
||||
$patch_protected_field_name = static::$patchProtectedFieldNames[$i];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->serialize($modified_entity, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field '" . $patch_protected_field_name . "'.", $response);
|
||||
$modified_entity->get($patch_protected_field_name)->setValue($original_values[$patch_protected_field_name]);
|
||||
}
|
||||
|
||||
// 200 for well-formed PATCH request that sends all fields (even including
|
||||
// read-only ones, but with unchanged values).
|
||||
$valid_request_body = $this->getNormalizedPatchEntity() + $this->serializer->normalize($this->entity, static::$format);
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->serialize($valid_request_body, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
@@ -1013,6 +1187,25 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// is not sent in the PATCH request.
|
||||
$this->assertSame('All the faith he had had had had no effect on the outcome of his life.', $updated_entity->get('field_rest_test')->value);
|
||||
|
||||
// Multi-value field: remove item 0. Then item 1 becomes item 0.
|
||||
$normalization_multi_value_tests = $this->getNormalizedPatchEntity();
|
||||
$normalization_multi_value_tests['field_rest_test_multivalue'] = $this->entity->get('field_rest_test_multivalue')->getValue();
|
||||
$normalization_remove_item = $normalization_multi_value_tests;
|
||||
unset($normalization_remove_item['field_rest_test_multivalue'][0]);
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization_remove_item, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$this->assertSame([0 => ['value' => 'Two']], $this->entityStorage->loadUnchanged($this->entity->id())->get('field_rest_test_multivalue')->getValue());
|
||||
|
||||
// Multi-value field: add one item before the existing one, and one after.
|
||||
$normalization_add_items = $normalization_multi_value_tests;
|
||||
$normalization_add_items['field_rest_test_multivalue'][2] = ['value' => 'Three'];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization_add_items, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$this->assertSame([0 => ['value' => 'One'], 1 => ['value' => 'Two'], 2 => ['value' => 'Three']], $this->entityStorage->loadUnchanged($this->entity->id())->get('field_rest_test_multivalue')->getValue());
|
||||
|
||||
// BC: rest_update_8203().
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
$request_options[RequestOptions::BODY] = $parseable_valid_request_body_2;
|
||||
@@ -1082,7 +1275,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
// DX: forgetting authentication: authentication provider-specific error
|
||||
// response.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
$this->assertResponseWhenMissingAuthentication($response);
|
||||
$this->assertResponseWhenMissingAuthentication('DELETE', $response);
|
||||
}
|
||||
|
||||
$request_options = NestedArray::mergeDeep($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
@@ -1099,14 +1292,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// 204 for well-formed request.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
$this->assertSame(204, $response->getStatusCode());
|
||||
// DELETE responses should not include a Content-Type header. But Apache
|
||||
// sets it to 'text/html' by default. We also cannot detect the presence of
|
||||
// Apache either here in the CLI. For now having this documented here is all
|
||||
// we can do.
|
||||
// $this->assertSame(FALSE, $response->hasHeader('Content-Type'));
|
||||
$this->assertSame('', (string) $response->getBody());
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
$this->assertResourceResponse(204, '', $response);
|
||||
|
||||
$this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE);
|
||||
$this->refreshTestStateAfterRestConfigChange();
|
||||
@@ -1121,11 +1307,7 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
|
||||
// 204 for well-formed request.
|
||||
$response = $this->request('DELETE', $url, $request_options);
|
||||
$this->assertSame(204, $response->getStatusCode());
|
||||
// @todo Uncomment the following line when https://www.drupal.org/node/2821711 is fixed.
|
||||
// $this->assertSame(FALSE, $response->hasHeader('Content-Type'));
|
||||
$this->assertSame('', (string) $response->getBody());
|
||||
$this->assertFalse($response->hasHeader('X-Drupal-Cache'));
|
||||
$this->assertResourceResponse(204, '', $response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1184,40 +1366,84 @@ abstract class EntityResourceTestBase extends ResourceTestBase {
|
||||
return $has_create_url ? Url::fromUri('internal:' . $this->entity->getEntityType()->getLinkTemplate('create')) : Url::fromUri('base:entity/' . static::$entityTypeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the given entity and modifies all PATCH-protected fields.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity being tested and to modify.
|
||||
*
|
||||
* @return array
|
||||
* Contains two items:
|
||||
* 1. The modified entity object.
|
||||
* 2. The original field values, keyed by field name.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected static function getModifiedEntityForPatchTesting(EntityInterface $entity) {
|
||||
$modified_entity = clone $entity;
|
||||
$original_values = [];
|
||||
foreach (static::$patchProtectedFieldNames as $field_name) {
|
||||
$field = $modified_entity->get($field_name);
|
||||
$original_values[$field_name] = $field->getValue();
|
||||
switch ($field->getItemDefinition()->getClass()) {
|
||||
case EntityReferenceItem::class:
|
||||
// EntityReferenceItem::generateSampleValue() picks one of the last 50
|
||||
// entities of the supported type & bundle. We don't care if the value
|
||||
// is valid, we only care that it's different.
|
||||
$field->setValue(['target_id' => 99999]);
|
||||
break;
|
||||
case BooleanItem::class:
|
||||
// BooleanItem::generateSampleValue() picks either 0 or 1. So a 50%
|
||||
// chance of not picking a different value.
|
||||
$field->value = ((int) $field->value) === 1 ? '0' : '1';
|
||||
break;
|
||||
case PathItem::class:
|
||||
// PathItem::generateSampleValue() doesn't set a PID, which causes
|
||||
// PathItem::postSave() to fail. Keep the PID (and other properties),
|
||||
// just modify the alias.
|
||||
$field->alias = str_replace(' ', '-', strtolower((new Random())->sentences(3)));
|
||||
break;
|
||||
default:
|
||||
$original_field = clone $field;
|
||||
while ($field->equals($original_field)) {
|
||||
$field->generateSampleItems();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [$modified_entity, $original_values];
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the given entity normalization invalid.
|
||||
*
|
||||
* @param array $normalization
|
||||
* An entity normalization.
|
||||
* @param string $entity_key
|
||||
* The entity key whose normalization to make invalid.
|
||||
*
|
||||
* @return array
|
||||
* The updated entity normalization, now invalid.
|
||||
*/
|
||||
protected function makeNormalizationInvalid(array $normalization) {
|
||||
// Add a second label to this entity to make it invalid.
|
||||
$label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
|
||||
$normalization[$label_field][1]['value'] = 'Second Title';
|
||||
|
||||
protected function makeNormalizationInvalid(array $normalization, $entity_key) {
|
||||
$entity_type = $this->entity->getEntityType();
|
||||
switch ($entity_key) {
|
||||
case 'label':
|
||||
// Add a second label to this entity to make it invalid.
|
||||
$label_field = $entity_type->hasKey('label') ? $entity_type->getKey('label') : static::$labelFieldName;
|
||||
$normalization[$label_field][1]['value'] = 'Second Title';
|
||||
break;
|
||||
case 'id':
|
||||
$normalization[$entity_type->getKey('id')][0]['value'] = $this->anotherEntity->id();
|
||||
break;
|
||||
case 'uuid':
|
||||
$normalization[$entity_type->getKey('uuid')][0]['value'] = $this->anotherEntity->uuid();
|
||||
break;
|
||||
}
|
||||
return $normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes fields from a normalization.
|
||||
*
|
||||
* @param array $normalization
|
||||
* An entity normalization.
|
||||
* @param string[] $field_names
|
||||
* The field names to remove from the entity normalization.
|
||||
*
|
||||
* @return array
|
||||
* The updated entity normalization.
|
||||
*
|
||||
* @see ::testPatch
|
||||
*/
|
||||
protected function removeFieldsFromNormalization(array $normalization, $field_names) {
|
||||
return array_diff_key($normalization, array_flip($field_names));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a 406 response… or in some cases a 403 response, because weirdness.
|
||||
*
|
||||
|
||||
+2
@@ -3,6 +3,7 @@
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\FormatSpecificGetBcRouteTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
@@ -10,6 +11,7 @@ use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
class EntityTestJsonAnonTest extends EntityTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use FormatSpecificGetBcRouteTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* Test that internal properties are not exposed in the 'json' format.
|
||||
*
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestJsonInternalPropertyNormalizerTest extends EntityTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$expected = parent::getExpectedNormalizedEntity();
|
||||
// The 'internal_value' property in test field type is not exposed in the
|
||||
// normalization because setInternal(FALSE) was not called for this
|
||||
// property.
|
||||
// @see \Drupal\entity_test\Plugin\Field\FieldType\InternalPropertyTestFieldItem::propertyDefinitions
|
||||
$expected['field_test_internal'] = [
|
||||
[
|
||||
'value' => 'This value shall not be internal!',
|
||||
'non_internal_value' => 'Computed! This value shall not be internal!',
|
||||
],
|
||||
];
|
||||
return $expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
if (!FieldStorageConfig::loadByName('entity_test', 'field_test_internal')) {
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'field_test_internal',
|
||||
'type' => 'internal_property_test',
|
||||
'cardinality' => 1,
|
||||
'translatable' => FALSE,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'entity_type' => 'entity_test',
|
||||
'field_name' => 'field_test_internal',
|
||||
'bundle' => 'entity_test',
|
||||
'label' => 'Test field with internal and non-internal properties',
|
||||
])->save();
|
||||
}
|
||||
|
||||
$entity = parent::createEntity();
|
||||
$entity->field_test_internal = [
|
||||
'value' => 'This value shall not be internal!',
|
||||
];
|
||||
$entity->save();
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'field_test_internal' => [
|
||||
[
|
||||
'value' => 'This value shall not be internal!',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['request_format']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags(parent::getExpectedCacheTags(), ['you_are_it', 'no_tag_backs']);
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -5,11 +5,13 @@ namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\Tests\Traits\ExpectDeprecationTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
abstract class EntityTestResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
use ExpectDeprecationTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -53,9 +55,20 @@ abstract class EntityTestResourceTestBase extends EntityResourceTestBase {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Set flag so that internal field 'internal_string_field' is created.
|
||||
// @see entity_test_entity_base_field_info()
|
||||
$this->container->get('state')->set('entity_test.internal_field', TRUE);
|
||||
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
|
||||
|
||||
$entity_test = EntityTest::create([
|
||||
'name' => 'Llama',
|
||||
'type' => 'entity_test',
|
||||
// Set a value for the internal field to confirm that it will not be
|
||||
// returned in normalization.
|
||||
// @see entity_test_entity_base_field_info().
|
||||
'internal_string_field' => [
|
||||
'value' => 'This value shall not be internal!',
|
||||
],
|
||||
]);
|
||||
$entity_test->setOwnerId(0);
|
||||
$entity_test->save();
|
||||
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\filter\Entity\FilterFormat;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestTextItemNormalizerTest extends EntityTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['filter_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
parent::setUpAuthorization($method);
|
||||
if (in_array($method, ['POST', 'PATCH'], TRUE)) {
|
||||
$this->grantPermissionsToTestedRole(['use text format my_text_format']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$expected = parent::getExpectedNormalizedEntity();
|
||||
$expected['field_test_text'] = [
|
||||
[
|
||||
'value' => 'Cádiz is the oldest continuously inhabited city in Spain and a nice place to spend a Sunday with friends.',
|
||||
'format' => 'my_text_format',
|
||||
'processed' => '<p>Cádiz is the oldest continuously inhabited city in Spain and a nice place to spend a Sunday with friends.</p>' . "\n" . '<p>This is a dynamic llama.</p>',
|
||||
],
|
||||
];
|
||||
return $expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$entity = parent::createEntity();
|
||||
if (!FilterFormat::load('my_text_format')) {
|
||||
FilterFormat::create([
|
||||
'format' => 'my_text_format',
|
||||
'name' => 'My Text Format',
|
||||
'filters' => [
|
||||
'filter_test_assets' => [
|
||||
'weight' => -1,
|
||||
'status' => TRUE,
|
||||
],
|
||||
'filter_test_cache_tags' => [
|
||||
'weight' => 0,
|
||||
'status' => TRUE,
|
||||
],
|
||||
'filter_test_cache_contexts' => [
|
||||
'weight' => 0,
|
||||
'status' => TRUE,
|
||||
],
|
||||
'filter_test_cache_merge' => [
|
||||
'weight' => 0,
|
||||
'status' => TRUE,
|
||||
],
|
||||
'filter_test_placeholders' => [
|
||||
'weight' => 1,
|
||||
'status' => TRUE,
|
||||
],
|
||||
'filter_autop' => [
|
||||
'status' => TRUE,
|
||||
],
|
||||
],
|
||||
])->save();
|
||||
}
|
||||
$entity->field_test_text = [
|
||||
'value' => 'Cádiz is the oldest continuously inhabited city in Spain and a nice place to spend a Sunday with friends.',
|
||||
'format' => 'my_text_format',
|
||||
];
|
||||
$entity->save();
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
$post_entity = parent::getNormalizedPostEntity();
|
||||
$post_entity['field_test_text'] = [
|
||||
[
|
||||
'value' => 'Llamas are awesome.',
|
||||
'format' => 'my_text_format',
|
||||
],
|
||||
];
|
||||
return $post_entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheTags() {
|
||||
return Cache::mergeTags([
|
||||
// The cache tag set by the processed_text element itself.
|
||||
'config:filter.format.my_text_format',
|
||||
// The cache tags set by the filter_test_cache_tags filter.
|
||||
'foo:bar',
|
||||
'foo:baz',
|
||||
// The cache tags set by the filter_test_cache_merge filter.
|
||||
'merge:tag'
|
||||
], parent::getExpectedCacheTags());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCacheContexts() {
|
||||
return Cache::mergeContexts([
|
||||
// The cache context set by the filter_test_cache_contexts filter.
|
||||
'languages:' . LanguageInterface::TYPE_CONTENT,
|
||||
// The default cache contexts for Renderer.
|
||||
'languages:' . LanguageInterface::TYPE_INTERFACE,
|
||||
'theme',
|
||||
// The cache tags set by the filter_test_cache_merge filter.
|
||||
'user.permissions',
|
||||
], parent::getExpectedCacheContexts());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests GETting an entity with the test text field set to a specific format.
|
||||
*
|
||||
* @dataProvider providerTestGetWithFormat
|
||||
*/
|
||||
public function testGetWithFormat($text_format_id, array $expected_cache_tags) {
|
||||
FilterFormat::create([
|
||||
'name' => 'Pablo Piccasso',
|
||||
'format' => 'pablo',
|
||||
'langcode' => 'es',
|
||||
'filters' => [],
|
||||
])->save();
|
||||
|
||||
// Set TextItemBase field's value for testing, using the given text format.
|
||||
$value = [
|
||||
'value' => $this->randomString(),
|
||||
];
|
||||
if ($text_format_id !== FALSE) {
|
||||
$value['format'] = $text_format_id;
|
||||
}
|
||||
$this->entity->set('field_test_text', $value)->save();
|
||||
|
||||
$this->initAuthentication();
|
||||
$url = $this->getEntityResourceUrl();
|
||||
$url->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = $this->getAuthenticationRequestOptions('GET');
|
||||
$this->provisionEntityResource();
|
||||
$this->setUpAuthorization('GET');
|
||||
$response = $this->request('GET', $url, $request_options);
|
||||
$expected_cache_tags = Cache::mergeTags($expected_cache_tags, parent::getExpectedCacheTags());
|
||||
$this->assertSame($expected_cache_tags, explode(' ', $response->getHeader('X-Drupal-Cache-Tags')[0]));
|
||||
}
|
||||
|
||||
public function providerTestGetWithFormat() {
|
||||
return [
|
||||
'format specified (different from fallback format)' => [
|
||||
'pablo',
|
||||
['config:filter.format.pablo'],
|
||||
],
|
||||
'format specified (happens to be the same as fallback format)' => [
|
||||
'plain_text',
|
||||
['config:filter.format.plain_text'],
|
||||
],
|
||||
'no format specified: fallback format used automatically' => [
|
||||
FALSE,
|
||||
['config:filter.format.plain_text', 'config:filter.settings'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\FormatSpecificGetBcRouteTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestXmlAnonTest extends EntityTestResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use FormatSpecificGetBcRouteTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestXmlBasicAuthTest extends EntityTestResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestXmlCookieTest extends EntityTestResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestBundle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestBundleXmlAnonTest extends EntityTestBundleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestBundle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestBundleXmlBasicAuthTest extends EntityTestBundleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestBundle;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestBundleXmlCookieTest extends EntityTestBundleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelXmlAnonTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelXmlBasicAuthTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityTestLabel;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityTestLabelXmlCookieTest extends EntityTestLabelResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityViewDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityViewDisplayJsonAnonTest extends EntityViewDisplayResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\rest\Functional\EntityResource\EntityViewDisplay;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class EntityViewDisplayJsonBasicAuthTest extends EntityViewDisplayResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user