Passed
Pull Request — master (#40)
by David
01:43
created

GlobControllerQueryProvider   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
eloc 37
dl 0
loc 107
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A getAggregateControllerQueryProvider() 0 6 2
A getInstancesList() 0 11 3
A getQueries() 0 3 1
A getMutations() 0 3 1
A buildInstancesList() 0 18 5
1
<?php
2
3
4
namespace TheCodingMachine\GraphQL\Controllers;
5
6
use Doctrine\Common\Annotations\Reader;
7
use GraphQL\Type\Definition\InputType;
8
use GraphQL\Type\Definition\OutputType;
9
use Mouf\Composer\ClassNameMapper;
10
use Psr\Container\ContainerInterface;
11
use Psr\SimpleCache\CacheInterface;
12
use TheCodingMachine\ClassExplorer\Glob\GlobClassExplorer;
13
use TheCodingMachine\GraphQL\Controllers\AggregateControllerQueryProvider;
14
use TheCodingMachine\GraphQL\Controllers\Annotations\Type;
15
use TheCodingMachine\GraphQL\Controllers\AnnotationUtils;
16
use TheCodingMachine\GraphQL\Controllers\QueryField;
17
use TheCodingMachine\GraphQL\Controllers\QueryProviderInterface;
18
use TheCodingMachine\GraphQL\Controllers\Registry\RegistryInterface;
19
use TheCodingMachine\GraphQL\Controllers\TypeGenerator;
20
21
/**
22
 * Scans all the classes in a given namespace of the main project (not the vendor directory).
23
 * Analyzes all classes and detects "Query" and "Mutation" annotations.
24
 *
25
 * Assumes that the container contains a class whose identifier is the same as the class name.
26
 */
27
final class GlobControllerQueryProvider implements QueryProviderInterface
28
{
29
    /**
30
     * @var string
31
     */
32
    private $namespace;
33
    /**
34
     * @var CacheInterface
35
     */
36
    private $cache;
37
    /**
38
     * @var int|null
39
     */
40
    private $cacheTtl;
41
    /**
42
     * @var array<string,string>|null
43
     */
44
    private $instancesList;
45
    /**
46
     * @var ContainerInterface
47
     */
48
    private $container;
49
    /**
50
     * @var AggregateControllerQueryProvider
51
     */
52
    private $aggregateControllerQueryProvider;
53
    /**
54
     * @var RegistryInterface
55
     */
56
    private $registry;
57
58
    /**
59
     * @param string $namespace The namespace that contains the GraphQL types (they must have a `@Type` annotation)
60
     * @param ContainerInterface|null $container The container we will fetch controllers from. If not specified, container from the registry is used instead.
61
     */
62
    public function __construct(string $namespace, RegistryInterface $registry, ?ContainerInterface $container, CacheInterface $cache, ?int $cacheTtl = null)
63
    {
64
        $this->namespace = $namespace;
65
        $this->registry = $registry;
66
        $this->container = $container ?: $registry;
67
        $this->cache = $cache;
68
        $this->cacheTtl = $cacheTtl;
69
    }
70
71
    private function getAggregateControllerQueryProvider(): AggregateControllerQueryProvider
72
    {
73
        if ($this->aggregateControllerQueryProvider === null) {
74
            $this->aggregateControllerQueryProvider = new AggregateControllerQueryProvider($this->getInstancesList(), $this->registry, $this->container);
75
        }
76
        return $this->aggregateControllerQueryProvider;
77
    }
78
79
    /**
80
     * Returns an array of fully qualified class names.
81
     *
82
     * @return string[]
83
     */
84
    private function getInstancesList(): array
85
    {
86
        if ($this->instancesList === null) {
87
            $key = 'globQueryProvider_'.str_replace('\\', '_', $this->namespace);
88
            $this->instancesList = $this->cache->get($key);
89
            if ($this->instancesList === null) {
90
                $this->instancesList = $this->buildInstancesList();
91
                $this->cache->set($key, $this->instancesList, $this->cacheTtl);
92
            }
93
        }
94
        return $this->instancesList;
95
    }
96
97
    /**
98
     * @return string[]
99
     */
100
    private function buildInstancesList(): array
101
    {
102
        $explorer = new GlobClassExplorer($this->namespace, $this->cache, $this->cacheTtl, ClassNameMapper::createFromComposerFile(null, null, true));
103
        $classes = $explorer->getClasses();
104
        $instances = [];
105
        foreach ($classes as $className) {
106
            if (!\class_exists($className)) {
107
                continue;
108
            }
109
            $refClass = new \ReflectionClass($className);
110
            if (!$refClass->isInstantiable()) {
111
                continue;
112
            }
113
            if ($this->container->has($className)) {
114
                $instances[] = $className;
115
            }
116
        }
117
        return $instances;
118
    }
119
120
    /**
121
     * @return QueryField[]
122
     */
123
    public function getQueries(): array
124
    {
125
        return $this->getAggregateControllerQueryProvider()->getQueries();
126
    }
127
128
    /**
129
     * @return QueryField[]
130
     */
131
    public function getMutations(): array
132
    {
133
        return $this->getAggregateControllerQueryProvider()->getMutations();
134
    }
135
}
136