140 lines
3.8 KiB
PHP
140 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace Nuwave\Lighthouse\Execution\DataLoader;
|
|
|
|
use GraphQL\Deferred;
|
|
|
|
/**
|
|
* @deprecated implement your own batch loader instead.
|
|
* @see \Nuwave\Lighthouse\Execution\BatchLoader\BatchLoaderRegistry to resolve instances.
|
|
*/
|
|
abstract class BatchLoader
|
|
{
|
|
/**
|
|
* Active BatchLoader instances.
|
|
*
|
|
* @var array<string, static>
|
|
*/
|
|
protected static $instances = [];
|
|
|
|
/**
|
|
* Map from keys to metainfo for resolving.
|
|
*
|
|
* @var array<mixed, array<mixed>>
|
|
*/
|
|
protected $keys = [];
|
|
|
|
/**
|
|
* Map from keys to resolved values.
|
|
*
|
|
* @var array<mixed, mixed>
|
|
*/
|
|
protected $results = [];
|
|
|
|
/**
|
|
* Check if data has been loaded.
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $hasLoaded = false;
|
|
|
|
/**
|
|
* Return an instance of a BatchLoader for a specific field.
|
|
*
|
|
* @param string $loaderClass The class name of the concrete BatchLoader to instantiate
|
|
* @param array<int|string> $pathToField Path to the GraphQL field from the root, is used as a key for BatchLoader instances
|
|
* @param array<mixed> $constructorArgs Those arguments are passed to the constructor of the new BatchLoader instance
|
|
* @return static
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public static function instance(string $loaderClass, array $pathToField, array $constructorArgs = []): self
|
|
{
|
|
// The path to the field serves as the unique key for the instance
|
|
$instanceName = static::instanceKey($pathToField);
|
|
|
|
if (isset(self::$instances[$instanceName])) {
|
|
return self::$instances[$instanceName];
|
|
}
|
|
|
|
return self::$instances[$instanceName] = app()->makeWith($loaderClass, $constructorArgs);
|
|
}
|
|
|
|
/**
|
|
* Generate a unique key for the instance, using the path in the query.
|
|
*
|
|
* @param array<int|string> $path
|
|
*/
|
|
public static function instanceKey(array $path): string
|
|
{
|
|
$significantPathSegments = array_filter(
|
|
$path,
|
|
function ($path): bool {
|
|
// Ignore numeric path entries, as those signify a list of fields.
|
|
// Combining the queries for those is the very purpose of the
|
|
// batch loader, so they must not be included.
|
|
return ! is_numeric($path);
|
|
}
|
|
);
|
|
$pathIgnoringLists = implode('.', $significantPathSegments);
|
|
|
|
return 'nuwave/lighthouse/batchloader/'.$pathIgnoringLists;
|
|
}
|
|
|
|
/**
|
|
* Remove all stored BatchLoaders.
|
|
*
|
|
* This is called after Lighthouse has resolved a query, so multiple
|
|
* queries can be handled in a single request/session.
|
|
*/
|
|
public static function forgetInstances(): void
|
|
{
|
|
self::$instances = [];
|
|
}
|
|
|
|
/**
|
|
* Schedule a result to be loaded.
|
|
*
|
|
* @param array<mixed> $metaInfo
|
|
*/
|
|
public function load(string $key, array $metaInfo = []): Deferred
|
|
{
|
|
$this->keys[$key] = $metaInfo;
|
|
|
|
return new Deferred(function () use ($key) {
|
|
if (! $this->hasLoaded) {
|
|
$this->results = $this->resolve();
|
|
$this->hasLoaded = true;
|
|
}
|
|
|
|
return $this->results[$key];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Schedule multiple results to be loaded.
|
|
*
|
|
* @param array<mixed> $keys
|
|
* @param array<mixed> $metaInfo
|
|
* @return array<\GraphQL\Deferred>
|
|
*/
|
|
public function loadMany(array $keys, array $metaInfo = []): array
|
|
{
|
|
return array_map(
|
|
function ($key) use ($metaInfo): Deferred {
|
|
return $this->load($key, $metaInfo);
|
|
},
|
|
$keys
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Resolve the keys.
|
|
*
|
|
* The result has to be a map from keys to resolved values.
|
|
*
|
|
* @return array<mixed, mixed>
|
|
*/
|
|
abstract public function resolve(): array;
|
|
}
|