Skip to content

Commit 9b3d8f3

Browse files
committed
Introduce scope-aware Context and #[MapContext]
Resolvers often need per-request data that is neither a GraphQL input nor a DI service: the current HTTP request, the authenticated user, or a value computed by an ancestor field. Until now the generated resolver closures ignored webonyx's context value entirely, so the only escape hatches were `#[Arg]` (client input) and `#[Autowire]` (container), and there was no way to thread request state to a resolver. This adds a first-class `Context` value object and a `#[MapContext]` parameter attribute. `Context` is a webonyx `ScopedContext` that stores objects by class (`attachObject`/`getObject`/`maybeGetObject`) and also implements `ArrayAccess`; because it is scoped, a value attached by a resolver is visible to its descendants without leaking to siblings. `#[MapContext]` injects an object from the `Context` into a resolver parameter by its type — nullable parameters resolve to `null` when absent, non-nullable parameters throw. The generated query, mutation, and field closures now receive webonyx's context as a `mixed` value and pass it through to `ArgumentNodeResolver`. The value is left untouched (it can be anything the server provides); only `#[MapContext]` resolution requires it to be a `Context`, throwing a `ContextException` otherwise. Wiring a `Context` onto the server is up to the consumer via the webonyx `context` option (see the docs).
1 parent 960bb5a commit 9b3d8f3

34 files changed

Lines changed: 928 additions & 16 deletions

docs/getting_started.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ $server = new StandardServer(ServerConfig::create([
4545
]));
4646
```
4747

48+
💡 *Want to pass per-request data (the HTTP request, the current user, …) to your resolvers? Set a*
49+
`Context` *as the server's context value and read it with* `#[MapContext]`*. See*
50+
[#[MapContext]](usage.md#mapcontext) *and* [Context](usage.md#context).
51+
4852
📌 *This library does not create a GraphQL server for you.*
4953

5054
To learn how to set up a server, check the [webonyx documentation](https://webonyx.github.io/graphql-php/executing-queries/#using-server).

docs/usage.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ You can use the following attributes:
2121
- [#[Field]](#field)
2222
- [#[Arg]](#arg)
2323
- [#[Autowire]](#autowire)
24+
- [#[MapContext]](#mapcontext)
2425
- [#[Scalar]](#scalar)
2526
- [#[Cursor]](#cursor)
2627

@@ -492,6 +493,107 @@ By default, the service to inject is determined by the parameter type. If needed
492493
|-----------|------------------------------------------------------------------------------------|
493494
| `service` | *(Optional)* Custom service identifier to retrieve from the DI container (PSR-11). |
494495

496+
### #[MapContext]
497+
498+
Webonyx/graphql-php passes a **context value** to every resolver. This library wraps it in a
499+
`Context` object (see [Context](#context)) that you can populate per request — for example with the
500+
current HTTP request, the authenticated user, or any value resolved higher up in the query tree.
501+
502+
`#[MapContext]` injects an object stored in that `Context` into a resolver parameter, looked up by the
503+
parameter's type. It works on `#[Query]`, `#[Mutation]`, and `#[Field]` method parameters.
504+
505+
```php
506+
use Jerowork\GraphqlAttributeSchema\Attribute\MapContext;
507+
use Jerowork\GraphqlAttributeSchema\Attribute\Query;
508+
use Symfony\Component\HttpFoundation\Request;
509+
510+
final readonly class YourQuery
511+
{
512+
#[Query]
513+
public function yourQuery(
514+
int $filter,
515+
#[MapContext]
516+
Request $request,
517+
): YourType {
518+
// $request is fetched from the Context by its class
519+
}
520+
}
521+
```
522+
523+
A resolver can also attach objects to the `Context` so descendant fields can read them through
524+
`#[MapContext]`. Because `Context` is a webonyx `ScopedContext`, children receive a clone, so values
525+
attached by a resolver are visible to its descendants without leaking to sibling fields:
526+
527+
```php
528+
#[Field]
529+
public function getChild(Context $context): ChildType
530+
{
531+
$context->attachObject(new Locale('en'));
532+
// ... children resolving under this field can now `#[MapContext] Locale $locale`
533+
}
534+
```
535+
536+
#### Nullable parameters
537+
538+
- A **non-nullable** parameter (`Request $request`) throws a `ContextException` when no matching object
539+
is present in the `Context`.
540+
- A **nullable** parameter (`?Request $request`) resolves to `null` when no matching object is present.
541+
542+
#### Requirements
543+
544+
- The parameter must be type-hinted with a class (not a built-in type).
545+
- The GraphQL context value **must** be an instance of
546+
`Jerowork\GraphqlAttributeSchema\Context`. If it is anything else, a `ContextException` is thrown when
547+
the parameter is resolved. See [Context](#context) for how to set this up on your server.
548+
549+
### Context
550+
551+
`Jerowork\GraphqlAttributeSchema\Context` is the per-request context value passed to your resolvers. It
552+
stores objects keyed by their class and also implements `ArrayAccess`, so you can use it as a typed
553+
container or as a simple map.
554+
555+
```php
556+
use Jerowork\GraphqlAttributeSchema\Context;
557+
558+
$context = new Context();
559+
560+
// Attach by class
561+
$context->attachObject($request); // stored under Request::class
562+
$request = $context->getObject(Request::class); // throws if missing/wrong type
563+
$request = $context->maybeGetObject(Request::class); // null if missing
564+
565+
// Or as an array (any key)
566+
$context[Request::class] = $request;
567+
$locale = $context['locale'] ?? null;
568+
```
569+
570+
Set it on your server through the webonyx `context` option. Using a callable means a fresh `Context`
571+
is built per request:
572+
573+
```php
574+
use GraphQL\Error\DebugFlag;
575+
use GraphQL\Server\ServerConfig;
576+
use GraphQL\Server\StandardServer;
577+
use Jerowork\GraphqlAttributeSchema\Context;
578+
use Symfony\Component\HttpFoundation\Request;
579+
580+
$config = [
581+
'schema' => $this->createSchema(),
582+
'context' => function () {
583+
$context = new Context();
584+
$context[Request::class] = $this->requestStack->getMainRequest();
585+
586+
return $context;
587+
},
588+
];
589+
590+
if ($this->environment !== EnvironmentName::PROD) {
591+
$config['debugFlag'] = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE | DebugFlag::RETHROW_INTERNAL_EXCEPTIONS;
592+
}
593+
594+
return new StandardServer(ServerConfig::create($config));
595+
```
596+
495597
### #[Scalar]
496598

497599
Webonyx/graphql-php comes with four built-in scalar types:

phpstan-baseline.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
'path' => __DIR__ . '/src/Node/Child/ArgNode.php',
99
];
1010
$ignoreErrors[] = [
11-
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\FieldNode\\:\\:toArray\\(\\) should return array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\|array\\{service\\?\\: string, propertyName\\: string\\}\\}\\>, fieldType\\: string, methodName\\: string\\|null, propertyName\\: string\\|null, deprecationReason\\: string\\|null, \\.\\.\\.\\} but returns array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, fieldType\\: \'method\'\\|\'property\', methodName\\: string\\|null, propertyName\\: string\\|null, deprecationReason\\: string\\|null, \\.\\.\\.\\}\\.$#',
11+
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\FieldNode\\:\\:toArray\\(\\) should return array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{className\\: class\\-string, propertyName\\: string, nullable\\: bool\\}\\|array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\|array\\{service\\?\\: string, propertyName\\: string\\}\\}\\>, fieldType\\: string, methodName\\: string\\|null, propertyName\\: string\\|null, deprecationReason\\: string\\|null, \\.\\.\\.\\} but returns array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, fieldType\\: \'method\'\\|\'property\', methodName\\: string\\|null, propertyName\\: string\\|null, deprecationReason\\: string\\|null, \\.\\.\\.\\}\\.$#',
1212
'identifier' => 'return.type',
1313
'count' => 1,
1414
'path' => __DIR__ . '/src/Node/Child/FieldNode.php',
@@ -20,7 +20,7 @@
2020
'path' => __DIR__ . '/src/Node/Child/FieldNode.php',
2121
];
2222
$ignoreErrors[] = [
23-
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\MutationNode\\:\\:toArray\\(\\) should return array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{propertyName\\: string\\}\\|array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\}\\>, outputReference\\: array\\{type\\: class\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\} but returns array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, outputReference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\}\\.$#',
23+
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\MutationNode\\:\\:toArray\\(\\) should return array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{className\\: class\\-string, propertyName\\: string, nullable\\: bool\\}\\|array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\|array\\{service\\?\\: string, propertyName\\: string\\}\\}\\>, outputReference\\: array\\{type\\: class\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\} but returns array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, outputReference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\}\\.$#',
2424
'identifier' => 'return.type',
2525
'count' => 1,
2626
'path' => __DIR__ . '/src/Node/MutationNode.php',
@@ -32,7 +32,7 @@
3232
'path' => __DIR__ . '/src/Node/MutationNode.php',
3333
];
3434
$ignoreErrors[] = [
35-
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\QueryNode\\:\\:toArray\\(\\) should return array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{propertyName\\: string\\}\\|array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\}\\>, outputReference\\: array\\{type\\: class\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\} but returns array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, outputReference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\}\\.$#',
35+
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\QueryNode\\:\\:toArray\\(\\) should return array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>, payload\\: array\\{className\\: class\\-string, propertyName\\: string, nullable\\: bool\\}\\|array\\{reference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>, payload\\: array\\<string, mixed\\>\\}, name\\: string, description\\: string\\|null, propertyName\\: string\\}\\|array\\{service\\?\\: string, propertyName\\: string\\}\\}\\>, outputReference\\: array\\{type\\: class\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\} but returns array\\{className\\: class\\-string, name\\: string, description\\: string\\|null, argumentNodes\\: list\\<array\\{node\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\Child\\\\ArgumentNode\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}\\>, outputReference\\: array\\{type\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Node\\\\TypeReference\\\\TypeReference\\>&literal\\-string, payload\\: array\\<string, mixed\\>\\}, methodName\\: string, deprecationReason\\: string\\|null, deferredTypeLoader\\: class\\-string\\<Jerowork\\\\GraphqlAttributeSchema\\\\Type\\\\Loader\\\\DeferredTypeLoader\\>\\|null\\}\\.$#',
3636
'identifier' => 'return.type',
3737
'count' => 1,
3838
'path' => __DIR__ . '/src/Node/QueryNode.php',
@@ -97,6 +97,12 @@
9797
'count' => 1,
9898
'path' => __DIR__ . '/src/NodeParser/Child/CursorNodeParser.php',
9999
];
100+
$ignoreErrors[] = [
101+
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\NodeParser\\\\Child\\\\MapContextNodeParser\\:\\:getAttribute\\(\\) has parameter \\$reflector with generic class ReflectionClass but does not specify its types\\: T$#',
102+
'identifier' => 'missingType.generics',
103+
'count' => 1,
104+
'path' => __DIR__ . '/src/NodeParser/Child/MapContextNodeParser.php',
105+
];
100106
$ignoreErrors[] = [
101107
'message' => '#^Method Jerowork\\\\GraphqlAttributeSchema\\\\NodeParser\\\\EnumNodeParser\\:\\:getAttribute\\(\\) has parameter \\$reflector with generic class ReflectionClass but does not specify its types\\: T$#',
102108
'identifier' => 'missingType.generics',

src/Attribute/MapContext.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jerowork\GraphqlAttributeSchema\Attribute;
6+
7+
use Attribute;
8+
9+
/**
10+
* Maps a resolver method parameter to an object stored in the GraphQL Context.
11+
*
12+
* The object is fetched from the Context by the parameter's type. A nullable parameter resolves to
13+
* null when the object is absent; a non-nullable parameter throws when it is absent.
14+
*/
15+
#[Attribute(Attribute::TARGET_PARAMETER)]
16+
final readonly class MapContext {}

src/Context.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jerowork\GraphqlAttributeSchema;
6+
7+
use ArrayAccess;
8+
use ArrayIterator;
9+
use GraphQL\Executor\ScopedContext;
10+
use IteratorAggregate;
11+
use Override;
12+
use Traversable;
13+
14+
/**
15+
* Per-request GraphQL context.
16+
*
17+
* Stores arbitrary values, keyed by class-string for objects (see attachObject/getObject) and by
18+
* any key through the ArrayAccess interface. As a webonyx ScopedContext, child fields receive a
19+
* clone, so values attached by a resolver are visible to its descendants without leaking to siblings.
20+
*
21+
* @implements ArrayAccess<array-key, mixed>
22+
* @implements IteratorAggregate<array-key, mixed>
23+
*/
24+
final class Context implements ArrayAccess, IteratorAggregate, ScopedContext
25+
{
26+
/**
27+
* @param array<array-key, mixed> $store
28+
*/
29+
public function __construct(
30+
private array $store = [],
31+
) {}
32+
33+
public function attachObject(object $object): void
34+
{
35+
$this->store[$object::class] = $object;
36+
}
37+
38+
/**
39+
* @template T of object
40+
*
41+
* @param class-string<T> $fqcn
42+
*
43+
* @throws ContextException
44+
*
45+
* @return T
46+
*/
47+
public function getObject(string $fqcn): object
48+
{
49+
if (!array_key_exists($fqcn, $this->store)) {
50+
throw ContextException::missingObject($fqcn);
51+
}
52+
53+
$object = $this->store[$fqcn];
54+
55+
if (!$object instanceof $fqcn) {
56+
throw ContextException::unexpectedObjectType($fqcn);
57+
}
58+
59+
return $object;
60+
}
61+
62+
/**
63+
* @template T of object
64+
*
65+
* @param class-string<T> $fqcn
66+
*
67+
* @throws ContextException
68+
*
69+
* @return null|T
70+
*/
71+
public function maybeGetObject(string $fqcn): ?object
72+
{
73+
if (!array_key_exists($fqcn, $this->store)) {
74+
return null;
75+
}
76+
77+
$object = $this->store[$fqcn];
78+
79+
if (!$object instanceof $fqcn) {
80+
throw ContextException::unexpectedObjectType($fqcn);
81+
}
82+
83+
return $object;
84+
}
85+
86+
#[Override]
87+
public function offsetExists(mixed $offset): bool
88+
{
89+
return isset($this->store[$offset]);
90+
}
91+
92+
#[Override]
93+
public function offsetGet(mixed $offset): mixed
94+
{
95+
return $this->store[$offset] ?? null;
96+
}
97+
98+
#[Override]
99+
public function offsetSet(mixed $offset, mixed $value): void
100+
{
101+
if ($offset === null) {
102+
$this->store[] = $value;
103+
104+
return;
105+
}
106+
107+
$this->store[$offset] = $value;
108+
}
109+
110+
#[Override]
111+
public function offsetUnset(mixed $offset): void
112+
{
113+
unset($this->store[$offset]);
114+
}
115+
116+
#[Override]
117+
public function getIterator(): Traversable
118+
{
119+
return new ArrayIterator($this->store);
120+
}
121+
122+
#[Override]
123+
public function clone(): self
124+
{
125+
return new self($this->store);
126+
}
127+
}

src/ContextException.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Jerowork\GraphqlAttributeSchema;
6+
7+
use RuntimeException;
8+
9+
final class ContextException extends RuntimeException
10+
{
11+
public static function contextNotAvailable(string $fqcn): self
12+
{
13+
return new self(sprintf(
14+
'Cannot map context parameter of type %s: the GraphQL context value is not an instance of %s. '
15+
. 'Provide a %s as the context value on your GraphQL server.',
16+
$fqcn,
17+
Context::class,
18+
Context::class,
19+
));
20+
}
21+
22+
public static function missingObject(string $fqcn): self
23+
{
24+
return new self(sprintf('No object of type %s found in context', $fqcn));
25+
}
26+
27+
public static function unexpectedObjectType(string $fqcn): self
28+
{
29+
return new self(sprintf('Object in context is not of expected type %s', $fqcn));
30+
}
31+
}

0 commit comments

Comments
 (0)