Passed
Pull Request — master (#64)
by Mark
24:35 queued 11:56
created

AbstractFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 0
c 1
b 0
f 0
dl 0
loc 2
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Doctrine\Factory;
6
7
use Doctrine\Bundle\DoctrineBundle\Mapping\MappingDriver;
8
use Doctrine\Common\Annotations\Reader;
9
use Doctrine\ORM\EntityManager;
10
use Doctrine\Persistence\Mapping\Driver\AnnotationDriver;
11
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
12
use GraphQL\Doctrine\Annotation\Exclude;
13
use GraphQL\Doctrine\Exception;
14
use GraphQL\Doctrine\Factory\MetadataReader\MappingDriverChainAdapter;
1 ignored issue
show
Bug introduced by
The type GraphQL\Doctrine\Factory...ppingDriverChainAdapter was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use GraphQL\Doctrine\Types;
16
use GraphQL\Type\Definition\Type;
17
use ReflectionClass;
18
use ReflectionProperty;
19
20
/**
21
 * Abstract factory to be aware of types and entityManager.
22
 */
23
abstract class AbstractFactory
24
{
25
    public function __construct(protected Types $types, protected EntityManager $entityManager)
26
    {
27
    }
28
29
    /**
30
     * Get annotation reader.
31
     */
32 46
    final protected function getAnnotationReader(): Reader
33
    {
34 46
        $driver = $this->entityManager->getConfiguration()->getMetadataDriverImpl();
35
36
        // if the doctrine-bundle wraps the driver, unwrap it first
37 46
        if ($driver instanceof MappingDriver) {
38
            $driver = $driver->getDriver();
39
        }
40
41 46
        if ($driver instanceof AnnotationDriver) {
42 42
            return $driver->getReader();
43
        }
44
45 4
        if ($driver instanceof MappingDriverChain) {
46 3
            return new MappingDriverChainAdapter($driver);
47
        }
48
49 1
        throw new Exception('graphql-doctrine requires Doctrine to be configured with a `' . AnnotationDriver::class . '`.');
50
    }
51
52
    /**
53
     * Returns whether the property is excluded.
54
     */
55 17
    final protected function isPropertyExcluded(ReflectionProperty $property): bool
56
    {
57 17
        $exclude = $this->getAnnotationReader()->getPropertyAnnotation($property, Exclude::class);
58
59 17
        return $exclude !== null;
60
    }
61
62
    /**
63
     * Get instance of GraphQL type from a PHP class name.
64
     *
65
     * Supported syntaxes are the following:
66
     *
67
     *  - `?MyType`
68
     *  - `null|MyType`
69
     *  - `MyType|null`
70
     *  - `MyType[]`
71
     *  - `?MyType[]`
72
     *  - `null|MyType[]`
73
     *  - `MyType[]|null`
74
     */
75 32
    final protected function getTypeFromPhpDeclaration(ReflectionClass $class, ?string $typeDeclaration, bool $isEntityId = false): ?Type
76
    {
77 32
        if (!$typeDeclaration) {
78 21
            return null;
79
        }
80
81 26
        $isNullable = 0;
82 26
        $name = preg_replace('~(^\?|^null\||\|null$)~', '', $typeDeclaration, -1, $isNullable);
83
84 26
        $isList = 0;
85 26
        $name = preg_replace('~^(.*)\[\]$~', '$1', $name, -1, $isList);
86 26
        $name = $this->adjustNamespace($class, $name);
87 26
        $type = $this->getTypeFromRegistry($name, $isEntityId);
88
89 26
        if ($isList) {
90 6
            $type = Type::listOf(Type::nonNull($type));
91
        }
92
93 26
        if (!$isNullable) {
94 15
            $type = Type::nonNull($type);
95
        }
96
97 26
        return $type;
98
    }
99
100
    /**
101
     * Prepend namespace of the method if the class actually exists.
102
     */
103 26
    private function adjustNamespace(ReflectionClass $class, string $type): string
104
    {
105 26
        if ($type === 'self') {
106 2
            $type = $class->getName();
107
        }
108
109 26
        $namespace = $class->getNamespaceName();
110 26
        if ($namespace) {
111 26
            $namespacedType = $namespace . '\\' . $type;
112
113 26
            if (class_exists($namespacedType)) {
114 2
                return $namespacedType;
115
            }
116
        }
117
118 26
        return $type;
119
    }
120
121
    /**
122
     * Returns a type from our registry.
123
     */
124 27
    final protected function getTypeFromRegistry(string $type, bool $isEntityId): Type
125
    {
126 27
        if ($this->types->isEntity($type) && $isEntityId) {
127
            // @phpstan-ignore-next-line
128 7
            return $this->types->getId($type);
129
        }
130
131 27
        if ($this->types->isEntity($type) && !$isEntityId) {
132
            // @phpstan-ignore-next-line
133 9
            return $this->types->getOutput($type);
134
        }
135
136 25
        return $this->types->get($type);
137
    }
138
}
139