Promise
2 months ago
ExecutionContext.php
2 months ago
ExecutionResult.php
2 months ago
Executor.php
2 months ago
ExecutorImplementation.php
2 months ago
PromiseExecutor.php
2 months ago
ReferenceExecutor.php
2 months ago
ScopedContext.php
2 months ago
Values.php
2 months ago
Executor.php
220 lines
| 1 | <?php declare(strict_types=1); |
| 2 | |
| 3 | namespace Automattic\WooCommerce\Vendor\GraphQL\Executor; |
| 4 | |
| 5 | use Automattic\WooCommerce\Vendor\GraphQL\Error\InvariantViolation; |
| 6 | use Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter; |
| 7 | use Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\Promise; |
| 8 | use Automattic\WooCommerce\Vendor\GraphQL\Executor\Promise\PromiseAdapter; |
| 9 | use Automattic\WooCommerce\Vendor\GraphQL\Language\AST\DocumentNode; |
| 10 | use Automattic\WooCommerce\Vendor\GraphQL\Language\AST\FieldNode; |
| 11 | use Automattic\WooCommerce\Vendor\GraphQL\Type\Definition\FieldDefinition; |
| 12 | use Automattic\WooCommerce\Vendor\GraphQL\Type\Definition\ResolveInfo; |
| 13 | use Automattic\WooCommerce\Vendor\GraphQL\Type\Schema; |
| 14 | use Automattic\WooCommerce\Vendor\GraphQL\Utils\Utils; |
| 15 | |
| 16 | /** |
| 17 | * Implements the "Evaluating requests" section of the Automattic\WooCommerce\Vendor\GraphQL specification. |
| 18 | * |
| 19 | * @phpstan-type ArgsMapper callable(array<string, mixed>, FieldDefinition, FieldNode, mixed): mixed |
| 20 | * @phpstan-type FieldResolver callable(mixed, array<string, mixed>, mixed, ResolveInfo): mixed |
| 21 | * @phpstan-type ImplementationFactory callable(PromiseAdapter, Schema, DocumentNode, mixed, mixed, array<mixed>, ?string, callable, callable): ExecutorImplementation |
| 22 | * |
| 23 | * @see \Automattic\WooCommerce\Vendor\GraphQL\Tests\Executor\ExecutorTest |
| 24 | */ |
| 25 | class Executor |
| 26 | { |
| 27 | /** |
| 28 | * @var callable |
| 29 | * |
| 30 | * @phpstan-var FieldResolver |
| 31 | */ |
| 32 | private static $defaultFieldResolver = [self::class, 'defaultFieldResolver']; |
| 33 | |
| 34 | /** |
| 35 | * @var callable |
| 36 | * |
| 37 | * @phpstan-var ArgsMapper |
| 38 | */ |
| 39 | private static $defaultArgsMapper = [self::class, 'defaultArgsMapper']; |
| 40 | |
| 41 | private static ?PromiseAdapter $defaultPromiseAdapter; |
| 42 | |
| 43 | /** |
| 44 | * @var callable |
| 45 | * |
| 46 | * @phpstan-var ImplementationFactory |
| 47 | */ |
| 48 | private static $implementationFactory = [ReferenceExecutor::class, 'create']; |
| 49 | |
| 50 | /** @phpstan-return FieldResolver */ |
| 51 | public static function getDefaultFieldResolver(): callable |
| 52 | { |
| 53 | return self::$defaultFieldResolver; |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Set a custom default resolve function. |
| 58 | * |
| 59 | * @phpstan-param FieldResolver $fieldResolver |
| 60 | */ |
| 61 | public static function setDefaultFieldResolver(callable $fieldResolver): void |
| 62 | { |
| 63 | self::$defaultFieldResolver = $fieldResolver; |
| 64 | } |
| 65 | |
| 66 | /** @phpstan-return ArgsMapper */ |
| 67 | public static function getDefaultArgsMapper(): callable |
| 68 | { |
| 69 | return self::$defaultArgsMapper; |
| 70 | } |
| 71 | |
| 72 | /** @phpstan-param ArgsMapper $argsMapper */ |
| 73 | public static function setDefaultArgsMapper(callable $argsMapper): void |
| 74 | { |
| 75 | self::$defaultArgsMapper = $argsMapper; |
| 76 | } |
| 77 | |
| 78 | public static function getDefaultPromiseAdapter(): PromiseAdapter |
| 79 | { |
| 80 | return self::$defaultPromiseAdapter ??= new SyncPromiseAdapter(); |
| 81 | } |
| 82 | |
| 83 | /** Set a custom default promise adapter. */ |
| 84 | public static function setDefaultPromiseAdapter(?PromiseAdapter $defaultPromiseAdapter = null): void |
| 85 | { |
| 86 | self::$defaultPromiseAdapter = $defaultPromiseAdapter; |
| 87 | } |
| 88 | |
| 89 | /** @phpstan-return ImplementationFactory */ |
| 90 | public static function getImplementationFactory(): callable |
| 91 | { |
| 92 | return self::$implementationFactory; |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Set a custom executor implementation factory. |
| 97 | * |
| 98 | * @phpstan-param ImplementationFactory $implementationFactory |
| 99 | */ |
| 100 | public static function setImplementationFactory(callable $implementationFactory): void |
| 101 | { |
| 102 | self::$implementationFactory = $implementationFactory; |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * Executes DocumentNode against given $schema. |
| 107 | * |
| 108 | * Always returns ExecutionResult and never throws. |
| 109 | * All errors which occur during operation execution are collected in `$result->errors`. |
| 110 | * |
| 111 | * @param mixed $rootValue |
| 112 | * @param mixed $contextValue |
| 113 | * @param array<string, mixed>|null $variableValues |
| 114 | * |
| 115 | * @phpstan-param FieldResolver|null $fieldResolver |
| 116 | * |
| 117 | * @api |
| 118 | * |
| 119 | * @throws InvariantViolation |
| 120 | */ |
| 121 | public static function execute( |
| 122 | Schema $schema, |
| 123 | DocumentNode $documentNode, |
| 124 | $rootValue = null, |
| 125 | $contextValue = null, |
| 126 | ?array $variableValues = null, |
| 127 | ?string $operationName = null, |
| 128 | ?callable $fieldResolver = null |
| 129 | ): ExecutionResult { |
| 130 | $promiseAdapter = new SyncPromiseAdapter(); |
| 131 | |
| 132 | $result = static::promiseToExecute( |
| 133 | $promiseAdapter, |
| 134 | $schema, |
| 135 | $documentNode, |
| 136 | $rootValue, |
| 137 | $contextValue, |
| 138 | $variableValues, |
| 139 | $operationName, |
| 140 | $fieldResolver |
| 141 | ); |
| 142 | |
| 143 | return $promiseAdapter->wait($result); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Same as execute(), but requires promise adapter and returns a promise which is always |
| 148 | * fulfilled with an instance of ExecutionResult and never rejected. |
| 149 | * |
| 150 | * Useful for async PHP platforms. |
| 151 | * |
| 152 | * @param mixed $rootValue |
| 153 | * @param mixed $contextValue |
| 154 | * @param array<string, mixed>|null $variableValues |
| 155 | * |
| 156 | * @phpstan-param FieldResolver|null $fieldResolver |
| 157 | * @phpstan-param ArgsMapper|null $argsMapper |
| 158 | * |
| 159 | * @api |
| 160 | */ |
| 161 | public static function promiseToExecute( |
| 162 | PromiseAdapter $promiseAdapter, |
| 163 | Schema $schema, |
| 164 | DocumentNode $documentNode, |
| 165 | $rootValue = null, |
| 166 | $contextValue = null, |
| 167 | ?array $variableValues = null, |
| 168 | ?string $operationName = null, |
| 169 | ?callable $fieldResolver = null, |
| 170 | ?callable $argsMapper = null |
| 171 | ): Promise { |
| 172 | $executor = (self::$implementationFactory)( |
| 173 | $promiseAdapter, |
| 174 | $schema, |
| 175 | $documentNode, |
| 176 | $rootValue, |
| 177 | $contextValue, |
| 178 | $variableValues ?? [], |
| 179 | $operationName, |
| 180 | $fieldResolver ?? self::$defaultFieldResolver, |
| 181 | $argsMapper ?? self::$defaultArgsMapper, |
| 182 | ); |
| 183 | |
| 184 | return $executor->doExecute(); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * If a resolve function is not given, then a default resolve behavior is used |
| 189 | * which takes the property of the root value of the same name as the field |
| 190 | * and returns it as the result, or if it's a function, returns the result |
| 191 | * of calling that function while passing along args and context. |
| 192 | * |
| 193 | * @param mixed $objectLikeValue |
| 194 | * @param array<string, mixed> $args |
| 195 | * @param mixed $contextValue |
| 196 | * |
| 197 | * @return mixed |
| 198 | */ |
| 199 | public static function defaultFieldResolver($objectLikeValue, array $args, $contextValue, ResolveInfo $info) |
| 200 | { |
| 201 | $property = Utils::extractKey($objectLikeValue, $info->fieldName); |
| 202 | |
| 203 | return $property instanceof \Closure |
| 204 | ? $property($objectLikeValue, $args, $contextValue, $info) |
| 205 | : $property; |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * @template T of array<string, mixed> |
| 210 | * |
| 211 | * @param T $args |
| 212 | * |
| 213 | * @return T |
| 214 | */ |
| 215 | public static function defaultArgsMapper(array $args): array |
| 216 | { |
| 217 | return $args; |
| 218 | } |
| 219 | } |
| 220 |