diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 76bc81e728aa85e1dd79d465ef88f715eb53a3c6..19ad8ddc359c54eeb7721d7c71c7859bb2f118ed 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,7 @@ variables: OPT_IN_TEST_PREVIOUS_MINOR: 1 OPT_IN_TEST_NEXT_MINOR: 1 OPT_IN_TEST_MAX_PHP: 1 + _PHPUNIT_CONCURRENT: 1 phpstan (custom): extends: phpstan diff --git a/composer.json b/composer.json index 3c16f405edfa5b986e3770a59249789d43923712..064b79dae36291a46073978a112a3cb939de68e6 100644 --- a/composer.json +++ b/composer.json @@ -10,14 +10,14 @@ "webonyx/graphql-php": "^15.19.1" }, "require-dev": { - "drupal/coder": "8.3.26", + "drupal/coder": "8.3.28", "slevomat/coding-standard": "^8.16", "drupal/redirect": "^1.0", - "phpstan/phpstan": "^1.11.2", - "mglaman/phpstan-drupal": "^1.1.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "jangregor/phpstan-prophecy": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan": "^2.1.11 || ^1", + "mglaman/phpstan-drupal": "^2.0.2 || ^1", + "phpstan/phpstan-deprecation-rules": "^2 || ^1", + "jangregor/phpstan-prophecy": "^2 || ^1", + "phpstan/phpstan-phpunit": "^2 || ^1", "phpstan/extension-installer": "^1.0" }, "minimum-stability": "dev" diff --git a/examples/graphql_composable/graphql_composable.info.yml b/examples/graphql_composable/graphql_composable.info.yml index 08add43f5203066ab455e17b9e614cad654b5453..a8bf56c5c8347d0f52b97d20ac2bb363daafd844 100644 --- a/examples/graphql_composable/graphql_composable.info.yml +++ b/examples/graphql_composable/graphql_composable.info.yml @@ -5,4 +5,4 @@ package: GraphQL dependencies: - graphql:graphql - node:node -core_version_requirement: ^10.2 || ^11 +core_version_requirement: ^10.4 || ^11 diff --git a/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php b/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php index 5df91ca2056a1e7d19ce56bc904eaa442c8a5861..9e37162e8ff688c4747e0079b0bd95407007e783 100644 --- a/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php +++ b/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php @@ -7,6 +7,8 @@ namespace Drupal\graphql_composable\Plugin\GraphQL\Schema; use Drupal\graphql\Plugin\GraphQL\Schema\ComposableSchema; /** + * Example of a composable schema. + * * @Schema( * id = "composable", * name = "Composable Example schema", diff --git a/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php b/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php index f16d4ab9b2a5fb36b335d8d4ceb3272c2d9a7bba..730ab8f30d04c439f2b2690a00792dc88110afbf 100644 --- a/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php +++ b/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php @@ -11,6 +11,8 @@ use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase; use Drupal\graphql_composable\GraphQL\Response\ArticleResponse; /** + * Example schema plugin for extending the composable schema. + * * @SchemaExtension( * id = "composable_extension", * name = "Composable Example extension", diff --git a/examples/graphql_example/graphql_examples.info.yml b/examples/graphql_example/graphql_examples.info.yml index 4f03a1abe8a47e3eb6bf95d71518946e85b2abaf..ef277a30692444e23273a5b78a7310ed1f15f5fb 100644 --- a/examples/graphql_example/graphql_examples.info.yml +++ b/examples/graphql_example/graphql_examples.info.yml @@ -5,4 +5,4 @@ package: GraphQL dependencies: - graphql:graphql - node:node -core_version_requirement: ^10.2 || ^11 +core_version_requirement: ^10.4 || ^11 diff --git a/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php b/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php index 8174e218145ffb1d41b31c6fd79ca349d4eb080d..7a52afcfb0a65f85523cdb58b33f579e62ff9778 100644 --- a/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php +++ b/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php @@ -15,6 +15,8 @@ use GraphQL\Error\UserError; use Symfony\Component\DependencyInjection\ContainerInterface; /** + * Example data producer that loads a list of articles. + * * @DataProducer( * id = "query_articles", * name = @Translation("Load articles"), @@ -71,9 +73,7 @@ class QueryArticles extends DataProducerPluginBase implements ContainerFactoryPl } /** - * - * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + * Resolves the query by preparing an entity query for executing later. */ public function resolve(int $offset, int $limit, RefinableCacheableDependencyInterface $metadata): QueryConnection { if ($limit > static::MAX_LIMIT) { diff --git a/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php b/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php index 8012c5528b05807ef18f3ecbf349e13987d53f11..c5d327547939efedfc2ec10ec8e8185c5f5eddc5 100644 --- a/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php +++ b/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php @@ -11,6 +11,8 @@ use Drupal\graphql\Plugin\GraphQL\Schema\SdlSchemaPluginBase; use Drupal\graphql_examples\Wrappers\QueryConnection; /** + * Example schema plugin that maps article data. + * * @Schema( * id = "example", * name = "Example schema" diff --git a/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php b/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php index 80f35743d91eeb84b55b22f17e736891dfe8baef..21c35281674cdcd5759d0c0c740ddbce05170c25 100644 --- a/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php +++ b/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php @@ -9,6 +9,8 @@ use Drupal\graphql\GraphQL\ResolverRegistryInterface; use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase; /** + * Example schema extension that adds to the mapping. + * * @SchemaExtension( * id = "example_extension", * name = "Example extension", diff --git a/graphql.info.yml b/graphql.info.yml index e97d14ff6e9f35716804644ea2d4b86322835f6b..e07fdd8b4eb731ba41c37ec735a6868295a585d2 100644 --- a/graphql.info.yml +++ b/graphql.info.yml @@ -3,6 +3,6 @@ type: module description: 'Base module for integrating GraphQL with Drupal.' package: GraphQL configure: entity.graphql_server.collection -core_version_requirement: ^10.3 || ^11 +core_version_requirement: ^10.4 || ^11 dependencies: - typed_data:typed_data diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 9309f733a5cf357d878feb971ac02565c3cc71fe..22ac87315ba442e835ce207c5a5a12287787ace1 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -34,41 +34,13 @@ <exclude-pattern>src/GraphQL/Buffers/BufferBase.php</exclude-pattern> <exclude-pattern>src/GraphQL/Execution/FieldContext.php</exclude-pattern> <exclude-pattern>src/GraphQL/Execution/ResolveContext.php</exclude-pattern> + <exclude-pattern>src/GraphQL/Utility/FileUpload.php</exclude-pattern> <exclude-pattern>src/Plugin/GraphQL/DataProducer/Utility/Seek.php</exclude-pattern> <exclude-pattern>src/SubRequestResponse.php</exclude-pattern> <exclude-pattern>tests/src/Traits/QueryResultAssertionTrait.php</exclude-pattern> <exclude-pattern>tests/src/Traits/MockingTrait.php</exclude-pattern> </rule> - <rule ref="Drupal.Commenting.DocComment.MissingShort"> - <exclude-pattern>src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php</exclude-pattern> - <exclude-pattern>src/Plugin/GraphQL/Schema/ComposableSchema.php</exclude-pattern> - <exclude-pattern>src/Plugin/DataProducerPluginManager.php</exclude-pattern> - <exclude-pattern>src/Plugin/PersistedQueryPluginInterface.php</exclude-pattern> - <exclude-pattern>src/Plugin/DataProducerPluginCachingInterface.php</exclude-pattern> - <exclude-pattern>src/Controller/RequestController.php</exclude-pattern> - <exclude-pattern>examples/graphql_example/src/Wrappers/QueryConnection.php</exclude-pattern> - <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php</exclude-pattern> - <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php</exclude-pattern> - <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php</exclude-pattern> - <exclude-pattern>examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php</exclude-pattern> - <exclude-pattern>examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php</exclude-pattern> - <exclude-pattern>tests/src/Traits/MockingTrait.php</exclude-pattern> - <exclude-pattern>tests/src/Traits/QueryResultAssertionTrait.php</exclude-pattern> - <exclude-pattern>tests/src/Traits/DataProducerExecutionTrait.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/ResolverBuilderTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/EntityBufferTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/DataProducer/MenuTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/DataProducer/EntityMultipleTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/DataProducer/EntityTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/EntityUuidBufferTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/Framework/PersistedQueriesTest.php</exclude-pattern> - <exclude-pattern>tests/src/Kernel/GraphQLTestBase.php</exclude-pattern> - <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php</exclude-pattern> - <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php</exclude-pattern> - <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php</exclude-pattern> - </rule> - <rule ref="Drupal.Commenting.FunctionComment.MissingParamComment"> <exclude-pattern>src/PermissionProvider.php</exclude-pattern> <exclude-pattern>src/Config/LanguageConfigOverride.php</exclude-pattern> diff --git a/src/Entity/Server.php b/src/Entity/Server.php index 352f1ea68a3a0e791d45c54652706b9dca2c25c7..e13dddfda90151d2fda557285edbb62e375e80f8 100644 --- a/src/Entity/Server.php +++ b/src/Entity/Server.php @@ -148,13 +148,6 @@ class Server extends ConfigEntityBase implements ServerInterface { */ protected ?array $persisted_query_instances = NULL; - /** - * The sorted persisted query plugin instances available on this server. - * - * @var array|null - */ - protected ?array $sorted_persisted_query_instances = NULL; - /** * {@inheritdoc} */ @@ -302,9 +295,7 @@ class Server extends ConfigEntityBase implements ServerInterface { return function (OperationParams $params, DocumentNode $document, $type) use ($schema, $config) { $context = new ResolveContext($this, $params, $document, $type, $config); $context->addCacheTags(['graphql_response']); - if ($this instanceof CacheableDependencyInterface) { - $context->addCacheableDependency($this); - } + $context->addCacheableDependency($this); if ($schema instanceof CacheableDependencyInterface) { $context->addCacheableDependency($schema); @@ -371,7 +362,6 @@ class Server extends ConfigEntityBase implements ServerInterface { */ public function removeAllPersistedQueryInstances(): void { $this->persisted_query_instances = NULL; - $this->sorted_persisted_query_instances = NULL; } /** @@ -381,6 +371,7 @@ class Server extends ConfigEntityBase implements ServerInterface { if (!is_null($this->persisted_query_instances)) { return $this->persisted_query_instances; } + $this->persisted_query_instances = []; /** @var \Drupal\graphql\Plugin\PersistedQueryPluginManager $plugin_manager */ $plugin_manager = \Drupal::service('plugin.manager.graphql.persisted_query'); @@ -392,24 +383,11 @@ class Server extends ConfigEntityBase implements ServerInterface { $this->persisted_query_instances[$id] = $plugin_manager->createInstance($id, $configuration); } } + uasort($this->persisted_query_instances, function ($a, $b) { + return $a->getWeight() <= $b->getWeight() ? -1 : 1; + }); - return $this->persisted_query_instances ?? []; - } - - /** - * {@inheritDoc} - */ - public function getSortedPersistedQueryInstances(): array { - if (!is_null($this->sorted_persisted_query_instances)) { - return $this->sorted_persisted_query_instances; - } - $this->sorted_persisted_query_instances = $this->getPersistedQueryInstances(); - if (!empty($this->sorted_persisted_query_instances)) { - uasort($this->sorted_persisted_query_instances, function ($a, $b) { - return $a->getWeight() <= $b->getWeight() ? -1 : 1; - }); - } - return $this->sorted_persisted_query_instances; + return $this->persisted_query_instances; } /** @@ -420,7 +398,7 @@ class Server extends ConfigEntityBase implements ServerInterface { */ protected function getPersistedQueryLoader(): callable { return function ($id, OperationParams $params) { - $sortedPersistedQueryInstances = $this->getSortedPersistedQueryInstances(); + $sortedPersistedQueryInstances = $this->getPersistedQueryInstances(); if (!empty($sortedPersistedQueryInstances)) { foreach ($sortedPersistedQueryInstances as $persistedQueryInstance) { $query = $persistedQueryInstance->getQuery($id, $params); diff --git a/src/Entity/ServerInterface.php b/src/Entity/ServerInterface.php index b618f889942b7643806baca52c5354d6d801b78e..6351911da9d3fc891e7d5ce9732f4920d8eb74ba 100644 --- a/src/Entity/ServerInterface.php +++ b/src/Entity/ServerInterface.php @@ -55,18 +55,11 @@ interface ServerInterface extends ConfigEntityInterface { */ public function removeAllPersistedQueryInstances(): void; - /** - * Returns the current persisted queries set. - * - * @return array<\Drupal\graphql\Plugin\PersistedQueryPluginInterface> - */ - public function getPersistedQueryInstances(): array; - /** * Returns the current persisted queries set, sorted by the plugins weight. * * @return array<\Drupal\graphql\Plugin\PersistedQueryPluginInterface> */ - public function getSortedPersistedQueryInstances(): array; + public function getPersistedQueryInstances(): array; } diff --git a/src/GraphQL/Execution/Executor.php b/src/GraphQL/Execution/Executor.php index 24fd5e02029e6b6284521cf42f3a1ac980bb385d..9c22ec11c899d3f2ac9102811ab3e7a07b36d1f8 100644 --- a/src/GraphQL/Execution/Executor.php +++ b/src/GraphQL/Execution/Executor.php @@ -13,7 +13,6 @@ use Drupal\Core\Utility\Error as ErrorUtil; use Drupal\graphql\Event\OperationEvent; use Drupal\graphql\GraphQL\Execution\ExecutionResult as CacheableExecutionResult; use Drupal\graphql\GraphQL\Utility\DocumentSerializer; -use GraphQL\Error\ClientAware; use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\ExecutorImplementation; use GraphQL\Executor\Promise\Promise; @@ -200,7 +199,7 @@ class Executor implements ExecutorImplementation { // Don't log errors intended for clients, only log those that // a client would not be able to solve, they'd require work from // a server developer. - if ($error instanceof ClientAware && $error->isClientSafe()) { + if ($error->isClientSafe()) { continue; } diff --git a/src/GraphQL/Resolver/Path.php b/src/GraphQL/Resolver/Path.php deleted file mode 100644 index 827e5cfa34088b2caddd6518e1db141c22bfb19b..0000000000000000000000000000000000000000 --- a/src/GraphQL/Resolver/Path.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Drupal\graphql\GraphQL\Resolver; - -use Drupal\Core\Cache\CacheableDependencyInterface; -use Drupal\Core\Render\BubbleableMetadata; -use Drupal\Core\TypedData\DataDefinition; -use Drupal\Core\TypedData\DataDefinitionInterface; -use Drupal\Core\TypedData\TypedDataTrait; -use Drupal\graphql\GraphQL\Execution\FieldContext; -use Drupal\graphql\GraphQL\Execution\ResolveContext; -use Drupal\typed_data\DataFetcherTrait; -use GraphQL\Type\Definition\ResolveInfo; - -/** - * Resolves a property path. - * - * @todo Delete this resolver. This is a plugin already. - */ -class Path implements ResolverInterface { - - use TypedDataTrait; - use DataFetcherTrait; - - /** - * Name of the context. - */ - protected string|DataDefinitionInterface $type; - - /** - * Source resolver. - */ - protected mixed $path; - - /** - * Resolver. - */ - protected mixed $value; - - /** - * Path constructor. - */ - public function __construct(string $type, mixed $path, ?ResolverInterface $value = NULL) { - $this->type = $type; - $this->path = $path; - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function resolve(mixed $value, array $args, ResolveContext $context, ResolveInfo $info, FieldContext $field): mixed { - $value = $this->value ?? new ParentValue(); - $value = $value->resolve($value, $args, $context, $info, $field); - $metadata = new BubbleableMetadata(); - - $type = $this->type instanceof DataDefinitionInterface ? $this->type : DataDefinition::create($this->type); - $data = $this->getTypedDataManager()->create($type, $value); - $output = $this->getDataFetcher()->fetchDataByPropertyPath($data, $this->path, $metadata)->getValue(); - - $context->addCacheableDependency($metadata); - if ($output instanceof CacheableDependencyInterface) { - $context->addCacheableDependency($output); - } - - return $output; - } - -} diff --git a/src/GraphQL/ResolverRegistry.php b/src/GraphQL/ResolverRegistry.php index 0e0935f69fed9d328fa208f4beab56fbeb2cd736..f17832710fd8e2b3cf229e9e4db1e5150da5f811 100644 --- a/src/GraphQL/ResolverRegistry.php +++ b/src/GraphQL/ResolverRegistry.php @@ -22,7 +22,7 @@ class ResolverRegistry implements ResolverRegistryInterface { * * Contains a nested list of callables, keyed by type and field name. * - * @var array<callable> + * @var array<string, array<string, \Drupal\graphql\GraphQL\Resolver\ResolverInterface>> */ protected array $fieldResolvers = []; @@ -109,12 +109,7 @@ class ResolverRegistry implements ResolverRegistryInterface { } /** - * Return all field resolvers in the registry. - * - * @return array<callable> - * A nested list of callables, keyed by type and field name. - * - * @todo This should be added to ResolverRegistryInterface in 5.0.0. + * {@inheritdoc} */ public function getAllFieldResolvers(): array { return $this->fieldResolvers; @@ -136,24 +131,7 @@ class ResolverRegistry implements ResolverRegistryInterface { } /** - * Get a field resolver for the type or any of the interfaces it implements. - * - * This allows common functionality (such as for Edge's or Connections) to be - * implemented for an interface and re-used on any concrete type that extends - * it. - * - * This should be used instead of `getFieldResolver` unless you're certain you - * want the resolver only for the specific type. - * - * @param \GraphQL\Type\Definition\Type $type - * The type to find a resolver for. - * @param string $fieldName - * The name of the field to find a resolver for. - * - * @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface|null - * The defined resolver for the field or NULL if none exists. - * - * @todo This should be added to ResolverRegistryInterface in 5.0.0. + * {@inheritdoc} */ public function getFieldResolverWithInheritance(Type $type, string $fieldName): ?ResolverInterface { if ($resolver = $this->getFieldResolver($type->toString(), $fieldName)) { diff --git a/src/GraphQL/ResolverRegistryInterface.php b/src/GraphQL/ResolverRegistryInterface.php index f7f51ba5a32571f0918eff7b5f65e259a441ccf2..244349cf0ce2ce801ccd7fe28f0e9991ea3dfaa8 100644 --- a/src/GraphQL/ResolverRegistryInterface.php +++ b/src/GraphQL/ResolverRegistryInterface.php @@ -8,6 +8,7 @@ use Drupal\graphql\GraphQL\Execution\FieldContext; use Drupal\graphql\GraphQL\Execution\ResolveContext; use Drupal\graphql\GraphQL\Resolver\ResolverInterface; use GraphQL\Type\Definition\ResolveInfo; +use GraphQL\Type\Definition\Type; /** * Defines a registry to resolve any field in the GraphQL schema tree. @@ -29,11 +30,39 @@ interface ResolverRegistryInterface { */ public function addFieldResolver(string $type, string $field, ResolverInterface $resolver): static; + /** + * Get a field resolver for the type or any of the interfaces it implements. + * + * This allows common functionality (such as for Edge's or Connections) to be + * implemented for an interface and re-used on any concrete type that extends + * it. + * + * This should be used instead of `getFieldResolver` unless you're certain you + * want the resolver only for the specific type. + * + * @param \GraphQL\Type\Definition\Type $type + * The type to find a resolver for. + * @param string $fieldName + * The name of the field to find a resolver for. + * + * @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface|null + * The defined resolver for the field or NULL if none exists. + */ + public function getFieldResolverWithInheritance(Type $type, string $fieldName): ?ResolverInterface; + /** * Return the field resolver for a given type and field name. */ public function getFieldResolver(string $type, string $field): ?ResolverInterface; + /** + * Return all field resolvers in the registry. + * + * @return array<string, array<string, \Drupal\graphql\GraphQL\Resolver\ResolverInterface>> + * A nested list of resolvers, keyed by type and field name. + */ + public function getAllFieldResolvers(): array; + /** * Add a type resolver. * diff --git a/src/GraphQL/Utility/FileUpload.php b/src/GraphQL/Utility/FileUpload.php index 0d058d81aab593ec70fa57adb2c96b6e94bf8d69..d4b07b4610f8d3bca878744dd28d0dbe4afabc02 100644 --- a/src/GraphQL/Utility/FileUpload.php +++ b/src/GraphQL/Utility/FileUpload.php @@ -13,6 +13,7 @@ use Drupal\Core\Config\ImmutableConfig; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\File\Event\FileUploadSanitizeNameEvent; use Drupal\Core\File\Exception\FileException; +use Drupal\Core\File\FileExists; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Image\ImageFactory; use Drupal\Core\Lock\LockBackendInterface; @@ -235,10 +236,7 @@ class FileUpload { $file_uri = "{$destination}/{$prepared_filename}"; $temp_file_path = $uploaded_file->getRealPath(); - - // Drupal 10.3 compatibility: use the deprecated constant for now. - // @phpstan-ignore-next-line as it is deprecated in D12. - $file_uri = $this->fileSystem->getDestinationFilename($file_uri, FileSystemInterface::EXISTS_RENAME); + $file_uri = $this->fileSystem->getDestinationFilename($file_uri, FileExists::Rename); // Lock based on the prepared file URI. $lock_id = $this->generateLockIdFromFileUri($file_uri); @@ -286,9 +284,7 @@ class FileUpload { // FileSystemInterface::EXISTS_ERROR as the file location has already been // determined above in FileSystem::getDestinationFilename(). try { - // Drupal 10.3 compatibility: use the deprecated constant for now. - // @phpstan-ignore-next-line as it is deprecated in D12. - $this->fileSystem->move($temp_file_path, $file_uri, FileSystemInterface::EXISTS_ERROR); + $this->fileSystem->move($temp_file_path, $file_uri, FileExists::Rename); } catch (FileException $e) { $response->addViolation($this->t('Unknown error while uploading the file "@file".', [ @@ -321,7 +317,7 @@ class FileUpload { /** * Validates uploaded files, saves them and returns a file upload response. * - * @param array<\Symfony\Component\HttpFoundation\File\UploadedFile> $uploaded_files + * @param array<\Symfony\Component\HttpFoundation\File\UploadedFile|mixed> $uploaded_files * The file entities to upload. * @param array $settings * File settings as specified in regular file field config. Contains keys: diff --git a/src/GraphQL/Validator.php b/src/GraphQL/Validator.php index e877c4d2f300cc03a9cb7161618e68c3a3cb63e2..f6910ba5703985a95e305b5a2d165fb3aefa8376 100644 --- a/src/GraphQL/Validator.php +++ b/src/GraphQL/Validator.php @@ -61,17 +61,6 @@ class Validator implements ValidatorInterface { $plugin = $this->getSchemaPlugin($server); $resolver_registry = $plugin->getResolverRegistry(); - if (!method_exists($resolver_registry, "getFieldResolverWithInheritance")) { - $this->logger->warning( - "Could not get missing resolvers for @server_name as its registry class (@class) does not implement getFieldResolverWithInheritance.", - [ - '@server_name' => $server->id(), - '@class' => get_class($resolver_registry), - ] - ); - return []; - } - try { $schema = $plugin->getSchema($resolver_registry); } @@ -127,17 +116,6 @@ class Validator implements ValidatorInterface { return []; } - if (!method_exists($resolver_registry, "getAllFieldResolvers")) { - $this->logger->warning( - "Could not get orphaned resolvers for @server_name as its registry class (@class) does not implement getAllFieldResolvers.", - [ - '@server_name' => $server->id(), - '@class' => get_class($resolver_registry), - ] - ); - return []; - } - $orphaned_resolvers = []; /** * @var string $type_name diff --git a/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php b/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php index 4c369b17075f6b6f3604d9e678474854a409ea48..3776227c6acec02ac693d09dc31900cbde7e4584 100644 --- a/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php +++ b/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php @@ -129,6 +129,8 @@ abstract class EntityQueryBase extends DataProducerPluginBase implements Contain } // Ensure that desired access checking is performed on the query. + // Not sure why PHPStan complains about this? + // @phpstan-ignore-next-line $query->accessCheck($access); // Filter entities only of given bundles, if desired. diff --git a/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php b/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php index a2dad2945280edb0023ea7bdc2cc358399f9d891..30573ca1eb34a5727d739652f2ad9366e340da8d 100644 --- a/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php +++ b/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php @@ -5,7 +5,6 @@ declare(strict_types=1); namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Menu; use Drupal\Core\DependencyInjection\DependencySerializationTrait; -use Drupal\Core\Menu\MenuLinkInterface; use Drupal\Core\Menu\MenuLinkTreeElement; use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Menu\MenuTreeParameters; @@ -88,7 +87,7 @@ class MenuLinks extends DataProducerPluginBase implements ContainerFactoryPlugin return array_filter($this->menuLinkTree->transform($tree, $manipulators), function (MenuLinkTreeElement $item) use ($context) { $context->addCacheableDependency($item->access); - return $item->link instanceof MenuLinkInterface && $item->link->isEnabled() && $item->access->isAllowed(); + return $item->link->isEnabled() && $item->access->isAllowed(); }); } diff --git a/src/Plugin/GraphQL/Schema/ComposableSchema.php b/src/Plugin/GraphQL/Schema/ComposableSchema.php index 78eea5a4311b1e63c91567723b3933025c3173f0..81aec33c05f22bed9973233c6f334e639b2e82e1 100644 --- a/src/Plugin/GraphQL/Schema/ComposableSchema.php +++ b/src/Plugin/GraphQL/Schema/ComposableSchema.php @@ -12,6 +12,8 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\graphql\GraphQL\ResolverRegistry; /** + * A schema that is composed of extensions, each adding to the schema. + * * @Schema( * id = "composable", * name = "Composable schema" diff --git a/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php b/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php index 2cfb22f0df3c1d3d5ec2d37b4cc1fd41668b16f9..3469d22de4e5f82adb2df24ca53eec90de0a59da 100644 --- a/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php +++ b/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php @@ -155,6 +155,8 @@ abstract class SdlSchemaPluginBase extends PluginBase implements SchemaPluginInt } /** + * Returns the list of schema extension plugins. + * * @return array<\Drupal\graphql\Plugin\SchemaExtensionPluginInterface> */ protected function getExtensions(): array { @@ -281,11 +283,8 @@ abstract class SdlSchemaPluginBase extends PluginBase implements SchemaPluginInt // Configurable schema plugins should be cached per server since the schema // depends on the server configuration. if ($this instanceof ConfigurableInterface) { - $server_id = $this->getConfiguration()['server_id'] ?? NULL; - if ($server_id) { - return "{$type}:{$this->getPluginId()}:{$server_id}"; - } - @trigger_error('Retrieving a GraphQL schema from a configurable schema plugin instance without setting the "server_id" in the plugin configuration is deprecated in graphql:4.11.0 and will cause an InvalidPluginDefinitionException to be thrown from graphql:5.0.0. Ensure to always pass this configuration value so that the schema can be properly cached per server. See https://www.drupal.org/project/graphql/issues/3491736', E_USER_DEPRECATED); + $server_id = $this->getConfiguration()['server_id']; + return "{$type}:{$this->getPluginId()}:{$server_id}"; } return "{$type}:{$this->getPluginId()}"; } diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php index 1cc813a7b05811a4a9e6f6dbf824c3318006f6f5..389133368d1b0d7d2bc2492150def0e95cfdedeb 100644 --- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php +++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php @@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase; use GraphQL\Server\OperationParams; /** + * Test persisted plugin. + * * @PersistedQuery( * id = "persisted_query_plugin_one", * label = "Persisted Query One", * description = "This is the first persisted query plugin" * ) - * - * Class PersistedQueryPluginOne - * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery */ class PersistedQueryPluginOne extends PersistedQueryPluginBase { diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php index d4f5a91eff3983d8ff6e8777af4d877bc7a6e601..aae70b1aba367ca842c77b9dff7b389731642d7b 100644 --- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php +++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php @@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase; use GraphQL\Server\OperationParams; /** + * Test persisted plugin. + * * @PersistedQuery( * id = "persisted_query_plugin_three", * label = "Persisted Query Three", * description = "This is the third persisted query plugin" * ) - * - * Class PersistedQueryPluginThree - * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery */ class PersistedQueryPluginThree extends PersistedQueryPluginBase { diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php index 13ab82a9bf193b13803807ffba35c3f1f7382d45..7b906612733a3c8550531b055cec3f5b783327cf 100644 --- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php +++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php @@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase; use GraphQL\Server\OperationParams; /** + * Test persisted plugin. + * * @PersistedQuery( * id = "persisted_query_plugin_two", * label = "Persisted Query Two", * description = "This is the second persisted query plugin" * ) - * - * Class PersistedQueryPluginTwo - * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery */ class PersistedQueryPluginTwo extends PersistedQueryPluginBase { diff --git a/tests/src/Kernel/AlterableSchemaTest.php b/tests/src/Kernel/AlterableSchemaTest.php index bf8c639b894cdaaa10aaf2ee4e3ef7268f6d62d9..9402f474d846b53664c45793d0e0de999af38eef 100644 --- a/tests/src/Kernel/AlterableSchemaTest.php +++ b/tests/src/Kernel/AlterableSchemaTest.php @@ -148,10 +148,7 @@ class AlterableSchemaTest extends GraphQLTestBase { ->method('getBaseDefinition') ->willReturn(''); - // Different extension definition for different tests. - // PHPUnit compatibility: remove once support for Drupal 10.2 is dropped. - $methodName = method_exists($this, 'name') ? 'name' : 'getName'; - switch ($this->$methodName()) { + switch ($this->name()) { case 'testEmptySchemaExtensionAlteredQueryResultPropertyAdded': $extensionDefinition = ''; break; @@ -179,7 +176,10 @@ class AlterableSchemaTest extends GraphQLTestBase { // Replace mock schema with our own implementation. $this->schema = $this->getMockBuilder(AlterableComposableSchema::class) ->setConstructorArgs([ - [], + [ + 'extensions' => ['graphql_alterable_schema_test' => 'graphql_alterable_schema_test'], + 'server_id' => 'test_server', + ], $id, [], $this->container->get('cache.graphql.ast'), @@ -188,7 +188,7 @@ class AlterableSchemaTest extends GraphQLTestBase { ['development' => FALSE], $this->container->get('event_dispatcher'), ]) - ->onlyMethods(['getSchemaDefinition', 'getResolverRegistry', 'getConfiguration']) + ->onlyMethods(['getSchemaDefinition', 'getResolverRegistry']) ->getMock(); $this->schema->expects(static::any()) @@ -199,9 +199,6 @@ class AlterableSchemaTest extends GraphQLTestBase { $this->schema->expects($this->any()) ->method('getResolverRegistry') ->willReturn($this->registry); - $this->schema->expects($this->any()) - ->method('getConfiguration') - ->willReturn(['extensions' => ['graphql_alterable_schema_test' => 'graphql_alterable_schema_test']]); } } diff --git a/tests/src/Kernel/DataProducer/RoutingTest.php b/tests/src/Kernel/DataProducer/RoutingTest.php index 6d02953fa0b6284d8ce7bbcc4356329b0591c9c8..7afb4fe1b1f33b040eb54899e87d4af5d30e5755 100644 --- a/tests/src/Kernel/DataProducer/RoutingTest.php +++ b/tests/src/Kernel/DataProducer/RoutingTest.php @@ -72,7 +72,6 @@ class RoutingTest extends GraphQLTestBase { $redirect->setRedirect($nodeUrl); $redirect->save(); - /** @var \Drupal\Core\Url $result */ $result = $this->executeDataProducer('route_load', [ 'path' => 'internal-url', ]); diff --git a/tests/src/Kernel/EntityBufferTest.php b/tests/src/Kernel/EntityBufferTest.php index 6edabef3d33e77b3c503c8c19f1c769c0bbb271d..367f2fa2cc7e774176cbb19ae7ede2d3b6eb80d0 100644 --- a/tests/src/Kernel/EntityBufferTest.php +++ b/tests/src/Kernel/EntityBufferTest.php @@ -14,11 +14,6 @@ use Drupal\node\Entity\NodeType; */ class EntityBufferTest extends GraphQLTestBase { - /** - * @var array<string> - */ - protected array $nodeIds = []; - /** * {@inheritdoc} */ @@ -36,7 +31,6 @@ class EntityBufferTest extends GraphQLTestBase { 'type' => 'test', ]); $node->save(); - $this->nodeIds[] = $node->id(); } $schema = <<<GQL diff --git a/tests/src/Kernel/Framework/LoggerTest.php b/tests/src/Kernel/Framework/LoggerTest.php index ee2cc000ce737557f86d3bb07f3f72a40eb2da63..2e28bf652e0e1dcdf449bd4e7e21fb6e901aecdf 100644 --- a/tests/src/Kernel/Framework/LoggerTest.php +++ b/tests/src/Kernel/Framework/LoggerTest.php @@ -52,9 +52,6 @@ GQL; /** * {@inheritdoc} - * - * @todo For some reason, PHPStan wants to see a type hint for the level here, - * which is not correct. */ public function log($level, string|\Stringable $message, array $context = []): void { $this->loggerCalls[] = [ diff --git a/tests/src/Kernel/ResolverRegistryTest.php b/tests/src/Kernel/ResolverRegistryTest.php index 018b7f345e7f9f1ce33d44ab57c15a1c59ec7520..6d931e9a19b6259c18e9f9b2096fe4d65306197a 100644 --- a/tests/src/Kernel/ResolverRegistryTest.php +++ b/tests/src/Kernel/ResolverRegistryTest.php @@ -4,8 +4,6 @@ declare(strict_types=1); namespace Drupal\Tests\graphql\Kernel; -use Drupal\graphql\GraphQL\ResolverRegistry; - /** * Tests that the resolver registry behaves correctly. * @@ -41,11 +39,6 @@ class ResolverRegistryTest extends GraphQLTestBase { GQL; $this->setUpSchema($schema); - - // Our mocking trait sets up the ResolverRegistry that we're interested in - // testing for us. This assertion guards against the mock implementation - // invalidating that and this test becoming useless. - self::assertInstanceOf(ResolverRegistry::class, $this->registry); } /** diff --git a/tests/src/Kernel/ServerConfigurationTest.php b/tests/src/Kernel/ServerConfigurationTest.php index fde20eb85d227380c9ad94f626abdd33852787d7..465a621425b9afa447fe126d842f2fa5d9715ec8 100644 --- a/tests/src/Kernel/ServerConfigurationTest.php +++ b/tests/src/Kernel/ServerConfigurationTest.php @@ -78,7 +78,6 @@ class ServerConfigurationTest extends GraphQLTestBase { // Replace the schema plugin manager with a mocked version that returns the // requested mocked schema extension plugins. $schemaPluginManager = $this->mockPluginManager(array_keys(self::TEST_SCHEMAS)); - // @phpstan-ignore-next-line PHPStan doesn't find this method on the parent. $schemaPluginManager->method('createInstance') ->willReturnCallback(fn ($pluginId, $pluginConfig) => match ([$pluginId, $pluginConfig['server_id']]) { ['composable', $this->servers['node']->id()] => $this->extensionPlugins['node'], diff --git a/tests/src/Kernel/ValidatorTest.php b/tests/src/Kernel/ValidatorTest.php index 50acb5c0c1984db2f9e1c86a64a00235a3b09ce2..5f3ef73af9d0685fabd428b21eb3ee4e7b11951c 100644 --- a/tests/src/Kernel/ValidatorTest.php +++ b/tests/src/Kernel/ValidatorTest.php @@ -36,10 +36,12 @@ GQL; } /** - * @covers ::getMissingResolvers + * Test interfaces. * * Interfaces are ignored because the implementing types are used to check * whether a resolver is present. + * + * @covers ::getMissingResolvers */ public function testGetMissingResolversIgnoresMissingFieldsOnInterfaces(): void { $schema = <<<GQL