Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
"psr/simple-cache": "^1.0.1 || ^2 || ^3",
"symfony/cache": "^4.3 || ^5 || ^6 || ^7",
"symfony/expression-language": "^4 || ^5 || ^6 || ^7",
"thecodingmachine/cache-utils": "^1",
"webonyx/graphql-php": "^v15.0",
"kcs/class-finder": "^0.5.0"
},
Expand Down
3 changes: 2 additions & 1 deletion examples/no-framework/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"require": {
"thecodingmachine/graphqlite": "@dev",
"mouf/picotainer": "^1.1",
"symfony/cache": "^4.2"
"symfony/cache": "^4.3",
"psr/simple-cache": "^1.0"
},
"repositories": [
{
Expand Down
5 changes: 3 additions & 2 deletions examples/no-framework/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
use TheCodingMachine\GraphQLite\SchemaFactory;
use TheCodingMachine\GraphQLite\Context\Context;

use Symfony\Component\Cache\Simple\FilesystemCache;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Mouf\Picotainer\Picotainer;
use GraphQL\Utils\SchemaPrinter;
use App\Controllers\MyController;

require_once __DIR__ . '/vendor/autoload.php';

// $cache is any PSR-16 compatible cache.
$cache = new FilesystemCache();
$cache = new Psr16Cache(new FilesystemAdapter());;

// $container is any PSR-11 compatible container which has
// been populated with your controller classes.
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ parameters:
message: '#Unreachable statement - code above always terminates.#'
path: src/Http/WebonyxGraphqlMiddleware.php
-
message: '#Property TheCodingMachine\\GraphQLite\\Annotations\\Type::\$class \(class-string<object>\\|null\) does not accept string.#'
message: '#Property TheCodingMachine\\GraphQLite\\Annotations\\Type::\$class \(class-string<object>\|null\) does not accept string.#'
path: src/Annotations/Type.php
-
message: '#Method TheCodingMachine\\GraphQLite\\AnnotationReader::(getMethodAnnotations|getPropertyAnnotations)\(\) should return array<int, T of object> but returns array<object>.#'
Expand Down
43 changes: 43 additions & 0 deletions src/Cache/ClassBoundCacheContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Cache;

use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;
use ReflectionClass;

use function str_replace;

class ClassBoundCacheContract implements ClassBoundCacheContractInterface
{
private readonly string $cachePrefix;

public function __construct(private readonly CacheInterface $classBoundCache, string $cachePrefix = '')
{
$this->cachePrefix = str_replace(['\\', '{', '}', '(', ')', '/', '@', ':'], '_', $cachePrefix);
}

/**
* @param string $key An optional key to differentiate between cache items attached to the same class.
*
* @throws InvalidArgumentException
*/
public function get(ReflectionClass $reflectionClass, callable $resolver, string $key = '', int|null $ttl = null): mixed
{
$cacheKey = $reflectionClass->getName() . '__' . $key;
$cacheKey = $this->cachePrefix . str_replace(['\\', '{', '}', '(', ')', '/', '@', ':'], '_', $cacheKey);

$item = $this->classBoundCache->get($cacheKey);
if ($item !== null) {
return $item;
}

$item = $resolver();

$this->classBoundCache->set($cacheKey, $item, $ttl);

return $item;
}
}
15 changes: 15 additions & 0 deletions src/Cache/ClassBoundCacheContractFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Cache;

use Psr\SimpleCache\CacheInterface;

class ClassBoundCacheContractFactory implements ClassBoundCacheContractFactoryInterface
{
public function make(CacheInterface $classBoundCache, string $cachePrefix = ''): ClassBoundCacheContractInterface
{
return new ClassBoundCacheContract($classBoundCache, $cachePrefix);
}
}
12 changes: 12 additions & 0 deletions src/Cache/ClassBoundCacheContractFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Cache;

use Psr\SimpleCache\CacheInterface;

interface ClassBoundCacheContractFactoryInterface
{
public function make(CacheInterface $classBoundCache, string $cachePrefix = ''): ClassBoundCacheContractInterface;
}
13 changes: 13 additions & 0 deletions src/Cache/ClassBoundCacheContractInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace TheCodingMachine\GraphQLite\Cache;

use ReflectionClass;

interface ClassBoundCacheContractInterface
{
/** @param string $key An optional key to differentiate between cache items attached to the same class. */
public function get(ReflectionClass $reflectionClass, callable $resolver, string $key = '', int|null $ttl = null): mixed;
}
7 changes: 7 additions & 0 deletions src/FactoryContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Psr\Container\ContainerInterface;
use Psr\SimpleCache\CacheInterface;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactoryInterface;
use TheCodingMachine\GraphQLite\Mappers\RecursiveTypeMapperInterface;
use TheCodingMachine\GraphQLite\Types\InputTypeValidatorInterface;
use TheCodingMachine\GraphQLite\Types\TypeResolver;
Expand All @@ -31,6 +32,7 @@ public function __construct(
private readonly InputTypeValidatorInterface|null $inputTypeValidator,
private readonly int|null $globTTL,
private readonly int|null $mapTTL = null,
private readonly ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory = null,
) {
}

Expand Down Expand Up @@ -84,6 +86,11 @@ public function getCache(): CacheInterface
return $this->cache;
}

public function getClassBoundCacheContractFactory(): ClassBoundCacheContractFactoryInterface|null
{
return $this->classBoundCacheContractFactory;
}

public function getInputTypeValidator(): InputTypeValidatorInterface|null
{
return $this->inputTypeValidator;
Expand Down
26 changes: 8 additions & 18 deletions src/Mappers/AbstractTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
use ReflectionMethod;
use Symfony\Component\Cache\Adapter\Psr16Adapter;
use Symfony\Contracts\Cache\CacheInterface as CacheContractInterface;
use TheCodingMachine\CacheUtils\ClassBoundCache;
use TheCodingMachine\CacheUtils\ClassBoundCacheContract;
use TheCodingMachine\CacheUtils\ClassBoundCacheContractInterface;
use TheCodingMachine\CacheUtils\ClassBoundMemoryAdapter;
use TheCodingMachine\CacheUtils\FileBoundCache;
use TheCodingMachine\GraphQLite\AnnotationReader;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactory;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactoryInterface;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractInterface;
use TheCodingMachine\GraphQLite\InputTypeGenerator;
use TheCodingMachine\GraphQLite\InputTypeUtils;
use TheCodingMachine\GraphQLite\NamingStrategyInterface;
Expand Down Expand Up @@ -66,23 +64,15 @@ public function __construct(
private readonly CacheInterface $cache,
protected int|null $globTTL = 2,
private readonly int|null $mapTTL = null,
ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory = null,
)
{
$this->cacheContract = new Psr16Adapter($this->cache, $cachePrefix, $this->globTTL ?? 0);

$classToAnnotationsCache = new ClassBoundCache(
new FileBoundCache($this->cache, 'classToAnnotations_' . $cachePrefix),
);
$this->mapClassToAnnotationsCache = new ClassBoundCacheContract(
new ClassBoundMemoryAdapter($classToAnnotationsCache),
);

$classToExtendedAnnotationsCache = new ClassBoundCache(
new FileBoundCache($this->cache, 'classToExtendAnnotations_' . $cachePrefix),
);
$this->mapClassToExtendAnnotationsCache = new ClassBoundCacheContract(
new ClassBoundMemoryAdapter($classToExtendedAnnotationsCache),
);
$classBoundCacheContractFactory = $classBoundCacheContractFactory ?? new ClassBoundCacheContractFactory();

$this->mapClassToAnnotationsCache = $classBoundCacheContractFactory->make($cache, 'classToAnnotations_' . $cachePrefix);
$this->mapClassToExtendAnnotationsCache = $classBoundCacheContractFactory->make($cache, 'classToExtendAnnotations_' . $cachePrefix);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/Mappers/GlobTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Psr\SimpleCache\CacheInterface;
use ReflectionClass;
use TheCodingMachine\GraphQLite\AnnotationReader;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactoryInterface;
use TheCodingMachine\GraphQLite\InputTypeGenerator;
use TheCodingMachine\GraphQLite\InputTypeUtils;
use TheCodingMachine\GraphQLite\NamingStrategyInterface;
Expand Down Expand Up @@ -44,6 +45,7 @@ public function __construct(
CacheInterface $cache,
int|null $globTTL = 2,
int|null $mapTTL = null,
ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory = null,
) {
$cachePrefix = str_replace(
['\\', '{', '}', '(', ')', '/', '@', ':'],
Expand All @@ -63,6 +65,7 @@ public function __construct(
$cache,
$globTTL,
$mapTTL,
$classBoundCacheContractFactory,
);
}

Expand Down
3 changes: 3 additions & 0 deletions src/Mappers/StaticClassListTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Psr\SimpleCache\CacheInterface;
use ReflectionClass;
use TheCodingMachine\GraphQLite\AnnotationReader;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactoryInterface;
use TheCodingMachine\GraphQLite\GraphQLRuntimeException;
use TheCodingMachine\GraphQLite\InputTypeGenerator;
use TheCodingMachine\GraphQLite\InputTypeUtils;
Expand Down Expand Up @@ -45,6 +46,7 @@ public function __construct(
CacheInterface $cache,
int|null $globTTL = 2,
int|null $mapTTL = null,
ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory = null,
) {
$cachePrefix = str_replace(
['\\', '{', '}', '(', ')', '/', '@', ':'],
Expand All @@ -64,6 +66,7 @@ public function __construct(
$cache,
$globTTL,
$mapTTL,
$classBoundCacheContractFactory,
);
}

Expand Down
1 change: 1 addition & 0 deletions src/Mappers/StaticClassListTypeMapperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function create(FactoryContext $context): TypeMapperInterface
$context->getCache(),
$context->getGlobTTL(),
$context->getMapTTL(),
$context->getClassBoundCacheContractFactory(),
);
}
}
17 changes: 16 additions & 1 deletion src/SchemaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Psr\SimpleCache\CacheInterface;
use Symfony\Component\Cache\Adapter\Psr16Adapter;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactoryInterface;
use TheCodingMachine\GraphQLite\Mappers\CompositeTypeMapper;
use TheCodingMachine\GraphQLite\Mappers\GlobTypeMapper;
use TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterHandler;
Expand Down Expand Up @@ -120,7 +121,7 @@ class SchemaFactory

private string $cacheNamespace;

public function __construct(private readonly CacheInterface $cache, private readonly ContainerInterface $container)
public function __construct(private readonly CacheInterface $cache, private readonly ContainerInterface $container, private ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory = null)
{
$this->cacheNamespace = substr(md5(Versions::getVersion('thecodingmachine/graphqlite')), 0, 8);
}
Expand Down Expand Up @@ -259,6 +260,18 @@ public function setGlobTTL(int|null $globTTL): self
return $this;
}

/**
* Set a custom ClassBoundCacheContractFactory.
* This is used to create CacheContracts that store reflection results.
* Set this to "null" to use the default fallback factory.
*/
public function setClassBoundCacheContractFactory(ClassBoundCacheContractFactoryInterface|null $classBoundCacheContractFactory): self
{
$this->classBoundCacheContractFactory = $classBoundCacheContractFactory;

return $this;
}

/**
* Sets GraphQLite in "prod" mode (cache settings optimized for best performance).
*
Expand Down Expand Up @@ -430,6 +443,7 @@ public function createSchema(): Schema
$recursiveTypeMapper,
$namespacedCache,
$this->globTTL,
classBoundCacheContractFactory: $this->classBoundCacheContractFactory,
));
}

Expand All @@ -447,6 +461,7 @@ public function createSchema(): Schema
$namespacedCache,
$this->inputTypeValidator,
$this->globTTL,
classBoundCacheContractFactory: $this->classBoundCacheContractFactory,
);
}

Expand Down
5 changes: 4 additions & 1 deletion tests/FactoryContextTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Psr16Cache;
use TheCodingMachine\GraphQLite\Cache\ClassBoundCacheContractFactory;
use TheCodingMachine\GraphQLite\Containers\EmptyContainer;
use TheCodingMachine\GraphQLite\Fixtures\Inputs\Validator;

Expand All @@ -16,6 +17,7 @@ public function testContext(): void
$namingStrategy = new NamingStrategy();
$container = new EmptyContainer();
$arrayCache = new Psr16Cache(new ArrayAdapter());
$classBoundCacheContractFactory = new ClassBoundCacheContractFactory();
$validator = new Validator();

$context = new FactoryContext(
Expand All @@ -30,7 +32,8 @@ public function testContext(): void
$container,
$arrayCache,
$validator,
self::GLOB_TTL_SECONDS
self::GLOB_TTL_SECONDS,
classBoundCacheContractFactory: $classBoundCacheContractFactory,
);

$this->assertSame($this->getAnnotationReader(), $context->getAnnotationReader());
Expand Down