From 0b59566cd40bf5dfebc0a1553e5f6f252ca8d51f Mon Sep 17 00:00:00 2001 From: Oleksandr Prypkhan Date: Fri, 22 Mar 2024 02:00:41 +0200 Subject: [PATCH 1/5] Use ComposerFinder's useAutoloading method --- composer.json | 2 +- src/GlobControllerQueryProvider.php | 4 +--- src/SchemaFactory.php | 22 ++++++++++++++++++++-- src/Utils/Namespaces/NamespaceFactory.php | 11 +++++------ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index d3e79e0426..51848345d0 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "symfony/expression-language": "^4 || ^5 || ^6 || ^7", "thecodingmachine/cache-utils": "^1", "webonyx/graphql-php": "^v15.0", - "kcs/class-finder": "^0.4.0" + "kcs/class-finder": "dev-master" }, "require-dev": { "beberlei/porpaginas": "^1.2 || ^2.0", diff --git a/src/GlobControllerQueryProvider.php b/src/GlobControllerQueryProvider.php index 6fc7e659d1..6774656622 100644 --- a/src/GlobControllerQueryProvider.php +++ b/src/GlobControllerQueryProvider.php @@ -33,7 +33,6 @@ final class GlobControllerQueryProvider implements QueryProviderInterface { /** @var array|null */ private array|null $instancesList = null; - private FinderInterface $finder; private AggregateControllerQueryProvider|null $aggregateControllerQueryProvider = null; private CacheContractInterface $cacheContract; @@ -47,11 +46,10 @@ public function __construct( private readonly ContainerInterface $container, private readonly AnnotationReader $annotationReader, private readonly CacheInterface $cache, - FinderInterface|null $finder = null, + private readonly FinderInterface $finder, int|null $cacheTtl = null, ) { - $this->finder = $finder ?? new ComposerFinder(); $this->cacheContract = new Psr16Adapter( $this->cache, str_replace(['\\', '{', '}', '(', ')', '/', '@', ':'], '_', $namespace), diff --git a/src/SchemaFactory.php b/src/SchemaFactory.php index e49f51e8a1..1326bbe990 100644 --- a/src/SchemaFactory.php +++ b/src/SchemaFactory.php @@ -8,6 +8,7 @@ use Doctrine\Common\Annotations\PsrCachedReader; use Doctrine\Common\Annotations\Reader; use GraphQL\Type\SchemaConfig; +use Kcs\ClassFinder\Finder\ComposerFinder; use Kcs\ClassFinder\Finder\FinderInterface; use MyCLabs\Enum\Enum; use PackageVersions\Versions; @@ -125,6 +126,8 @@ class SchemaFactory private string $cacheNamespace; + private ?bool $useAutoloading = null; + public function __construct(private CacheInterface $cache, private ContainerInterface $container) { $this->cacheNamespace = substr(md5(Versions::getVersion('thecodingmachine/graphqlite')), 0, 8); @@ -269,6 +272,16 @@ public function setFinder(FinderInterface $finder): self return $this; } + /** + * Use autoloading when scanning for classes or not. + */ + public function useAutoloading(bool $value = true): self + { + $this->useAutoloading = $value; + + return $this; + } + /** * Sets the time to live time of the cache for annotations in files. * By default this is set to 2 seconds which is ok for development environments. @@ -343,8 +356,13 @@ public function createSchema(): Schema $cachedDocBlockFactory = new CachedDocBlockFactory($namespacedCache); $namingStrategy = $this->namingStrategy ?: new NamingStrategy(); $typeRegistry = new TypeRegistry(); + $finder = $this->finder ?? new ComposerFinder(); + + if ($this->useAutoloading !== null) { + $finder = $finder->useAutoloading($this->useAutoloading); + } - $namespaceFactory = new NamespaceFactory($namespacedCache, $this->finder, $this->globTTL); + $namespaceFactory = new NamespaceFactory($namespacedCache, $finder, $this->globTTL); $nsList = array_map( static fn (string $namespace) => $namespaceFactory->createNamespace($namespace), $this->typeNamespaces, @@ -493,7 +511,7 @@ public function createSchema(): Schema $this->container, $annotationReader, $namespacedCache, - $this->finder, + $finder, $this->globTTL, ); } diff --git a/src/Utils/Namespaces/NamespaceFactory.php b/src/Utils/Namespaces/NamespaceFactory.php index e4d462cc2a..ed2e4fb224 100644 --- a/src/Utils/Namespaces/NamespaceFactory.php +++ b/src/Utils/Namespaces/NamespaceFactory.php @@ -15,12 +15,11 @@ */ final class NamespaceFactory { - private FinderInterface $finder; - - public function __construct(private readonly CacheInterface $cache, FinderInterface|null $finder = null, private int|null $globTTL = 2) - { - $this->finder = $finder ?? new ComposerFinder(); - } + public function __construct( + private readonly CacheInterface $cache, + private readonly FinderInterface $finder, + private int|null $globTTL = 2 + ) {} /** @param string $namespace A PHP namespace */ public function createNamespace(string $namespace): NS From 294a41d792fc1e342470499da0ee3aaee7e5e260 Mon Sep 17 00:00:00 2001 From: Oleksandr Prypkhan Date: Tue, 26 Mar 2024 15:36:10 +0200 Subject: [PATCH 2/5] Drop useAutoloading() method --- composer.json | 2 +- src/SchemaFactory.php | 16 ---------------- src/Utils/Namespaces/NS.php | 2 +- tests/AbstractQueryProviderTest.php | 3 ++- .../BadNamespace/BadlyNamespacedClass.php | 8 -------- .../BadNamespace/ClassWithoutNamespace.php | 5 ----- .../Integration/Models/BadNamespaceClass.php | 9 --------- tests/Integration/IntegrationTestCase.php | 10 +++++++++- 8 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 tests/Fixtures/BadNamespace/BadlyNamespacedClass.php delete mode 100644 tests/Fixtures/BadNamespace/ClassWithoutNamespace.php delete mode 100644 tests/Fixtures/Integration/Models/BadNamespaceClass.php diff --git a/composer.json b/composer.json index 51848345d0..eea76d30ac 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "symfony/expression-language": "^4 || ^5 || ^6 || ^7", "thecodingmachine/cache-utils": "^1", "webonyx/graphql-php": "^v15.0", - "kcs/class-finder": "dev-master" + "kcs/class-finder": "^0.5.0" }, "require-dev": { "beberlei/porpaginas": "^1.2 || ^2.0", diff --git a/src/SchemaFactory.php b/src/SchemaFactory.php index 1326bbe990..04e4bfa6ba 100644 --- a/src/SchemaFactory.php +++ b/src/SchemaFactory.php @@ -126,8 +126,6 @@ class SchemaFactory private string $cacheNamespace; - private ?bool $useAutoloading = null; - public function __construct(private CacheInterface $cache, private ContainerInterface $container) { $this->cacheNamespace = substr(md5(Versions::getVersion('thecodingmachine/graphqlite')), 0, 8); @@ -272,16 +270,6 @@ public function setFinder(FinderInterface $finder): self return $this; } - /** - * Use autoloading when scanning for classes or not. - */ - public function useAutoloading(bool $value = true): self - { - $this->useAutoloading = $value; - - return $this; - } - /** * Sets the time to live time of the cache for annotations in files. * By default this is set to 2 seconds which is ok for development environments. @@ -358,10 +346,6 @@ public function createSchema(): Schema $typeRegistry = new TypeRegistry(); $finder = $this->finder ?? new ComposerFinder(); - if ($this->useAutoloading !== null) { - $finder = $finder->useAutoloading($this->useAutoloading); - } - $namespaceFactory = new NamespaceFactory($namespacedCache, $finder, $this->globTTL); $nsList = array_map( static fn (string $namespace) => $namespaceFactory->createNamespace($namespace), diff --git a/src/Utils/Namespaces/NS.php b/src/Utils/Namespaces/NS.php index 262a42494b..f1c51f3a18 100644 --- a/src/Utils/Namespaces/NS.php +++ b/src/Utils/Namespaces/NS.php @@ -79,7 +79,7 @@ public function getClassList(): array $this->classes = []; /** @var class-string $className */ /** @var ReflectionClass $reflector */ - foreach ($this->finder->inNamespace($this->namespace) as $className => $reflector) { + foreach ((clone $this->finder)->inNamespace($this->namespace) as $className => $reflector) { if (! ($reflector instanceof ReflectionClass)) { continue; } diff --git a/tests/AbstractQueryProviderTest.php b/tests/AbstractQueryProviderTest.php index 16b6de62d5..04c98fd4c8 100644 --- a/tests/AbstractQueryProviderTest.php +++ b/tests/AbstractQueryProviderTest.php @@ -9,6 +9,7 @@ use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\OutputType; use GraphQL\Type\Definition\Type; +use Kcs\ClassFinder\Finder\ComposerFinder; use phpDocumentor\Reflection\TypeResolver as PhpDocumentorTypeResolver; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; @@ -466,7 +467,7 @@ protected function getNamespaceFactory(): NamespaceFactory $arrayAdapter->setLogger(new ExceptionLogger()); $psr16Cache = new Psr16Cache($arrayAdapter); - $this->namespaceFactory = new NamespaceFactory($psr16Cache); + $this->namespaceFactory = new NamespaceFactory($psr16Cache, new ComposerFinder()); } return $this->namespaceFactory; } diff --git a/tests/Fixtures/BadNamespace/BadlyNamespacedClass.php b/tests/Fixtures/BadNamespace/BadlyNamespacedClass.php deleted file mode 100644 index 258dac6fd5..0000000000 --- a/tests/Fixtures/BadNamespace/BadlyNamespacedClass.php +++ /dev/null @@ -1,8 +0,0 @@ - static function (ContainerInterface $container) { return new Schema($container->get(QueryProviderInterface::class), $container->get(RecursiveTypeMapperInterface::class), $container->get(TypeResolver::class), $container->get(RootTypeMapperInterface::class)); }, + FinderInterface::class => fn () => new ComposerFinder(), QueryProviderInterface::class => static function (ContainerInterface $container) { $queryProvider = new GlobControllerQueryProvider( 'TheCodingMachine\\GraphQLite\\Fixtures\\Integration\\Controllers', @@ -94,6 +97,7 @@ public function createContainer(array $overloadedServices = []): ContainerInterf $container->get(BasicAutoWiringContainer::class), $container->get(AnnotationReader::class), new Psr16Cache(new ArrayAdapter()), + $container->get(FinderInterface::class), ); $queryProvider = new AggregateQueryProvider([ @@ -104,6 +108,7 @@ public function createContainer(array $overloadedServices = []): ContainerInterf $container->get(BasicAutoWiringContainer::class), $container->get(AnnotationReader::class), new Psr16Cache(new ArrayAdapter()), + $container->get(FinderInterface::class), ), ]); @@ -201,7 +206,10 @@ public function createContainer(array $overloadedServices = []): ContainerInterf NamespaceFactory::class => static function (ContainerInterface $container) { $arrayAdapter = new ArrayAdapter(); $arrayAdapter->setLogger(new ExceptionLogger()); - return new NamespaceFactory(new Psr16Cache($arrayAdapter)); + return new NamespaceFactory( + new Psr16Cache($arrayAdapter), + $container->get(FinderInterface::class), + ); }, GlobTypeMapper::class => static function (ContainerInterface $container) { $arrayAdapter = new ArrayAdapter(); From 2f291c856e0aa5874c225386e2b381ac83c4b26f Mon Sep 17 00:00:00 2001 From: Oleksandr Prypkhan Date: Tue, 26 Mar 2024 16:17:06 +0200 Subject: [PATCH 3/5] Add "Disabling autoloading" section to the docs --- website/docs/other-frameworks.mdx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/website/docs/other-frameworks.mdx b/website/docs/other-frameworks.mdx index 64806bd84a..0700fc8390 100644 --- a/website/docs/other-frameworks.mdx +++ b/website/docs/other-frameworks.mdx @@ -98,6 +98,26 @@ use TheCodingMachine\GraphQLite\Context\Context; $result = GraphQL::executeQuery($schema, $query, null, new Context(), $variableValues); ``` +### Disabling autoloading + +GraphQLite uses `kcs/class-finder` to iterate over classes and find all that have GraphQLite attributes. By default, +it uses autoloading under the hood. But if you have an older codebase that contains classes with incorrect or missing +namespaces, you may need to use `include_once` instead. To do so, you can overwrite the finder using `setFinder()`: + +```php +use Kcs\ClassFinder\Finder\ComposerFinder; +use TheCodingMachine\GraphQLite\SchemaFactory; + +$factory = new SchemaFactory($cache, $container); +$factory->addControllerNamespace('App\\Controllers\\') + ->addTypeNamespace('App\\') + ->setFinder( + (new ComposerFinder())->useAutoloading(false) + ); + +$schema = $factory->createSchema(); +``` + ## Minimal example The smallest working example using no framework is: From 95d6d5e012d7fea67342226e1386778a2f6d26d8 Mon Sep 17 00:00:00 2001 From: Oleksandr Prypkhan Date: Tue, 26 Mar 2024 16:20:04 +0200 Subject: [PATCH 4/5] Fix code style --- src/GlobControllerQueryProvider.php | 1 - src/Utils/Namespaces/NamespaceFactory.php | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/GlobControllerQueryProvider.php b/src/GlobControllerQueryProvider.php index 6774656622..f7ed17170e 100644 --- a/src/GlobControllerQueryProvider.php +++ b/src/GlobControllerQueryProvider.php @@ -6,7 +6,6 @@ use GraphQL\Type\Definition\FieldDefinition; use InvalidArgumentException; -use Kcs\ClassFinder\Finder\ComposerFinder; use Kcs\ClassFinder\Finder\FinderInterface; use Psr\Container\ContainerInterface; use Psr\SimpleCache\CacheInterface; diff --git a/src/Utils/Namespaces/NamespaceFactory.php b/src/Utils/Namespaces/NamespaceFactory.php index ed2e4fb224..719c80bb22 100644 --- a/src/Utils/Namespaces/NamespaceFactory.php +++ b/src/Utils/Namespaces/NamespaceFactory.php @@ -4,7 +4,6 @@ namespace TheCodingMachine\GraphQLite\Utils\Namespaces; -use Kcs\ClassFinder\Finder\ComposerFinder; use Kcs\ClassFinder\Finder\FinderInterface; use Psr\SimpleCache\CacheInterface; @@ -18,8 +17,9 @@ final class NamespaceFactory public function __construct( private readonly CacheInterface $cache, private readonly FinderInterface $finder, - private int|null $globTTL = 2 - ) {} + private int|null $globTTL = 2, + ) { + } /** @param string $namespace A PHP namespace */ public function createNamespace(string $namespace): NS From 59d52f1cfea870b94e4eb8304928923bcd3d8b64 Mon Sep 17 00:00:00 2001 From: Oleksandr Prypkhan Date: Tue, 26 Mar 2024 16:28:11 +0200 Subject: [PATCH 5/5] Change docs wording --- website/docs/other-frameworks.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/other-frameworks.mdx b/website/docs/other-frameworks.mdx index 0700fc8390..358e8095fd 100644 --- a/website/docs/other-frameworks.mdx +++ b/website/docs/other-frameworks.mdx @@ -100,8 +100,8 @@ $result = GraphQL::executeQuery($schema, $query, null, new Context(), $variableV ### Disabling autoloading -GraphQLite uses `kcs/class-finder` to iterate over classes and find all that have GraphQLite attributes. By default, -it uses autoloading under the hood. But if you have an older codebase that contains classes with incorrect or missing +GraphQLite uses `kcs/class-finder` to find all classes that have GraphQLite attributes. By default, it uses +autoloading under the hood. But if you have an older codebase that contains classes with incorrect or missing namespaces, you may need to use `include_once` instead. To do so, you can overwrite the finder using `setFinder()`: ```php