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

FindVocabularyAnnotationsIncludingInheritedAnnotations()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 21
rs 9.9332
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 $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($term instanceof ITerm || is_string($term), '$term should be a string or instanceof iTerm');
36
        if (null === $term) {
0 ignored issues
show
introduced by
The condition null === $term is always false.
Loading history...
37
            return $this->processNullVocabularyAnnotationTerm($element, $qualifier, $type);
38
        }
39
        if (is_string($term)) {
40
            $termName = $term;
41
            // Look up annotations on the element by name. There's no particular advantage in searching for a term first.
42
            $name = null;
43
            $namespaceName = null;
44
45
            if (EdmUtil::TryGetNamespaceNameFromQualifiedName($termName, $namespaceName, $name)) {
46
                /**
47
                 * @var IVocabularyAnnotation $annotation
48
                 */
49
                foreach ($this->FindVocabularyAnnotations($element) as $annotation) {
50
                    if (null !== $type && !is_a($annotation, $type)) {
51
                        continue;
52
                    }
53
                    $annotationTerm = $annotation->getTerm();
54
                    if ($annotationTerm->getNamespace() === $namespaceName &&
55
                        $annotationTerm->getName() === $name &&
56
                        (
57
                            null === $qualifier ||
58
                            $qualifier == $annotation->getQualifier()
59
                        )
60
                    ) {
61
                        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...
62
                    }
63
                }
64
            }
65
        } else {
66
            return $this->processTermVocabularyAnnotationTerm($element, $term, $qualifier, $type);
67
        }
68
    }
69
70
    /**
71
     * Gets an annotatable element's vocabulary annotations defined in a specific model and models referenced by
72
     * that model.
73
     * @param IVocabularyAnnotatable $element Element to check for annotations.
74
     * @return IVocabularyAnnotation[] Annotations attached to the element (or, if the element is a type, to its base
75
     * types) by this model or by models referenced by this model.
76
     */
77
    public function FindVocabularyAnnotationsIncludingInheritedAnnotations(IVocabularyAnnotatable $element): array
78
    {
79
        /**
80
         * @var IVocabularyAnnotation[] $result
81
         */
82
        $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

82
        /** @scrutinizer ignore-call */ 
83
        $result = $this->FindDeclaredVocabularyAnnotations($element);
Loading history...
83
84
        if ($element instanceof IStructuredType) {
85
            $typeElement = $element;
86
            assert($typeElement instanceof IStructuredType);
87
            $typeElement = $typeElement->getBaseType();
88
            while (null !== $typeElement) {
89
                if ($typeElement instanceof IVocabularyAnnotatable) {
90
                    $result = array_merge($result, $this->FindDeclaredVocabularyAnnotations($typeElement));
91
                }
92
93
                $typeElement = $typeElement->getBaseType();
94
            }
95
        }
96
97
        return $result;
98
    }
99
100
    /**
101
     * @param IVocabularyAnnotatable $element
102
     * @param string $qualifier
103
     * @param string $type
104
     * @return IVocabularyAnnotation[]|array
105
     */
106
    protected function processNullVocabularyAnnotationTerm(
107
        IVocabularyAnnotatable $element,
108
        string $qualifier,
109
        string $type
110
    ): array {
111
        assert(null === $qualifier);
112
        assert(null === $type);
113
        $result = $this->FindVocabularyAnnotationsIncludingInheritedAnnotations($element);
114
        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

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