Passed
Pull Request — master (#66)
by Alex
05:53
created

Helpers::annotationValue()   A

Complexity

Conditions 6
Paths 9

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 9
nop 2
dl 0
loc 25
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AlgoWeb\ODataMetadata\Helpers;
6
7
use AlgoWeb\ODataMetadata\CsdlConstants;
8
use AlgoWeb\ODataMetadata\EdmConstants;
9
use AlgoWeb\ODataMetadata\Exception\InvalidOperationException;
10
use AlgoWeb\ODataMetadata\Interfaces\IEdmElement;
11
use AlgoWeb\ODataMetadata\Interfaces\IEntityType;
12
use AlgoWeb\ODataMetadata\Interfaces\IModel;
13
use AlgoWeb\ODataMetadata\Interfaces\INavigationProperty;
14
use AlgoWeb\ODataMetadata\Interfaces\ITypeReference;
15
use AlgoWeb\ODataMetadata\StringConst;
16
17
abstract class Helpers
18
{
19
    public const AssociationNameEscapeChar          = '_';
20
    public const AssociationNameEscapeString        = '_';
21
    public const AssociationNameEscapeStringEscaped = '__';
22
23
    public static function getPathSegmentEntityType(ITypeReference $segmentType): IEntityType
24
    {
25
        return ($segmentType->isCollection() ? $segmentType->asCollection()->elementType() : $segmentType)
26
            ->asEntity()->entityDefinition();
27
    }
28
29
    /**
30
     * @param IModel $model
31
     * @param string $qualifiedName
32
     * @param callable $finder
33
     * @param callable $ambiguousCreator
34
     * @return IEdmElement|null
35
     */
36
    public static function findAcrossModels(
37
        IModel $model,
38
        string $qualifiedName,
39
        callable $finder,
40
        callable $ambiguousCreator
41
    ): ?IEdmElement {
42
        $candidate = $finder($model, $qualifiedName);
43
44
        foreach ($model->getReferencedModels() as $reference) {
45
            $fromReference = $finder($reference, $qualifiedName);
46
            if ($fromReference != null) {
47
                $candidate = $candidate == null ? $fromReference : $ambiguousCreator($candidate, $fromReference);
48
            }
49
        }
50
51
        return $candidate;
52
    }
53
54
55
    /**
56
     * @param  string     $typeOf     type of the annotation being returned
57
     * @param  mixed      $annotation
58
     * @return mixed|null
59
     */
60
    public static function annotationValue(string $typeOf, $annotation)
61
    {
62
        if ($annotation != null) {
63
            if ('array' === $typeOf) {
64
                $isSpecificAnnotation = is_array($annotation);
65
            } elseif ('string' === $typeOf) {
66
                $isSpecificAnnotation = is_string($annotation);
67
            } elseif ('?string' === $typeOf) {
68
                $isSpecificAnnotation = is_string($annotation);
69
            } else {
70
                $isSpecificAnnotation = is_a($annotation, $typeOf);
71
            }
72
73
            if ($isSpecificAnnotation) {
74
                return $annotation;
75
            }
76
77
            /**if ($annotation instanceof IValue)
78
            {
79
            }*/
80
81
            throw new InvalidOperationException(StringConst::Annotations_TypeMismatch(get_class($annotation), $typeOf));
82
        }
83
84
        return null;
85
    }
86
87
    public static function classNameToLocalName(string $className): string
88
    {
89
        // Use the name of the type as its local name for annotations.
90
        // Filter out special characters to produce a valid name:
91
        // '.'                      Appears in qualified names.
92
        // '`', '[', ']', ','       Appear in generic instantiations.
93
        // '+'                      Appears in names of local classes.
94
        return str_replace(
95
            '_',
96
            '_____',
97
            str_replace(
98
                '.',
99
                '_',
100
                str_replace(
101
                    '[',
102
                    '',
103
                    str_replace(
104
                        ']',
105
                        '',
106
                        str_replace(
107
                            ',',
108
                            '__',
109
                            str_replace(
110
                                '`',
111
                                '___',
112
                                str_replace(
113
                                    '+',
114
                                    '____',
115
                                    $className
116
                                )
117
                            )
118
                        )
119
                    )
120
                )
121
            )
122
        );
123
    }
124
125
    /**
126
     * Gets the namespace used for the association serialized for a navigation property.
127
     *
128
     * @param  IModel              $model    model containing the navigation property
129
     * @param  INavigationProperty $property the navigation property
130
     * @return string              the association namespace
131
     */
132
    public static function getAssociationNamespace(IModel $model, INavigationProperty $property): string
133
    {
134
        $property->populateCaches();
135
        $associationNamespace = $model->getAnnotationValue('string', $property, EdmConstants::InternalUri, CsdlConstants::AssociationNamespaceAnnotation);
136
        if ($associationNamespace == null) {
137
            $associationNamespace = $property->getPrimary()->declaringEntityType()->getNamespace();
138
        }
139
140
        return $associationNamespace;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $associationNamespace could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
141
    }
142
143
144
    public static function getQualifiedAndEscapedPropertyName(INavigationProperty $property): string
145
    {
146
        return
147
            str_replace('.', self::AssociationNameEscapeChar, self::escapeName($property->declaringEntityType()->getNamespace())) .
0 ignored issues
show
Bug introduced by
It seems like $property->declaringEntityType()->getNamespace() can also be of type null; however, parameter $name of AlgoWeb\ODataMetadata\He...s\Helpers::escapeName() 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

147
            str_replace('.', self::AssociationNameEscapeChar, self::escapeName(/** @scrutinizer ignore-type */ $property->declaringEntityType()->getNamespace())) .
Loading history...
148
            self::AssociationNameEscapeChar .
149
            self::escapeName($property->declaringEntityType()->getNamespace()) .
150
            self::AssociationNameEscapeChar .
151
            self::escapeName($property->getName());
152
    }
153
154
    private static function escapeName(string $name): string
155
    {
156
        return str_replace(self::AssociationNameEscapeString, self::AssociationNameEscapeStringEscaped, $name);
157
    }
158
}
159