Skip to content
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

### Fixed

- Cache the query AST as an array in `query_cache.mode: store`, so restricting `cache.serializable_classes` no longer makes the cached AST come back as `__PHP_Incomplete_Class` https://github.com/nuwave/lighthouse/pull/2785

## v6.69.2

### Fixed
Expand Down
18 changes: 17 additions & 1 deletion src/Cache/QueryCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,24 @@ public function fromCacheOrParse(string $hash, \Closure $parse): DocumentNode
protected function fromStoreOrParse(string $hash, \Closure $parse): DocumentNode
{
$store = $this->makeCacheStore();
$key = "lighthouse:query:{$hash}";

// The AST is cached as an array rather than as a DocumentNode instance.
// Cache stores serialize objects, and applications may restrict which classes
// unserialize() accepts, which would turn the AST into __PHP_Incomplete_Class.
// Anything else found under this key predates that and is simply reparsed.
$astArray = $store->get(key: $key);
if (is_array($astArray)) {
$astInstance = AST::fromArray($astArray);
assert($astInstance instanceof DocumentNode, 'The cached AST array is expected to convert to a DocumentNode.');

return $astInstance;
}

$query = $parse();
$store->put(key: $key, value: $query->toArray(), ttl: $this->ttl);

return $store->remember(key: "lighthouse:query:{$hash}", ttl: $this->ttl, callback: $parse);
return $query;
}

/** @param \Closure(): DocumentNode $parse */
Expand Down
33 changes: 33 additions & 0 deletions tests/Integration/QueryCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,39 @@ public function testEnabledWithDefaults(): void
$event->assertDispatchedTimes(KeyWritten::class, 1);
}

public function testStoreModeWithRestrictedSerializableClasses(): void
{
$config = $this->app->make(ConfigRepository::class);
$config->set('lighthouse.query_cache.enable', true);
$config->set('lighthouse.validation_cache.enable', false);

// Laravel 13 lets applications restrict which classes may be unserialized from the cache.
// Any store that serializes values then calls unserialize() with `allowed_classes`,
// turning every disallowed object back into __PHP_Incomplete_Class.
$config->set('cache.stores.array.serialize', true);
$config->set('cache.serializable_classes', []);

$query = /** @lang GraphQL */ <<<'GRAPHQL'
{
foo
}
GRAPHQL;

// Populates the query cache.
$this->graphQL($query)->assertExactJson([
'data' => [
'foo' => Foo::THE_ANSWER,
],
]);

// Reads the cached query back out of the store.
$this->graphQL($query)->assertExactJson([
'data' => [
'foo' => Foo::THE_ANSWER,
],
]);
}

public function testDifferentQueriesHasDifferentKeys(): void
{
$config = $this->app->make(ConfigRepository::class);
Expand Down