Completed
Pull Request — master (#1)
by Arthur
02:21
created

DoctrineGuesser::guessAssociation()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 23
rs 8.5906
cc 6
eloc 13
nc 10
nop 3
1
<?php
2
namespace Arthem\GraphQLMapper\Mapping\Guesser;
3
4
use Arthem\GraphQLMapper\Mapping\Context\ContainerContext;
5
use Arthem\GraphQLMapper\Mapping\Context\FieldContext;
6
use Arthem\GraphQLMapper\Mapping\Field;
7
use Arthem\GraphQLMapper\Mapping\Guesser\Guess\Guess;
8
use Arthem\GraphQLMapper\Mapping\Guesser\Guess\TypeGuess;
9
use Arthem\GraphQLMapper\Mapping\SchemaContainer;
10
use Arthem\GraphQLMapper\Mapping\Type;
11
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
12
use Doctrine\Common\Persistence\Mapping\MappingException;
13
use Doctrine\Common\Persistence\ObjectManager;
14
use Doctrine\DBAL\Types\Type as DoctrineType;
15
use Doctrine\ORM\Mapping\ClassMetadataInfo;
16
17
class DoctrineGuesser implements TypeResolveGuesserInterface, FieldResolveGuesserInterface, FieldTypeGuesserInterface
18
{
19
    /**
20
     * @var ClassMetadataFactory
21
     */
22
    private $metadataFactory;
23
24
    /**
25
     * @param ObjectManager $objectManager
26
     */
27
    public function __construct(ObjectManager $objectManager)
28
    {
29
        $this->metadataFactory = $objectManager->getMetadataFactory();
30
    }
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function guessFieldType(FieldContext $fieldContext)
36
    {
37
        if (!$this->isFieldContainerSupported($fieldContext)) {
38
            return;
39
        }
40
41
        /** @var Type $fieldContainer */
42
        $fieldContainer = $fieldContext->getContainer();
43
        $model          = $fieldContainer->getModel();
44
45
        if (null === $metadata = $this->getMetadata($model)) {
46
            return;
47
        }
48
49
        $field = $fieldContext->getField();
50
51
        $property = $field->getProperty() ?: $field->getName();
52
53
        if ($metadata->hasAssociation($property)) {
54
            return $this->guessAssociation($metadata, $field, $fieldContext->getSchema());
55
        }
56
57
        switch ($metadata->getTypeOfField($property)) {
58
            case DoctrineType::TARRAY:
59
            case DoctrineType::JSON_ARRAY:
60
                return $this->wrapRequired($metadata, $property, '[String]', Guess::LOW_CONFIDENCE);
61
            case DoctrineType::BOOLEAN:
62
                return new TypeGuess('Boolean', Guess::HIGH_CONFIDENCE);
63
            case DoctrineType::DATETIME:
64
            case DoctrineType::DATETIMETZ:
65
            case 'vardatetime':
66
            case DoctrineType::DATE:
67
            case DoctrineType::TIME:
68
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
69
            case DoctrineType::DECIMAL:
70
            case DoctrineType::FLOAT:
71
                return $this->wrapRequired($metadata, $property, 'Number', Guess::MEDIUM_CONFIDENCE);
72
            case DoctrineType::INTEGER:
73
            case DoctrineType::BIGINT:
74
            case DoctrineType::SMALLINT:
75
                return $this->wrapRequired($metadata, $property, 'Int', Guess::MEDIUM_CONFIDENCE);
76
            case DoctrineType::STRING:
77
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
78
            case DoctrineType::TEXT:
79
                return $this->wrapRequired($metadata, $property, 'String', Guess::MEDIUM_CONFIDENCE);
80
            default:
81
                return $this->wrapRequired($metadata, $property, 'String', Guess::LOW_CONFIDENCE);
82
        }
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 View Code Duplication
    public function guessFieldResolveConfig(FieldContext $fieldContext)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
    {
90
        if (!$this->isFieldContainerSupported($fieldContext)) {
91
            return;
92
        }
93
94
        /** @var Type $type */
95
        $type = $fieldContext->getContainer();
96
97
        return new ResolveConfigGuess([
98
            'handler' => 'doctrine',
99
            'entity'  => $type->getModel(),
100
        ]);
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106 View Code Duplication
    public function guessTypeResolveConfig(ContainerContext $containerContext)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
    {
108
        if (!$this->isFieldContainerSupported($containerContext)) {
109
            return;
110
        }
111
112
        /** @var Type $type */
113
        $type = $containerContext->getContainer();
114
115
        return new ResolveConfigGuess([
116
            'handler' => 'doctrine',
117
            'entity'  => $type->getModel(),
118
        ]);
119
    }
120
121
    /**
122
     * @param ClassMetadataInfo $metadata
123
     * @param string            $property
124
     * @param string            $type
125
     * @param int               $confidence
126
     * @return TypeGuess
127
     */
128
    private function wrapRequired(ClassMetadataInfo $metadata, $property, $type, $confidence)
129
    {
130
        if (!$metadata->isNullable($property)) {
131
            $type .= '!';
132
        }
133
134
        return new TypeGuess($type, $confidence);
135
    }
136
137
    /**
138
     * @param ClassMetadataInfo $metadata
139
     * @param Field             $field
140
     * @param SchemaContainer   $schemaContainer
141
     * @return TypeGuess
142
     * @throws MappingException
143
     */
144
    private function guessAssociation(ClassMetadataInfo $metadata, Field $field, SchemaContainer $schemaContainer)
145
    {
146
        $property = $field->getProperty() ?: $field->getName();
147
        $multiple = $metadata->isCollectionValuedAssociation($property);
148
        $mapping  = $metadata->getAssociationMapping($property);
149
150
        foreach ($schemaContainer->getTypes() as $type) {
151
            $containerContext = new ContainerContext($type, $schemaContainer);
152
153
            if (!$this->isFieldContainerSupported($containerContext)) {
154
                continue;
155
            }
156
157
            if ($type->getModel() === $mapping['targetEntity']) {
158
                $typeName = $type->getName();
159
                if ($multiple) {
160
                    $typeName = sprintf('[%s]', $typeName);
161
                }
162
163
                return new TypeGuess($typeName, Guess::HIGH_CONFIDENCE);
164
            }
165
        }
166
    }
167
168
    /**
169
     * @param ContainerContext $containerContext
170
     * @return bool
171
     */
172
    private function isFieldContainerSupported(ContainerContext $containerContext)
173
    {
174
        $fieldContainer = $containerContext->getContainer();
175
        if (!$fieldContainer instanceof Type) {
176
            return false;
177
        }
178
179
        return !empty($fieldContainer->getModel());
180
    }
181
182
    /**
183
     * @param string $class
184
     * @return ClassMetadataInfo
185
     */
186
    protected function getMetadata($class)
187
    {
188
        try {
189
            return $this->metadataFactory->getMetadataFor($class);
190
        } catch (MappingException $e) {
0 ignored issues
show
Bug introduced by
The class Doctrine\Common\Persiste...apping\MappingException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
191
            // not an entity or mapped super class
192
        }
193
    }
194
}
195