Completed
Push — master ( dca783...294a52 )
by Przemysław eRIZ
02:30
created

Factory::getConfigurationForFieldByGroup()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 17
ccs 9
cts 9
cp 1
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 2
crap 4
1
<?php
2
3
namespace Er1z\FakeMock\Metadata;
4
5
use Doctrine\Common\Annotations\AnnotationReader;
6
use Doctrine\Common\Annotations\AnnotationRegistry;
7
use Doctrine\Common\Annotations\Reader;
8
use Er1z\FakeMock\Annotations\AnnotationCollection;
9
use Er1z\FakeMock\Annotations\FakeMock;
10
use Er1z\FakeMock\Annotations\FakeMockField;
11
use phpDocumentor\Reflection\DocBlock\Tag;
12
use phpDocumentor\Reflection\Type;
13
use phpDocumentor\Reflection\Types\ContextFactory;
14
15
class Factory implements FactoryInterface
16
{
17
    protected $reader;
18
19 90
    public function __construct(?Reader $reader = null)
20
    {
21
        // can't wait for v2...
22 90
        if (class_exists(AnnotationRegistry::class)) {
23 90
            AnnotationRegistry::registerLoader('class_exists');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...istry::registerLoader() has been deprecated: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists') ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

23
            /** @scrutinizer ignore-deprecated */ AnnotationRegistry::registerLoader('class_exists');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
24
        }
25
26 90
        $this->reader = $reader ?? new AnnotationReader();
27 90
    }
28
29 50
    public function getObjectConfiguration(\ReflectionClass $object): ?FakeMock
30
    {
31 50
        return $this->reader->getClassAnnotation($object, FakeMock::class);
32
    }
33
34
    /**
35
     * @param $object
36
     * @param FakeMock $objectConfiguration
37
     * @param \ReflectionProperty $property
38
     * @return FieldMetadata[]
39
     */
40 46
    public function create($object, FakeMock $objectConfiguration, \ReflectionProperty $property)
41
    {
42 46
        $annotations = new AnnotationCollection($this->reader->getPropertyAnnotations($property));
43 46
        $fieldAnnotations = $annotations->findAllBy(FakeMockField::class);
44
45 46
        if (!$fieldAnnotations) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldAnnotations of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
46 8
            return null;
47
        }
48
49 38
        $result = [];
50
51
52 38
        foreach($fieldAnnotations as $a){
53 38
            $f = new FieldMetadata();
54 38
            $f->property = $property;
55 38
            $f->objectConfiguration = $objectConfiguration;
56 38
            $f->annotations = $annotations;
57 38
            $f->type = $this->getPhpDocType($property);
58 38
            $f->object = $object;
59 38
            $f->configuration = $this->mergeGlobalConfigurationWithLocal($objectConfiguration, $a);
60
61 38
            $result[] = $f;
62
        }
63
64 38
        return $result;
65
    }
66
67
    /**
68
     * @param FieldMetadata[] $annotations
69
     * @param string|null $group
70
     * @return FieldMetadata[]
71
     */
72 50
    public function getConfigurationForFieldByGroup($annotations, ?string $group = null){
73
74 50
        if(empty($annotations)){
75 8
            return null;
76
        }
77
78 42
        if(is_null($group)){
79 34
            return array_shift($annotations);
80
        }
81
82
        $result = array_filter($annotations, function($item) use ($group){
83 12
            return !empty($item->configuration->groups) && in_array($group, $item->configuration->groups);
84 12
        });
85
86 12
        $filtered = array_values($result);
87
88 12
        return array_shift($filtered);
89
    }
90
91 42
    protected function mergeGlobalConfigurationWithLocal(FakeMock $objectConfig, FakeMockField $fieldConfig): FakeMockField
92
    {
93 42
        if (is_null($fieldConfig->useAsserts)) {
0 ignored issues
show
introduced by
The condition is_null($fieldConfig->useAsserts) is always false.
Loading history...
94 38
            $fieldConfig->useAsserts = $objectConfig->useAsserts;
95
        }
96
97 42
        if (is_null($fieldConfig->satisfyAssertsConditions)) {
0 ignored issues
show
introduced by
The condition is_null($fieldConfig->satisfyAssertsConditions) is always false.
Loading history...
98 42
            $fieldConfig->satisfyAssertsConditions = $objectConfig->satisfyAssertsConditions;
99
        }
100
101 42
        if(is_null($fieldConfig->recursive)){
102 42
            $fieldConfig->recursive = $objectConfig->recursive;
103
        }
104
105 42
        return $fieldConfig;
106
    }
107
108 42
    protected function getPhpDocType(\ReflectionProperty $property): ?Type
109
    {
110 42
        $factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
111 42
        $docComment = $property->getDocComment();
112
113 42
        if (!$docComment) {
114 4
            return null;
115
        }
116
117 42
        $ctxFactory = new ContextFactory();
118
119 42
        $data = $factory->create(
120 42
            $docComment, $ctxFactory->createFromReflector($property)
0 ignored issues
show
Bug introduced by
It seems like $docComment can also be of type true; however, parameter $docblock of phpDocumentor\Reflection\DocBlockFactory::create() does only seem to accept object|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
            /** @scrutinizer ignore-type */ $docComment, $ctxFactory->createFromReflector($property)
Loading history...
121
        );
122
123
        /**
124
         * @var $vars Tag[]
125
         */
126 42
        if ($vars = $data->getTagsByName('var')) {
127 30
            return $vars[0]->getType();
0 ignored issues
show
Bug introduced by
The method getType() does not exist on phpDocumentor\Reflection\DocBlock\Tag. It seems like you code against a sub-type of phpDocumentor\Reflection\DocBlock\Tag such as phpDocumentor\Reflection\DocBlock\Tags\Property or phpDocumentor\Reflection\DocBlock\Tags\Var_ or phpDocumentor\Reflection\DocBlock\Tags\Param or phpDocumentor\Reflection...lock\Tags\PropertyWrite or phpDocumentor\Reflection\DocBlock\Tags\Return_ or phpDocumentor\Reflection\DocBlock\Tags\Throws or phpDocumentor\Reflection...Block\Tags\PropertyRead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

127
            return $vars[0]->/** @scrutinizer ignore-call */ getType();
Loading history...
128
        }
129
130 19
        return null;
131
    }
132
}
133