FieldResolver::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApiSkeletons\Doctrine\ORM\GraphQL\Resolve;
6
7
use ApiSkeletons\Doctrine\ORM\GraphQL\Config;
8
use ApiSkeletons\Doctrine\ORM\GraphQL\Type\Entity\EntityTypeContainer;
9
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
10
use Doctrine\Persistence\Proxy;
11
use GraphQL\Error\Error;
12
use GraphQL\Type\Definition\ResolveInfo;
13
14
use function assert;
15
use function is_object;
16
use function spl_object_hash;
17
18
/**
19
 * A field resolver that uses the Doctrine Laminas hydrator to extract values
20
 */
21
class FieldResolver
22
{
23
    /**
24
     * Cache all hydrator extract operations based on spl object hash
25
     *
26
     * @var mixed[]
27
     */
28
    private array $extractValues = [];
29
30
    public function __construct(
31
        protected readonly Config $config,
32
        protected readonly EntityTypeContainer $entityTypeContainer,
33
    ) {
34
    }
35
36
    /** @throws Error */
37
    public function __invoke(mixed $source, mixed $args, mixed $context, ResolveInfo $info): mixed
38
    {
39
        assert(is_object($source), 'A non-object was passed to the FieldResolver.  '
40
            . 'Verify you\'re wrapping your Doctrine GraphQL type() call in a connection.');
41
42
        // Proxy objects cannot hydrate by reference without loading
43
        if ($source instanceof Proxy) {
44
            $source->__load();
45
        }
46
47
        $defaultProxyClassNameResolver = new DefaultProxyClassNameResolver();
48
49
        $entityClass   = $defaultProxyClassNameResolver->getClass($source);
50
        $splObjectHash = spl_object_hash($source);
51
52
        /**
53
         * For disabled hydrator cache, store only the last hydrator result and reuse for consecutive calls
54
         * then drop the cache if it doesn't hit.
55
         */
56
        if (! $this->config->getUseHydratorCache()) {
57
            if (isset($this->extractValues[$splObjectHash])) {
58
                return $this->extractValues[$splObjectHash][$info->fieldName] ?? null;
59
            }
60
61
            $this->extractValues = [];
62
63
            $this->extractValues[$splObjectHash] = $this->entityTypeContainer
64
                ->get($entityClass)
65
                    ->getHydrator()->extract($source);
66
67
            return $this->extractValues[$splObjectHash][$info->fieldName] ?? null;
68
        }
69
70
        // Use full hydrator cache
71
        if (isset($this->extractValues[$splObjectHash][$info->fieldName])) {
72
            return $this->extractValues[$splObjectHash][$info->fieldName] ?? null;
73
        }
74
75
        $this->extractValues[$splObjectHash] = $this->entityTypeContainer
76
            ->get($entityClass)
77
            ->getHydrator()->extract($source);
78
79
        return $this->extractValues[$splObjectHash][$info->fieldName] ?? null;
80
    }
81
}
82