diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 35c938b..2133c9d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,6 +13,7 @@ jobs: matrix: install-args: ['', '--prefer-lowest'] php-version: ['7.2', '7.3', '7.4', '8.0'] + fail-fast: false steps: # Cancel previous runs of the same branch - name: cancel @@ -36,7 +37,7 @@ jobs: - name: composer-cache uses: actions/cache@v2.1.6 with: - path: ${{ needs.prepare.outputs.composercachedir }} + path: ${{ steps.composercache.outputs.dir }} key: composer-${{ hashFiles('**/composer.json') }}-${{ matrix.install-args }} restore-keys: | composer-${{ hashFiles('**/composer.json') }}-${{ matrix.install-args }} @@ -45,12 +46,11 @@ jobs: - name: composer run: | - composer check-platform-reqs --no-interaction composer update ${{ matrix.install-args }} --no-interaction --no-progress --prefer-dist - name: phpunit run: | - vendor/bin/phpunit + vendor/bin/simple-phpunit --no-coverage - name: phpstan-cache uses: actions/cache@v2.1.6 @@ -66,5 +66,4 @@ jobs: - name: phpstan run: | mkdir -p .phpstan-cache - APP_ENV=dev bin/console cache:clear vendor/bin/phpstan analyse --no-progress --no-interaction --memory-limit=1G diff --git a/Controller/GraphQL/LoginController.php b/Controller/GraphQL/LoginController.php index 2188e51..b2d8eb7 100644 --- a/Controller/GraphQL/LoginController.php +++ b/Controller/GraphQL/LoginController.php @@ -82,6 +82,7 @@ public function login(string $userName, string $password, Request $request): Use // Fire the login event manually $event = new InteractiveLoginEvent($request, $token); + // @phpstan-ignore-next-line BC for Symfony4 $this->eventDispatcher->dispatch($event, 'security.interactive_login'); return $user; diff --git a/Controller/GraphqliteController.php b/Controller/GraphqliteController.php index 61ea3fe..3efde0f 100644 --- a/Controller/GraphqliteController.php +++ b/Controller/GraphqliteController.php @@ -106,18 +106,16 @@ private function handlePsr7Request(ServerRequestInterface $request, Request $sym return new JsonResponse($result->toArray($this->debug), $httpCodeDecider->decideHttpStatusCode($result)); } if (is_array($result)) { - $finalResult = array_map(function (ExecutionResult $executionResult) { + $finalResult = array_map(function (ExecutionResult $executionResult): array { return $executionResult->toArray($this->debug); }, $result); // Let's return the highest result. $statuses = array_map([$httpCodeDecider, 'decideHttpStatusCode'], $result); $status = empty($statuses) ? 500 : max($statuses); + return new JsonResponse($finalResult, $status); } - if ($result instanceof Promise) { - throw new RuntimeException('Only SyncPromiseAdapter is supported'); - } - /* @phpstan-ignore-next-line */ - throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); // @codeCoverageIgnore + + throw new RuntimeException('Only SyncPromiseAdapter is supported'); } } diff --git a/DependencyInjection/GraphqliteCompilerPass.php b/DependencyInjection/GraphqliteCompilerPass.php index e661e5e..6a2fa71 100644 --- a/DependencyInjection/GraphqliteCompilerPass.php +++ b/DependencyInjection/GraphqliteCompilerPass.php @@ -13,6 +13,7 @@ use Symfony\Component\Cache\Psr16Cache; use TheCodingMachine\GraphQLite\Mappers\StaticClassListTypeMapper; use TheCodingMachine\GraphQLite\Mappers\StaticClassListTypeMapperFactory; +use Webmozart\Assert\Assert; use function class_exists; use Doctrine\Common\Annotations\AnnotationException; use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; @@ -102,14 +103,19 @@ class GraphqliteCompilerPass implements CompilerPassInterface public function process(ContainerBuilder $container): void { $reader = $this->getAnnotationReader(); - $this->cacheDir = $container->getParameter('kernel.cache_dir'); + $cacheDir = $container->getParameter('kernel.cache_dir'); + Assert::string($cacheDir); + $this->cacheDir = $cacheDir; //$inputTypeUtils = new InputTypeUtils($reader, $namingStrategy); // Let's scan the whole container and tag the services that belong to the namespace we want to inspect. $controllersNamespaces = $container->getParameter('graphqlite.namespace.controllers'); + Assert::isIterable($controllersNamespaces); $typesNamespaces = $container->getParameter('graphqlite.namespace.types'); + Assert::isIterable($typesNamespaces); $firewallName = $container->getParameter('graphqlite.security.firewall_name'); + Assert::string($firewallName); $firewallConfigServiceName = 'security.firewall.map.config.'.$firewallName; // 2 seconds of TTL in environment mode. Otherwise, let's cache forever! @@ -183,14 +189,23 @@ public function process(ContainerBuilder $container): void if ($container->getParameter('graphqlite.security.introspection') === false) { $rulesDefinition[] = $container->findDefinition(DisableIntrospection::class); } - if ($container->getParameter('graphqlite.security.maximum_query_complexity')) { - $complexity = (int) $container->getParameter('graphqlite.security.maximum_query_complexity'); - $rulesDefinition[] = $container->findDefinition(QueryComplexity::class)->setArgument(0, $complexity); + + $complexity = $container->getParameter('graphqlite.security.maximum_query_complexity'); + if ($complexity) { + Assert::integerish($complexity); + + $rulesDefinition[] = $container->findDefinition(QueryComplexity::class) + ->setArgument(0, (int) $complexity); } - if ($container->getParameter('graphqlite.security.maximum_query_depth')) { - $depth = (int) $container->getParameter('graphqlite.security.maximum_query_depth'); - $rulesDefinition[] = $container->findDefinition(QueryDepth::class)->setArgument(0, $depth); + + $depth = $container->getParameter('graphqlite.security.maximum_query_depth'); + if ($depth) { + Assert::integerish($depth); + + $rulesDefinition[] = $container->findDefinition(QueryDepth::class) + ->setArgument(0, (int) $depth); } + $serverConfigDefinition->addMethodCall('setValidationRules', [$rulesDefinition]); if ($disableMe === false) { @@ -333,7 +348,7 @@ private function mapAdderToTag(string $tag, string $methodName, ContainerBuilder */ private function makePublicInjectedServices(ReflectionClass $refClass, AnnotationReader $reader, ContainerBuilder $container, bool $isController): void { - $services = $this->getCodeCache()->get($refClass, function() use ($refClass, $reader, $container, $isController) { + $services = $this->getCodeCache()->get($refClass, function() use ($refClass, $reader, $container, $isController): array { $services = []; foreach ($refClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { $field = $reader->getRequestAnnotation($method, Field::class) ?? $reader->getRequestAnnotation($method, Query::class) ?? $reader->getRequestAnnotation($method, Mutation::class); @@ -347,6 +362,7 @@ private function makePublicInjectedServices(ReflectionClass $refClass, Annotatio } } } + return $services; }); @@ -485,7 +501,7 @@ private function getClassList(string $namespace, int $globTtl = 2, bool $recursi // The autoloader might trigger errors if the file does not respect PSR-4 or if the // Symfony DebugAutoLoader is installed. (see https://github.com/thecodingmachine/graphqlite/issues/216) require_once $phpFile; - // Does it exists now? + // @phpstan-ignore-next-line Does it exist now? if (! class_exists($className, false)) { continue; } diff --git a/DependencyInjection/GraphqliteExtension.php b/DependencyInjection/GraphqliteExtension.php index 403a70c..2943c2c 100644 --- a/DependencyInjection/GraphqliteExtension.php +++ b/DependencyInjection/GraphqliteExtension.php @@ -42,7 +42,12 @@ public function load(array $configs, ContainerBuilder $container): void if (!is_array($controllers)) { $controllers = [ $controllers ]; } - $namespaceController = array_map(function($namespace) { return rtrim($namespace, '\\') . '\\'; }, $controllers); + $namespaceController = array_map( + function($namespace): string { + return rtrim($namespace, '\\') . '\\'; + }, + $controllers + ); } else { $namespaceController = []; } @@ -51,7 +56,12 @@ public function load(array $configs, ContainerBuilder $container): void if (!is_array($types)) { $types = [ $types ]; } - $namespaceType = array_map(function($namespace) { return rtrim($namespace, '\\') . '\\'; }, $types); + $namespaceType = array_map( + function($namespace): string { + return rtrim($namespace, '\\') . '\\'; + }, + $types + ); } else { $namespaceType = []; } @@ -84,20 +94,6 @@ public function load(array $configs, ContainerBuilder $container): void ->addTag('graphql.root_type_mapper_factory'); } - private function getNamespaceDir(string $namespace): string - { - $classNameMapper = ClassNameMapper::createFromComposerFile(null, null, true); - - $possibleFileNames = $classNameMapper->getPossibleFileNames($namespace.'Xxx'); - if (count($possibleFileNames) > 1) { - throw new \RuntimeException(sprintf('According to your composer.json, classes belonging to the "%s" namespace can be located in several directories: %s. This is an issue for the GraphQLite lib. Please make sure that a namespace can only be resolved to one PHP file.', $namespace, implode(", ", $possibleFileNames))); - } elseif (empty($possibleFileNames)) { - throw new \RuntimeException(sprintf('Files in namespace "%s" cannot be autoloaded by Composer. Please set up a PSR-4 autoloader in Composer or change the namespace configured in "graphqlite.namespace.controllers" and "graphqlite.namespace.types"', $namespace)); - } - - return substr($possibleFileNames[0], 0, -8); - } - /** * @param array $debug * @return int diff --git a/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php b/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php index 43df7ef..4b50c6a 100644 --- a/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php +++ b/DependencyInjection/OverblogGraphiQLEndpointWiringPass.php @@ -2,8 +2,6 @@ namespace TheCodingMachine\Graphqlite\Bundle\DependencyInjection; -use Overblog\GraphiQLBundle\Config\GraphiQLControllerEndpoint; -use Overblog\GraphiQLBundle\Config\GraphqlEndpoint\RootResolver; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; diff --git a/GraphiQL/EndpointResolver.php b/GraphiQL/EndpointResolver.php index 26f6698..4064844 100644 --- a/GraphiQL/EndpointResolver.php +++ b/GraphiQL/EndpointResolver.php @@ -3,10 +3,15 @@ namespace TheCodingMachine\Graphqlite\Bundle\GraphiQL; use Overblog\GraphiQLBundle\Config\GraphiQLControllerEndpoint; +use Overblog\GraphiQLBundle\Config\GraphQLEndpoint\GraphQLEndpointInvalidSchemaException; use Symfony\Component\HttpFoundation\RequestStack; +use Webmozart\Assert\Assert; final class EndpointResolver implements GraphiQLControllerEndpoint { + /** + * @var RequestStack + */ protected $requestStack; public function __construct(RequestStack $requestStack) @@ -18,6 +23,7 @@ public function getBySchema($name) { if ('default' === $name) { $request = $this->requestStack->getCurrentRequest(); + Assert::notNull($request); return $request->getBaseUrl().'/graphql'; } diff --git a/Mappers/RequestParameterMiddleware.php b/Mappers/RequestParameterMiddleware.php index 2f67f3c..9f23d5a 100644 --- a/Mappers/RequestParameterMiddleware.php +++ b/Mappers/RequestParameterMiddleware.php @@ -6,6 +6,7 @@ use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\Type; +use ReflectionNamedType; use ReflectionParameter; use Symfony\Component\HttpFoundation\Request; use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; @@ -15,13 +16,13 @@ class RequestParameterMiddleware implements ParameterMiddlewareInterface { - public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $next): ParameterInterface { $parameterType = $parameter->getType(); - if ($parameterType && $parameterType->getName() === Request::class) { + if ($parameterType instanceof ReflectionNamedType && $parameterType->getName() === Request::class) { return new RequestParameter(); } + return $next->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations); } } diff --git a/Server/ServerConfig.php b/Server/ServerConfig.php index ef0f4e1..b831f15 100644 --- a/Server/ServerConfig.php +++ b/Server/ServerConfig.php @@ -4,6 +4,9 @@ namespace TheCodingMachine\Graphqlite\Bundle\Server; use GraphQL\Error\InvariantViolation; +use GraphQL\GraphQL; +use GraphQL\Language\AST\DocumentNode; +use GraphQL\Server\OperationParams; use GraphQL\Utils\Utils; use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\Rules\ValidationRule; @@ -27,7 +30,15 @@ class ServerConfig extends \GraphQL\Server\ServerConfig */ public function setValidationRules($validationRules) { - parent::setValidationRules(array_merge(DocumentValidator::defaultRules(), $validationRules)); + parent::setValidationRules( + function (OperationParams $params, DocumentNode $doc, string $operationType) use ($validationRules): array { + $validationRules = is_callable($validationRules) + ? $validationRules($params, $doc, $operationType) + : $validationRules; + + return array_merge(DocumentValidator::defaultRules(), $validationRules); + } + ); return $this; } diff --git a/Tests/FunctionalTest.php b/Tests/FunctionalTest.php index 2075b74..586795f 100644 --- a/Tests/FunctionalTest.php +++ b/Tests/FunctionalTest.php @@ -534,6 +534,9 @@ private function logIn(ContainerInterface $container) $container->get('security.token_storage')->setToken($token); } + /** + * @requires PHP 8.0 + */ public function testPhp8Attributes(): void { $kernel = new GraphqliteTestingKernel(); diff --git a/Tests/NoSecurityBundleTest.php b/Tests/NoSecurityBundleTest.php index a71f617..5cf5290 100644 --- a/Tests/NoSecurityBundleTest.php +++ b/Tests/NoSecurityBundleTest.php @@ -29,6 +29,7 @@ public function testServiceWiring(): void $kernel = new GraphqliteTestingKernel(true, null, false, null, true, null, null, ['TheCodingMachine\\Graphqlite\\Bundle\\Tests\\NoSecurityBundleFixtures\\Controller\\']); $kernel->boot(); $container = $kernel->getContainer(); + self::assertNotNull($container); $schema = $container->get(Schema::class); $this->assertInstanceOf(Schema::class, $schema); diff --git a/Types/SymfonyUserInterfaceType.php b/Types/SymfonyUserInterfaceType.php index 3dc99d5..ea0fd2c 100644 --- a/Types/SymfonyUserInterfaceType.php +++ b/Types/SymfonyUserInterfaceType.php @@ -3,17 +3,36 @@ namespace TheCodingMachine\Graphqlite\Bundle\Types; +use Symfony\Component\Security\Core\Role\Role; use TheCodingMachine\GraphQLite\Annotations\Field; use TheCodingMachine\GraphQLite\Annotations\SourceField; use TheCodingMachine\GraphQLite\Annotations\Type; use Symfony\Component\Security\Core\User\UserInterface; +use TheCodingMachine\GraphQLite\FieldNotFoundException; /** * @Type(class=UserInterface::class) - * @SourceField(name="userName") */ class SymfonyUserInterfaceType { + /** + * @Field + */ + public function getUserName(UserInterface $user): string + { + // @phpstan-ignore-next-line Forward Compatibility for Symfony >=5.3 + if (method_exists($user, 'getUserIdentifier')) { + return $user->getUserIdentifier(); + } + + // @phpstan-ignore-next-line Backward Compatibility for Symfony <5.3 + if (method_exists($user, 'getUsername')) { + return $user->getUsername(); + } + + throw FieldNotFoundException::missingField(UserInterface::class, 'userName'); + } + /** * @Field() * @return string[] @@ -22,8 +41,13 @@ public function getRoles(UserInterface $user): array { $roles = []; foreach ($user->getRoles() as $role) { - $roles[] = (string) $role; + // @phpstan-ignore-next-line BC for Symfony 4 + if (class_exists(Role::class) && $role instanceof Role) { + $role = $role->getRole(); + } + + $roles[] = $role; } return $roles; } -} \ No newline at end of file +} diff --git a/composer.json b/composer.json index 3e0f96e..0643288 100644 --- a/composer.json +++ b/composer.json @@ -17,12 +17,13 @@ ], "require" : { "php" : ">=7.2", - "thecodingmachine/graphqlite" : "^4.1", + "ext-json": "*", + "thecodingmachine/graphqlite" : "^4.1.2", "thecodingmachine/graphqlite-symfony-validator-bridge" : "^4.1", - "symfony/framework-bundle": "^4.1.9 | ^5", - "symfony/validator": "^4.1.9 | ^5", - "symfony/translation": "^4.1.9 | ^5", - "doctrine/annotations": "^1.6", + "symfony/framework-bundle": "^4.2 || ^5", + "symfony/validator": "^4.2 || ^5", + "symfony/translation": "^4.2 || ^5", + "doctrine/annotations": "^1.10.4", "doctrine/cache": "^1.8", "symfony/psr-http-message-bridge": "^2.0", "nyholm/psr7": "^1.1", @@ -31,14 +32,22 @@ "thecodingmachine/cache-utils": "^1" }, "require-dev": { - "symfony/security-bundle": "^4.1.9 | ^5", - "symfony/yaml": "^4.1.9 | ^5", - "phpunit/phpunit": "^8.5.5", - "phpstan/phpstan": "^0.12.25", + "symfony/security-bundle": "^4.2 || ^5", + "symfony/yaml": "^4.2 || ^5", + "phpstan/phpstan": "^0.12.90", "beberlei/porpaginas": "^1.2", "php-coveralls/php-coveralls": "^2.1.0", - "symfony/phpunit-bridge": "^4.1.9 | ^5.1", - "thecodingmachine/phpstan-strict-rules": "^0.12.1" + "symfony/phpunit-bridge": "^5.3", + "thecodingmachine/phpstan-strict-rules": "^v0.12.1", + "composer/package-versions-deprecated": "^1.8", + "phpstan/phpstan-webmozart-assert": "^0.12.12" + }, + "conflict": { + "mouf/classname-mapper": "<1.0.2", + "symfony/event-dispatcher": "<4.3", + "symfony/security-core": "<4.3", + "symfony/routing": "<4.3", + "phpdocumentor/type-resolver": "<1.4" }, "scripts": { "phpstan": "phpstan analyse GraphqliteBundle.php DependencyInjection/ Controller/ Resources/ Security/ -c phpstan.neon --level=7 --no-progress" @@ -56,6 +65,5 @@ "dev-master": "4.1.x-dev" } }, - "minimum-stability": "dev", "prefer-stable": true } diff --git a/phpstan.baseline.neon b/phpstan.baseline.neon deleted file mode 100644 index 21658cb..0000000 --- a/phpstan.baseline.neon +++ /dev/null @@ -1,162 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Anonymous function should have native return typehint \"array\"\\.$#" - count: 1 - path: Controller/GraphqliteController.php - - - - message: "#^Instanceof between GraphQL\\\\Executor\\\\Promise\\\\Promise and GraphQL\\\\Executor\\\\Promise\\\\Promise will always evaluate to true\\.$#" - count: 1 - path: Controller/GraphqliteController.php - - - - message: "#^Anonymous function should have native return typehint \"array\"\\.$#" - count: 1 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Argument of an invalid type array\\|bool\\|float\\|int\\|string\\|null supplied for foreach, only iterables are supported\\.$#" - count: 3 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Binary operation \"\\.\" between 'security\\.firewall…' and array\\|bool\\|float\\|int\\|string\\|null results in an error\\.$#" - count: 2 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Cannot cast \\(array&nonEmpty\\)\\|float\\|int\\\\|int\\<1, max\\>\\|string\\|true to int\\.$#" - count: 2 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Negated boolean expression is always true\\.$#" - count: 1 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Property TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\DependencyInjection\\\\GraphqliteCompilerPass\\:\\:\\$cacheDir \\(string\\) does not accept array\\|bool\\|float\\|int\\|string\\|null\\.$#" - count: 1 - path: DependencyInjection/GraphqliteCompilerPass.php - - - - message: "#^Anonymous function should have native return typehint \"string\"\\.$#" - count: 2 - path: DependencyInjection/GraphqliteExtension.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\DependencyInjection\\\\GraphqliteExtension\\:\\:getNamespaceDir\\(\\) is unused\\.$#" - count: 1 - path: DependencyInjection/GraphqliteExtension.php - - - - message: "#^Class Overblog\\\\GraphiQLBundle\\\\Config\\\\GraphQLEndpoint\\\\RootResolver referenced with incorrect case\\: Overblog\\\\GraphiQLBundle\\\\Config\\\\GraphqlEndpoint\\\\RootResolver\\.$#" - count: 1 - path: DependencyInjection/OverblogGraphiQLEndpointWiringPass.php - - - - message: "#^Call to static method forSchemaAndResolver\\(\\) on an unknown class TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\GraphiQL\\\\GraphQLEndpointInvalidSchemaException\\.$#" - count: 1 - path: GraphiQL/EndpointResolver.php - - - - message: "#^Property TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\GraphiQL\\\\EndpointResolver\\:\\:\\$requestStack has no typehint specified\\.$#" - count: 1 - path: GraphiQL/EndpointResolver.php - - - - message: "#^Call to an undefined method ReflectionType\\:\\:getName\\(\\)\\.$#" - count: 1 - path: Mappers/RequestParameterMiddleware.php - - - - message: "#^Parameter \\#2 \\.\\.\\.\\$args of function array_merge expects array, array\\\\|\\(callable\\) given\\.$#" - count: 1 - path: Server/ServerConfig.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\Fixtures\\\\Controller\\\\TestGraphqlController\\:\\:contacts\\(\\) return type has no value type specified in iterable type Porpaginas\\\\Arrays\\\\ArrayResult\\.$#" - count: 1 - path: Tests/Fixtures/Controller/TestGraphqlController.php - - - - message: "#^PHPDoc tag @return with type array\\ is incompatible with native type Porpaginas\\\\Arrays\\\\ArrayResult\\.$#" - count: 1 - path: Tests/Fixtures/Controller/TestGraphqlController.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\Fixtures\\\\Entities\\\\Contact\\:\\:injectServicePrefetch\\(\\) has parameter \\$prefetchData with no typehint specified\\.$#" - count: 1 - path: Tests/Fixtures/Entities/Contact.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\Fixtures\\\\Entities\\\\Contact\\:\\:prefetchData\\(\\) has no return typehint specified\\.$#" - count: 1 - path: Tests/Fixtures/Entities/Contact.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\Fixtures\\\\Entities\\\\Contact\\:\\:prefetchData\\(\\) has parameter \\$iterable with no value type specified in iterable type iterable\\.$#" - count: 1 - path: Tests/Fixtures/Entities/Contact.php - - - - message: "#^Cannot call method assertValid\\(\\) on object\\|null\\.$#" - count: 2 - path: Tests/FunctionalTest.php - - - - message: "#^Cannot call method handleRequest\\(\\) on object\\|null\\.$#" - count: 1 - path: Tests/FunctionalTest.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\FunctionalTest\\:\\:logIn\\(\\) has no return typehint specified\\.$#" - count: 1 - path: Tests/FunctionalTest.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 15 - path: Tests/FunctionalTest.php - - - - message: "#^Parameter \\#3 \\$message of method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: Tests/FunctionalTest.php - - - - message: "#^Anonymous function should have native return typehint \"void\"\\.$#" - count: 1 - path: Tests/GraphqliteTestingKernel.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\GraphqliteTestingKernel\\:\\:configureContainer\\(\\) has no return typehint specified\\.$#" - count: 1 - path: Tests/GraphqliteTestingKernel.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\GraphqliteTestingKernel\\:\\:configureRoutes\\(\\) has no return typehint specified\\.$#" - count: 1 - path: Tests/GraphqliteTestingKernel.php - - - - message: "#^Method TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\GraphqliteTestingKernel\\:\\:configureRoutes\\(\\) has parameter \\$routes with no typehint specified\\.$#" - count: 1 - path: Tests/GraphqliteTestingKernel.php - - - - message: "#^Property TheCodingMachine\\\\Graphqlite\\\\Bundle\\\\Tests\\\\GraphqliteTestingKernel\\:\\:\\$enableLogin \\(string\\) does not accept string\\|null\\.$#" - count: 1 - path: Tests/GraphqliteTestingKernel.php - - - - message: "#^Cannot call method assertValid\\(\\) on object\\|null\\.$#" - count: 1 - path: Tests/NoSecurityBundleTest.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: Tests/NoSecurityBundleTest.php - diff --git a/phpstan.neon b/phpstan.neon index 65342ca..05e8f67 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ includes: - vendor/phpstan/phpstan/conf/bleedingEdge.neon + - vendor/phpstan/phpstan-webmozart-assert/extension.neon - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon - - phpstan.baseline.neon parameters: tmpDir: .phpstan-cache paths: @@ -10,6 +10,7 @@ parameters: - vendor - cache - .phpstan-cache + - Tests level: max polluteScopeWithLoopInitialAssignments: false polluteScopeWithAlwaysIterableForeach: false @@ -22,5 +23,7 @@ parameters: checkMissingClosureNativeReturnTypehintRule: true checkTooWideReturnTypesInProtectedAndPublicMethods: true treatPhpDocTypesAsCertain: false + reportUnmatchedIgnoredErrors: false ignoreErrors: - - "#Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeDefinition::children\\(\\)#" + # Wrong return type hint in Symfony's TreeBuilder + - '#Call to an undefined method Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition::\w+\(\).#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0548e50..cdfcc0f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,21 +1,27 @@ - + + + + + + + + ./Tests/ + ./ @@ -28,20 +34,13 @@ ./var - + + - - - - - - 0 - - - +