GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#69)
by joseph
14:54
created

UsesPHPMetaDataTrait   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Test Coverage

Coverage 87.1%

Importance

Changes 0
Metric Value
wmc 41
eloc 122
dl 0
loc 357
rs 9.1199
c 0
b 0
f 0
ccs 108
cts 124
cp 0.871

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A setChangeTrackingPolicy() 0 3 1
A loadClassDoctrineMetaData() 0 5 1
A loadPropertyDoctrineMetaData() 0 21 4
A __toString() 0 3 1
A getSetters() 0 25 6
A getPlural() 0 11 3
A runInitMethods() 0 14 6
A getGetters() 0 27 5
A getShortName() 0 3 1
A getSingular() 0 27 4
A getIdField() 0 3 1
A loadMetadata() 0 13 2
A getStaticMethods() 0 28 5

How to fix   Complexity   

Complex Class

Complex classes like UsesPHPMetaDataTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UsesPHPMetaDataTrait, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\Entity\Traits;
4
5
use Doctrine\Common\Util\Debug;
6
use Doctrine\Common\Util\Inflector;
7
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
8
use Doctrine\ORM\Mapping\ClassMetadata as DoctrineClassMetaData;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator;
10
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\UsesPHPMetaDataInterface;
11
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
12
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
13
14
trait UsesPHPMetaDataTrait
15
{
16
17
    /**
18
     * @var \ts\Reflection\ReflectionClass
19
     */
20
    private static $reflectionClass;
21
22
    /**
23
     * @var string
24
     */
25
    private static $singular;
26
27
    /**
28
     * @var string
29
     */
30
    private static $plural;
31
32
    /**
33
     * @var array
34
     */
35
    private static $setters;
36
37
    /**
38
     * @var array
39
     */
40
    private static $getters;
41
42
43
    /**
44
     * UsesPHPMetaDataTrait constructor.
45
     *
46
     * @throws \ReflectionException
47
     */
48 1
    public function __construct()
49
    {
50 1
        $this->runInitMethods();
51 1
    }
52
53
    /**
54
     * Find and run all init methods
55
     * - defined in relationship traits and generally to init ArrayCollection properties
56
     *
57
     * @throws \ReflectionException
58
     */
59 56
    protected function runInitMethods(): void
60
    {
61 56
        if (!static::$reflectionClass instanceof \ReflectionClass) {
0 ignored issues
show
Bug introduced by
Since $reflectionClass is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $reflectionClass to at least protected.
Loading history...
introduced by
static::reflectionClass is never a sub-type of ReflectionClass. If static::reflectionClass can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:18.
Loading history...
62 29
            static::$reflectionClass = new \ts\Reflection\ReflectionClass(static::class);
63
        }
64 56
        $methods = static::$reflectionClass->getMethods(\ReflectionMethod::IS_PRIVATE);
65 56
        foreach ($methods as $method) {
66 56
            if ($method instanceof \ReflectionMethod) {
67 56
                $method = $method->getName();
68
            }
69 56
            if (\ts\stringContains($method, UsesPHPMetaDataInterface::METHOD_PREFIX_INIT)
70 56
                && \ts\stringStartsWith($method, UsesPHPMetaDataInterface::METHOD_PREFIX_INIT)
71
            ) {
72 56
                $this->$method();
73
            }
74
        }
75 56
    }
76
77
    /**
78
     * Loads the class and property meta data in the class
79
     *
80
     * This is the method called by Doctrine to load the meta data
81
     *
82
     * @param DoctrineClassMetaData $metadata
83
     *
84
     * @throws DoctrineStaticMetaException
85
     * @SuppressWarnings(PHPMD.StaticAccess)
86
     */
87 47
    public static function loadMetadata(DoctrineClassMetaData $metadata): void
88
    {
89
        try {
90 47
            $builder                 = new ClassMetadataBuilder($metadata);
91 47
            static::$reflectionClass = $metadata->getReflectionClass();
0 ignored issues
show
Bug introduced by
Since $reflectionClass is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $reflectionClass to at least protected.
Loading history...
Documentation Bug introduced by
It seems like $metadata->getReflectionClass() of type ReflectionClass is incompatible with the declared type ts\Reflection\ReflectionClass of property $reflectionClass.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
92 47
            static::loadPropertyDoctrineMetaData($builder);
93 47
            static::loadClassDoctrineMetaData($builder);
94 47
            static::setChangeTrackingPolicy($builder);
95
        } catch (\Exception $e) {
96
            throw new DoctrineStaticMetaException(
97
                'Exception in '.__METHOD__.': '.$e->getMessage(),
98
                $e->getCode(),
99
                $e
100
            );
101
        }
102 47
    }
103
104
    /**
105
     * Setting the change policy to be Notify - best performance
106
     *
107
     * @see http://doctrine-orm.readthedocs.io/en/latest/reference/change-tracking-policies.html
108
     *
109
     * @param ClassMetadataBuilder $builder
110
     */
111 47
    public static function setChangeTrackingPolicy(ClassMetadataBuilder $builder): void
112
    {
113 47
        $builder->setChangeTrackingPolicyNotify();
114 47
    }
115
116
    /**
117
     * This method will reflect on the entity class and pull out all the methods that begin with
118
     * UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META
119
     *
120
     * Once it has an array of methods, it calls them all, passing in the $builder
121
     *
122
     * @param ClassMetadataBuilder $builder
123
     *
124
     * @throws DoctrineStaticMetaException
125
     * @SuppressWarnings(PHPMD.StaticAccess)
126
     */
127 47
    protected static function loadPropertyDoctrineMetaData(ClassMetadataBuilder $builder): void
128
    {
129 47
        $methodName = '__no_method__';
130
        try {
131 47
            $staticMethods = static::getStaticMethods();
132
            //now loop through and call them
133 47
            foreach ($staticMethods as $method) {
134 47
                $methodName = $method->getName();
135 47
                if (0 === stripos(
136 47
                    $methodName,
137 47
                    UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META
138
                )
139
                ) {
140 47
                    static::$methodName($builder);
141
                }
142
            }
143
        } catch (\Exception $e) {
144
            throw new DoctrineStaticMetaException(
145
                'Exception in '.__METHOD__.'for '
146
                .static::$reflectionClass->getName()."::$methodName\n\n"
0 ignored issues
show
Bug introduced by
Since $reflectionClass is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $reflectionClass to at least protected.
Loading history...
147
                .$e->getMessage()
148
            );
149
        }
150 47
    }
151
152
    /**
153
     * Get class level meta data, eg table name, custom repository
154
     *
155
     * @param ClassMetadataBuilder $builder
156
     *
157
     * @SuppressWarnings(PHPMD.StaticAccess)
158
     */
159 47
    protected static function loadClassDoctrineMetaData(ClassMetadataBuilder $builder): void
160
    {
161 47
        $tableName = MappingHelper::getTableNameForEntityFqn(static::class);
162 47
        $builder->setTable($tableName);
163 47
        static::setCustomRepositoryClass($builder);
164 47
    }
165
166
    /**
167
     * In the class itself, we need to specify the repository class name
168
     *
169
     * @param ClassMetadataBuilder $builder
170
     *
171
     * @return mixed
172
     */
173
    abstract protected static function setCustomRepositoryClass(ClassMetadataBuilder $builder);
174
175
    /**
176
     * Get an array of all static methods implemented by the current class
177
     *
178
     * Merges trait methods
179
     * Filters out this trait
180
     *
181
     * @return array|\ReflectionMethod[]
182
     * @throws \ReflectionException
183
     */
184 65
    protected static function getStaticMethods(): array
185
    {
186 65
        $currentClass = static::class;
187
        // get class level static methods
188 65
        if (!static::$reflectionClass instanceof \ReflectionClass
0 ignored issues
show
Bug introduced by
Since $reflectionClass is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $reflectionClass to at least protected.
Loading history...
introduced by
static::reflectionClass is never a sub-type of ReflectionClass. If static::reflectionClass can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:18.
Loading history...
189 65
            || static::$reflectionClass->getName() !== $currentClass
190
        ) {
191
            static::$reflectionClass = new \ts\Reflection\ReflectionClass($currentClass);
192
        }
193 65
        $staticMethods = static::$reflectionClass->getMethods(
194 65
            \ReflectionMethod::IS_STATIC
195
        );
196
        // get static methods from traits
197 65
        $traits = self::$reflectionClass->getTraits();
198 65
        foreach ($traits as $trait) {
199 65
            if ($trait->getShortName() === 'UsesPHPMetaData') {
200
                continue;
201
            }
202 65
            $traitStaticMethods = $trait->getMethods(
203 65
                \ReflectionMethod::IS_STATIC
204
            );
205 65
            array_merge(
206 65
                $staticMethods,
207 65
                $traitStaticMethods
208
            );
209
        }
210
211 65
        return $staticMethods;
212
    }
213
214
215
    /**
216
     * Get the property name the Entity is mapped by when plural
217
     *
218
     * Override it in your entity class if you are using an Entity class name that doesn't pluralize nicely
219
     *
220
     * @return string
221
     * @throws DoctrineStaticMetaException
222
     * @SuppressWarnings(PHPMD.StaticAccess)
223
     */
224 6
    public static function getPlural(): string
225
    {
226
        try {
227 6
            if (null === static::$plural) {
0 ignored issues
show
introduced by
The condition static::plural is always false. If static::plural can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:28
Loading history...
Bug introduced by
Since $plural is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $plural to at least protected.
Loading history...
228 6
                $singular       = static::getSingular();
229 6
                static::$plural = Inflector::pluralize($singular);
230
            }
231
232 6
            return static::$plural;
233
        } catch (\Exception $e) {
234
            throw new DoctrineStaticMetaException('Exception in '.__METHOD__.': '.$e->getMessage(), $e->getCode(), $e);
235
        }
236
    }
237
238
    /**
239
     * Get the property the name the Entity is mapped by when singular
240
     *
241
     * @return string
242
     * @throws DoctrineStaticMetaException
243
     * @SuppressWarnings(PHPMD.StaticAccess)
244
     */
245 7
    public static function getSingular(): string
246
    {
247
        try {
248 7
            if (null === static::$singular) {
0 ignored issues
show
introduced by
The condition static::singular is always false. If static::singular can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:23
Loading history...
Bug introduced by
Since $singular is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $singular to at least protected.
Loading history...
249 6
                if (null === self::$reflectionClass) {
250 5
                    self::$reflectionClass = new \ts\Reflection\ReflectionClass(static::class);
251
                }
252
253 6
                $shortName         = self::$reflectionClass->getShortName();
254 6
                $singularShortName = Inflector::singularize($shortName);
255
256 6
                $namespaceName   = self::$reflectionClass->getNamespaceName();
257 6
                $namespaceParts  = \explode(AbstractGenerator::ENTITIES_FOLDER_NAME, $namespaceName);
258 6
                $entityNamespace = \array_pop($namespaceParts);
259
260 6
                $namespacedShortName = \preg_replace(
261 6
                    '/\\\\/',
262 6
                    '',
263 6
                    $entityNamespace.$singularShortName
264
                );
265
266 6
                static::$singular = \lcfirst($namespacedShortName);
267
            }
268
269 7
            return static::$singular;
270
        } catch (\Exception $e) {
271
            throw new DoctrineStaticMetaException('Exception in '.__METHOD__.': '.$e->getMessage(), $e->getCode(), $e);
272
        }
273
    }
274
275
    /**
276
     * Get an array of setters by name
277
     *
278
     * @return array|string[]
279
     */
280 2
    public function getSetters(): array
281
    {
282 2
        if (null !== static::$setters) {
0 ignored issues
show
Bug introduced by
Since $setters is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $setters to at least protected.
Loading history...
introduced by
The condition static::setters is always true. If static::setters can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:33
Loading history...
283 1
            return static::$setters;
284
        }
285
        $skip            = [
286 2
            'setChangeTrackingPolicy' => true,
287
        ];
288 2
        static::$setters = [];
289 2
        foreach (self::$reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
290 2
            $methodName = $method->getName();
291 2
            if (isset($skip[$methodName])) {
292 2
                continue;
293
            }
294 2
            if (\ts\stringStartsWith($methodName, 'set')) {
295 2
                static::$setters[] = $methodName;
296 2
                continue;
297
            }
298 2
            if (\ts\stringStartsWith($methodName, 'add')) {
299 1
                static::$setters[] = $methodName;
300 2
                continue;
301
            }
302
        }
303
304 2
        return static::$setters;
305
    }
306
307
    /**
308
     * Get an array of getters by name
309
     * [];
310
     *
311
     * @return array|string[]
312
     */
313 1
    public function getGetters(): array
314
    {
315 1
        if (null !== static::$getters) {
0 ignored issues
show
Bug introduced by
Since $getters is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $getters to at least protected.
Loading history...
introduced by
The condition static::getters is always true. If static::getters can have other possible types, add them to src/Entity/Traits/UsesPHPMetaDataTrait.php:38
Loading history...
316
            return static::$getters;
317
        }
318
        $skip = [
319 1
            'getPlural'    => true,
320
            'getSingular'  => true,
321
            'getSetters'   => true,
322
            'getGetters'   => true,
323
            'getIdField'   => true,
324
            'getShortName' => true,
325
        ];
326
327 1
        static::$getters = [];
328 1
        foreach (self::$reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
329 1
            $methodName = $method->getName();
330 1
            if (isset($skip[$methodName])) {
331 1
                continue;
332
            }
333 1
            if (\ts\stringStartsWith($methodName, 'get')) {
334 1
                static::$getters[] = $methodName;
335 1
                continue;
336
            }
337
        }
338
339 1
        return static::$getters;
340
    }
341
342
    /**
343
     * Which field is being used for ID - will normally be `id` as implemented by
344
     * \EdmondsCommerce\DoctrineStaticMeta\Fields\Traits\IdField
345
     *
346
     * @return string
347
     * @SuppressWarnings(PHPMD.StaticAccess)
348
     */
349 2
    public static function getIdField(): string
350
    {
351 2
        return 'id';
352
    }
353
354
    /**
355
     * Get the short name (without fully qualified namespace) of the current Entity
356
     *
357
     * @return string
358
     */
359 2
    public function getShortName(): string
360
    {
361 2
        return static::$reflectionClass->getShortName();
0 ignored issues
show
Bug introduced by
Since $reflectionClass is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $reflectionClass to at least protected.
Loading history...
362
    }
363
364
    /**
365
     * @return string
366
     * @SuppressWarnings(PHPMD.StaticAccess)
367
     */
368 3
    public function __toString(): string
369
    {
370 3
        return (string)print_r(Debug::export($this, 2), true);
371
    }
372
}
373