Issues (126)

src/Helpers/ModelHelpersVocabularyAnnotation.php (2 issues)

1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * Created by PhpStorm.
6
 * User: alex
7
 * Date: 22/07/20
8
 * Time: 10:26 PM.
9
 */
10
11
namespace AlgoWeb\ODataMetadata\Helpers;
12
13
use AlgoWeb\ODataMetadata\EdmUtil;
14
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IVocabularyAnnotation;
15
use AlgoWeb\ODataMetadata\Interfaces\IModel;
16
use AlgoWeb\ODataMetadata\Interfaces\IStructuredType;
17
use AlgoWeb\ODataMetadata\Interfaces\ITerm;
18
use AlgoWeb\ODataMetadata\Interfaces\IVocabularyAnnotatable;
19
20
trait ModelHelpersVocabularyAnnotation
21
{
22
    /**
23
     * Gets an annotatable element's vocabulary annotations that bind a particular term.
24
     *
25
     * @param  IVocabularyAnnotatable           $element   element to check for annotations
26
     * @param  ITerm|string|null                $term      Term to search for. OR Name of the term to search for.
27
     * @param  string|null                      $qualifier qualifier to apply
28
     * @param  string|null                      $type      type of the annotation being returned
29
     * @return iterable|IVocabularyAnnotation[] annotations attached to the element by this model or by models
30
     *                                                    referenced by this model that bind the term with the given
31
     *                                                    qualifier
32
     */
33
    public function findVocabularyAnnotations(
34
        IVocabularyAnnotatable $element,
35
        $term = null,
36
        string $qualifier = null,
37
        string $type = null
38
    ): iterable {
39
        assert(
40
            null === $term || $term instanceof ITerm || is_string($term),
41
            '$term should be a string or instanceof iTerm'
42
        );
43
        if (null === $term) {
44
            return $this->processNullVocabularyAnnotationTerm($element);
45
        }
46
        if (is_string($term)) {
47
            $termName = $term;
48
            // Look up annotations on the element by name. There's no particular advantage in searching for a term first.
49
            $name          = null;
50
            $namespaceName = null;
51
52
            if (EdmUtil::tryGetNamespaceNameFromQualifiedName($termName, $namespaceName, $name)) {
53
                /**
54
                 * @var IVocabularyAnnotation $annotation
55
                 */
56
                foreach ($this->findVocabularyAnnotations($element) as $annotation) {
57
                    if (null !== $type && !is_a($annotation, $type)) {
58
                        continue;
59
                    }
60
                    $annotationTerm = $annotation->getTerm();
61
                    if ($annotationTerm->getNamespace() === $namespaceName &&
62
                        $annotationTerm->getName() === $name &&
63
                        (
64
                            null === $qualifier ||
65
                            $qualifier == $annotation->getQualifier()
66
                        )
67
                    ) {
68
                        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...
69
                    }
70
                }
71
            }
72
        } else {
73
            return $this->processTermVocabularyAnnotationTerm($element, $term, $qualifier, $type);
74
        }
75
    }
76
77
    /**
78
     * Gets an annotatable element's vocabulary annotations defined in a specific model and models referenced by
79
     * that model.
80
     * @param  IVocabularyAnnotatable  $element element to check for annotations
81
     * @return IVocabularyAnnotation[] annotations attached to the element (or, if the element is a type, to its base
82
     *                                         types) by this model or by models referenced by this model
83
     */
84
    public function findVocabularyAnnotationsIncludingInheritedAnnotations(IVocabularyAnnotatable $element): array
85
    {
86
        /**
87
         * @var IVocabularyAnnotation[] $result
88
         */
89
        $result = $this->FindDeclaredVocabularyAnnotations($element);
0 ignored issues
show
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

89
        /** @scrutinizer ignore-call */ 
90
        $result = $this->FindDeclaredVocabularyAnnotations($element);
Loading history...
90
91
        if ($element instanceof IStructuredType) {
92
            $typeElement = $element;
93
            assert($typeElement instanceof IStructuredType);
94
            $typeElement = $typeElement->getBaseType();
95
            while (null !== $typeElement) {
96
                if ($typeElement instanceof IVocabularyAnnotatable) {
97
                    $result = array_merge($result, $this->FindDeclaredVocabularyAnnotations($typeElement));
98
                }
99
100
                $typeElement = $typeElement->getBaseType();
101
            }
102
        }
103
104
        return $result;
105
    }
106
107
    /**
108
     * @param  IVocabularyAnnotatable        $element
109
     * @return IVocabularyAnnotation[]|array
110
     */
111
    protected function processNullVocabularyAnnotationTerm(
112
        IVocabularyAnnotatable $element
113
    ): array {
114
        $result = $this->findVocabularyAnnotationsIncludingInheritedAnnotations($element);
115
        foreach ($this->getReferencedModels() as $referencedModel) {
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
    /**
155
     * @return IModel[] gets the collection of models referred to by this model
156
     */
157
    abstract public function getReferencedModels(): array;
158
}
159