Failed Conditions
Push — master ( 2b713c...735d0a )
by Alex
16s queued 13s
created

EdmModelCsdlSchemaWriter::writeInlineExpression()   C

Complexity

Conditions 13
Paths 24

Size

Total Lines 97
Code Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 83
nc 24
nop 1
dl 0
loc 97
rs 5.6642
c 0
b 0
f 0

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\Csdl\Internal\Serialization;
7
8
use AlgoWeb\ODataMetadata\Csdl\Internal\EdmValueWriter;
9
use AlgoWeb\ODataMetadata\CsdlConstants;
10
use AlgoWeb\ODataMetadata\EdmConstants;
11
use AlgoWeb\ODataMetadata\EdmUtil;
12
use AlgoWeb\ODataMetadata\Enums\ConcurrencyMode;
13
use AlgoWeb\ODataMetadata\Enums\ExpressionKind;
14
use AlgoWeb\ODataMetadata\Enums\FunctionParameterMode;
15
use AlgoWeb\ODataMetadata\Enums\Multiplicity;
16
use AlgoWeb\ODataMetadata\Enums\OnDeleteAction;
17
use AlgoWeb\ODataMetadata\Enums\PrimitiveTypeKind;
18
use AlgoWeb\ODataMetadata\Exception\InvalidOperationException;
19
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IDirectValueAnnotation;
20
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IPropertyValueBinding;
21
use AlgoWeb\ODataMetadata\Interfaces\Annotations\ITypeAnnotation;
22
use AlgoWeb\ODataMetadata\Interfaces\Annotations\IValueAnnotation;
23
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IApplyExpression;
24
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IAssertTypeExpression;
25
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IBinaryConstantExpression;
26
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IBooleanConstantExpression;
27
use AlgoWeb\ODataMetadata\Interfaces\Expressions\ICollectionExpression;
28
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IDateTimeConstantExpression;
29
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IDateTimeOffsetConstantExpression;
30
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IDecimalConstantExpression;
31
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IEntitySetReferenceExpression;
32
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IEnumMemberReferenceExpression;
33
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IExpression;
34
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IFloatingConstantExpression;
35
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IFunctionReferenceExpression;
36
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IGuidConstantExpression;
37
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IIfExpression;
38
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IIntegerConstantExpression;
39
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IIsTypeExpression;
40
use AlgoWeb\ODataMetadata\Interfaces\Expressions\ILabeledExpression;
41
use AlgoWeb\ODataMetadata\Interfaces\Expressions\INullExpression;
42
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IParameterReferenceExpression;
43
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IPathExpression;
44
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IPropertyReferenceExpression;
45
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IRecordExpression;
46
use AlgoWeb\ODataMetadata\Interfaces\Expressions\IStringConstantExpression;
47
use AlgoWeb\ODataMetadata\Interfaces\Expressions\ITimeConstantExpression;
48
use AlgoWeb\ODataMetadata\Interfaces\Expressions\RecordExpression\IPropertyConstructor;
49
use AlgoWeb\ODataMetadata\Interfaces\IBinaryTypeReference;
50
use AlgoWeb\ODataMetadata\Interfaces\ICollectionType;
51
use AlgoWeb\ODataMetadata\Interfaces\IComplexType;
52
use AlgoWeb\ODataMetadata\Interfaces\IDecimalTypeReference;
53
use AlgoWeb\ODataMetadata\Interfaces\IDocumentation;
54
use AlgoWeb\ODataMetadata\Interfaces\IEntityContainer;
55
use AlgoWeb\ODataMetadata\Interfaces\IEntitySet;
56
use AlgoWeb\ODataMetadata\Interfaces\IEntityType;
57
use AlgoWeb\ODataMetadata\Interfaces\IEnumMember;
58
use AlgoWeb\ODataMetadata\Interfaces\IEnumType;
59
use AlgoWeb\ODataMetadata\Interfaces\IFunction;
60
use AlgoWeb\ODataMetadata\Interfaces\IFunctionImport;
61
use AlgoWeb\ODataMetadata\Interfaces\IFunctionParameter;
62
use AlgoWeb\ODataMetadata\Interfaces\IModel;
63
use AlgoWeb\ODataMetadata\Interfaces\INavigationProperty;
64
use AlgoWeb\ODataMetadata\Interfaces\IProperty;
65
use AlgoWeb\ODataMetadata\Interfaces\ISchemaElement;
66
use AlgoWeb\ODataMetadata\Interfaces\ISchemaType;
67
use AlgoWeb\ODataMetadata\Interfaces\ISpatialTypeReference;
68
use AlgoWeb\ODataMetadata\Interfaces\IStringTypeReference;
69
use AlgoWeb\ODataMetadata\Interfaces\IStructuralProperty;
70
use AlgoWeb\ODataMetadata\Interfaces\ITemporalTypeReference;
71
use AlgoWeb\ODataMetadata\Interfaces\ITerm;
72
use AlgoWeb\ODataMetadata\Interfaces\ITypeReference;
73
use AlgoWeb\ODataMetadata\Interfaces\IValueTerm;
74
use AlgoWeb\ODataMetadata\Interfaces\Values\IPrimitiveValue;
75
use AlgoWeb\ODataMetadata\Interfaces\Values\IStringValue;
76
use AlgoWeb\ODataMetadata\StringConst;
77
use AlgoWeb\ODataMetadata\Version;
78
use ReflectionFunction;
79
use ReflectionMethod;
80
use ReflectionNamedType;
81
use XMLWriter;
82
83
class EdmModelCsdlSchemaWriter implements IEdmModelCsdlSchemaWriter
84
{
85
    /**
86
     * @var XMLWriter
87
     */
88
    protected $xmlWriter;
89
    /**
90
     * @var Version
91
     */
92
    protected $version;
93
    /**
94
     * @var array<string, string>
95
     */
96
    private $namespaceAliasMappings;
97
    /**
98
     * @var IModel
99
     */
100
    private $model;
101
102
    /**
103
     * EdmModelCsdlSchemaWriter constructor.
104
     * @param IModel    $model
105
     * @param array     $namespaceAliasMappings
106
     * @param Version   $version
107
     * @param XMLWriter $xmlWriter
108
     */
109
    public function __construct(IModel $model, array $namespaceAliasMappings, Version $version, XMLWriter $xmlWriter)
110
    {
111
        $this->xmlWriter              = $xmlWriter;
112
        $this->version                = $version;
113
        $this->namespaceAliasMappings = $namespaceAliasMappings;
114
        $this->model                  = $model;
115
    }
116
117
    /**
118
     * @param  IValueTerm           $term
119
     * @param  bool                 $inlineType
120
     * @throws \ReflectionException
121
     */
122
    public function writeValueTermElementHeader(IValueTerm $term, bool $inlineType): void
123
    {
124
        $this->xmlWriter->startElement(CsdlConstants::Element_ValueTerm);
125
        $this->writeRequiredAttribute(
126
            CsdlConstants::Attribute_Name,
127
            $term->getName(),
128
            [EdmValueWriter::class, 'stringAsXml']
129
        );
130
        if ($inlineType && null !== $term->getType()) {
131
            $this->writeRequiredAttribute(
132
                CsdlConstants::Attribute_Type,
133
                $term->getType(),
134
                [$this, 'typeReferenceAsXml']
135
            );
136
        }
137
    }
138
139
    /**
140
     * @param  INavigationProperty  $navigationProperty
141
     * @throws \ReflectionException
142
     */
143
    public function writeAssociationElementHeader(INavigationProperty $navigationProperty): void
144
    {
145
        $this->xmlWriter->startElement(CsdlConstants::Element_Association);
146
        $this->writeRequiredAttribute(
147
            CsdlConstants::Attribute_Name,
148
            $this->model->getAssociationName($navigationProperty),
149
            [EdmValueWriter::class, 'stringAsXml']
150
        );
151
    }
152
153
    /**
154
     * @param  IEntitySet           $entitySet
155
     * @param  INavigationProperty  $navigationProperty
156
     * @throws \ReflectionException
157
     */
158
    public function writeAssociationSetElementHeader(
159
        IEntitySet $entitySet,
160
        INavigationProperty $navigationProperty
161
    ): void {
162
        $this->xmlWriter->startElement(CsdlConstants::Element_AssociationSet);
163
        $this->writeRequiredAttribute(
164
            CsdlConstants::Attribute_Name,
165
            $this->model->getAssociationSetName($entitySet, $navigationProperty),
166
            [EdmValueWriter::class, 'stringAsXml']
167
        );
168
        $this->writeRequiredAttribute(
169
            CsdlConstants::Attribute_Association,
170
            $this->model->getAssociationFullName($navigationProperty),
171
            [EdmValueWriter::class, 'stringAsXml']
172
        );
173
    }
174
175
    /**
176
     * @param  IComplexType         $complexType
177
     * @throws \ReflectionException
178
     */
179
    public function writeComplexTypeElementHeader(IComplexType $complexType): void
180
    {
181
        $this->xmlWriter->startElement(CsdlConstants::Element_ComplexType);
182
        $this->writeRequiredAttribute(
183
            CsdlConstants::Attribute_Name,
184
            $complexType->getName(),
185
            [EdmValueWriter::class, 'stringAsXml']
186
        );
187
        $this->writeOptionalAttribute(
188
            CsdlConstants::Attribute_BaseType,
189
            $complexType->baseComplexType(),
190
            null,
191
            [$this, 'typeDefinitionAsXml']
192
        );
193
        $this->writeOptionalAttribute(
194
            CsdlConstants::Attribute_Abstract,
195
            $complexType->isAbstract(),
196
            CsdlConstants::Default_Abstract,
197
            [EdmValueWriter::class, 'booleanAsXml']
198
        );
199
    }
200
201
    /**
202
     * @param  IEnumType            $enumType
203
     * @throws \ReflectionException
204
     */
205
    public function writeEnumTypeElementHeader(IEnumType $enumType): void
206
    {
207
        $this->xmlWriter->startElement(CsdlConstants::Element_EnumType);
208
        $this->writeRequiredAttribute(
209
            CsdlConstants::Attribute_Name,
210
            $enumType->getName(),
211
            [EdmValueWriter::class, 'stringAsXml']
212
        );
213
        if ($enumType->getUnderlyingType()->getPrimitiveKind() != PrimitiveTypeKind::Int32()) {
214
            $this->writeRequiredAttribute(
215
                CsdlConstants::Attribute_UnderlyingType,
216
                $enumType->getUnderlyingType(),
217
                [$this, 'typeDefinitionAsXml']
218
            );
219
        }
220
221
        $this->writeOptionalAttribute(
222
            CsdlConstants::Attribute_IsFlags,
223
            $enumType->isFlags(),
224
            CsdlConstants::Default_IsFlags,
225
            [EdmValueWriter::class, 'booleanAsXml']
226
        );
227
    }
228
229
    public function writeDocumentationElement(IDocumentation $documentation): void
230
    {
231
        $this->xmlWriter->startElement(CsdlConstants::Element_Documentation);
232
233
        $summary = $documentation->getSummary();
234
        if (null !== $summary && !empty($summary)) {
235
            $this->xmlWriter->startElement(CsdlConstants::Element_Summary);
236
            $this->xmlWriter->text($summary);
237
            $this->writeEndElement();
238
        }
239
240
        $descript = $documentation->getDescription();
241
        if (null !== $descript && !empty($descript)) {
242
            $this->xmlWriter->startElement(CsdlConstants::Element_LongDescription);
243
            $this->xmlWriter->text($descript);
244
            $this->writeEndElement();
245
        }
246
247
        $this->writeEndElement();
248
    }
249
250
    /**
251
     * @param  IEntitySet           $entitySet
252
     * @param  INavigationProperty  $property
253
     * @throws \ReflectionException
254
     */
255
    public function writeAssociationSetEndElementHeader(IEntitySet $entitySet, INavigationProperty $property): void
256
    {
257
        $this->xmlWriter->startElement(CsdlConstants::Element_End);
258
        $this->writeRequiredAttribute(
259
            CsdlConstants::Attribute_Role,
260
            $this->model->getAssociationEndName($property),
261
            [EdmValueWriter::class, 'stringAsXml']
262
        );
263
        $this->writeRequiredAttribute(
264
            CsdlConstants::Attribute_EntitySet,
265
            $entitySet->getName(),
266
            [EdmValueWriter::class, 'stringAsXml']
267
        );
268
    }
269
270
    /**
271
     * @param  INavigationProperty  $associationEnd
272
     * @throws \ReflectionException
273
     */
274
    public function writeAssociationEndElementHeader(INavigationProperty $associationEnd): void
275
    {
276
        $this->xmlWriter->startElement(CsdlConstants::Element_End);
277
        $declaringType = $associationEnd->getDeclaringType();
278
        assert($declaringType instanceof IEntityType);
279
        $this->writeRequiredAttribute(
280
            CsdlConstants::Attribute_Type,
281
            $declaringType->fullName(),
282
            [EdmValueWriter::class, 'stringAsXml']
283
        );
284
        $this->writeRequiredAttribute(
285
            CsdlConstants::Attribute_Role,
286
            $this->model->getAssociationEndName($associationEnd),
287
            [EdmValueWriter::class, 'stringAsXml']
288
        );
289
        $this->writeRequiredAttribute(
290
            CsdlConstants::Attribute_Multiplicity,
291
            $associationEnd->multiplicity(),
292
            [self::class, 'multiplicityAsXml']
293
        );
294
    }
295
296
    /**
297
     * @param  IEntityContainer     $container
298
     * @throws \ReflectionException
299
     */
300
    public function writeEntityContainerElementHeader(IEntityContainer $container): void
301
    {
302
        $this->xmlWriter->startElement(CsdlConstants::Element_EntityContainer);
303
        $this->writeRequiredAttribute(
304
            CsdlConstants::Attribute_Name,
305
            $container->getName(),
306
            [EdmValueWriter::class, 'stringAsXml']
307
        );
308
        if ($container->isDefault()) {
309
            $this->xmlWriter->writeAttributeNs(
310
                CsdlConstants::Prefix_ODataMetadata,
311
                CsdlConstants::Attribute_IsDefaultEntityContainer,
312
                null,
313
                'true'
314
            );
315
        }
316
        if ($container->isLazyLoadEnabled()) {
317
            $this->xmlWriter->writeAttributeNs(
318
                CsdlConstants::Prefix_Annotations,
319
                CsdlConstants::Attribute_LazyLoadingEnabled,
320
                null,
321
                'true'
322
            );
323
        }
324
    }
325
326
    /**
327
     * @param  IEntitySet           $entitySet
328
     * @throws \ReflectionException
329
     */
330
    public function writeEntitySetElementHeader(IEntitySet $entitySet): void
331
    {
332
        $this->xmlWriter->startElement(CsdlConstants::Element_EntitySet);
333
        $this->writeRequiredAttribute(
334
            CsdlConstants::Attribute_Name,
335
            $entitySet->getName(),
336
            [EdmValueWriter::class, 'stringAsXml']
337
        );
338
        $this->writeRequiredAttribute(
339
            CsdlConstants::Attribute_EntityType,
340
            $entitySet->getElementType()->fullName(),
341
            [EdmValueWriter::class, 'stringAsXml']
342
        );
343
    }
344
345
    /**
346
     * @param  IEntityType          $entityType
347
     * @throws \ReflectionException
348
     */
349
    public function writeEntityTypeElementHeader(IEntityType $entityType): void
350
    {
351
        $this->xmlWriter->startElement(CsdlConstants::Element_EntityType);
352
        $this->writeRequiredAttribute(
353
            CsdlConstants::Attribute_Name,
354
            $entityType->getName(),
355
            [EdmValueWriter::class, 'stringAsXml']
356
        );
357
        $this->writeOptionalAttribute(
358
            CsdlConstants::Attribute_BaseType,
359
            $entityType->baseEntityType(),
360
            null,
361
            [$this, 'typeDefinitionAsXml']
362
        );
363
        $this->writeOptionalAttribute(
364
            CsdlConstants::Attribute_Abstract,
365
            $entityType->isAbstract(),
366
            CsdlConstants::Default_Abstract,
367
            [EdmValueWriter::class, 'booleanAsXml']
368
        );
369
        $this->writeOptionalAttribute(
370
            CsdlConstants::Attribute_OpenType,
371
            $entityType->isOpen(),
372
            CsdlConstants::Default_OpenType,
373
            [EdmValueWriter::class, 'booleanAsXml']
374
        );
375
    }
376
377
    public function writeDeclaredKeyPropertiesElementHeader(): void
378
    {
379
        $this->xmlWriter->startElement(CsdlConstants::Element_Key);
380
    }
381
382
    /**
383
     * @param  IStructuralProperty  $property
384
     * @throws \ReflectionException
385
     */
386
    public function writePropertyRefElement(IStructuralProperty $property): void
387
    {
388
        $this->xmlWriter->startElement(CsdlConstants::Element_PropertyRef);
389
        $this->writeRequiredAttribute(
390
            CsdlConstants::Attribute_Name,
391
            $property->getName(),
392
            [EdmValueWriter::class, 'stringAsXml']
393
        );
394
        $this->writeEndElement();
395
    }
396
397
    /**
398
     * @param  INavigationProperty  $member
399
     * @throws \ReflectionException
400
     */
401
    public function writeNavigationPropertyElementHeader(INavigationProperty $member): void
402
    {
403
        $this->xmlWriter->startElement(CsdlConstants::Element_NavigationProperty);
404
        $this->writeRequiredAttribute(
405
            CsdlConstants::Attribute_Name,
406
            $member->getName(),
407
            [EdmValueWriter::class, 'stringAsXml']
408
        );
409
        $this->writeRequiredAttribute(
410
            CsdlConstants::Attribute_Relationship,
411
            $this->model->getAssociationFullName($member),
412
            [EdmValueWriter::class, 'stringAsXml']
413
        );
414
        $this->writeRequiredAttribute(
415
            CsdlConstants::Attribute_ToRole,
416
            $this->model->getAssociationEndName($member->getPartner()),
417
            [EdmValueWriter::class, 'stringAsXml']
418
        );
419
        $this->writeRequiredAttribute(
420
            CsdlConstants::Attribute_FromRole,
421
            $this->model->getAssociationEndName($member),
422
            [EdmValueWriter::class, 'stringAsXml']
423
        );
424
        $this->writeOptionalAttribute(
425
            CsdlConstants::Attribute_ContainsTarget,
426
            $member->containsTarget(),
427
            CsdlConstants::Default_ContainsTarget,
428
            [EdmValueWriter::class, 'booleanAsXml']
429
        );
430
    }
431
432
    /**
433
     * @param  string               $elementName
434
     * @param  OnDeleteAction       $operationAction
435
     * @throws \ReflectionException
436
     */
437
    public function writeOperationActionElement(string $elementName, OnDeleteAction $operationAction): void
438
    {
439
        $this->xmlWriter->startElement($elementName);
440
        $this->writeRequiredAttribute(
441
            CsdlConstants::Attribute_Action,
442
            strval($operationAction),
443
            [EdmValueWriter::class, 'stringAsXml']
444
        );
445
        $this->writeEndElement();
446
    }
447
448
    /**
449
     * @param  EdmSchema            $schema
450
     * @param  string|null          $alias
451
     * @param  array                $mappings
452
     * @throws \ReflectionException
453
     */
454
    public function writeSchemaElementHeader(EdmSchema $schema, ?string $alias, array $mappings): void
455
    {
456
        $xmlNamespace = self::getCsdlNamespace($this->version);
0 ignored issues
show
Unused Code introduced by
The assignment to $xmlNamespace is dead and can be removed.
Loading history...
457
        $this->xmlWriter->startElement(CsdlConstants::Element_Schema);
458
        $this->writeOptionalAttribute(
459
            CsdlConstants::Attribute_Namespace,
460
            $schema->getNamespace(),
461
            '',
462
            [EdmValueWriter::class, 'stringAsXml']
463
        );
464
        $this->writeOptionalAttribute(
465
            CsdlConstants::Attribute_Alias,
466
            $alias,
467
            null,
468
            [EdmValueWriter::class, 'stringAsXml']
469
        );
470
        foreach ($mappings as $mappingKey => $mappingValue) {
471
            $this->xmlWriter->writeAttributeNs(EdmConstants::XmlNamespacePrefix, $mappingKey, null, $mappingValue);
472
        }
473
    }
474
475
    /**
476
     * @param  string               $annotationsTarget
477
     * @throws \ReflectionException
478
     */
479
    public function writeAnnotationsElementHeader(string $annotationsTarget): void
480
    {
481
        $this->xmlWriter->startElement(CsdlConstants::Element_Annotations);
482
        $this->writeRequiredAttribute(
483
            CsdlConstants::Attribute_Target,
484
            $annotationsTarget,
485
            [EdmValueWriter::class, 'stringAsXml']
486
        );
487
    }
488
489
    /**
490
     * @param  IStructuralProperty  $property
491
     * @param  bool                 $inlineType
492
     * @throws \ReflectionException
493
     */
494
    public function writeStructuralPropertyElementHeader(IStructuralProperty $property, bool $inlineType): void
495
    {
496
        $this->xmlWriter->startElement(CsdlConstants::Element_Property);
497
        $this->writeRequiredAttribute(
498
            CsdlConstants::Attribute_Name,
499
            $property->getName(),
500
            [EdmValueWriter::class, 'stringAsXml']
501
        );
502
        if ($inlineType) {
503
            $this->writeRequiredAttribute(
504
                CsdlConstants::Attribute_Type,
505
                $property->getType(),
506
                [$this, 'typeReferenceAsXml']
507
            );
508
        }
509
510
        $this->writeOptionalAttribute(
511
            CsdlConstants::Attribute_ConcurrencyMode,
512
            $property->getConcurrencyMode(),
513
            CsdlConstants::$Default_ConcurrencyMode,
514
            [self::class, 'concurrencyModeAsXml']
515
        );
516
        $this->writeOptionalAttribute(
517
            CsdlConstants::Attribute_DefaultValue,
518
            $property->getDefaultValueString(),
519
            null,
520
            [EdmValueWriter::class, 'stringAsXml']
521
        );
522
    }
523
524
    /**
525
     * @param  IEnumMember          $member
526
     * @throws \ReflectionException
527
     */
528
    public function writeEnumMemberElementHeader(IEnumMember $member): void
529
    {
530
        $this->xmlWriter->startElement(CsdlConstants::Element_Member);
531
        $this->writeRequiredAttribute(
532
            CsdlConstants::Attribute_Name,
533
            $member->getName(),
534
            [EdmValueWriter::class, 'stringAsXml']
535
        );
536
        $isExplicit = $member->isValueExplicit($this->model);
537
        if (null === $isExplicit || $isExplicit) {
538
            $this->writeRequiredAttribute(
539
                CsdlConstants::Attribute_Value,
540
                $member->getValue(),
541
                [EdmValueWriter::class, 'primitiveValueAsXml']
542
            );
543
        }
544
    }
545
546
    /**
547
     * @param  ITypeReference       $reference
548
     * @throws \ReflectionException
549
     */
550
    public function writeNullableAttribute(ITypeReference $reference): void
551
    {
552
        $this->writeOptionalAttribute(
553
            CsdlConstants::Attribute_Nullable,
554
            $reference->getNullable(),
555
            CsdlConstants::Default_Nullable,
556
            [EdmValueWriter::class, 'booleanAsXml']
557
        );
558
    }
559
560
    /**
561
     * @param  IBinaryTypeReference $reference
562
     * @throws \ReflectionException
563
     */
564
    public function writeBinaryTypeAttributes(IBinaryTypeReference $reference): void
565
    {
566
        if ($reference->isUnBounded()) {
567
            $this->writeRequiredAttribute(
568
                CsdlConstants::Attribute_MaxLength,
569
                CsdlConstants::Value_Max,
570
                [EdmValueWriter::class, 'stringAsXml']
571
            );
572
        } else {
573
            $this->writeOptionalAttribute(
574
                CsdlConstants::Attribute_MaxLength,
575
                $reference->getMaxLength(),
576
                null,
577
                [EdmValueWriter::class, 'intAsXml']
578
            );
579
        }
580
581
        $this->writeOptionalAttribute(
582
            CsdlConstants::Attribute_FixedLength,
583
            $reference->isFixedLength(),
584
            null,
585
            [EdmValueWriter::class, 'booleanAsXml']
586
        );
587
    }
588
589
    /**
590
     * @param  IDecimalTypeReference $reference
591
     * @throws \ReflectionException
592
     */
593
    public function writeDecimalTypeAttributes(IDecimalTypeReference $reference): void
594
    {
595
        $this->writeOptionalAttribute(
596
            CsdlConstants::Attribute_Precision,
597
            $reference->getPrecision(),
598
            null,
599
            [EdmValueWriter::class, 'intAsXml']
600
        );
601
        $this->writeOptionalAttribute(
602
            CsdlConstants::Attribute_Scale,
603
            $reference->getScale(),
604
            null,
605
            [EdmValueWriter::class, 'intAsXml']
606
        );
607
    }
608
609
    /**
610
     * @param  ISpatialTypeReference $reference
611
     * @throws \ReflectionException
612
     */
613
    public function writeSpatialTypeAttributes(ISpatialTypeReference $reference): void
614
    {
615
        $this->writeRequiredAttribute(
616
            CsdlConstants::Attribute_Srid,
617
            $reference->getSpatialReferenceIdentifier(),
618
            [self::class, 'sridAsXml']
619
        );
620
    }
621
622
    /**
623
     * @param  IStringTypeReference $reference
624
     * @throws \ReflectionException
625
     */
626
    public function writeStringTypeAttributes(IStringTypeReference $reference): void
627
    {
628
        $this->writeOptionalAttribute(
629
            CsdlConstants::Attribute_Collation,
630
            $reference->getCollation(),
631
            null,
632
            [EdmValueWriter::class, 'stringAsXml']
633
        );
634
        if ($reference->isUnbounded()) {
635
            $this->writeRequiredAttribute(
636
                CsdlConstants::Attribute_MaxLength,
637
                CsdlConstants::Value_Max,
638
                [EdmValueWriter::class, 'stringAsXml']
639
            );
640
        } else {
641
            $this->writeOptionalAttribute(
642
                CsdlConstants::Attribute_MaxLength,
643
                $reference->getMaxLength(),
644
                null,
645
                [EdmValueWriter::class, 'intAsXml']
646
            );
647
        }
648
649
        $this->writeOptionalAttribute(
650
            CsdlConstants::Attribute_FixedLength,
651
            $reference->isFixedLength(),
652
            null,
653
            [EdmValueWriter::class, 'booleanAsXml']
654
        );
655
        $this->writeOptionalAttribute(
656
            CsdlConstants::Attribute_Unicode,
657
            $reference->isUnicode(),
658
            null,
659
            [EdmValueWriter::class, 'booleanAsXml']
660
        );
661
    }
662
663
    /**
664
     * @param  ITemporalTypeReference $reference
665
     * @throws \ReflectionException
666
     */
667
    public function writeTemporalTypeAttributes(ITemporalTypeReference $reference): void
668
    {
669
        $this->writeOptionalAttribute(
670
            CsdlConstants::Attribute_Precision,
671
            $reference->getPrecision(),
672
            null,
673
            [EdmValueWriter::class, 'intAsXml']
674
        );
675
    }
676
677
    public function writeReferentialConstraintElementHeader(INavigationProperty $constraint): void
678
    {
679
        $this->xmlWriter->startElement(CsdlConstants::Element_ReferentialConstraint);
680
    }
681
682
    /**
683
     * @param  INavigationProperty  $end
684
     * @throws \ReflectionException
685
     */
686
    public function writeReferentialConstraintPrincipalEndElementHeader(INavigationProperty $end): void
687
    {
688
        $this->xmlWriter->startElement(CsdlConstants::Element_Principal);
689
        $this->writeRequiredAttribute(
690
            CsdlConstants::Attribute_Role,
691
            $this->model->getAssociationEndName($end),
692
            [EdmValueWriter::class, 'stringAsXml']
693
        );
694
    }
695
696
    /**
697
     * @param  INavigationProperty  $end
698
     * @throws \ReflectionException
699
     */
700
    public function writeReferentialConstraintDependentEndElementHeader(INavigationProperty $end): void
701
    {
702
        $this->xmlWriter->startElement(CsdlConstants::Element_Dependent);
703
        $this->writeRequiredAttribute(
704
            CsdlConstants::Attribute_Role,
705
            $this->model->getAssociationEndName($end),
706
            [EdmValueWriter::class, 'stringAsXml']
707
        );
708
    }
709
710
    /**
711
     * @param  string               $usingNamespace
712
     * @param  string               $alias
713
     * @throws \ReflectionException
714
     */
715
    public function writeNamespaceUsingElement(string $usingNamespace, string $alias): void
716
    {
717
        $this->xmlWriter->startElement(CsdlConstants::Element_Using);
718
        $this->writeRequiredAttribute(
719
            CsdlConstants::Attribute_Namespace,
720
            $usingNamespace,
721
            [EdmValueWriter::class, 'stringAsXml']
722
        );
723
        $this->writeRequiredAttribute(CsdlConstants::Attribute_Alias, $alias, [EdmValueWriter::class, 'stringAsXml']);
724
        $this->writeEndElement();
725
    }
726
727
    /**
728
     * @param  IDirectValueAnnotation                                 $annotation
729
     * @throws \AlgoWeb\ODataMetadata\Exception\NotSupportedException
730
     */
731
    public function writeAnnotationStringAttribute(IDirectValueAnnotation $annotation): void
732
    {
733
        $edmValue = $annotation->getValue();
734
        if ($edmValue instanceof IPrimitiveValue) {
735
            $this->xmlWriter->writeAttributeNs(
736
                '',
737
                $annotation->getName(),
738
                $annotation->getNamespaceUri(),
739
                EdmValueWriter::primitiveValueAsXml($edmValue)
740
            );
741
        }
742
    }
743
744
    public function writeAnnotationStringElement(IDirectValueAnnotation $annotation): void
745
    {
746
        $edmValue = $annotation->getValue();
747
        if ($edmValue instanceof IStringValue) {
748
            $this->xmlWriter->writeRaw($edmValue->getValue());
749
        }
750
    }
751
752
    /**
753
     * @param  IFunction            $function
754
     * @param  bool                 $inlineReturnType
755
     * @throws \ReflectionException
756
     */
757
    public function writeFunctionElementHeader(IFunction $function, bool $inlineReturnType): void
758
    {
759
        $this->xmlWriter->startElement(CsdlConstants::Element_Function);
760
        $this->writeRequiredAttribute(
761
            CsdlConstants::Attribute_Name,
762
            $function->getName(),
763
            [EdmValueWriter::class, 'stringAsXml']
764
        );
765
        if ($inlineReturnType) {
766
            $this->writeRequiredAttribute(
767
                CsdlConstants::Attribute_ReturnType,
768
                $function->getReturnType(),
769
                [$this, 'typeReferenceAsXml']
770
            );
771
        }
772
    }
773
774
    public function writeDefiningExpressionElement(string $expression): void
775
    {
776
        $this->xmlWriter->startElement(CsdlConstants::Element_DefiningExpression);
777
        $this->xmlWriter->text($expression);
778
        $this->xmlWriter->endElement();
779
    }
780
781
    public function writeReturnTypeElementHeader()
782
    {
783
        $this->xmlWriter->startElement(CsdlConstants::Element_ReturnType);
784
    }
785
786
    /**
787
     * @param  IFunctionImport      $functionImport
788
     * @throws \ReflectionException
789
     */
790
    public function writeFunctionImportElementHeader(IFunctionImport $functionImport): void
791
    {
792
        // functionImport can't be Composable and sideEffecting at the same time.
793
        if ($functionImport->isComposable() && $functionImport->isSideEffecting()) {
794
            throw new InvalidOperationException(
795
                StringConst::EdmModel_Validator_Semantic_ComposableFunctionImportCannotBeSideEffecting(
796
                    $functionImport->getName()
797
                )
798
            );
799
        }
800
801
        $this->xmlWriter->startElement(CsdlConstants::Element_FunctionImport);
802
        $this->writeRequiredAttribute(
803
            CsdlConstants::Attribute_Name,
804
            $functionImport->getName(),
805
            [EdmValueWriter::class, 'stringAsXml']
806
        );
807
        $this->writeOptionalAttribute(
808
            CsdlConstants::Attribute_ReturnType,
809
            $functionImport->getReturnType(),
810
            null,
811
            [$this, 'typeReferenceAsXml']
812
        );
813
814
        // IsSideEffecting is optional, however its default applies to non-composable function imports only.
815
        // Composable function imports can't be side-effecting, so we don't emit false.
816
        if (!$functionImport->isComposable() &&
817
            $functionImport->isSideEffecting() != CsdlConstants::Default_IsSideEffecting) {
818
            $this->writeRequiredAttribute(
819
                CsdlConstants::Attribute_IsSideEffecting,
820
                $functionImport->isSideEffecting(),
821
                [EdmValueWriter::class, 'booleanAsXml']
822
            );
823
        }
824
825
        $this->writeOptionalAttribute(
826
            CsdlConstants::Attribute_IsComposable,
827
            $functionImport->isComposable(),
828
            CsdlConstants::Default_IsComposable,
829
            [EdmValueWriter::class, 'booleanAsXml']
830
        );
831
        $this->writeOptionalAttribute(
832
            CsdlConstants::Attribute_IsBindable,
833
            $functionImport->isBindable(),
834
            CsdlConstants::Default_IsBindable,
835
            [EdmValueWriter::class, 'booleanAsXml']
836
        );
837
        $entitySetReference = $functionImport->getEntitySet();
838
        if (null !== $functionImport->getEntitySet()) {
839
            if ($entitySetReference instanceof IEntitySetReferenceExpression) {
840
                $this->writeOptionalAttribute(
841
                    CsdlConstants::Attribute_EntitySet,
842
                    $entitySetReference->getReferencedEntitySet()->getName(),
843
                    null,
844
                    [EdmValueWriter::class, 'stringAsXml']
845
                );
846
            } else {
847
                $pathExpression = $functionImport->getEntitySet();
848
                if ($pathExpression instanceof IPathExpression) {
849
                    $this->writeOptionalAttribute(
850
                        CsdlConstants::Attribute_EntitySetPath,
851
                        $pathExpression->getPath(),
852
                        null,
853
                        [self::class, 'pathAsXml']
854
                    );
855
                } else {
856
                    throw new InvalidOperationException(
857
                        StringConst::EdmModel_Validator_Semantic_FunctionImportEntitySetExpressionIsInvalid(
858
                            $functionImport->getName()
859
                        )
860
                    );
861
                }
862
            }
863
        }
864
    }
865
866
    /**
867
     * @param  IFunctionParameter   $parameter
868
     * @param  bool                 $inlineType
869
     * @throws \ReflectionException
870
     */
871
    public function writeFunctionParameterElementHeader(IFunctionParameter $parameter, bool $inlineType): void
872
    {
873
        $this->xmlWriter->startElement(CsdlConstants::Element_Parameter);
874
        $this->writeRequiredAttribute(
875
            CsdlConstants::Attribute_Name,
876
            $parameter->getName(),
877
            [EdmValueWriter::class, 'stringAsXml']
878
        );
879
        if ($inlineType) {
880
            $this->writeRequiredAttribute(
881
                CsdlConstants::Attribute_Type,
882
                $parameter->getType(),
883
                [$this, 'typeReferenceAsXml']
884
            );
885
        }
886
887
        $this->writeOptionalAttribute(
888
            CsdlConstants::Attribute_Mode,
889
            $parameter->getMode(),
890
            CsdlConstants::$Default_FunctionParameterMode,
891
            [self::class, 'functionParameterModeAsXml']
892
        );
893
    }
894
895
    /**
896
     * @param  ICollectionType      $collectionType
897
     * @param  bool                 $inlineType
898
     * @throws \ReflectionException
899
     */
900
    public function writeCollectionTypeElementHeader(ICollectionType $collectionType, bool $inlineType): void
901
    {
902
        $this->xmlWriter->startElement(CsdlConstants::Element_CollectionType);
903
        if ($inlineType) {
904
            $this->writeRequiredAttribute(
905
                CsdlConstants::Attribute_ElementType,
906
                $collectionType->getElementType(),
907
                [$this, 'typeReferenceAsXml']
908
            );
909
        }
910
    }
911
912
    public function writeRowTypeElementHeader(): void
913
    {
914
        $this->xmlWriter->startElement(CsdlConstants::Element_RowType);
915
    }
916
917
    /**
918
     * @param  IExpression          $expression
919
     * @throws \ReflectionException
920
     */
921
    public function writeInlineExpression(IExpression $expression): void
922
    {
923
        if (method_exists($expression, 'getValue')) {
924
            EdmUtil::checkArgumentNull($expression->getValue(), 'expression->getValue');
925
        }
926
        switch ($expression->getExpressionKind()) {
927
            case ExpressionKind::BinaryConstant():
928
                assert($expression instanceof IBinaryConstantExpression);
929
                $this->writeRequiredAttribute(
930
                    CsdlConstants::Attribute_Binary,
931
                    $expression->getValue(),
932
                    [EdmValueWriter::class, 'binaryAsXml']
933
                );
934
                break;
935
            case ExpressionKind::BooleanConstant():
936
                assert($expression instanceof IBooleanConstantExpression);
937
                $this->writeRequiredAttribute(
938
                    CsdlConstants::Attribute_Bool,
939
                    $expression->getValue(),
940
                    [EdmValueWriter::class, 'booleanAsXml']
941
                );
942
                break;
943
            case ExpressionKind::DateTimeConstant():
944
                assert($expression instanceof IDateTimeConstantExpression);
945
                $this->writeRequiredAttribute(
946
                    CsdlConstants::Attribute_DateTime,
947
                    $expression->getValue(),
948
                    [EdmValueWriter::class, 'dateTimeAsXml']
949
                );
950
                break;
951
            case ExpressionKind::DateTimeOffsetConstant():
952
                assert($expression instanceof IDateTimeOffsetConstantExpression);
953
                $this->writeRequiredAttribute(
954
                    CsdlConstants::Attribute_DateTimeOffset,
955
                    $expression->getValue(),
956
                    [EdmValueWriter::class, 'dateTimeOffsetAsXml']
957
                );
958
                break;
959
            case ExpressionKind::DecimalConstant():
960
                assert($expression instanceof IDecimalConstantExpression);
961
                $this->writeRequiredAttribute(
962
                    CsdlConstants::Attribute_Decimal,
963
                    $expression->getValue(),
964
                    [EdmValueWriter::class, 'decimalAsXml']
965
                );
966
                break;
967
            case ExpressionKind::FloatingConstant():
968
                assert($expression instanceof IFloatingConstantExpression);
969
                $this->writeRequiredAttribute(
970
                    CsdlConstants::Attribute_Float,
971
                    $expression->getValue(),
972
                    [EdmValueWriter::class, 'floatAsXml']
973
                );
974
                break;
975
            case ExpressionKind::GuidConstant():
976
                assert($expression instanceof IGuidConstantExpression);
977
                $this->writeRequiredAttribute(
978
                    CsdlConstants::Attribute_Guid,
979
                    $expression->getValue(),
980
                    [EdmValueWriter::class, 'guidAsXml']
981
                );
982
                break;
983
            case ExpressionKind::IntegerConstant():
984
                assert($expression instanceof IIntegerConstantExpression);
985
                $this->writeRequiredAttribute(
986
                    CsdlConstants::Attribute_Int,
987
                    $expression->getValue(),
988
                    [EdmValueWriter::class, 'longAsXml']
989
                );
990
                break;
991
            case ExpressionKind::Path():
992
                assert($expression instanceof IPathExpression);
993
                $this->writeRequiredAttribute(
994
                    CsdlConstants::Attribute_Path,
995
                    $expression->getPath(),
996
                    [self::class, 'pathAsXml']
997
                );
998
                break;
999
            case ExpressionKind::StringConstant():
1000
                assert($expression instanceof IStringConstantExpression);
1001
                $this->writeRequiredAttribute(
1002
                    CsdlConstants::Attribute_String,
1003
                    $expression->getValue(),
1004
                    [EdmValueWriter::class, 'stringAsXml']
1005
                );
1006
                break;
1007
            case ExpressionKind::TimeConstant():
1008
                assert($expression instanceof ITimeConstantExpression);
1009
                $this->writeRequiredAttribute(
1010
                    CsdlConstants::Attribute_Time,
1011
                    $expression->getValue(),
1012
                    [EdmValueWriter::class, 'timeAsXml']
1013
                );
1014
                break;
1015
            default:
1016
                throw new InvalidOperationException(
1017
                    StringConst::UnknownEnumVal_ExpressionKind($expression->getExpressionKind()->getKey())
1018
                );
1019
        }
1020
    }
1021
1022
    /**
1023
     * @param  IValueAnnotation     $annotation
1024
     * @param  bool                 $isInline
1025
     * @throws \ReflectionException
1026
     */
1027
    public function writeValueAnnotationElementHeader(IValueAnnotation $annotation, bool $isInline): void
1028
    {
1029
        $this->xmlWriter->startElement(CsdlConstants::Element_ValueAnnotation);
1030
        $this->writeRequiredAttribute(CsdlConstants::Attribute_Term, $annotation->getTerm(), [$this, 'termAsXml']);
1031
        $this->writeOptionalAttribute(
1032
            CsdlConstants::Attribute_Qualifier,
1033
            $annotation->getQualifier(),
1034
            null,
1035
            [EdmValueWriter::class, 'stringAsXml']
1036
        );
1037
        if ($isInline) {
1038
            $this->writeInlineExpression($annotation->getValue());
1039
        }
1040
    }
1041
1042
    /**
1043
     * @param  ITypeAnnotation      $annotation
1044
     * @throws \ReflectionException
1045
     */
1046
    public function writeTypeAnnotationElementHeader(ITypeAnnotation $annotation): void
1047
    {
1048
        $this->xmlWriter->startElement(CsdlConstants::Element_TypeAnnotation);
1049
        $this->writeRequiredAttribute(CsdlConstants::Attribute_Term, $annotation->getTerm(), [$this, 'termAsXml']);
1050
        $this->writeOptionalAttribute(
1051
            CsdlConstants::Attribute_Qualifier,
1052
            $annotation->getQualifier(),
1053
            null,
1054
            [EdmValueWriter::class, 'stringAsXml']
1055
        );
1056
    }
1057
1058
    /**
1059
     * @param  IPropertyValueBinding $value
1060
     * @param  bool                  $isInline
1061
     * @throws \ReflectionException
1062
     */
1063
    public function writePropertyValueElementHeader(IPropertyValueBinding $value, bool $isInline): void
1064
    {
1065
        $this->xmlWriter->startElement(CsdlConstants::Element_PropertyValue);
1066
        $this->writeRequiredAttribute(
1067
            CsdlConstants::Attribute_Property,
1068
            $value->getBoundProperty()->getName(),
1069
            [EdmValueWriter::class, 'stringAsXml']
1070
        );
1071
        if ($isInline) {
1072
            $this->writeInlineExpression($value->getValue());
1073
        }
1074
    }
1075
1076
    /**
1077
     * @param  IRecordExpression    $expression
1078
     * @throws \ReflectionException
1079
     */
1080
    public function writeRecordExpressionElementHeader(IRecordExpression $expression)
1081
    {
1082
        $this->xmlWriter->startElement(CsdlConstants::Element_Record);
1083
        $this->writeOptionalAttribute(
1084
            CsdlConstants::Attribute_Type,
1085
            $expression->getDeclaredType(),
1086
            null,
1087
            [$this, 'typeReferenceAsXml']
1088
        );
1089
    }
1090
1091
    /**
1092
     * @param  IPropertyConstructor $constructor
1093
     * @param  bool                 $isInline
1094
     * @throws \ReflectionException
1095
     */
1096
    public function writePropertyConstructorElementHeader(IPropertyConstructor $constructor, bool $isInline): void
1097
    {
1098
        EdmUtil::checkArgumentNull($constructor->getName(), 'constructor->getName');
1099
        $this->xmlWriter->startElement(CsdlConstants::Element_PropertyValue);
1100
        $this->writeRequiredAttribute(
1101
            CsdlConstants::Attribute_Property,
1102
            $constructor->getName(),
1103
            [EdmValueWriter::class, 'stringAsXml']
1104
        );
1105
        if ($isInline) {
1106
            EdmUtil::checkArgumentNull($constructor->getValue(), 'constructor->getValue()');
1107
            $this->writeInlineExpression($constructor->getValue());
1108
        }
1109
    }
1110
1111
    public function writeStringConstantExpressionElement(IStringConstantExpression $expression): void
1112
    {
1113
        EdmUtil::checkArgumentNull($expression->getValue(), 'expression->getValue');
1114
        $this->xmlWriter->startElement(CsdlConstants::Element_String);
1115
        $this->xmlWriter->text(EdmValueWriter::stringAsXml($expression->getValue()));
1116
        $this->writeEndElement();
1117
    }
1118
1119
    public function writeBinaryConstantExpressionElement(IBinaryConstantExpression $expression): void
1120
    {
1121
        EdmUtil::checkArgumentNull($expression->getValue(), 'expression->getValue');
1122
        $this->xmlWriter->startElement(CsdlConstants::Element_String);
1123
        $this->xmlWriter->text(EdmValueWriter::binaryAsXml($expression->getValue()));
1124
        $this->writeEndElement();
1125
    }
1126
1127
    public function writeBooleanConstantExpressionElement(IBooleanConstantExpression $expression): void
1128
    {
1129
        $this->xmlWriter->startElement(CsdlConstants::Element_Bool);
1130
        $this->xmlWriter->text(EdmValueWriter::booleanAsXml($expression->getValue()));
1131
        $this->writeEndElement();
1132
    }
1133
1134
    public function writeNullConstantExpressionElement(INullExpression $expression): void
1135
    {
1136
        $this->xmlWriter->startElement(CsdlConstants::Element_Null);
1137
        $this->writeEndElement();
1138
    }
1139
1140
    public function writeDateTimeConstantExpressionElement(IDateTimeConstantExpression $expression): void
1141
    {
1142
        $this->xmlWriter->startElement(CsdlConstants::Element_DateTime);
1143
        $this->xmlWriter->text(EdmValueWriter::dateTimeAsXml($expression->getValue()));
1144
        $this->writeEndElement();
1145
    }
1146
1147
    public function writeDateTimeOffsetConstantExpressionElement(IDateTimeOffsetConstantExpression $expression): void
1148
    {
1149
        $this->xmlWriter->startElement(CsdlConstants::Element_DateTimeOffset);
1150
        $this->xmlWriter->text(EdmValueWriter::dateTimeOffsetAsXml($expression->getValue()));
1151
        $this->writeEndElement();
1152
    }
1153
1154
    public function writeDecimalConstantExpressionElement(IDecimalConstantExpression $expression): void
1155
    {
1156
        $this->xmlWriter->startElement(CsdlConstants::Element_Decimal);
1157
        $this->xmlWriter->text(EdmValueWriter::decimalAsXml($expression->getValue()));
1158
        $this->writeEndElement();
1159
    }
1160
1161
    public function writeFloatingConstantExpressionElement(IFloatingConstantExpression $expression): void
1162
    {
1163
        $this->xmlWriter->startElement(CsdlConstants::Element_Float);
1164
        $this->xmlWriter->text(EdmValueWriter::floatAsXml($expression->getValue()));
1165
        $this->writeEndElement();
1166
    }
1167
1168
    /**
1169
     * @param  IApplyExpression     $expression
1170
     * @param  bool                 $isFunction
1171
     * @throws \ReflectionException
1172
     */
1173
    public function writeFunctionApplicationElementHeader(IApplyExpression $expression, bool $isFunction): void
1174
    {
1175
        $this->xmlWriter->startElement(CsdlConstants::Element_Apply);
1176
        if ($isFunction) {
1177
            $appliedFunction = $expression->getAppliedFunction();
1178
            assert($appliedFunction instanceof IFunctionReferenceExpression);
1179
            $this->writeRequiredAttribute(
1180
                CsdlConstants::Attribute_Function,
1181
                $appliedFunction->getReferencedFunction(),
1182
                [$this, 'functionAsXml']
1183
            );
1184
        }
1185
    }
1186
1187
    public function writeGuidConstantExpressionElement(IGuidConstantExpression $expression): void
1188
    {
1189
        $this->xmlWriter->startElement(CsdlConstants::Element_Guid);
1190
        $this->xmlWriter->text(EdmValueWriter::guidAsXml($expression->getValue()));
1191
        $this->writeEndElement();
1192
    }
1193
1194
    public function writeIntegerConstantExpressionElement(IIntegerConstantExpression $expression): void
1195
    {
1196
        $this->xmlWriter->startElement(CsdlConstants::Element_Int);
1197
        $this->xmlWriter->text(EdmValueWriter::longAsXml($expression->getValue()));
1198
        $this->writeEndElement();
1199
    }
1200
1201
    public function writePathExpressionElement(IPathExpression $expression): void
1202
    {
1203
        $this->xmlWriter->startElement(CsdlConstants::Element_Path);
1204
        $this->xmlWriter->text(self::pathAsXml($expression->getPath()));
1205
        $this->writeEndElement();
1206
    }
1207
1208
    public function writeIfExpressionElementHeader(IIfExpression $expression): void
1209
    {
1210
        $this->xmlWriter->startElement(CsdlConstants::Element_If);
1211
    }
1212
1213
    public function writeCollectionExpressionElementHeader(ICollectionExpression $expression): void
1214
    {
1215
        $this->xmlWriter->startElement(CsdlConstants::Element_Collection);
1216
    }
1217
1218
    /**
1219
     * @param  ILabeledExpression   $labeledElement
1220
     * @throws \ReflectionException
1221
     */
1222
    public function writeLabeledElementHeader(ILabeledExpression $labeledElement): void
1223
    {
1224
        $this->xmlWriter->startElement(CsdlConstants::Element_LabeledElement);
1225
        $this->writeRequiredAttribute(
1226
            CsdlConstants::Attribute_Name,
1227
            $labeledElement->getName(),
1228
            [EdmValueWriter::class, 'stringAsXml']
1229
        );
1230
    }
1231
1232
    /**
1233
     * @param  IIsTypeExpression    $expression
1234
     * @param  bool                 $inlineType
1235
     * @throws \ReflectionException
1236
     */
1237
    public function writeIsTypeExpressionElementHeader(IIsTypeExpression $expression, bool $inlineType): void
1238
    {
1239
        $this->xmlWriter->startElement(CsdlConstants::Element_IsType);
1240
        if ($inlineType) {
1241
            $this->writeRequiredAttribute(
1242
                CsdlConstants::Attribute_Type,
1243
                $expression->getType(),
1244
                [$this, 'typeReferenceAsXml']
1245
            );
1246
        }
1247
    }
1248
1249
    /**
1250
     * @param  IAssertTypeExpression $expression
1251
     * @param  bool                  $inlineType
1252
     * @throws \ReflectionException
1253
     */
1254
    public function writeAssertTypeExpressionElementHeader(IAssertTypeExpression $expression, bool $inlineType): void
1255
    {
1256
        $this->xmlWriter->startElement(CsdlConstants::Element_AssertType);
1257
        if ($inlineType) {
1258
            $this->writeRequiredAttribute(
1259
                CsdlConstants::Attribute_Type,
1260
                $expression->getType(),
1261
                [$this, 'typeReferenceAsXml']
1262
            );
1263
        }
1264
    }
1265
1266
    /**
1267
     * @param  IEntitySetReferenceExpression $expression
1268
     * @throws \ReflectionException
1269
     */
1270
    public function writeEntitySetReferenceExpressionElement(IEntitySetReferenceExpression $expression): void
1271
    {
1272
        $this->xmlWriter->startElement(CsdlConstants::Element_EntitySetReference);
1273
        $this->writeRequiredAttribute(
1274
            CsdlConstants::Attribute_Name,
1275
            $expression->getReferencedEntitySet(),
1276
            [self::class, 'entitySetAsXml']
1277
        );
1278
        $this->writeEndElement();
1279
    }
1280
1281
    /**
1282
     * @param  IParameterReferenceExpression $expression
1283
     * @throws \ReflectionException
1284
     */
1285
    public function writeParameterReferenceExpressionElement(IParameterReferenceExpression $expression): void
1286
    {
1287
        $this->xmlWriter->startElement(CsdlConstants::Element_ParameterReference);
1288
        $this->writeRequiredAttribute(
1289
            CsdlConstants::Attribute_Name,
1290
            $expression->getReferencedParameter(),
1291
            [self::class, 'parameterAsXml']
1292
        );
1293
        $this->writeEndElement();
1294
    }
1295
1296
    /**
1297
     * @param  IFunctionReferenceExpression $expression
1298
     * @throws \ReflectionException
1299
     */
1300
    public function writeFunctionReferenceExpressionElement(IFunctionReferenceExpression $expression): void
1301
    {
1302
        $this->xmlWriter->startElement(CsdlConstants::Element_FunctionReference);
1303
        $this->writeRequiredAttribute(
1304
            CsdlConstants::Attribute_Name,
1305
            $expression->getReferencedFunction(),
1306
            [$this, 'functionAsXml']
1307
        );
1308
        $this->writeEndElement();
1309
    }
1310
1311
    /**
1312
     * @param  IEnumMemberReferenceExpression $expression
1313
     * @throws \ReflectionException
1314
     */
1315
    public function writeEnumMemberReferenceExpressionElement(IEnumMemberReferenceExpression $expression): void
1316
    {
1317
        $this->xmlWriter->startElement(CsdlConstants::Element_EnumMemberReference);
1318
        $this->writeRequiredAttribute(
1319
            CsdlConstants::Attribute_Name,
1320
            $expression->getReferencedEnumMember(),
1321
            [self::class, 'enumMemberAsXml']
1322
        );
1323
        $this->writeEndElement();
1324
    }
1325
1326
    /**
1327
     * @param  IPropertyReferenceExpression $expression
1328
     * @throws \ReflectionException
1329
     */
1330
    public function writePropertyReferenceExpressionElementHeader(IPropertyReferenceExpression $expression): void
1331
    {
1332
        $this->xmlWriter->startElement(CsdlConstants::Element_PropertyReference);
1333
        $this->writeRequiredAttribute(
1334
            CsdlConstants::Attribute_Name,
1335
            $expression->getReferencedProperty(),
1336
            [self::class, 'propertyAsXml']
1337
        );
1338
    }
1339
1340
    public function writeEndElement(): void
1341
    {
1342
        $this->xmlWriter->endElement();
1343
    }
1344
1345
    /**
1346
     * @param  string               $attribute
1347
     * @param  mixed                $value
1348
     * @param  mixed                $defaultValue
1349
     * @param  callable             $toXml
1350
     * @throws \ReflectionException
1351
     */
1352
    public function writeOptionalAttribute(string $attribute, $value, $defaultValue, callable $toXml): void
1353
    {
1354
        $stem = is_array($toXml) ? new ReflectionMethod(...$toXml) :
1355
            new ReflectionFunction($toXml);
1356
        /* @noinspection PhpUnhandledExceptionInspection suppressing exceptions for asserts.*/
1357
        assert(
1358
            1 === count(($stem)->getParameters()),
1359
            '$toXml should be a callable taking one parameter of mixed type'
1360
        );
1361
        $stemType = $stem->getReturnType();
1362
        $name     = $stemType instanceof ReflectionNamedType ?
1363
            $stemType->getName() :
1364
            strval($stemType);
1365
        /* @noinspection PhpUnhandledExceptionInspection suppressing exceptions for asserts.*/
1366
        assert(
1367
            'string' === $name,
1368
            '$toXml should be a callable returning a string'
1369
        );
1370
        if ($value !== $defaultValue) {
1371
            $this->xmlWriter->writeAttribute($attribute, $toXml($value));
1372
        }
1373
    }
1374
1375
    /**
1376
     * @param  string               $attribute
1377
     * @param  mixed                $value
1378
     * @param  callable             $toXml
1379
     * @throws \ReflectionException
1380
     */
1381
    public function writeRequiredAttribute(string $attribute, $value, callable $toXml): void
1382
    {
1383
        $stem = is_array($toXml) ? new ReflectionMethod(...$toXml) :
1384
            new ReflectionFunction($toXml);
1385
        /* @noinspection PhpUnhandledExceptionInspection suppressing exceptions for asserts.*/
1386
        assert(
1387
            1 === count($stem->getParameters()),
1388
            '$toXml should be a callable taking one parameter of mixed type'
1389
        );
1390
        $stemType = $stem->getReturnType();
1391
        $name     = $stemType instanceof ReflectionNamedType ?
1392
            $stemType->getName() :
1393
            strval($stemType);
1394
        /* @noinspection PhpUnhandledExceptionInspection suppressing exceptions for asserts.*/
1395
        assert(
1396
            'string' === $name,
1397
            '$toXml should be a callable returning a string'
1398
        );
1399
        $this->xmlWriter->writeAttribute($attribute, $toXml($value));
1400
    }
1401
1402
    /**
1403
     * @param  Multiplicity              $endKind
1404
     * @throws InvalidOperationException
1405
     * @return string
1406
     */
1407
    private static function multiplicityAsXml(Multiplicity $endKind): string
1408
    {
1409
        switch ($endKind) {
1410
            case Multiplicity::Many():
1411
                return CsdlConstants::Value_EndMany;
1412
            case Multiplicity::One():
1413
                return CsdlConstants::Value_EndRequired;
1414
            case Multiplicity::ZeroOrOne():
1415
                return CsdlConstants::Value_EndOptional;
1416
            default:
1417
                throw new InvalidOperationException(StringConst::UnknownEnumVal_Multiplicity($endKind->getKey()));
1418
        }
1419
    }
1420
1421
    /**
1422
     * @param  FunctionParameterMode     $mode
1423
     * @throws InvalidOperationException
1424
     * @return string
1425
     */
1426
    private static function functionParameterModeAsXml(FunctionParameterMode $mode): string
1427
    {
1428
        switch ($mode) {
1429
            case FunctionParameterMode::In():
1430
                return CsdlConstants::Value_ModeIn;
1431
            case FunctionParameterMode::InOut():
1432
                return CsdlConstants::Value_ModeInOut;
1433
            case FunctionParameterMode::Out():
1434
                return CsdlConstants::Value_ModeOut;
1435
            default:
1436
                throw new InvalidOperationException(StringConst::UnknownEnumVal_FunctionParameterMode($mode->getKey()));
1437
        }
1438
    }
1439
1440
    /**
1441
     * @param  ConcurrencyMode           $mode
1442
     * @throws InvalidOperationException
1443
     * @return string
1444
     */
1445
    private static function concurrencyModeAsXml(ConcurrencyMode $mode): string
1446
    {
1447
        switch ($mode) {
1448
            case ConcurrencyMode::Fixed():
1449
                return CsdlConstants::Value_Fixed;
1450
            case ConcurrencyMode::None():
1451
                return CsdlConstants::Value_None;
1452
            default:
1453
                throw new InvalidOperationException(StringConst::UnknownEnumVal_ConcurrencyMode($mode->getKey()));
1454
        }
1455
    }
1456
1457
    /**
1458
     * @param  string[] $path
1459
     * @return string
1460
     */
1461
    private static function pathAsXml(array $path): string
1462
    {
1463
        return implode('/', $path);
1464
    }
1465
1466
    private static function parameterAsXml(IFunctionParameter $parameter): string
1467
    {
1468
        return $parameter->getName() ?? '';
1469
    }
1470
1471
    private static function propertyAsXml(IProperty $property): string
1472
    {
1473
        return $property->getName() ?? '';
1474
    }
1475
1476
    private static function enumMemberAsXml(IEnumMember $member): string
1477
    {
1478
        return $member->getDeclaringType()->fullName() . '/' . $member->getName();
1479
    }
1480
1481
    private static function entitySetAsXml(IEntitySet $set): string
1482
    {
1483
        $stem = $set->getContainer() ? $set->getContainer()->fullName() : '';
1484
1485
        return $stem . '/' . $set->getName();
1486
    }
1487
1488
    private static function sridAsXml(?int $i): string
1489
    {
1490
        return $i !== null ? strval($i) :  CsdlConstants::Value_SridVariable;
1491
    }
1492
1493
    /**
1494
     * @param  Version                   $edmVersion
1495
     * @throws InvalidOperationException
1496
     * @return string
1497
     */
1498
    private static function getCsdlNamespace(Version $edmVersion): string
1499
    {
1500
        $namespaces = CsdlConstants::versionToEdmNamespace($edmVersion);
1501
        if ($namespaces !== null) {
1502
            return $namespaces;
1503
        }
1504
1505
        throw new InvalidOperationException(StringConst::Serializer_UnknownEdmVersion());
1506
    }
1507
1508
    private function serializationName(ISchemaElement $element): string
1509
    {
1510
        EdmUtil::checkArgumentNull($element->getNamespace(), 'element->getNamespace');
1511
        if ($this->namespaceAliasMappings != null) {
1512
            if (array_key_exists($element->getNamespace(), $this->namespaceAliasMappings)) {
1513
                return $this->namespaceAliasMappings[$element->getNamespace()] . '.' . $element->getName();
1514
            }
1515
        }
1516
1517
        return $element->fullName();
1518
    }
1519
1520
    private function typeReferenceAsXml(ITypeReference $type): string
1521
    {
1522
        if ($type->isCollection()) {
1523
            $collectionReference   = $type->asCollection();
1524
            $elementTypeDefinition = $collectionReference->elementType()->getDefinition();
1525
            assert(
1526
                $elementTypeDefinition instanceof ISchemaElement,
1527
                'Cannot inline parameter type if not a named element or collection of named elements'
1528
            );
1529
            return CsdlConstants::Value_Collection . '(' . $this->serializationName($elementTypeDefinition) . ')';
1530
        } elseif ($type->isEntityReference()) {
1531
            $entityReferenceDefinitionType = $type->asEntityReference()->entityReferenceDefinition()->getEntityType();
1532
            return CsdlConstants::Value_Ref . '(' . $this->serializationName($entityReferenceDefinitionType) . ')';
0 ignored issues
show
Bug introduced by
It seems like $entityReferenceDefinitionType can also be of type null; however, parameter $element of AlgoWeb\ODataMetadata\Cs...er::serializationName() does only seem to accept AlgoWeb\ODataMetadata\Interfaces\ISchemaElement, 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

1532
            return CsdlConstants::Value_Ref . '(' . $this->serializationName(/** @scrutinizer ignore-type */ $entityReferenceDefinitionType) . ')';
Loading history...
1533
        }
1534
        $typeDefinition = $type->getDefinition();
1535
        assert(
1536
            $typeDefinition instanceof ISchemaElement,
1537
            'Cannot inline parameter type if not a named element or collection of named elements'
1538
        );
1539
        return $this->serializationName($typeDefinition);
1540
    }
1541
1542
    private function typeDefinitionAsXml(ISchemaType $type): string
1543
    {
1544
        return $this->serializationName($type);
1545
    }
1546
1547
    private function functionAsXml(IFunction $function): string
1548
    {
1549
        return $this->serializationName($function);
1550
    }
1551
1552
    private function termAsXml(?ITerm $term): string
1553
    {
1554
        if ($term == null) {
1555
            return '';
1556
        }
1557
1558
        return $this->serializationName($term);
1559
    }
1560
}
1561