Passed
Push — master ( 6b2979...464731 )
by Alex
04:00 queued 11s
created

AtomODataWriter::writeFeed()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 26
c 0
b 0
f 0
nc 16
nop 2
dl 0
loc 39
rs 9.1928
1
<?php
2
3
declare(strict_types=1);
4
5
namespace POData\Writers\Atom;
6
7
use DateTimeZone;
8
use Exception;
9
use POData\Common\MimeTypes;
10
use POData\Common\ODataConstants;
11
use POData\Common\ODataException;
12
use POData\Common\Version;
13
use POData\Configuration\ServiceConfiguration;
14
use POData\ObjectModel\ODataBagContent;
15
use POData\ObjectModel\ODataCategory;
16
use POData\ObjectModel\ODataEntry;
17
use POData\ObjectModel\ODataFeed;
18
use POData\ObjectModel\ODataLink;
19
use POData\ObjectModel\ODataProperty;
20
use POData\ObjectModel\ODataPropertyContent;
21
use POData\ObjectModel\ODataTitle;
22
use POData\ObjectModel\ODataURL;
23
use POData\ObjectModel\ODataURLCollection;
24
use POData\Providers\Metadata\Type\DateTime;
25
use POData\Providers\ProvidersWrapper;
26
use POData\Writers\IODataWriter;
27
use XMLWriter;
28
29
/**
30
 * Class AtomODataWriter.
31
 */
32
class AtomODataWriter implements IODataWriter
33
{
34
    /**
35
     * XML prefix for the Atom namespace.
36
     *
37
     * @var string
38
     */
39
    const ATOM_NAMESPACE_PREFIX = 'atom';
40
    /**
41
     * XML prefix for the Atom Publishing Protocol namespace.
42
     *
43
     * @var string
44
     */
45
    const APP_NAMESPACE_PREFIX = 'app';
46
47
    /*
48
     * Update time to insert into ODataEntry/ODataFeed fields
49
     * @var \DateTime;
50
     */
51
    /**
52
     * Writer to which output (CSDL Document) is sent.
53
     *
54
     * @var XMLWriter
55
     */
56
    public $xmlWriter;
57
    /**
58
     * The service base uri.
59
     *
60
     * @var string
61
     */
62
    protected $baseUri;
63
    private $updated;
64
65
    /**
66
     * Construct a new instance of AtomODataWriter.
67
     *
68
     * @param string $absoluteServiceUri The absolute service Uri
69
     */
70
    public function __construct(string $eol, bool $prettyPrint, $absoluteServiceUri = '')
71
    {
72
        $final = substr($absoluteServiceUri, -1);
73
        if ('/' != $final) {
74
            $absoluteServiceUri .= '/';
75
        }
76
        $this->baseUri = $absoluteServiceUri;
77
        $this->updated = DateTime::now();
78
79
        $this->xmlWriter = new XMLWriter();
80
        $this->xmlWriter->openMemory();
81
        $this->xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
82
        $this->xmlWriter->setIndent($prettyPrint);
83
        $this->xmlWriter->setIndentString($prettyPrint ? '    ' : '');
84
    }
85
86
    /**
87
     * Serialize the exception.
88
     *
89
     * @param ODataException $exception Exception to serialize
90
     *
91
     * @return string
92
     */
93
    public static function serializeException(ODataException $exception, ServiceConfiguration $config)
94
    {
95
        $xmlWriter = new XMLWriter();
96
        $xmlWriter->openMemory();
97
        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
98
        $xmlWriter->setIndent($config->getPrettyOutput());
99
        $xmlWriter->setIndentString($config->getPrettyOutput() ? '    ' : '');
100
101
        $xmlWriter->startElement(ODataConstants::XML_ERROR_ELEMENT_NAME);
102
        //$xmlWriter->writeAttributeNs(
103
        //    ODataConstants::XMLNS_NAMESPACE_PREFIX,
104
        //    ODataConstants::XML_NAMESPACE_PREFIX,
105
        //    ODataConstants::XML_NAMESPACE,
106
        //    null
107
        //);
108
        $xmlWriter->writeAttribute(
109
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
110
            ODataConstants::ODATA_METADATA_NAMESPACE
111
        );
112
        $xmlWriter->endAttribute();
113
        $xmlWriter->startElement(ODataConstants::XML_ERROR_CODE_ELEMENT_NAME);
114
        if (null != $exception->getStatusCode()) {
115
            $xmlWriter->text(strval($exception->getStatusCode()));
116
        }
117
        $xmlWriter->endElement();
118
        $xmlWriter->startElement(ODataConstants::XML_ERROR_MESSAGE_ELEMENT_NAME);
119
        $xmlWriter->text($exception->getMessage());
120
        $xmlWriter->endElement();
121
        $xmlWriter->endElement();
122
        $xmlWriter->endDocument();
123
124
        return $xmlWriter->outputMemory(true);
125
    }
126
127
    /**
128
     * Determines if the given writer is capable of writing the response or not.
129
     *
130
     * @param Version $responseVersion the OData version of the response
131
     * @param string  $contentType     the Content Type of the response
132
     *
133
     * @return bool true if the writer can handle the response, false otherwise
134
     */
135
    public function canHandle(Version $responseVersion, $contentType)
136
    {
137
        $parts = explode(';', $contentType);
138
139
        //first 2 parts are for service documents, second part is for Resources
140
        //TODO: i'm not sold about this first part not being constrained to v1 (or maybe v2)..
141
        //but it's how WS DS works. See #94
142
        return in_array(MimeTypes::MIME_APPLICATION_XML, $parts)
143
            || in_array(MimeTypes::MIME_APPLICATION_ATOMSERVICE, $parts)
144
            || in_array(MimeTypes::MIME_APPLICATION_ATOM, $parts);
145
    }
146
147
    /**
148
     * Write the given OData model in a specific response format.
149
     *
150
     * @param ODataURL|ODataURLCollection|ODataPropertyContent|ODataFeed|ODataEntry $model Object of requested content
151
     *
152
     * @throws Exception
153
     * @return AtomODataWriter
154
     */
155
    public function write($model)
156
    {
157
        if ($model instanceof ODataURL) {
158
            return $this->writeUrl($model);
159
        }
160
161
        if ($model instanceof ODataURLCollection) {
162
            return $this->writeUrlCollection($model);
163
        }
164
165
        if ($model instanceof ODataPropertyContent) {
166
            return $this->writeProperties($model, true);
167
        }
168
169
        if ($model instanceof ODataFeed) {
170
            return $this->writeFeed($model, true);
171
        }
172
173
        if ($model instanceof ODataEntry) {
0 ignored issues
show
introduced by
$model is always a sub-type of POData\ObjectModel\ODataEntry.
Loading history...
174
            return $this->writeEntry($model, true);
175
        }
176
177
        return $this;
178
    }
179
180
    /**
181
     * @param ODataURL $url the url to write
182
     *
183
     * @return AtomODataWriter
184
     */
185
    protected function writeUrl(ODataURL $url)
186
    {
187
        $this->xmlWriter->startElement(ODataConstants::ATOM_URI_ELEMENT_NAME);
188
        $this->xmlWriter->writeAttribute(ODataConstants::XMLNS_NAMESPACE_PREFIX, ODataConstants::ODATA_NAMESPACE);
189
        $this->xmlWriter->text($url->getUrl());
190
        $this->xmlWriter->endElement();
191
192
        return $this;
193
    }
194
195
    /**
196
     * Begin write OData links.
197
     *
198
     * @param ODataURLCollection $urls Object of ODataUrlCollection to start writing collection of url
199
     *
200
     * @return AtomODataWriter
201
     */
202
    public function writeUrlCollection(ODataURLCollection $urls)
203
    {
204
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINKS_ELEMENT_NAME);
205
        $this->xmlWriter->writeAttribute(
206
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
207
            ODataConstants::ODATA_NAMESPACE
208
        );
209
        $this->xmlWriter->endAttribute();
210
        if ($urls->getCount() !== null) {
211
            $this->xmlWriter->writeAttributeNs(
212
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
213
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
214
                null,
215
                ODataConstants::ODATA_METADATA_NAMESPACE
216
            );
217
            $this->xmlWriter->endAttribute();
218
            $this->xmlWriter->startElementNs(
219
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
220
                ODataConstants::ROWCOUNT_ELEMENT,
221
                null
222
            );
223
            $this->xmlWriter->text(strval($urls->getCount()));
224
            $this->xmlWriter->endElement();
225
        }
226
        foreach ($urls->getUrls() as $url) {
227
            $this->writeNodeValue(ODataConstants::ATOM_URI_ELEMENT_NAME, $url->getUrl());
228
        }
229
230
        if ($urls->getNextPageLink() != null) {
231
            $this->writeLinkNode($urls->getNextPageLink(), false);
232
        }
233
        $this->xmlWriter->endElement();
234
235
        return $this;
236
    }
237
238
    /**
239
     * Function to create element only contain value without argument.
240
     *
241
     * @param string $node  Element name
242
     * @param string $value Element value
243
     *
244
     * @return AtomODataWriter
245
     */
246
    public function writeNodeValue($node, $value)
247
    {
248
        $this->xmlWriter->startElement($node);
249
        $this->xmlWriter->text($value ?? '');
250
        $this->xmlWriter->endElement();
251
252
        return $this;
253
    }
254
255
    /**
256
     * Function to create link element with arguments.
257
     *
258
     * @param ODataLink $link       Link object to make link element
259
     * @param bool      $isExpanded Is link expanded or not
260
     *
261
     * @return AtomODataWriter
262
     */
263
    protected function writeLinkNode(ODataLink $link, $isExpanded)
264
    {
265
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
266
        $this->xmlWriter->writeAttribute(
267
            ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME,
268
            $link->getName() ?? ''
269
        );
270
        if ($link->getType() != null) {
271
            $this->xmlWriter->writeAttribute(
272
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
273
                $link->getType() ?? ''
274
            );
275
        }
276
        if ($link->getTitle() != null) {
277
            $this->xmlWriter->writeAttribute(
278
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
279
                $link->getTitle() ?? ''
280
            );
281
        }
282
        $this->xmlWriter->writeAttribute(
283
            ODataConstants::ATOM_HREF_ATTRIBUTE_NAME,
284
            $link->getUrl() ?? ''
285
        );
286
        if (!$isExpanded) {
287
            $this->xmlWriter->endElement();
288
        }
289
290
        return $this;
291
    }
292
293
    /**
294
     * Write the given collection of properties.
295
     * (properties of an entity or complex type).
296
     *
297
     * @param ODataPropertyContent $properties Collection of properties
298
     * @param bool                 $topLevel   is this property content is the top level response to be written?
299
     *
300
     * @throws Exception
301
     * @return AtomODataWriter
302
     */
303
    protected function writeProperties(ODataPropertyContent $properties = null, $topLevel = false)
304
    {
305
        if (null !== $properties) {
306
            foreach ($properties as $property) {
307
                $this->beginWriteProperty($property, $topLevel);
308
309
                if ($property->getValue() == null) {
310
                    $this->writeNullValue($property);
311
                } elseif ($property->getValue() instanceof ODataPropertyContent) {
312
                    $this->writeProperties($property->getValue(), false);
313
                } elseif ($property->getValue() instanceof ODataBagContent) {
314
                    $this->writeBagContent($property->getValue());
315
                } else {
316
                    $value = $this->beforeWriteValue($property->getValue(), $property->getTypeName());
317
                    $this->xmlWriter->text(strval($value));
318
                }
319
320
                $this->xmlWriter->endElement();
321
            }
322
        }
323
324
        return $this;
325
    }
326
327
    /**
328
     * Write a property.
329
     *
330
     * @param ODataProperty $property   Property to be written
331
     * @param bool          $isTopLevel is link top level or not
332
     *
333
     * @return AtomODataWriter
334
     */
335
    protected function beginWriteProperty(ODataProperty $property, $isTopLevel)
336
    {
337
        $this->xmlWriter->startElementNs(
338
            ODataConstants::ODATA_NAMESPACE_PREFIX,
339
            $property->getName(),
340
            null
341
        );
342
        if (!empty($property->getTypeName())) {
343
            $this->xmlWriter->startAttributeNs(
344
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
345
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
346
                null
347
            );
348
            $this->xmlWriter->text($property->getTypeName());
349
        }
350
        if ($isTopLevel) {
351
            $this->xmlWriter->startAttribute(ODataConstants::XMLNS_NAMESPACE_PREFIX);
352
            $this->xmlWriter->text(ODataConstants::ODATA_METADATA_NAMESPACE);
353
            $this->xmlWriter->startAttributeNs(
354
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
355
                ODataConstants::ODATA_NAMESPACE_PREFIX,
356
                null
357
            );
358
            $this->xmlWriter->text(ODataConstants::ODATA_NAMESPACE);
359
            $this->xmlWriter->startAttributeNs(
360
                ODataConstants::XMLNS_NAMESPACE_PREFIX,
361
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
362
                null
363
            );
364
            $this->xmlWriter->text(ODataConstants::ODATA_METADATA_NAMESPACE);
365
        }
366
        if (!empty($property->getTypeName()) || $isTopLevel) {
367
            $this->xmlWriter->endAttribute();
368
        }
369
370
        return $this;
371
    }
372
373
    /**
374
     * Write null value.
375
     *
376
     * @param ODataProperty $property ODataProperty object to write null value
377
     *                                according to property type
378
     *
379
     * @return AtomODataWriter
380
     */
381
    protected function writeNullValue(ODataProperty $property)
382
    {
383
        $this->xmlWriter->writeAttributeNs(
384
            ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
385
            ODataConstants::ATOM_NULL_ATTRIBUTE_NAME,
386
            null,
387
            ODataConstants::XML_TRUE_LITERAL
388
        );
389
390
        return $this;
391
    }
392
393
    /**
394
     * Begin an item in a collection.
395
     *
396
     * @param ODataBagContent $bag Bag property object to begin write property
397
     *
398
     * @throws Exception
399
     * @return AtomODataWriter
400
     */
401
    protected function writeBagContent(ODataBagContent $bag)
402
    {
403
        foreach ($bag->getPropertyContents() as $content) {
404
            if ($content instanceof ODataPropertyContent) {
405
                $this->xmlWriter->startElementNs(
406
                    ODataConstants::ODATA_NAMESPACE_PREFIX,
407
                    ODataConstants::COLLECTION_ELEMENT_NAME,
408
                    null
409
                );
410
                $this->writeProperties($content);
411
                $this->xmlWriter->endElement();
412
            } else {
413
                //probably just a primitive string
414
                $this->xmlWriter->startElementNs(
415
                    ODataConstants::ODATA_NAMESPACE_PREFIX,
416
                    ODataConstants::COLLECTION_ELEMENT_NAME,
417
                    null
418
                );
419
                $this->xmlWriter->text($content);
420
                $this->xmlWriter->endElement();
421
            }
422
        }
423
424
        return $this;
425
    }
426
427
    /**
428
     * XML write a basic data type (string, number, boolean, null).
429
     *
430
     * @param string $value value to be written
431
     * @param string $type  |null data type of the value
432
     *
433
     * @throws Exception
434
     * @return string
435
     */
436
    protected function beforeWriteValue($value, $type = null)
437
    {
438
        switch ($type) {
439
            case 'Edm.DateTime':
440
                $dateTime = new \DateTime($value, new DateTimeZone('UTC'));
441
                $result   = $dateTime->format('Y-m-d\TH:i:s');
442
                break;
443
444
            default:
445
                $result = $value;
446
        }
447
448
        return $result;
449
    }
450
451
    /**
452
     * Begin write OData Feed.
453
     *
454
     * @param ODataFeed $feed       Object of OData feed to start writing feed
455
     * @param bool      $isTopLevel indicates if this is the top level feed in the response
456
     *
457
     * @throws Exception
458
     * @return AtomODataWriter
459
     */
460
    protected function writeFeed(ODataFeed $feed, $isTopLevel = false)
461
    {
462
        $this->xmlWriter->startElement(ODataConstants::ATOM_FEED_ELEMENT_NAME);
463
        if ($isTopLevel) {
464
            $this->writeBaseUriAndDefaultNamespaces();
465
        }
466
467
        $effectiveTitle = $feed->getTitle()->getTitle();
468
        $this
469
            ->writeNodeAttributeValue(
470
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
471
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
472
                MimeTypes::MIME_TEXTTYPE,
473
                $effectiveTitle
474
            )
475
            ->writeNodeValue(ODataConstants::ATOM_ID_ELEMENT_NAME, $feed->id)
476
            ->writeNodeValue(ODataConstants::ATOM_UPDATED_ELEMENT_NAME, $this->getUpdated()->format(DATE_ATOM))
477
            ->writeLinkNode($feed->getSelfLink(), false);
0 ignored issues
show
Bug introduced by
It seems like $feed->getSelfLink() can also be of type null; however, parameter $link of POData\Writers\Atom\Atom...Writer::writeLinkNode() does only seem to accept POData\ObjectModel\ODataLink, 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

477
            ->writeLinkNode(/** @scrutinizer ignore-type */ $feed->getSelfLink(), false);
Loading history...
478
479
        if ($feed->getRowCount() != null) {
480
            $this->xmlWriter->startElementNs(
481
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
482
                ODataConstants::ROWCOUNT_ELEMENT,
483
                null
484
            );
485
            $this->xmlWriter->text(strval($feed->getRowCount()));
486
            $this->xmlWriter->endElement();
487
        }
488
489
        foreach ($feed->getEntries() as $entry) {
490
            $this->writeEntry($entry);
491
        }
492
493
        if ($feed->getNextPageLink() != null) {
494
            $this->writeLinkNode($feed->getNextPageLink(), false);
495
        }
496
        $this->xmlWriter->endElement();
497
498
        return $this;
499
    }
500
501
    /**
502
     * Function to write base uri and default namespaces for top level elements.
503
     *
504
     * @return AtomODataWriter
505
     */
506
    public function writeBaseUriAndDefaultNamespaces()
507
    {
508
        $this->xmlWriter->writeAttribute(
509
            ODataConstants::XML_BASE_ATTRIBUTE_NAME_WITH_PREFIX,
510
            $this->baseUri
511
        );
512
        $this->xmlWriter->writeAttributeNs(
513
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
514
            ODataConstants::ODATA_NAMESPACE_PREFIX,
515
            null,
516
            ODataConstants::ODATA_NAMESPACE
517
        );
518
        $this->xmlWriter->writeAttributeNs(
519
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
520
            ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
521
            null,
522
            ODataConstants::ODATA_METADATA_NAMESPACE
523
        );
524
        $this->xmlWriter->writeAttribute(
525
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
526
            ODataConstants::ATOM_NAMESPACE
527
        );
528
529
        return $this;
530
    }
531
532
    /**
533
     * Function to create element with one attribute and value.
534
     *
535
     * @param string $node           Element name
536
     * @param string $attribute      Attribute name
537
     * @param string $attributeValue Attribute value
538
     * @param string $nodeValue      Element value
539
     *
540
     * @return AtomODataWriter
541
     */
542
    public function writeNodeAttributeValue(
543
        $node,
544
        $attribute,
545
        $attributeValue,
546
        $nodeValue
547
    ) {
548
        $this->xmlWriter->startElement($node);
549
        $this->xmlWriter->writeAttribute($attribute, $attributeValue);
550
        $this->xmlWriter->text($nodeValue ?? '');
551
        $this->xmlWriter->endElement();
552
553
        return $this;
554
    }
555
556
    /**
557
     * Get update timestamp.
558
     *
559
     * @return \DateTime
560
     */
561
    public function getUpdated()
562
    {
563
        return $this->updated;
564
    }
565
566
    /**
567
     * Write top level entry.
568
     *
569
     * @param ODataEntry $entry      Object of ODataEntry
570
     * @param bool       $isTopLevel
571
     *
572
     * @throws Exception
573
     * @return AtomODataWriter
574
     */
575
    protected function writeEntry(ODataEntry $entry, $isTopLevel = false)
576
    {
577
        $this->writeBeginEntry($entry, $isTopLevel);
578
        foreach ($entry->links as $link) {
579
            $this->writeLink($link);
580
        }
581
582
        $this
583
            ->preWriteProperties($entry)
584
            ->writeProperties($entry->propertyContent)
585
            ->postWriteProperties($entry);
586
587
        $this->xmlWriter->endElement();
588
589
        return $this;
590
    }
591
592
    /**
593
     * Start writing a entry.
594
     *
595
     * @param ODataEntry $entry      Entry to write
596
     * @param bool       $isTopLevel
597
     *
598
     * @return AtomODataWriter
599
     */
600
    protected function writeBeginEntry(ODataEntry $entry, $isTopLevel)
601
    {
602
        $this->xmlWriter->startElement(ODataConstants::ATOM_ENTRY_ELEMENT_NAME);
603
        if ($isTopLevel) {
604
            $this->writeBaseUriAndDefaultNamespaces();
605
        }
606
607
        if (null !== $entry->eTag) {
608
            $this->xmlWriter->startAttributeNs(
609
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
610
                ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
611
                null
612
            );
613
            $this->xmlWriter->text($entry->eTag);
614
            $this->xmlWriter->endAttribute();
615
        }
616
617
        $effectiveTitle = $entry->getTitle()->getTitle();
618
        $this
619
            ->writeNodeValue(ODataConstants::ATOM_ID_ELEMENT_NAME, $entry->id)
620
            ->writeNodeAttributeValue(
621
                ODataConstants::ATOM_TITLE_ELELMET_NAME,
622
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
623
                MimeTypes::MIME_TEXTTYPE,
624
                $effectiveTitle
625
            )
626
            ->writeNodeValue(ODataConstants::ATOM_UPDATED_ELEMENT_NAME, $this->getUpdated()->format(DATE_ATOM));
627
628
        $this->xmlWriter->startElement(ODataConstants::ATOM_AUTHOR_ELEMENT_NAME);
629
        $this->xmlWriter->startElement(ODataConstants::ATOM_NAME_ELEMENT_NAME);
630
        $this->xmlWriter->endElement();
631
        $this->xmlWriter->endElement();
632
633
634
        $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
635
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME);
636
        $this->xmlWriter->text(ODataConstants::ATOM_EDIT_RELATION_ATTRIBUTE_VALUE);
637
        $this->xmlWriter->endAttribute();
638
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
639
        $this->xmlWriter->text(strval($effectiveTitle));
640
        $this->xmlWriter->endAttribute();
641
        $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
642
        if (null === $entry->editLink || is_string($entry->editLink)) {
643
            $this->xmlWriter->text(strval($entry->editLink));
644
        } else {
645
            $this->xmlWriter->text($entry->editLink->getUrl());
646
        }
647
        $this->xmlWriter->endAttribute();
648
649
        $this->xmlWriter->endElement();
650
651
652
        if ($entry->isMediaLinkEntry) {
653
            $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
654
            if ($entry->mediaLink->eTag != null) {
655
                $this->xmlWriter->startAttributeNs(
656
                    ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
657
                    ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
658
                    null
659
                );
660
                $this->xmlWriter->text(strval($entry->mediaLink->eTag));
661
                $this->xmlWriter->endAttribute();
662
            }
663
            $this->xmlWriter->startAttribute(
664
                ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME
665
            );
666
            $this->xmlWriter->text(ODataConstants::ATOM_EDIT_MEDIA_RELATION_ATTRIBUTE_VALUE);
667
            $this->xmlWriter->endAttribute();
668
669
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME);
670
            $this->xmlWriter->text($entry->mediaLink->contentType);
671
            $this->xmlWriter->endAttribute();
672
673
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
674
            $this->xmlWriter->text($entry->mediaLink->name);
675
            $this->xmlWriter->endAttribute();
676
677
            $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
678
            $this->xmlWriter->text($entry->mediaLink->editLink);
679
            $this->xmlWriter->endAttribute();
680
            $this->xmlWriter->endElement();
681
682
683
            foreach ($entry->mediaLinks as $mediaLink) {
684
                $this->xmlWriter->startElement(ODataConstants::ATOM_LINK_ELEMENT_NAME);
685
                if ($mediaLink->eTag != null) {
686
                    $this->xmlWriter->startAttributeNs(
687
                        ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
688
                        ODataConstants::ATOM_ETAG_ATTRIBUTE_NAME,
689
                        null
690
                    );
691
                    $this->xmlWriter->text($mediaLink->eTag);
692
                    $this->xmlWriter->endAttribute();
693
                }
694
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_LINK_RELATION_ATTRIBUTE_NAME);
695
                $this->xmlWriter->text($mediaLink->rel);
696
                $this->xmlWriter->endAttribute();
697
698
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME);
699
                $this->xmlWriter->text($mediaLink->contentType);
700
                $this->xmlWriter->endAttribute();
701
702
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_TITLE_ELELMET_NAME);
703
                $this->xmlWriter->text($mediaLink->name);
704
                $this->xmlWriter->endAttribute();
705
706
                $this->xmlWriter->startAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME);
707
                $this->xmlWriter->text($mediaLink->editLink);
708
                $this->xmlWriter->endAttribute();
709
                $this->xmlWriter->endElement();
710
            }
711
        }
712
713
        return $this;
714
    }
715
716
    /**
717
     * @param ODataLink $link Link to write
718
     *
719
     * @throws Exception
720
     * @return AtomODataWriter
721
     */
722
    protected function writeLink(ODataLink $link)
723
    {
724
        $this->writeLinkNode($link, $link->isExpanded());
725
726
        if ($link->isExpanded()) {
727
            $this->xmlWriter->startElementNs(
728
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
729
                ODataConstants::ATOM_INLINE_ELEMENT_NAME,
730
                null
731
            );
732
733
            if (null !== $link->getExpandedResult() && null != $link->getExpandedResult()->getData()) {
734
                if ($link->isCollection()) {
735
                    $this->writeFeed($link->getExpandedResult()->getFeed());
736
                } else {
737
                    $this->writeEntry($link->getExpandedResult()->getEntry());
738
                }
739
            }
740
741
            $this->xmlWriter->endElement();
742
            $this->xmlWriter->endElement();
743
        }
744
745
        return $this;
746
    }
747
748
    /**
749
     * Write after last property.
750
     *
751
     * @param ODataEntry $entry Entry object to post writing properties
752
     *
753
     * @return AtomODataWriter
754
     */
755
    public function postWriteProperties(ODataEntry $entry)
756
    {
757
        if (true !== $entry->isMediaLinkEntry) {
758
            $this->xmlWriter->endElement();
759
        }
760
        $this->xmlWriter->endElement();
761
762
        return $this;
763
    }
764
765
    /**
766
     * Write the node which hold the entity properties as child.
767
     *
768
     * @param ODataEntry $entry ODataEntry object for pre writing properties
769
     *
770
     * @return AtomODataWriter
771
     */
772
    public function preWriteProperties(ODataEntry $entry)
773
    {
774
        $effectiveType = $entry->type instanceof ODataCategory ? $entry->type->getTerm() : $entry->type;
775
        $this->xmlWriter->startElement(ODataConstants::ATOM_CATEGORY_ELEMENT_NAME);
776
        $this->xmlWriter->writeAttribute(
777
            ODataConstants::ATOM_CATEGORY_TERM_ATTRIBUTE_NAME,
778
            strval($effectiveType)
779
        );
780
        $this->xmlWriter->writeAttribute(
781
            ODataConstants::ATOM_CATEGORY_SCHEME_ATTRIBUTE_NAME,
782
            ODataConstants::ODATA_SCHEME_NAMESPACE
783
        );
784
        $this->xmlWriter->endElement();
785
        $this->xmlWriter->startElement(ODataConstants::ATOM_CONTENT_ELEMENT_NAME);
786
        if ($entry->isMediaLinkEntry) {
787
            $this->xmlWriter->writeAttribute(
788
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
789
                $entry->mediaLink->contentType
790
            );
791
            $this->xmlWriter->writeAttribute(
792
                ODataConstants::ATOM_CONTENT_SRC_ATTRIBUTE_NAME,
793
                strval($entry->mediaLink->srcLink)
794
            );
795
            $this->xmlWriter->endElement();
796
            $this->xmlWriter->startElementNs(
797
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
798
                ODataConstants::ATOM_PROPERTIES_ELEMENT_NAME,
799
                null
800
            );
801
        } else {
802
            $this->xmlWriter->writeAttribute(
803
                ODataConstants::ATOM_TYPE_ATTRIBUTE_NAME,
804
                MimeTypes::MIME_APPLICATION_XML
805
            );
806
            $this->xmlWriter->startElementNs(
807
                ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX,
808
                ODataConstants::ATOM_PROPERTIES_ELEMENT_NAME,
809
                null
810
            );
811
        }
812
813
        return $this;
814
    }
815
816
    /**
817
     * Get the final result as string.
818
     *
819
     * @return string output of requested data in Atom format
820
     */
821
    public function getOutput()
822
    {
823
        $this->xmlWriter->endDocument();
824
825
        return $this->xmlWriter->outputMemory(true);
826
    }
827
828
    /**
829
     * @param ProvidersWrapper $providers
830
     *
831
     * @throws ODataException
832
     * @return IODataWriter
833
     */
834
    public function writeServiceDocument(ProvidersWrapper $providers)
835
    {
836
        $writer = $this->xmlWriter;
837
        $writer->startElementNs(
838
            null,
839
            ODataConstants::ATOM_PUBLISHING_SERVICE_ELEMENT_NAME,
840
            ODataConstants::APP_NAMESPACE
841
        );
842
        $writer->writeAttributeNs(
843
            ODataConstants::XML_NAMESPACE_PREFIX,
844
            ODataConstants::XML_BASE_ATTRIBUTE_NAME,
845
            null,
846
            $this->baseUri
847
        );
848
        $writer->writeAttributeNs(
849
            ODataConstants::XMLNS_NAMESPACE_PREFIX,
850
            self::ATOM_NAMESPACE_PREFIX,
851
            null,
852
            ODataConstants::ATOM_NAMESPACE
853
        );
854
        //$writer->writeAttributeNs(
855
        //ODataConstants::XMLNS_NAMESPACE_PREFIX,
856
        //self::APP_NAMESPACE_PREFIX,
857
        //null,
858
        //ODataConstants::APP_NAMESPACE
859
        //);
860
861
        $writer->startElement(ODataConstants::ATOM_PUBLISHING_WORKSPACE_ELEMNT_NAME);
862
        $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null);
863
        $writer->text(ODataConstants::ATOM_PUBLISHING_WORKSPACE_DEFAULT_VALUE);
864
        $writer->endElement();
865
        foreach ($providers->getResourceSets() as $resourceSetWrapper) {
866
            $name = $resourceSetWrapper->getName();
867
            $this->writeServiceDocumentNode($writer, $name);
868
        }
869
        foreach ($providers->getSingletons() as $single) {
870
            $name = $single->getName();
871
            //start collection node
872
            $this->writeServiceDocumentNode($writer, $name);
873
        }
874
875
        //End workspace and service nodes
876
        $writer->endElement();
877
        $writer->endElement();
878
879
        return $this;
880
    }
881
882
    /**
883
     * @param XMLWriter $writer
884
     * @param $name
885
     */
886
    private function writeServiceDocumentNode(&$writer, $name)
887
    {
888
        //start collection node
889
        $writer->startElement(ODataConstants::ATOM_PUBLISHING_COLLECTION_ELEMENT_NAME);
890
        $writer->writeAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME, $name);
891
        //start title node
892
        $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null);
893
        $writer->text($name);
894
        //end title node
895
        $writer->endElement();
896
        //end collection node
897
        $writer->endElement();
898
    }
899
}
900