Passed
Pull Request — master (#50)
by Alex
03:31
created

FindVocabularyAnnotations()   C

Complexity

Conditions 13
Paths 7

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 21
c 1
b 0
f 0
nc 7
nop 4
dl 0
loc 41
rs 6.6166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: alex
5
 * Date: 22/07/20
6
 * Time: 10:26 PM
7
 */
8
9
namespace AlgoWeb\ODataMetadata\Helpers;
10
11
use AlgoWeb\ODataMetadata\EdmUtil;
12
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IVocabularyAnnotation;
13
use AlgoWeb\ODataMetadata\Interfaces\IStructuredType;
14
use AlgoWeb\ODataMetadata\Interfaces\ITerm;
15
use AlgoWeb\ODataMetadata\Interfaces\IVocabularyAnnotatable;
16
17
trait ModelHelpersVocabularyAnnotation
18
{
19
    /**
20
     * Gets an annotatable element's vocabulary annotations that bind a particular term.
21
     *
22
     * @param IVocabularyAnnotatable $element  Element to check for annotations.
23
     * @param ITerm|string|null $term Term to search for. OR Name of the term to search for.
24
     * @param string|null $qualifier Qualifier to apply.
25
     * @param string|null $type Type of the annotation being returned.
26
     * @return iterable|IVocabularyAnnotation[] Annotations attached to the element by this model or by models
27
     * referenced by this model that bind the term with the given qualifier.
28
     */
29
    public function FindVocabularyAnnotations(
30
        IVocabularyAnnotatable $element,
31
        $term = null,
32
        string $qualifier = null,
33
        string $type = null
34
    ): iterable {
35
        assert(
36
            null === $term || $term instanceof ITerm || is_string($term),
37
               '$term should be a string or instanceof iTerm'
38
        );
39
        if (null === $term) {
40
            return $this->processNullVocabularyAnnotationTerm($element, $qualifier, $type);
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type null; however, parameter $type of AlgoWeb\ODataMetadata\He...abularyAnnotationTerm() does only seem to accept 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

40
            return $this->processNullVocabularyAnnotationTerm($element, $qualifier, /** @scrutinizer ignore-type */ $type);
Loading history...
Bug introduced by
It seems like $qualifier can also be of type null; however, parameter $qualifier of AlgoWeb\ODataMetadata\He...abularyAnnotationTerm() does only seem to accept 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

40
            return $this->processNullVocabularyAnnotationTerm($element, /** @scrutinizer ignore-type */ $qualifier, $type);
Loading history...
41
        }
42
        if (is_string($term)) {
43
            $termName = $term;
44
            // Look up annotations on the element by name. There's no particular advantage in searching for a term first.
45
            $name = null;
46
            $namespaceName = null;
47
48
            if (EdmUtil::TryGetNamespaceNameFromQualifiedName($termName, $namespaceName, $name)) {
49
                /**
50
                 * @var IVocabularyAnnotation $annotation
51
                 */
52
                foreach ($this->FindVocabularyAnnotations($element) as $annotation) {
53
                    if (null !== $type && !is_a($annotation, $type)) {
54
                        continue;
55
                    }
56
                    $annotationTerm = $annotation->getTerm();
57
                    if ($annotationTerm->getNamespace() === $namespaceName &&
58
                        $annotationTerm->getName() === $name &&
59
                        (
60
                            null === $qualifier ||
61
                            $qualifier == $annotation->getQualifier()
62
                        )
63
                    ) {
64
                        yield $annotation;
0 ignored issues
show
Bug Best Practice introduced by
The expression yield $annotation returns the type Generator which is incompatible with the documented return type AlgoWeb\ODataMetadata\In...ryAnnotation[]|iterable.
Loading history...
65
                    }
66
                }
67
            }
68
        } else {
69
            return $this->processTermVocabularyAnnotationTerm($element, $term, $qualifier, $type);
70
        }
71
    }
72
73
    /**
74
     * Gets an annotatable element's vocabulary annotations defined in a specific model and models referenced by
75
     * that model.
76
     * @param IVocabularyAnnotatable $element Element to check for annotations.
77
     * @return IVocabularyAnnotation[] Annotations attached to the element (or, if the element is a type, to its base
78
     * types) by this model or by models referenced by this model.
79
     */
80
    public function FindVocabularyAnnotationsIncludingInheritedAnnotations(IVocabularyAnnotatable $element): array
81
    {
82
        /**
83
         * @var IVocabularyAnnotation[] $result
84
         */
85
        $result = $this->FindDeclaredVocabularyAnnotations($element);
0 ignored issues
show
Bug introduced by
It seems like FindDeclaredVocabularyAnnotations() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

85
        /** @scrutinizer ignore-call */ 
86
        $result = $this->FindDeclaredVocabularyAnnotations($element);
Loading history...
86
87
        if ($element instanceof IStructuredType) {
88
            $typeElement = $element;
89
            assert($typeElement instanceof IStructuredType);
90
            $typeElement = $typeElement->getBaseType();
91
            while (null !== $typeElement) {
92
                if ($typeElement instanceof IVocabularyAnnotatable) {
93
                    $result = array_merge($result, $this->FindDeclaredVocabularyAnnotations($typeElement));
94
                }
95
96
                $typeElement = $typeElement->getBaseType();
97
            }
98
        }
99
100
        return $result;
101
    }
102
103
    /**
104
     * @param IVocabularyAnnotatable $element
105
     * @param string $qualifier
106
     * @param string $type
107
     * @return IVocabularyAnnotation[]|array
108
     */
109
    protected function processNullVocabularyAnnotationTerm(
110
        IVocabularyAnnotatable $element,
111
        string $qualifier,
0 ignored issues
show
Unused Code introduced by
The parameter $qualifier is not used and could be removed. ( Ignorable by Annotation )

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

111
        /** @scrutinizer ignore-unused */ string $qualifier,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
112
        string $type
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

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

112
        /** @scrutinizer ignore-unused */ string $type

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
113
    ): array {
114
        $result = $this->FindVocabularyAnnotationsIncludingInheritedAnnotations($element);
115
        foreach ($this->getReferencedModels() as $referencedModel) {
0 ignored issues
show
Bug introduced by
It seems like getReferencedModels() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

115
        foreach ($this->/** @scrutinizer ignore-call */ getReferencedModels() as $referencedModel) {
Loading history...
116
            $result = array_merge(
117
                $result,
118
                $referencedModel->FindVocabularyAnnotationsIncludingInheritedAnnotations($element)
119
            );
120
        }
121
        return $result;
122
    }
123
124
    /**
125
     * @param IVocabularyAnnotatable $element
126
     * @param ITerm $term
127
     * @param string $qualifier
128
     * @param string $type
129
     * @return array
130
     */
131
    protected function processTermVocabularyAnnotationTerm(
132
        IVocabularyAnnotatable $element,
133
        ITerm $term,
134
        string $qualifier = null,
135
        string $type = null
136
    ): array {
137
        $result = [];
138
        /**
139
         * @var IVocabularyAnnotation $annotation
140
         */
141
        foreach ($this->FindVocabularyAnnotations($element) as $annotation) {
142
            if (null !== $type && !is_a($annotation, $type)) {
143
                continue;
144
            }
145
146
            if ($annotation->getTerm() == $term && (null === $qualifier || $qualifier == $annotation->getQualifier())) {
147
                $result[] = $annotation;
148
            }
149
        }
150
151
        return $result;
152
    }
153
}
154