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

DoctrineGuesser   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 178
Duplicated Lines 15.73 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 37
c 1
b 0
f 0
lcom 1
cbo 7
dl 28
loc 178
rs 8.6

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C guessFieldType() 0 49 20
A guessFieldResolveConfig() 14 14 2
A guessTypeResolveConfig() 14 14 2
A wrapRequired() 0 8 2
B guessAssociation() 0 23 6
A isFieldContainerSupported() 0 9 2
A getMetadata() 0 8 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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