Completed
Push — master ( 67fb5e...175b65 )
by Alex
25s queued 14s
created

createNavigationPropertyType()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 17
rs 9.9332
1
<?php
2
3
declare(strict_types=1);
4
5
6
namespace AlgoWeb\ODataMetadata\Library;
7
8
use AlgoWeb\ODataMetadata\CsdlConstants;
9
use AlgoWeb\ODataMetadata\EdmUtil;
10
use AlgoWeb\ODataMetadata\Enums\Multiplicity;
11
use AlgoWeb\ODataMetadata\Enums\OnDeleteAction;
12
use AlgoWeb\ODataMetadata\Enums\PropertyKind;
13
use AlgoWeb\ODataMetadata\Exception\ArgumentException;
14
use AlgoWeb\ODataMetadata\Exception\ArgumentOutOfRangeException;
15
use AlgoWeb\ODataMetadata\Helpers\NavigationPropertyHelpers;
16
use AlgoWeb\ODataMetadata\Interfaces\ICollectionType;
17
use AlgoWeb\ODataMetadata\Interfaces\IEntityType;
18
use AlgoWeb\ODataMetadata\Interfaces\INavigationProperty;
19
use AlgoWeb\ODataMetadata\Interfaces\IStructuralProperty;
20
use AlgoWeb\ODataMetadata\Interfaces\ITypeReference;
21
use AlgoWeb\ODataMetadata\Library\Core\EdmCoreModel;
22
use AlgoWeb\ODataMetadata\StringConst;
23
24
class EdmNavigationProperty extends EdmProperty implements INavigationProperty
25
{
26
    use NavigationPropertyHelpers;
27
    /**
28
     * @var bool
29
     */
30
    private $containsTarget;
31
    /**
32
     * @var OnDeleteAction
33
     */
34
    private $onDelete;
35
    /**
36
     * @var EdmNavigationProperty
37
     */
38
    private $partner;
39
    /**
40
     * @var array<IStructuralProperty>
41
     */
42
    private $dependentProperties;
43
44
    public function __construct(
45
        IEntityType $declaringType,
46
        string $name,
47
        ITypeReference $type,
48
        ?array $dependentProperties,
49
        ?bool $containsTarget,
50
        ?OnDeleteAction $onDelete
51
    ) {
52
        parent::__construct($declaringType, $name, $type);
53
        $this->dependentProperties = $dependentProperties;
54
        $this->containsTarget      = $containsTarget ?? CsdlConstants::Default_ContainsTarget;
55
        $this->onDelete            = $onDelete ?? OnDeleteAction::None();
56
    }
57
58
    /**
59
     * @return INavigationProperty gets the partner of this navigation property
60
     */
61
    public function getPartner(): INavigationProperty
62
    {
63
        return $this->partner;
64
    }
65
66
    /**
67
     * @return OnDeleteAction gets the action to execute on the deletion of this end of a bidirectional association
68
     */
69
    public function getOnDelete(): OnDeleteAction
70
    {
71
        return $this->onDelete;
72
    }
73
74
    /**
75
     * @return bool gets whether this navigation property originates at the principal end of an association
76
     */
77
    public function isPrincipal(): bool
78
    {
79
        return $this->dependentProperties === null && $this->partner !== null &&
80
               $this->partner->dependentProperties !== null;
81
    }
82
83
    /**
84
     * @return IStructuralProperty[]|null gets the dependent properties of this navigation property, returning null if
85
     *                                    this is the principal end or if there is no referential constraint
86
     */
87
    public function getDependentProperties(): ?array
88
    {
89
        return $this->dependentProperties;
90
    }
91
92
    /**
93
     * @return bool gets a value indicating whether the navigation target is contained inside the navigation source
94
     */
95
    public function containsTarget(): bool
96
    {
97
        return $this->containsTarget;
98
    }
99
100
    /**
101
     * @return PropertyKind gets the kind of this property
102
     */
103
    public function getPropertyKind(): PropertyKind
104
    {
105
        return PropertyKind::Navigation();
106
    }
107
108
    /**
109
     * Creates two navigation properties representing an association between two entity types.
110
     *
111
     * @param  EdmNavigationPropertyInfo $propertyInfo information to create the navigation property
112
     * @param  EdmNavigationPropertyInfo $partnerInfo  information to create the partner navigation property
113
     * @return EdmNavigationProperty     created navigation property
114
     */
115
    public static function CreateNavigationPropertyWithPartnerFromInfo(
116
        EdmNavigationPropertyInfo $propertyInfo,
117
        EdmNavigationPropertyInfo $partnerInfo
118
    ): EdmNavigationProperty {
119
        EdmUtil::CheckArgumentNull($propertyInfo->name, 'propertyInfo.Name');
120
        EdmUtil::CheckArgumentNull($propertyInfo->target, 'propertyInfo.Target');
121
        EdmUtil::CheckArgumentNull($partnerInfo->name, 'partnerInfo.Name');
122
        EdmUtil::CheckArgumentNull($partnerInfo->target, 'partnerInfo.Target');
123
124
        $end1 = new EdmNavigationProperty(
125
            $partnerInfo->target,
126
            $propertyInfo->name,
127
            self::createNavigationPropertyType(
128
                $propertyInfo->target,
129
                $propertyInfo->targetMultiplicity
130
            ),
131
            $propertyInfo->dependentProperties,
132
            $propertyInfo->containsTarget,
133
            $propertyInfo->onDelete
134
        );
135
136
        $end2 = new EdmNavigationProperty(
137
            $propertyInfo->target,
138
            $partnerInfo->name,
139
            self::createNavigationPropertyType(
140
                $partnerInfo->target,
141
                $partnerInfo->targetMultiplicity
142
            ),
143
            $partnerInfo->dependentProperties,
144
            $partnerInfo->containsTarget,
145
            $partnerInfo->onDelete
146
        );
147
148
        $end1->partner = $end2;
149
        $end2->partner = $end1;
150
        return $end1;
151
    }
152
153
154
    /**
155
     * Creates two navigation properties representing an association between two entity types.
156
     *
157
     * @param  string                $propertyName               navigation property name
158
     * @param  ITypeReference        $propertyType               type of the navigation property
159
     * @param  IStructuralProperty[] $dependentProperties        dependent properties of the navigation source
160
     * @param  bool                  $containsTarget             a value indicating whether the navigation source logically contains the navigation target
161
     * @param  OnDeleteAction        $onDelete                   action to take upon deletion of an instance of the navigation source
162
     * @param  string                $partnerPropertyName        navigation partner property name
163
     * @param  ITypeReference        $partnerPropertyType        type of the navigation partner property
164
     * @param  IStructuralProperty[] $partnerDependentProperties dependent properties of the navigation target
165
     * @param  bool                  $partnerContainsTarget      a value indicating whether the navigation target logically contains the navigation source
166
     * @param  OnDeleteAction        $partnerOnDelete            action to take upon deletion of an instance of the navigation target
167
     * @return EdmNavigationProperty navigation property
168
     */
169
    public static function CreateNavigationPropertyWithPartner(
170
        string $propertyName,
171
        ITypeReference $propertyType,
172
        array $dependentProperties,
173
        bool $containsTarget,
174
        OnDeleteAction $onDelete,
175
        string $partnerPropertyName,
176
        ITypeReference $partnerPropertyType,
177
        array $partnerDependentProperties,
178
        bool $partnerContainsTarget,
179
        OnDeleteAction $partnerOnDelete
180
    ): EdmNavigationProperty {
181
        $declaringType = self::GetEntityType($partnerPropertyType);
182
        if ($declaringType == null) {
183
            throw new ArgumentException(
184
                StringConst::Constructable_EntityTypeOrCollectionOfEntityTypeExpected('partnerPropertyType')
185
            );
186
        }
187
188
        $partnerDeclaringType = self::GetEntityType($propertyType);
189
        if ($partnerDeclaringType == null) {
190
            throw new ArgumentException(
191
                StringConst::Constructable_EntityTypeOrCollectionOfEntityTypeExpected('propertyType')
192
            );
193
        }
194
195
        $end1 = new EdmNavigationProperty(
196
            $declaringType,
197
            $propertyName,
198
            $propertyType,
199
            $dependentProperties,
200
            $containsTarget,
201
            $onDelete
202
        );
203
204
        $end2 = new EdmNavigationProperty(
205
            $partnerDeclaringType,
206
            $partnerPropertyName,
207
            $partnerPropertyType,
208
            $partnerDependentProperties,
209
            $partnerContainsTarget,
210
            $partnerOnDelete
211
        );
212
213
        $end1->partner = $end2;
214
        $end2->partner = $end1;
215
        return $end1;
216
    }
217
218
    private static function GetEntityType(ITypeReference $type): ?IEntityType
219
    {
220
        $entityType = null;
221
        if ($type->IsEntity()) {
222
            /** @var IEntityType $entityType */
223
            $entityType = $type->getDefinition();
224
        } elseif ($type->IsCollection()) {
225
            $collectionDef = $type->getDefinition();
226
            assert($collectionDef instanceof ICollectionType);
227
            $type = $collectionDef->getElementType();
228
            if ($type->IsEntity()) {
229
                /** @var IEntityType $entityType */
230
                $entityType = $type->getDefinition();
231
                assert($entityType instanceof IEntityType);
232
            }
233
        }
234
235
        return $entityType;
236
    }
237
238
    private static function createNavigationPropertyType(
239
        IEntityType $entityType,
240
        Multiplicity $multiplicity
241
    ): ITypeReference {
242
        switch ($multiplicity) {
243
            case Multiplicity::ZeroOrOne():
244
                return new EdmEntityTypeReference($entityType, true);
245
246
            case Multiplicity::One():
247
                return new EdmEntityTypeReference($entityType, false);
248
249
            case Multiplicity::Many():
250
                return EdmCoreModel::GetCollection(new EdmEntityTypeReference($entityType, false));
251
252
            default:
253
                throw new ArgumentOutOfRangeException(
254
                    StringConst::UnknownEnumVal_Multiplicity($multiplicity->getKey())
255
                );
256
        }
257
    }
258
}
259