Passed
Branch master (950424)
by Christopher
11:06
created

AtomODataWriter::writeFeed()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 38
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 8.439
c 0
b 0
f 0
cc 5
eloc 25
nc 16
nop 2
1
<?php
2
3
namespace POData\Writers\Atom;
4
5
use Carbon\Carbon as Carbon;
6
use POData\Common\MimeTypes;
7
use POData\Common\ODataConstants;
8
use POData\Common\ODataException;
9
use POData\Common\Version;
10
use POData\ObjectModel\ODataBagContent;
11
use POData\ObjectModel\ODataEntry;
12
use POData\ObjectModel\ODataFeed;
13
use POData\ObjectModel\ODataLink;
14
use POData\ObjectModel\ODataProperty;
15
use POData\ObjectModel\ODataPropertyContent;
16
use POData\ObjectModel\ODataURL;
17
use POData\ObjectModel\ODataURLCollection;
18
use POData\Providers\ProvidersWrapper;
19
use POData\Writers\IODataWriter;
20
21
/**
22
 * Class AtomODataWriter.
23
 */
24
class AtomODataWriter implements IODataWriter
25
{
26
    /**
27
     * Writer to which output (CSDL Document) is sent.
28
     *
29
     * @var \XMLWriter
30
     */
31
    public $xmlWriter;
32
33
    /**
34
     * The service base uri.
35
     *
36
     * @var string
37
     */
38
    protected $baseUri;
39
40
    /*
41
     * Update time to insert into ODataEntry/ODataFeed fields
42
     * @var Carbon;
43
     */
44
    private $updated;
45
46
    /**
47
     * Construct a new instance of AtomODataWriter.
48
     *
49
     * @param string $absoluteServiceUri The absolute service Uri
50
     */
51
    public function __construct($absoluteServiceUri)
52
    {
53
        $final = substr($absoluteServiceUri, -1);
54
        if ('/' != $final) {
55
            $absoluteServiceUri .= '/';
56
        }
57
        $this->baseUri = $absoluteServiceUri;
58
        $this->updated = Carbon::now();
59
60
        $this->xmlWriter = new \XMLWriter();
61
        $this->xmlWriter->openMemory();
62
        $this->xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
63
        $this->xmlWriter->setIndent(4);
0 ignored issues
show
Bug introduced by
4 of type integer is incompatible with the type boolean expected by parameter $indent of XMLWriter::setIndent(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

63
        $this->xmlWriter->setIndent(/** @scrutinizer ignore-type */ 4);
Loading history...
64
    }
65
66
    /**
67
     * Determines if the given writer is capable of writing the response or not.
68
     *
69
     * @param Version $responseVersion the OData version of the response
70
     * @param string  $contentType     the Content Type of the response
71
     *
72
     * @return bool true if the writer can handle the response, false otherwise
73
     */
74
    public function canHandle(Version $responseVersion, $contentType)
75
    {
76
        $parts = explode(';', $contentType);
77
78
        //first 2 parts are for service documents, second part is for Resources
79
        //TODO: i'm not sold about this first part not being constrained to v1 (or maybe v2)..
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
80
        //but it's how WS DS works. See #94
81
        return in_array(MimeTypes::MIME_APPLICATION_XML, $parts)
82
               || in_array(MimeTypes::MIME_APPLICATION_ATOMSERVICE, $parts)
83
               || in_array(MimeTypes::MIME_APPLICATION_ATOM, $parts);
84
    }
85
86
    /**
87
     * Write the given OData model in a specific response format.
88
     *
89
     * @param ODataURL|ODataURLCollection|ODataPropertyContent|ODataFeed|ODataEntry $model Object of requested content
90
     *
91
     * @return AtomODataWriter
92
     */
93
    public function write($model)
94
    {
95
        if ($model instanceof ODataURL) {
96
            return $this->writeUrl($model);
97
        }
98
99
        if ($model instanceof ODataURLCollection) {
100
            return $this->writeUrlCollection($model);
101
        }
102
103
        if ($model instanceof ODataPropertyContent) {
104
            return $this->writeProperties($model, true);
105
        }
106
107
        if ($model instanceof ODataFeed) {
108
            return $this->writeFeed($model, true);
109
        }
110
111
        if ($model instanceof ODataEntry) {
112
            return $this->writeEntry($model, true);
113
        }
114
115
        return $this;
116
    }
117
118
    /**
119
     * @param ODataURL $url the url to write
120
     *
121
     * @return AtomODataWriter
122
     */
123
    protected function writeUrl(ODataURL $url)
124
    {
125
        $this->xmlWriter->startElement(ODataConstants::ATOM_URI_ELEMENT_NAME);
126
        $this->xmlWriter->writeAttribute(ODataConstants::XMLNS_NAMESPACE_PREFIX, ODataConstants::ODATA_NAMESPACE);
127
        $this->xmlWriter->text($url->url);
128
        $this->xmlWriter->endElement();
129
130
        return $this;
131
    }
132
133
    /**
134
     * Begin write odata links.
135
     *
136
     * @param ODataURLCollection $urls Object of ODataUrlCollection to start writing collection of url
137
     *
138
     * @return AtomODataWriter
139
     */
140
    public function writeUrlCollection(ODataURLCollection $urls)
141
    {
142
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINKS_ELEMENT_NAME);
143
        $this->xmlWriter->writeAttribute(
144
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
145
            ODataConstants::ODATA_NAMESPACE
146
        );
147
        $this->xmlWriter->endAttribute();
148
        if ($urls->count != null) {
149
            $this->xmlWriter->writeAttributeNs(
150
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
151
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
152
                null,
153
                ODataConstants::ODATA_METADATA_NAMESPACE
154
            );
155
            $this->xmlWriter->endAttribute();
156
            $this->xmlWriter->startElementNs(
157
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
158
                ODataConstants::ROWCOUNT_ELEMENT,
159
                null
160
            );
161
            $this->xmlWriter->text($urls->count);
162
            $this->xmlWriter->endElement();
163
        }
164
        foreach ($urls->urls as $url) {
165
            $this->writeNodeValue(ODataConstants::ATOM_URI_ELEMENT_NAME, $url->url);
166
        }
167
168
        if ($urls->nextPageLink != null) {
169
            $this->writeLinkNode($urls->nextPageLink, false);
170
        }
171
        $this->xmlWriter->endElement();
172
173
        return $this;
174
    }
175
176
    /**
177
     * Begin write OData Feed.
178
     *
179
     * @param ODataFeed $feed       Object of OData feed to start writing feed
180
     * @param bool      $isTopLevel indicates if this is the top level feed in the response
181
     *
182
     * @return AtomODataWriter
183
     */
184
    protected function writeFeed(ODataFeed $feed, $isTopLevel = false)
185
    {
186
        $this->xmlWriter->startElement(ODataConstants::ATOM_FEED_ELEMENT_NAME);
187
        if ($isTopLevel) {
188
            $this->writeBaseUriAndDefaultNamespaces();
189
        }
190
191
        $this
192
            ->writeNodeAttributeValue(
193
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
194
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
195
                MimeTypes::MIME_TEXTTYPE,
196
                $feed->title->title
197
            )
198
            ->writeNodeValue(ODataConstants::ATOM_ID_ELEMENT_NAME, $feed->id)
199
            ->writeNodeValue(ODataConstants::ATOM_UPDATED_ELEMENT_NAME, $this->getUpdated()->format(DATE_ATOM))
200
            ->writeLinkNode($feed->selfLink, false);
201
202
        if ($feed->rowCount != null) {
203
            $this->xmlWriter->startElementNs(
204
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
205
                ODataConstants::ROWCOUNT_ELEMENT,
206
                null
207
            );
208
            $this->xmlWriter->text($feed->rowCount);
209
            $this->xmlWriter->endElement();
210
        }
211
212
        foreach ($feed->entries as $entry) {
213
            $this->writeEntry($entry);
214
        }
215
216
        if ($feed->nextPageLink != null) {
217
            $this->writeLinkNode($feed->nextPageLink, false);
218
        }
219
        $this->xmlWriter->endElement();
220
221
        return $this;
222
    }
223
224
    /**
225
     * Write top level entry.
226
     *
227
     * @param ODataEntry $entry      Object of ODataEntry
228
     * @param bool       $isTopLevel
229
     *
230
     * @return AtomODataWriter
231
     */
232
    protected function writeEntry(ODataEntry $entry, $isTopLevel = false)
233
    {
234
        $this->writeBeginEntry($entry, $isTopLevel);
235
        foreach ($entry->links as $link) {
236
            $this->writeLink($link);
237
        }
238
239
        $this
240
            ->preWriteProperties($entry)
241
            ->writeProperties($entry->propertyContent)
242
            ->postWriteProperties($entry);
243
244
        $this->xmlWriter->endElement();
245
246
        return $this;
247
    }
248
249
    /**
250
     * Start writing a entry.
251
     *
252
     * @param ODataEntry $entry      Entry to write
253
     * @param bool       $isTopLevel
254
     *
255
     * @return AtomODataWriter
256
     */
257
    protected function writeBeginEntry(ODataEntry $entry, $isTopLevel)
258
    {
259
        $this->xmlWriter->startElement(ODataConstants::ATOM_ENTRY_ELEMENT_NAME);
260
        if ($isTopLevel) {
261
            $this->writeBaseUriAndDefaultNamespaces();
262
        }
263
264
        if (null !== $entry->eTag) {
265
            $this->xmlWriter->startAttributeNs(
266
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
267
                ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
268
                null
269
            );
270
            $this->xmlWriter->text($entry->eTag);
271
            $this->xmlWriter->endAttribute();
272
        }
273
274
        $this
275
            ->writeNodeValue(ODataConstants::ATOM_ID_ELEMENT_NAME, $entry->id)
276
            ->writeNodeAttributeValue(
277
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
278
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
279
                MimeTypes::MIME_TEXTTYPE,
280
                $entry->title->title
281
            )
282
            ->writeNodeValue(ODataConstants::ATOM_UPDATED_ELEMENT_NAME, $this->getUpdated()->format(DATE_ATOM));
283
284
        $this->xmlWriter->startElement(ODataConstants::ATOM_AUTHOR_ELEMENT_NAME);
285
        $this->xmlWriter->startElement(ODataConstants::ATOM_NAME_ELEMENT_NAME);
286
        $this->xmlWriter->endElement();
287
        $this->xmlWriter->endElement();
288
289
290
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
291
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME);
292
        $this->xmlWriter->text(ODataConstants::ATOM_EDIT_RELATION_ATTRIBUTE_VALUE);
293
        $this->xmlWriter->endAttribute();
294
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
295
        $this->xmlWriter->text($entry->title->title);
296
        $this->xmlWriter->endAttribute();
297
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
298
        if (is_string($entry->editLink)) {
299
            $this->xmlWriter->text($entry->editLink);
300
        } else {
301
            $this->xmlWriter->text($entry->editLink->url);
302
        }
303
        $this->xmlWriter->endAttribute();
304
305
        $this->xmlWriter->endElement();
306
307
308
        if ($entry->isMediaLinkEntry) {
309
            $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
310 View Code Duplication
            if ($entry->mediaLink->eTag != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
                $this->xmlWriter->startAttributeNs(
312
                    ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
313
                    ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
314
                    null
315
                );
316
                $this->xmlWriter->text($entry->mediaLink->eTag);
317
                $this->xmlWriter->endAttribute();
318
            }
319
            $this->xmlWriter->startAttribute(
320
                ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME
321
            );
322
            $this->xmlWriter->text(ODataConstants::ATOM_EDIT_MEDIA_RELATION_ATTRIBUTE_VALUE);
323
            $this->xmlWriter->endAttribute();
324
325
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME);
326
            $this->xmlWriter->text($entry->mediaLink->contentType);
327
            $this->xmlWriter->endAttribute();
328
329
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
330
            $this->xmlWriter->text($entry->mediaLink->name);
331
            $this->xmlWriter->endAttribute();
332
333
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
334
            $this->xmlWriter->text($entry->mediaLink->editLink);
335
            $this->xmlWriter->endAttribute();
336
            $this->xmlWriter->endElement();
337
338
339
            foreach ($entry->mediaLinks as $mediaLink) {
340
                $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
341 View Code Duplication
                if ($mediaLink->eTag != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
342
                    $this->xmlWriter->startAttributeNs(
343
                        ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
344
                        ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
345
                        null
346
                    );
347
                    $this->xmlWriter->text($mediaLink->eTag);
348
                    $this->xmlWriter->endAttribute();
349
                }
350
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME);
351
                $this->xmlWriter->text($mediaLink->rel);
352
                $this->xmlWriter->endAttribute();
353
354
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME);
355
                $this->xmlWriter->text($mediaLink->contentType);
356
                $this->xmlWriter->endAttribute();
357
358
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
359
                $this->xmlWriter->text($mediaLink->name);
360
                $this->xmlWriter->endAttribute();
361
362
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
363
                $this->xmlWriter->text($mediaLink->editLink);
364
                $this->xmlWriter->endAttribute();
365
                $this->xmlWriter->endElement();
366
            }
367
        }
368
369
        return $this;
370
    }
371
372
    /**
373
     * @param ODataLink $link Link to write
374
     *
375
     * @return AtomODataWriter
376
     */
377
    protected function writeLink(ODataLink $link)
378
    {
379
        $this->writeLinkNode($link, $link->isExpanded);
380
381
        if ($link->isExpanded) {
382
            $this->xmlWriter->startElementNs(
383
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
384
                ODataConstants::ATOM_INLINE_ELEMENT_NAME,
385
                null
386
            );
387
388
            if (null !== $link->expandedResult) {
389
                if ($link->isCollection) {
390
                    $this->writeFeed($link->expandedResult);
0 ignored issues
show
Bug introduced by
It seems like $link->expandedResult can also be of type POData\ObjectModel\ODataEntry; however, parameter $feed of POData\Writers\Atom\AtomODataWriter::writeFeed() does only seem to accept POData\ObjectModel\ODataFeed, 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

390
                    $this->writeFeed(/** @scrutinizer ignore-type */ $link->expandedResult);
Loading history...
391
                } else {
392
                    $this->writeEntry($link->expandedResult);
0 ignored issues
show
Bug introduced by
It seems like $link->expandedResult can also be of type POData\ObjectModel\ODataFeed; however, parameter $entry of POData\Writers\Atom\AtomODataWriter::writeEntry() does only seem to accept POData\ObjectModel\ODataEntry, 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

392
                    $this->writeEntry(/** @scrutinizer ignore-type */ $link->expandedResult);
Loading history...
393
                }
394
            }
395
396
            $this->xmlWriter->endElement();
397
            $this->xmlWriter->endElement();
398
        }
399
400
        return $this;
401
    }
402
403
    /**
404
     * Write the given collection of properties.
405
     * (properties of an entity or complex type).
406
     *
407
     * @param ODataPropertyContent $properties Collection of properties
408
     * @param bool                 $topLevel   is this property content is the top level response to be written?
409
     *
410
     * @return AtomODataWriter
411
     */
412
    protected function writeProperties(ODataPropertyContent $properties, $topLevel = false)
413
    {
414
        foreach ($properties->properties as $property) {
415
            $this->beginWriteProperty($property, $topLevel);
416
417
            if ($property->value == null) {
418
                $this->writeNullValue($property);
419
            } elseif ($property->value instanceof ODataPropertyContent) {
420
                $this->writeProperties($property->value, false);
421
            } elseif ($property->value instanceof ODataBagContent) {
422
                $this->writeBagContent($property->value);
423
            } else {
424
                $value = $this->beforeWriteValue($property->value, $property->typeName);
425
                $this->xmlWriter->text($value);
426
            }
427
428
            $this->xmlWriter->endElement();
429
        }
430
431
        return $this;
432
    }
433
434
    /**
435
     * XML write a basic data type (string, number, boolean, null).
436
     *
437
     * @param string $value     value to be written
438
     * @param string $type|null data type of the value
439
     *
440
     * @return string
441
     */
442
    protected function beforeWriteValue($value, $type = null)
443
    {
444
        switch ($type) {
445
            case 'Edm.DateTime':
446
                $dateTime = new Carbon($value, new \DateTimeZone('UTC'));
447
                $result = $dateTime->format('Y-m-d\TH:i:s');
448
                break;
449
450
            default:
451
                $result = $value;
452
        }
453
454
        return $result;
455
    }
456
457
    /**
458
     * Write the node which hold the entity properties as child.
459
     *
460
     * @param ODataEntry $entry ODataEntry object for pre writing properties
461
     *
462
     * @return AtomODataWriter
463
     */
464
    public function preWriteProperties(ODataEntry $entry)
465
    {
466
        $this->xmlWriter->startElement(ODataConstants::ATOM_CATEGORY_ELEMENT_NAME);
467
        $this->xmlWriter->writeAttribute(
468
            ODataConstants::ATOM_CATEGORY_TERM_ATTRIBUTE_NAME,
469
            $entry->type->term
470
        );
471
        $this->xmlWriter->writeAttribute(
472
            ODataConstants::ATOM_CATEGORY_SCHEME_ATTRIBUTE_NAME,
473
            ODataConstants::ODATA_SCHEME_NAMESPACE
474
        );
475
        $this->xmlWriter->endElement();
476
        $this->xmlWriter->startElement(ODataConstants::ATOM_CONTENT_ELEMENT_NAME);
477
        if ($entry->isMediaLinkEntry) {
478
            $this->xmlWriter->writeAttribute(
479
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
480
                $entry->mediaLink->contentType
481
            );
482
            $this->xmlWriter->writeAttribute(
483
                ODataConstants::ATOM_CONTENT_SRC_ATTRIBUTE_NAME,
484
                $entry->mediaLink->srcLink
485
            );
486
            $this->xmlWriter->endElement();
487
            $this->xmlWriter->startElementNs(
488
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
489
                ODataConstants::ATOM_PROPERTIES_ELEMENT_NAME,
490
                null
491
            );
492
        } else {
493
            $this->xmlWriter->writeAttribute(
494
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
495
                MimeTypes::MIME_APPLICATION_XML
496
            );
497
            $this->xmlWriter->startElementNs(
498
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
499
                ODataConstants::ATOM_PROPERTIES_ELEMENT_NAME,
500
                null
501
            );
502
        }
503
504
        return $this;
505
    }
506
507
    /**
508
     * Write a property.
509
     *
510
     * @param ODataProperty $property   Property to be written
511
     * @param bool          $isTopLevel is link top level or not
512
     *
513
     * @return AtomODataWriter
514
     */
515
    protected function beginWriteProperty(ODataProperty $property, $isTopLevel)
516
    {
517
        $this->xmlWriter->startElementNs(
518
            ODataConstants::ODATA_NAMESPACE_PREFIX,
519
            $property->name,
520
            null
521
        );
522
        if ($property->typeName != null) {
523
            $this->xmlWriter->startAttributeNs(
524
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
525
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
526
                null
527
            );
528
            $this->xmlWriter->text($property->typeName);
529
        }
530
        if ($isTopLevel) {
531
            $this->xmlWriter->startAttribute(ODataConstants::XMLNS_NAMESPACE_PREFIX);
532
            $this->xmlWriter->text(ODataConstants::ODATA_METADATA_NAMESPACE);
533
            $this->xmlWriter->startAttributeNs(
534
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
535
                ODataConstants::ODATA_NAMESPACE_PREFIX,
536
                null
537
            );
538
            $this->xmlWriter->text(ODataConstants::ODATA_NAMESPACE);
539
            $this->xmlWriter->startAttributeNs(
540
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
541
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
542
                null
543
            );
544
            $this->xmlWriter->text(ODataConstants::ODATA_METADATA_NAMESPACE);
545
        }
546
        if ($property->typeName != null || $isTopLevel) {
547
            $this->xmlWriter->endAttribute();
548
        }
549
550
        return $this;
551
    }
552
553
    /**
554
     * Write after last property.
555
     *
556
     * @param ODataEntry $entry Entry object to post writing properties
557
     *
558
     * @return AtomODataWriter
559
     */
560
    public function postWriteProperties(ODataEntry $entry)
561
    {
562
        if (!$entry->isMediaLinkEntry) {
563
            $this->xmlWriter->endElement();
564
        }
565
        $this->xmlWriter->endElement();
566
567
        return $this;
568
    }
569
570
    /**
571
     * Begin an item in a collection.
572
     *
573
     * @param ODataBagContent $bag Bag property object to begin write property
574
     *
575
     * @return AtomODataWriter
576
     */
577
    protected function writeBagContent(ODataBagContent $bag)
578
    {
579
        foreach ($bag->propertyContents as $content) {
580
            if ($content instanceof ODataPropertyContent) {
581
                $this->xmlWriter->startElementNs(
582
                    ODataConstants::ODATA_NAMESPACE_PREFIX,
583
                    ODataConstants::COLLECTION_ELEMENT_NAME,
584
                    null
585
                );
586
                $this->writeProperties($content);
587
                $this->xmlWriter->endElement();
588
            } else {
589
                //probably just a primitive string
590
                $this->xmlWriter->startElementNs(
591
                    ODataConstants::ODATA_NAMESPACE_PREFIX,
592
                    ODataConstants::COLLECTION_ELEMENT_NAME,
593
                    null
594
                );
595
                $this->xmlWriter->text($content);
596
                $this->xmlWriter->endElement();
597
            }
598
        }
599
600
        return $this;
601
    }
602
603
    /**
604
     * Write null value.
605
     *
606
     * @param ODataProperty $property ODataProperty object to write null value
607
     *                                according to property type
608
     *
609
     * @return AtomODataWriter
610
     */
611
    protected function writeNullValue(ODataProperty $property)
612
    {
613
        if (!(($property instanceof ODataBagContent) || ($property instanceof ODataPropertyContent))) {
614
            $this->xmlWriter->writeAttributeNs(
615
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
616
                ODataConstants::ATOM_NULL_ATTRIBUTE_NAME,
617
                null,
618
                ODataConstants::XML_TRUE_LITERAL
619
            );
620
        }
621
622
        return $this;
623
    }
624
625
    /**
626
     * Get the final result as string.
627
     *
628
     * @return string output of requested data in Atom format
629
     */
630
    public function getOutput()
631
    {
632
        $this->xmlWriter->endDocument();
633
634
        return $this->xmlWriter->outputMemory(true);
635
    }
636
637
    /**
638
     * Serialize the exception.
639
     *
640
     * @param ODataException $exception               Exception to serialize
641
     * @param bool           $serializeInnerException if set to true,
642
     *                                                serialize the inner exception if $exception is an ODataException
643
     *
644
     * @return string
645
     */
646
    public static function serializeException(ODataException $exception, $serializeInnerException)
0 ignored issues
show
Unused Code introduced by
The parameter $serializeInnerException is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

646
    public static function serializeException(ODataException $exception, /** @scrutinizer ignore-unused */ $serializeInnerException)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
647
    {
648
        $xmlWriter = new \XMLWriter();
649
        $xmlWriter->openMemory();
650
        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
651
        $xmlWriter->setIndent(4);
0 ignored issues
show
Bug introduced by
4 of type integer is incompatible with the type boolean expected by parameter $indent of XMLWriter::setIndent(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

651
        $xmlWriter->setIndent(/** @scrutinizer ignore-type */ 4);
Loading history...
652
653
        $xmlWriter->startElement(ODataConstants::XML_ERROR_ELEMENT_NAME);
654
        //$xmlWriter->writeAttributeNs(
655
        //    ODataConstants::XMLNS_NAMESPACE_PREFIX,
656
        //    ODataConstants::XML_NAMESPACE_PREFIX,
657
        //    ODataConstants::XML_NAMESPACE,
658
        //    null
659
        //);
660
        $xmlWriter->writeAttribute(
661
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
662
            ODataConstants::ODATA_METADATA_NAMESPACE
663
        );
664
        $xmlWriter->endAttribute();
665
        $xmlWriter->startElement(ODataConstants::XML_ERROR_CODE_ELEMENT_NAME);
666
        if (null != $exception->getStatusCode()) {
667
            $xmlWriter->text($exception->getStatusCode());
668
        }
669
        $xmlWriter->endElement();
670
        $xmlWriter->startElement(ODataConstants::XML_ERROR_MESSAGE_ELEMENT_NAME);
671
        $xmlWriter->text($exception->getMessage());
672
        $xmlWriter->endElement();
673
        $xmlWriter->endElement();
674
        $xmlWriter->endDocument();
675
676
        return $xmlWriter->outputMemory(true);
677
    }
678
679
    /**
680
     * Function to create element only contain value without argument.
681
     *
682
     * @param string $node  Element name
683
     * @param string $value Element value
684
     *
685
     * @return AtomODataWriter
686
     */
687
    public function writeNodeValue($node, $value)
688
    {
689
        $this->xmlWriter->startElement($node);
690
        $this->xmlWriter->text($value);
691
        $this->xmlWriter->endElement();
692
693
        return $this;
694
    }
695
696
    /**
697
     * Function to create element with one attribute and value.
698
     *
699
     * @param string $node           Element name
700
     * @param string $attribute      Attribute name
701
     * @param string $attributeValue Attribute value
702
     * @param string $nodeValue      Element value
703
     *
704
     * @return AtomODataWriter
705
     */
706
    public function writeNodeAttributeValue(
707
        $node,
708
        $attribute,
709
        $attributeValue,
710
        $nodeValue
711
    ) {
712
        $this->xmlWriter->startElement($node);
713
        $this->xmlWriter->writeAttribute($attribute, $attributeValue);
714
        $this->xmlWriter->text($nodeValue);
715
        $this->xmlWriter->endElement();
716
717
        return $this;
718
    }
719
720
    /**
721
     * Function to create link element with arguments.
722
     *
723
     * @param ODataLink $link       Link object to make link element
724
     * @param bool      $isExpanded Is link expanded or not
725
     *
726
     * @return AtomODataWriter
727
     */
728
    protected function writeLinkNode(ODataLink $link, $isExpanded)
729
    {
730
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
731
        $this->xmlWriter->writeAttribute(
732
            ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME,
733
            $link->name
734
        );
735
        if ($link->type != null) {
736
            $this->xmlWriter->writeAttribute(
737
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
738
                $link->type
739
            );
740
        }
741
        if ($link->title != null) {
742
            $this->xmlWriter->writeAttribute(
743
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
744
                $link->title
745
            );
746
        }
747
        $this->xmlWriter->writeAttribute(
748
            ODataConstants::ATOM_HREF_ATTRIBUTE_NAME,
749
            $link->url
750
        );
751
        if (!$isExpanded) {
752
            $this->xmlWriter->endElement();
753
        }
754
755
        return $this;
756
    }
757
758
    /**
759
     * Function to write base uri and default namespaces for top level elements.
760
     *
761
     * @return AtomODataWriter
762
     */
763
    public function writeBaseUriAndDefaultNamespaces()
764
    {
765
        $this->xmlWriter->writeAttribute(
766
            ODataConstants::XML_BASE_ATTRIBUTE_NAME_WITH_PREFIX,
767
            $this->baseUri
768
        );
769
        $this->xmlWriter->writeAttributeNs(
770
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
771
            ODataConstants::ODATA_NAMESPACE_PREFIX,
772
            null,
773
            ODataConstants::ODATA_NAMESPACE
774
        );
775
        $this->xmlWriter->writeAttributeNs(
776
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
777
            ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
778
            null,
779
            ODataConstants::ODATA_METADATA_NAMESPACE
780
        );
781
        $this->xmlWriter->writeAttribute(
782
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
783
            ODataConstants::ATOM_NAMESPACE
784
        );
785
786
        return $this;
787
    }
788
789
    /**
790
     * XML prefix for the Atom namespace.
791
     *
792
     * @var string
793
     */
794
    const ATOM_NAMESPACE_PREFIX = 'atom';
795
796
    /**
797
     * XML prefix for the Atom Publishing Protocol namespace.
798
     *
799
     * @var string
800
     */
801
    const APP_NAMESPACE_PREFIX = 'app';
802
803
    /**
804
     * @param ProvidersWrapper $providers
805
     *
806
     * @return IODataWriter
807
     */
808
    public function writeServiceDocument(ProvidersWrapper $providers)
809
    {
810
        $writer = $this->xmlWriter;
811
        $writer->startElementNs(
812
            null,
813
            ODataConstants::ATOM_PUBLISHING_SERVICE_ELEMENT_NAME,
814
            ODataConstants::APP_NAMESPACE
815
        );
816
        $writer->writeAttributeNs(
817
            ODataConstants::XML_NAMESPACE_PREFIX,
818
            ODataConstants::XML_BASE_ATTRIBUTE_NAME,
819
            null,
820
            $this->baseUri
821
        );
822
        $writer->writeAttributeNs(
823
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
824
            self::ATOM_NAMESPACE_PREFIX,
825
            null,
826
            ODataConstants::ATOM_NAMESPACE
827
        );
828
        //$writer->writeAttributeNs(
829
        //ODataConstants::XMLNS_NAMESPACE_PREFIX,
830
        //self::APP_NAMESPACE_PREFIX,
831
        //null,
832
        //ODataConstants::APP_NAMESPACE
833
        //);
834
835
        $writer->startElement(ODataConstants::ATOM_PUBLISHING_WORKSPACE_ELEMNT_NAME);
836
        $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null);
837
        $writer->text(ODataConstants::ATOM_PUBLISHING_WORKSPACE_DEFAULT_VALUE);
838
        $writer->endElement();
839
        foreach ($providers->getResourceSets() as $resourceSetWrapper) {
840
            $name = $resourceSetWrapper->getName();
841
            $this->writeServiceDocumentNode($writer, $name);
842
        }
843
        foreach ($providers->getSingletons() as $single) {
844
            $name = $single->getName();
845
            //start collection node
846
            $this->writeServiceDocumentNode($writer, $name);
847
        }
848
849
        //End workspace and service nodes
850
        $writer->endElement();
851
        $writer->endElement();
852
853
        return $this;
854
    }
855
856
    /**
857
     * Get update timestamp.
858
     *
859
     * @return Carbon
860
     */
861
    public function getUpdated()
862
    {
863
        return $this->updated;
864
    }
865
866
    /**
867
     * @param $writer
868
     * @param $name
869
     */
870
    private function writeServiceDocumentNode(&$writer, $name)
871
    {
872
        //start collection node
873
        $writer->startElement(ODataConstants::ATOM_PUBLISHING_COLLECTION_ELEMENT_NAME);
874
        $writer->writeAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME, $name);
875
        //start title node
876
        $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null);
877
        $writer->text($name);
878
        //end title node
879
        $writer->endElement();
880
        //end collection node
881
        $writer->endElement();
882
    }
883
}
884