Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 8.x-1.x
  • 8.x-1.0
  • 8.x-1.0-beta1
  • 8.x-1.0-beta2
  • 8.x-1.0-beta3
  • 8.x-1.0-beta4
  • 8.x-1.0-beta5
  • 8.x-1.1
  • 8.x-1.2
  • 8.x-1.3
10 results

Target

Select target project
  • project/jsonapi_resources
  • issue/jsonapi_resources-3187549
  • issue/jsonapi_resources-3189198
  • issue/jsonapi_resources-3275484
  • issue/jsonapi_resources-3175411
  • issue/jsonapi_resources-3304054
  • issue/jsonapi_resources-3339626
  • issue/jsonapi_resources-3351926
  • issue/jsonapi_resources-3417106
  • issue/jsonapi_resources-3200821
  • issue/jsonapi_resources-3444940
  • issue/jsonapi_resources-3172884
  • issue/jsonapi_resources-3105792
  • issue/jsonapi_resources-3198310
  • issue/jsonapi_resources-3431484
  • issue/jsonapi_resources-3155966
  • issue/jsonapi_resources-3362189
  • issue/jsonapi_resources-3458259
  • issue/jsonapi_resources-3114758
  • issue/jsonapi_resources-3461125
  • issue/jsonapi_resources-3461129
21 results
Select Git revision
  • 3362189-implement-valueresolverinterface-instead
  • 3431484-automated-drupal-11
  • 8.x-1.x
  • project-update-bot-only
  • 8.x-1.0-beta1
  • 8.x-1.0-beta2
  • 8.x-1.0-beta3
  • 8.x-1.0-beta4
  • 8.x-1.0-beta5
  • previous/3431484-automated-drupal-11/2024-05-25
  • previous/3431484-automated-drupal-11/2024-05-25-1
  • previous/3431484-automated-drupal-11/2024-06-03
  • previous/project-update-bot-only/2024-04-04
13 results
Show changes
Commits on Source (6)
Showing
with 400 additions and 127 deletions
################
# DrupalCI GitLabCI template
# GitLabCI template for Drupal projects.
#
# Gitlab-ci.yml to replicate DrupalCI testing for Contrib
#
# With thanks to:
# * The GitLab Acceleration Initiative participants
# * DrupalSpoons
################
################
# Guidelines
#
# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification. It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained.
#
# However, you can modify this template if you have additional needs for your project.
################
################
# Includes
#
# Additional configuration can be provided through includes.
# One advantage of include files is that if they are updated upstream, the changes affect all pipelines using that include.
#
# Includes can be overridden by re-declaring anything provided in an include, here in gitlab-ci.yml
# https://docs.gitlab.com/ee/ci/yaml/includes.html#override-included-configuration-values
# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification.
# It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained.
# As long as you include the project, ref and three files below, any future updates added by the Drupal Association will be used in your
# pipelines automatically. However, you can modify this template if you have additional needs for your project.
# The full documentation is on https://project.pages.drupalcode.org/gitlab_templates/
################
# For information on alternative values for 'ref' see https://project.pages.drupalcode.org/gitlab_templates/info/templates-version/
# To test a Drupal 7 project, change the first include filename from .main.yml to .main-d7.yml
include:
################
# DrupalCI includes:
# As long as you include this, any future includes added by the Drupal Association will be accessible to your pipelines automatically.
# View these include files at https://git.drupalcode.org/project/gitlab_templates/
################
- project: $_GITLAB_TEMPLATES_REPO
ref: $_GITLAB_TEMPLATES_REF
file:
- '/includes/include.drupalci.main.yml'
- '/includes/include.drupalci.variables.yml'
- '/includes/include.drupalci.workflows.yml'
- "/includes/include.drupalci.main.yml"
- "/includes/include.drupalci.variables.yml"
- "/includes/include.drupalci.workflows.yml"
# Require optional CI tests to pass.
phpcs:
allow_failure: false
################
# Pipeline configuration variables
#
# These are the variables provided to the Run Pipeline form that a user may want to override.
#
# Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
# Pipeline configuration variables are defined with default values and descriptions in the file
# https://git.drupalcode.org/project/gitlab_templates/-/blob/main/includes/include.drupalci.variables.yml
# Uncomment the lines below if you want to override any of the variables. The following is just an example.
################
variables:
OPT_IN_TEST_PREVIOUS_MAJOR: 1
CORE_PREVIOUS_PHP_MIN: 8.0
OPT_IN_TEST_PREVIOUS_MINOR: 1
OPT_IN_TEST_NEXT_MINOR: 1
###################################################################################
#
# *
# /(
# ((((,
# /(((((((
# ((((((((((*
# ,(((((((((((((((
# ,(((((((((((((((((((
# ((((((((((((((((((((((((*
# *(((((((((((((((((((((((((((((
# ((((((((((((((((((((((((((((((((((*
# *(((((((((((((((((( .((((((((((((((((((
# ((((((((((((((((((. /(((((((((((((((((*
# /((((((((((((((((( .(((((((((((((((((,
# ,(((((((((((((((((( ((((((((((((((((((
# .(((((((((((((((((((( .(((((((((((((((((
# ((((((((((((((((((((((( ((((((((((((((((/
# (((((((((((((((((((((((((((/ ,(((((((((((((((*
# .((((((((((((((/ /(((((((((((((. ,(((((((((((((((
# *(((((((((((((( ,(((((((((((((/ *((((((((((((((.
# ((((((((((((((, /(((((((((((((. ((((((((((((((,
# (((((((((((((/ ,(((((((((((((* ,(((((((((((((,
# *((((((((((((( .((((((((((((((( ,(((((((((((((
# ((((((((((((/ /((((((((((((((((((. ,((((((((((((/
# ((((((((((((( *(((((((((((((((((((((((* *((((((((((((
# ((((((((((((( ,(((((((((((((..((((((((((((( *((((((((((((
# ((((((((((((, /((((((((((((* /((((((((((((/ ((((((((((((
# ((((((((((((( /((((((((((((/ (((((((((((((* ((((((((((((
# (((((((((((((/ /(((((((((((( ,((((((((((((, *((((((((((((
# (((((((((((((( *(((((((((((/ *((((((((((((. ((((((((((((/
# *((((((((((((((((((((((((((, /(((((((((((((((((((((((((
# ((((((((((((((((((((((((( ((((((((((((((((((((((((,
# .(((((((((((((((((((((((/ ,(((((((((((((((((((((((
# ((((((((((((((((((((((/ ,(((((((((((((((((((((/
# *((((((((((((((((((((( (((((((((((((((((((((,
# ,(((((((((((((((((((((, ((((((((((((((((((((/
# ,(((((((((((((((((((((* /((((((((((((((((((((
# ((((((((((((((((((((((, ,/((((((((((((((((((((,
# ,(((((((((((((((((((((((((((((((((((((((((((((((((((
# .(((((((((((((((((((((((((((((((((((((((((((((
# .((((((((((((((((((((((((((((((((((((,.
# .,(((((((((((((((((((((((((.
#
###################################################################################
OPT_IN_TEST_NEXT_MAJOR: 1
name: 'JSON:API Resources'
description: "This module let's you define custom resources at routes of your choice that use existing resource types."
core_version_requirement: ^9.1 || ^10
core_version_requirement: ^9.1 || ^10 || ^11
type: module
dependencies:
- drupal:jsonapi
......@@ -106,7 +106,7 @@ abstract class ResourceBase {
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function createJsonapiResponse(ResourceObjectData $data, Request $request, $response_code = 200, array $headers = [], LinkCollection $links = NULL, array $meta = []): ResourceResponse {
protected function createJsonapiResponse(ResourceObjectData $data, Request $request, $response_code = 200, array $headers = [], ?LinkCollection $links = NULL, array $meta = []): ResourceResponse {
return $this->resourceResponseFactory->create($data, $request, $response_code, $headers, $links, $meta);
}
......
......@@ -7,41 +7,71 @@ namespace Drupal\jsonapi_resources\Unstable\Controller\ArgumentResolver;
use Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel;
use Drupal\jsonapi_resources\Unstable\DocumentExtractor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
// The ArgumentValueResolverInterface is deprecated since Symfony 6.2 and
// removed from Symfony 7. Hence, below workaround to run PHPUnit tests against
// Drupal 9, 10 and 11.
// @todo Remove when all supported versions require Symfony 7.
if (!interface_exists(ValueResolverInterface::class)) {
class_alias('\Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface', ValueResolverInterface::class);
}
/**
* Deserializes POST, PATCH and DELETE request documents.
*
* @internal
*/
final class DocumentResolver implements ArgumentValueResolverInterface {
final class DocumentResolver implements ValueResolverInterface {
public function __construct(
protected DocumentExtractor $documentExtractor,
) {}
/**
* The document extractor.
* Backwards-compatibility layer for Symfony < 7.
*
* @var \Drupal\jsonapi_resources\Unstable\DocumentExtractor
* @todo Remove when all supported versions of Drupal require Symfony 7.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* Request.
* @param \Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata $argument
* Argument metadata.
*
* @return bool
* Flag indicating supported status.
*/
protected $documentExtractor;
public function supports(Request $request, ArgumentMetadata $argument): bool {
return $this->shouldResolve($request, $argument);
}
/**
* Constructs a JSON:API document argument resolver.
*
* @param \Drupal\jsonapi_resources\Unstable\DocumentExtractor $document_extractor
* The document extractor.
* {@inheritdoc}
*/
public function __construct(DocumentExtractor $document_extractor) {
$this->documentExtractor = $document_extractor;
public function resolve(Request $request, ArgumentMetadata $argument): iterable {
if (!$this->shouldResolve($request, $argument)) {
return [];
}
yield $this->documentExtractor->getDocument($request);
}
/**
* {@inheritdoc}
* Gets whether the given request should be resolved.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request.
* @param \Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata $argument
* The argument.
*
* @return bool
* Whether the given request should be resolved.
*/
public function supports(Request $request, ArgumentMetadata $argument): bool {
private function shouldResolve(Request $request, ArgumentMetadata $argument): bool {
$supported_method = in_array($request->getMethod(), [
'POST',
'PATCH',
]);
], TRUE);
$is_delete = $request->isMethod('DELETE');
$is_relationship = $request->attributes->has('_jsonapi_relationship_field_name');
$supported_method = $supported_method || ($is_delete && $is_relationship);
......@@ -50,11 +80,4 @@ final class DocumentResolver implements ArgumentValueResolverInterface {
return $supported_method && $supported_format && $correct_type;
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument): iterable {
yield $this->documentExtractor->getDocument($request);
}
}
......@@ -52,7 +52,7 @@ trait EntityCreationTrait {
}
$entity = $this->resourceObjectToEntityMapper->createEntityFromResourceObject($data->getIterator()->current());
// Allow the class using this trait to modfiy the created entity before it
// Allow the class using this trait to modify the created entity before it
// is saved.
$this->modifyCreatedEntity($entity, $request);
......
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Drupal\jsonapi_resources\Unstable;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Http\Exception\CacheableBadRequestHttpException;
use Drupal\Core\Url;
use Drupal\jsonapi\CacheableResourceResponse;
use Drupal\jsonapi\IncludeResolver;
......@@ -13,9 +14,11 @@ use Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel;
use Drupal\jsonapi\JsonApiResource\Link;
use Drupal\jsonapi\JsonApiResource\LinkCollection;
use Drupal\jsonapi\JsonApiResource\NullIncludedData;
use Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface;
use Drupal\jsonapi\JsonApiResource\ResourceObject;
use Drupal\jsonapi\JsonApiResource\ResourceObjectData;
use Drupal\jsonapi\ResourceResponse;
use Drupal\jsonapi\ResourceType\ResourceType;
use Symfony\Component\HttpFoundation\Request;
/**
......@@ -66,7 +69,7 @@ final class ResourceResponseFactory {
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function create(ResourceObjectData $data, Request $request, $response_code = 200, array $headers = [], LinkCollection $links = NULL, array $meta = []) {
public function create(ResourceObjectData $data, Request $request, $response_code = 200, array $headers = [], ?LinkCollection $links = NULL, array $meta = []) {
$links = ($links ?: new LinkCollection([]));
if (!$links->hasLinkWithKey('self')) {
$self_link = new Link(new CacheableMetadata(), Url::fromUri($request->getUri()), 'self');
......@@ -97,21 +100,87 @@ final class ResourceResponseFactory {
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
* @param \Drupal\jsonapi\JsonApiResource\ResourceObject|\Drupal\jsonapi\JsonApiResource\ResourceObjectData $data
* @param \Drupal\jsonapi\JsonApiResource\ResourceObjectData|\Drupal\jsonapi\JsonApiResource\ResourceObject $data
* The response data from which to resolve includes.
*
* @return \Drupal\jsonapi\JsonApiResource\IncludedData
* A Data object to be included or a NullData object if the request does not
* A Data object to be included or a NullData object if the request does
* not
* specify any include paths.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
private function getIncludes(Request $request, $data): IncludedData {
private function getIncludes(Request $request, ResourceObjectData|ResourceObject $data): IncludedData {
assert($data instanceof ResourceObject || $data instanceof ResourceObjectData);
return $request->query->has('include') && ($include_parameter = $request->query->get('include')) && !empty($include_parameter)
? $this->includeResolver->resolve($data, $include_parameter)
: new NullIncludedData();
if (!$request->query->has('include')) {
return new NullIncludedData();
}
$include_parameter = $request->query->get('include');
if (empty($include_parameter)) {
return new NullIncludedData();
}
if ($data instanceof ResourceObject) {
return $this->includeResolver->resolve($data, $include_parameter);
}
/** @var \Drupal\jsonapi\ResourceType\ResourceType[] $route_resource_types */
$route_resource_types = $request->attributes->get('resource_types');
$relatable_resource_types = array_map(
static fn (ResourceType $type) => array_keys($type->getRelatableResourceTypes()),
$route_resource_types
);
// Group resource objects to optimize IncludeResolver::toIncludeTree.
$resource_objects_by_type = [];
foreach ($data as $resource_object) {
assert($resource_object instanceof ResourceIdentifierInterface);
$resource_objects_by_type[$resource_object->getTypeName()][] = $resource_object;
}
$include_paths = array_map('trim', explode(',', $include_parameter));
$unresolved_include_paths = [];
$included_data = [];
foreach ($resource_objects_by_type as $resource_objects) {
foreach ($include_paths as $include_path) {
try {
$included_data[] = $this->includeResolver->resolve(
new ResourceObjectData($resource_objects),
$include_path
);
$unresolved_include_paths[$include_path] = FALSE;
}
catch (\Exception) {
if (!isset($unresolved_include_paths[$include_path])) {
$unresolved_include_paths[$include_path] = TRUE;
}
}
}
}
if (count(array_filter($unresolved_include_paths)) > 0) {
// Throw an error if invalid include paths provided.
// @see \Drupal\jsonapi\Context\FieldResolver::resolveInternalIncludePath().
$message = sprintf(
'%s are not valid relationship names.',
implode(',', array_map(static fn (string $path) => "`$path`", array_keys($unresolved_include_paths)))
);
if (count($relatable_resource_types) > 0) {
$message .= sprintf(' Possible values: %s', implode(', ', array_unique(array_merge(...$relatable_resource_types))));
}
throw new CacheableBadRequestHttpException(
(new CacheableMetadata())->addCacheContexts(['url.query_args:include']),
$message
);
}
$included_data = array_reduce(
$included_data,
[IncludedData::class, 'merge'],
new IncludedData([])
);
return IncludedData::deduplicate($included_data);
}
}
......@@ -2,6 +2,7 @@ name: 'JSON:API Resources test module'
description: "Tests for JSON:API Resources."
type: module
package: Testing
core_version_requirement: ^9.1 || ^10 || ^11
dependencies:
- drupal:node
- jsonapi_resources:jsonapi_resources
......@@ -2,10 +2,10 @@
namespace Drupal\jsonapi_resources_test\Resource;
use Drupal\comment\CommentInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\comment\CommentInterface;
use Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel;
use Drupal\jsonapi\ResourceResponse;
use Drupal\jsonapi_resources\Resource\EntityQueryResourceBase;
......
......@@ -2,22 +2,28 @@
namespace Drupal\Tests\jsonapi_resources\Functional;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
use Drupal\Tests\jsonapi\Functional\JsonApiRequestTestTrait;
use Drupal\Tests\jsonapi\Functional\ResourceResponseTestTrait;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use GuzzleHttp\RequestOptions;
// Workaround to support tests against Drupal 9, 10 and 11.
// @todo Remove once we end support for Drupal 10.1.x and below.
if (!trait_exists(EntityReferenceFieldCreationTrait::class)) {
class_alias('\Drupal\Tests\field\Traits\EntityReferenceTestTrait', EntityReferenceFieldCreationTrait::class);
}
/**
* Tests JSON:API Resource processors.
*
......@@ -27,7 +33,7 @@ class JsonapiResourceTest extends BrowserTestBase {
use JsonApiRequestTestTrait;
use ResourceResponseTestTrait;
use EntityReferenceTestTrait;
use EntityReferenceFieldCreationTrait;
use CommentTestTrait;
/**
......@@ -300,7 +306,7 @@ class JsonapiResourceTest extends BrowserTestBase {
'attributes' => [
'entity_type' => 'node',
'field_name' => 'comment',
'subject' => 'Dramallama',
'subject' => 'Drama llama',
'status' => 1,
'comment_body' => [
'value' => 'Llamas are awesome.',
......
......@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi_resources\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi_resources\Unstable\Value\NewResourceObject;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Symfony\Component\HttpFoundation\Request;
......
<?php
declare(strict_types=1);
namespace Drupal\Tests\jsonapi_resources\Kernel;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Drupal\jsonapi\CacheableResourceResponse;
use Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel;
use Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface;
use Drupal\jsonapi\JsonApiResource\ResourceObject;
use Drupal\jsonapi\JsonApiResource\ResourceObjectData;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Symfony\Component\HttpFoundation\Request;
// Workaround to support tests against Drupal 9, 10 and 11.
// @todo Remove once we end support for Drupal 10.1.x and below.
if (!trait_exists(EntityReferenceFieldCreationTrait::class)) {
class_alias('\Drupal\Tests\field\Traits\EntityReferenceTestTrait', EntityReferenceFieldCreationTrait::class);
}
/**
* Tests ResourceResponseFactory.
*
* @coversDefaultClass \Drupal\jsonapi_resources\Unstable\ResourceResponseFactory
* @group jsonapi_resources
*/
final class ResourceResponseFactoryTest extends KernelTestBase {
use EntityReferenceFieldCreationTrait;
use UserCreationTrait;
private const NODE_TYPE_ARTICLE_UUID = 'e5da5021-d7a0-4606-a21c-9586a8cf79a4';
private const NODE_TYPE_PAGE_UUID = '8378b97d-36fd-4515-b2eb-22e90dfdc8dc';
private const NODE_TYPE_EVENT_UUID = '12cce39f-fa9c-4c64-b7f6-a0ec511ba1e7';
private const NODE_ARTICLE_1_UUID = '7bf77016-93d2-4098-84e4-c2634c4d8ecf';
private const NODE_ARTICLE_2_UUID = '36405873-6b42-44ec-9f47-b771d83149b1';
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'user',
'field',
'file',
'serialization',
'jsonapi',
'jsonapi_resources',
'node',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->account = $this->createUser();
$this->container->get('current_user')->setAccount($this->account);
NodeType::create([
'uuid' => self::NODE_TYPE_ARTICLE_UUID,
'name' => 'article',
'type' => 'article',
])->save();
NodeType::create([
'uuid' => self::NODE_TYPE_PAGE_UUID,
'name' => 'page',
'type' => 'page',
])->save();
NodeType::create([
'uuid' => self::NODE_TYPE_EVENT_UUID,
'name' => 'event',
'type' => 'event',
])->save();
$this->createEntityReferenceField(
'node',
'page',
'field_related_articles',
'Related articles',
'node',
'default',
[
'target_bundles' => [
'reminder' => 'article',
],
],
FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
);
$this->container->get('router.builder')->rebuildIfNeeded();
}
/**
* @covers ::create
* @dataProvider createData
*/
public function testCreate(
array $query,
array $expected_includes,
string $expected_error = '',
): void {
if ($expected_error !== '') {
$this->expectExceptionMessage($expected_error);
}
$article1 = Node::create([
'uuid' => self::NODE_ARTICLE_1_UUID,
'type' => 'article',
'title' => $this->randomString(),
'status' => 1,
]);
$article1->save();
$article2 = Node::create([
'uuid' => self::NODE_ARTICLE_2_UUID,
'type' => 'article',
'title' => $this->randomString(),
'status' => 1,
]);
$article2->save();
$page = Node::create([
'type' => 'page',
'title' => $this->randomString(),
'status' => 1,
'field_related_articles' => [$article1->id(), $article2->id()],
]);
$page->save();
$event = Node::create([
'type' => 'event',
'title' => $this->randomString(),
'status' => 1,
]);
$event->save();
$resource_type_repository = $this->container->get('jsonapi.resource_type.repository');
self::assertInstanceOf(ResourceTypeRepositoryInterface::class, $resource_type_repository);
$entities = [$article1, $page, $article2, $event];
$resource_types = [];
$resource_objects = [];
foreach ($entities as $entity) {
$resource_type = $resource_type_repository->get($entity->getEntityTypeId(), $entity->bundle());
$resource_types[$resource_type->getTypeName()] = $resource_type;
$resource_objects[] = ResourceObject::createFromEntity($resource_type, $entity);
}
$request = Request::create('/foo?' . http_build_query($query));
$request->attributes->set('resource_types', array_values($resource_types));
$sut = $this->container->get('jsonapi_resources.resource_response_factory');
$response = $sut->create(
new ResourceObjectData($resource_objects),
$request
);
self::assertInstanceOf(CacheableResourceResponse::class, $response);
$document_top_level = $response->getResponseData();
self::assertInstanceOf(JsonApiDocumentTopLevel::class, $document_top_level);
/** @var \Drupal\jsonapi\JsonApiResource\ResourceIdentifierInterface[] $includes_data */
$includes_data = $document_top_level->getIncludes()->toArray();
$includes_data = array_map(
static fn (ResourceIdentifierInterface $identifier) => [
'id' => $identifier->getId(),
'type' => $identifier->getTypeName(),
],
$includes_data
);
self::assertEquals($expected_includes, $includes_data);
}
/**
* Test data for testCreate.
*
* @return array[]
* The test data.
*/
public static function createData(): array {
return [
'mixed resource objects with same include' => [
['include' => 'node_type'],
[
[
'id' => self::NODE_TYPE_ARTICLE_UUID,
'type' => 'node_type--node_type',
],
[
'id' => self::NODE_TYPE_PAGE_UUID,
'type' => 'node_type--node_type',
],
[
'id' => self::NODE_TYPE_EVENT_UUID,
'type' => 'node_type--node_type',
],
],
],
'mixed resource objects with mismatched includes' => [
['include' => 'field_related_articles'],
[
[
'id' => self::NODE_ARTICLE_1_UUID,
'type' => 'node--article',
],
[
'id' => self::NODE_ARTICLE_2_UUID,
'type' => 'node--article',
],
],
],
'missing relationship in includes' => [
['include' => 'field_foobar'],
[],
'field_foobar` are not valid relationship names. Possible values: node_type, revision_uid, uid, field_related_articles',
],
];
}
}
......@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi_resources\Kernel;
use Drupal\jsonapi_resources\Unstable\Routing\Enhancer\ResourceEnhancer;
use Drupal\KernelTests\KernelTestBase;
use Drupal\jsonapi_resources\Unstable\Routing\Enhancer\ResourceEnhancer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
......@@ -46,7 +46,7 @@ final class ResourceEnhancerTest extends KernelTestBase {
// Ensure that the enhancer ignores routes that already have a controller
// defined.
$route_defaults = [
'_controller' => '\\Drupal\\mymodule\\Controller\\Doesnt::exist',
'_controller' => '\\Drupal\\mymodule\\Controller\\DoesNot::exist',
];
$enhanced_defaults = $resource_enhancer->enhance($route_defaults, Request::createFromGlobals());
$this->assertSame($enhanced_defaults['_controller'], $route_defaults['_controller']);
......
......@@ -5,10 +5,10 @@ declare(strict_types=1);
namespace Drupal\Tests\jsonapi_resources\Unit\Routing;
use Drupal\Core\Routing\RouteBuildEvent;
use Drupal\Tests\UnitTestCase;
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
use Drupal\jsonapi_resources\Exception\RouteDefinitionException;
use Drupal\jsonapi_resources\Unstable\Routing\ResourceRoutes;
use Drupal\Tests\UnitTestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
......@@ -35,7 +35,15 @@ final class ResourceRoutesTest extends UnitTestCase {
'_jsonapi_resource_types' => ['node--article'],
];
$route_collection->add('jsonapi_resource_route', new Route('/%jsonapi%/resource', $route_defaults));
$route_collection->add('jsonapi_resource_multi_method_route', new Route('/%jsonapi%/resource', $route_defaults, [], [], '', [], ['POST', 'PATCH']));
$route_collection->add('jsonapi_resource_multi_method_route', new Route(
'/%jsonapi%/resource',
$route_defaults,
[],
[],
'',
[],
['POST', 'PATCH'],
));
$route_rebuild_event = new RouteBuildEvent($route_collection);
......