Passed
Pull Request — master (#44)
by Alex
02:58
created

findTarget()   C

Complexity

Conditions 14
Paths 13

Size

Total Lines 87
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 63
c 1
b 0
f 0
nc 13
nop 2
dl 0
loc 87
rs 6.2666

How to fix   Long Method    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
declare(strict_types=1);
4
5
6
namespace AlgoWeb\ODataMetadata\Edm\Validation\ValidationRules\IVocabularyAnnotation;
7
8
use AlgoWeb\ODataMetadata\Edm\Validation\EdmErrorCode;
9
use AlgoWeb\ODataMetadata\Edm\Validation\ValidationContext;
10
use AlgoWeb\ODataMetadata\EdmUtil;
11
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IVocabularyAnnotation;
12
use AlgoWeb\ODataMetadata\Interfaces\IEdmElement;
13
use AlgoWeb\ODataMetadata\Interfaces\IEntityContainer;
14
use AlgoWeb\ODataMetadata\Interfaces\IEntitySet;
15
use AlgoWeb\ODataMetadata\Interfaces\IFunction;
16
use AlgoWeb\ODataMetadata\Interfaces\IFunctionBase;
17
use AlgoWeb\ODataMetadata\Interfaces\IFunctionImport;
18
use AlgoWeb\ODataMetadata\Interfaces\IFunctionParameter;
19
use AlgoWeb\ODataMetadata\Interfaces\IProperty;
20
use AlgoWeb\ODataMetadata\Interfaces\ISchemaType;
21
use AlgoWeb\ODataMetadata\Interfaces\IStructuredType;
22
use AlgoWeb\ODataMetadata\Interfaces\ITerm;
23
use AlgoWeb\ODataMetadata\StringConst;
24
25
/**
26
 * Validates that a vocabulary annotations target can be found through the model containing the annotation.
27
 *
28
 * @package AlgoWeb\ODataMetadata\Edm\Validation\ValidationRules\IVocabularyAnnotation
29
 */
30
class VocabularyAnnotationInaccessibleTarget extends VocabularyAnnotationRule
31
{
32
    public function __invoke(ValidationContext $context, ?IEdmElement $annotation)
33
    {
34
        assert($annotation instanceof IVocabularyAnnotation);
35
        $target      = $annotation->getTarget();
36
        $foundTarget = $this->findTarget($context, $target);
37
38
        if (!$foundTarget) {
39
            EdmUtil::checkArgumentNull($annotation->Location(), 'annotation->Location');
40
            $context->AddError(
41
                $annotation->Location(),
42
                EdmErrorCode::BadUnresolvedTarget(),
43
                StringConst::EdmModel_Validator_Semantic_InaccessibleTarget(EdmUtil::FullyQualifiedName($target))
44
            );
45
        }
46
    }
47
48
    /**
49
     * @param  ValidationContext                                        $context
50
     * @param  \AlgoWeb\ODataMetadata\Interfaces\IVocabularyAnnotatable $target
51
     * @return bool
52
     */
53
    protected function findTarget(
54
        ValidationContext $context,
55
        \AlgoWeb\ODataMetadata\Interfaces\IVocabularyAnnotatable $target
56
    ): bool {
57
        $foundTarget     = false;
58
        $entityContainer = $target;
59
        if ($entityContainer instanceof IEntityContainer) {
60
            $foundTarget = ($context->getModel()->findEntityContainer($entityContainer->FullName()) != null);
61
            return $foundTarget;
62
        }
63
        $entitySet = $target;
64
        if ($entitySet instanceof IEntitySet) {
65
            $container = $entitySet->getContainer();
66
            if ($container instanceof IEntityContainer) {
67
                $foundTarget = ($container->findEntitySet($entitySet->getName()) != null);
0 ignored issues
show
Bug introduced by
It seems like $entitySet->getName() can also be of type null; however, parameter $setName of AlgoWeb\ODataMetadata\In...tainer::findEntitySet() 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

67
                $foundTarget = ($container->findEntitySet(/** @scrutinizer ignore-type */ $entitySet->getName()) != null);
Loading history...
68
                return $foundTarget;
69
            }
70
            return false;
71
        }
72
        $schemaType = $target;
73
        if ($schemaType instanceof ISchemaType) {
74
            $foundTarget = ($context->getModel()->FindType($schemaType->FullName()) != null);
75
            return $foundTarget;
76
        }
77
        $term = $target;
78
        if ($term instanceof ITerm) {
79
            $foundTarget = ($context->getModel()->FindValueTerm($term->FullName()) != null);
80
            return $foundTarget;
81
        }
82
        $function = $target;
83
        if ($function instanceof IFunction) {
84
            $foundTarget = count($context->getModel()->FindFunctions($function->FullName())) > 0;
85
            return $foundTarget;
86
        }
87
        $functionImport = $target;
88
        if ($functionImport instanceof IFunctionImport) {
89
            EdmUtil::checkArgumentNull($functionImport->getName(), 'functionImport->getName');
90
            $funcName    = $functionImport->getName();
91
            $foundTarget = count($functionImport->getContainer()->findFunctionImports($funcName)) > 0;
92
            return $foundTarget;
93
        }
94
        $typeProperty = $target;
95
        if ($typeProperty instanceof IProperty) {
96
            $declaringType = $typeProperty->getDeclaringType();
97
            assert($declaringType instanceof ISchemaType);
98
            $declaringTypeFullName = EdmUtil::FullyQualifiedName($declaringType);
99
            EdmUtil::checkArgumentNull($declaringTypeFullName, 'declaringTypeFullName');
100
            EdmUtil::checkArgumentNull($typeProperty->getName(), 'typeProperty->getName');
101
            $modelType = $context->getModel()->FindType($declaringTypeFullName);
102
            if ($modelType !== null && $modelType instanceof IStructuredType) {
103
                // If we can find a structured type with this name in the model check if it
104
                // has a property with this name
105
                $foundTarget = ($modelType->findProperty($typeProperty->getName()) != null);
106
                return $foundTarget;
107
            }
108
            return false;
109
        }
110
        $functionParameter = $target;
111
        if ($functionParameter instanceof IFunctionParameter) {
112
            $paramName = $functionParameter->getName();
113
            EdmUtil::checkArgumentNull($paramName, 'functionParameter->getName');
114
            $declaringFunction = $functionParameter->getDeclaringFunction();
115
            switch (true) {
116
                case $declaringFunction instanceof IFunction:
117
                    $functions = $context->getModel()->FindFunctions($declaringFunction->FullName());
118
                    break;
119
                case $declaringFunction instanceof IFunctionImport:
120
                    $container = $declaringFunction->getContainer();
121
                    assert($container instanceof IEntityContainer);
122
                    $functions = $container->findFunctionImports($declaringFunction->getName());
0 ignored issues
show
Bug introduced by
It seems like $declaringFunction->getName() can also be of type null; however, parameter $functionName of AlgoWeb\ODataMetadata\In...::findFunctionImports() 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

122
                    $functions = $container->findFunctionImports(/** @scrutinizer ignore-type */ $declaringFunction->getName());
Loading history...
123
                    break;
124
                default:
125
                    return false;
126
            }
127
128
            // For all functions with this name declared in the model check if it has
129
            // a parameter with this name
130
            return 0 < count(array_filter($functions, function (IFunctionBase $func) use ($paramName) {
131
                return null !== $func->findParameter($paramName);
132
            }));
133
        } else {
134
            // Only validate annotations targeting elements that can be found via the
135
            // model API.
136
            // E.g. annotations targeting annotations will not be valid without this branch.
137
            $foundTarget = true;
138
        }
139
        return $foundTarget;
140
    }
141
}
142