1<?php
2
3/**
4 * @see       https://github.com/laminas/laminas-feed for the canonical source repository
5 * @copyright https://github.com/laminas/laminas-feed/blob/master/COPYRIGHT.md
6 * @license   https://github.com/laminas/laminas-feed/blob/master/LICENSE.md New BSD License
7 */
8
9namespace Laminas\Feed\Writer\Renderer\Feed;
10
11use DateTime;
12use DOMDocument;
13use DOMElement;
14use Laminas\Feed\Writer;
15use Laminas\Feed\Writer\Renderer;
16use Laminas\Feed\Writer\Version;
17
18class AbstractAtom extends Renderer\AbstractRenderer
19{
20    /**
21     * @param Writer\AbstractFeed $container
22     */
23    public function __construct($container)
24    {
25        parent::__construct($container);
26    }
27
28    /**
29     * Set feed language
30     *
31     * @param  DOMDocument $dom
32     * @param  DOMElement $root
33     * @return void
34     */
35    // @codingStandardsIgnoreStart
36    protected function _setLanguage(DOMDocument $dom, DOMElement $root)
37    {
38        // @codingStandardsIgnoreEnd
39        if ($this->getDataContainer()->getLanguage()) {
40            $root->setAttribute('xml:lang', $this->getDataContainer()->getLanguage());
41        }
42    }
43
44    /**
45     * Set feed title
46     *
47     * @param  DOMDocument $dom
48     * @param  DOMElement $root
49     * @return void
50     * @throws Writer\Exception\InvalidArgumentException
51     */
52    // @codingStandardsIgnoreStart
53    protected function _setTitle(DOMDocument $dom, DOMElement $root)
54    {
55        // @codingStandardsIgnoreEnd
56        if (! $this->getDataContainer()->getTitle()) {
57            $message   = 'Atom 1.0 feed elements MUST contain exactly one'
58                . ' atom:title element but a title has not been set';
59            $exception = new Writer\Exception\InvalidArgumentException($message);
60            if (! $this->ignoreExceptions) {
61                throw $exception;
62            } else {
63                $this->exceptions[] = $exception;
64                return;
65            }
66        }
67
68        $title = $dom->createElement('title');
69        $root->appendChild($title);
70        $title->setAttribute('type', 'text');
71        $text = $dom->createTextNode($this->getDataContainer()->getTitle());
72        $title->appendChild($text);
73    }
74
75    /**
76     * Set feed description
77     *
78     * @param  DOMDocument $dom
79     * @param  DOMElement $root
80     * @return void
81     */
82    // @codingStandardsIgnoreStart
83    protected function _setDescription(DOMDocument $dom, DOMElement $root)
84    {
85        // @codingStandardsIgnoreEnd
86        if (! $this->getDataContainer()->getDescription()) {
87            return;
88        }
89        $subtitle = $dom->createElement('subtitle');
90        $root->appendChild($subtitle);
91        $subtitle->setAttribute('type', 'text');
92        $text = $dom->createTextNode($this->getDataContainer()->getDescription());
93        $subtitle->appendChild($text);
94    }
95
96    /**
97     * Set date feed was last modified
98     *
99     * @param  DOMDocument $dom
100     * @param  DOMElement $root
101     * @return void
102     * @throws Writer\Exception\InvalidArgumentException
103     */
104    // @codingStandardsIgnoreStart
105    protected function _setDateModified(DOMDocument $dom, DOMElement $root)
106    {
107        // @codingStandardsIgnoreEnd
108        if (! $this->getDataContainer()->getDateModified()) {
109            $message   = 'Atom 1.0 feed elements MUST contain exactly one'
110                . ' atom:updated element but a modification date has not been set';
111            $exception = new Writer\Exception\InvalidArgumentException($message);
112            if (! $this->ignoreExceptions) {
113                throw $exception;
114            } else {
115                $this->exceptions[] = $exception;
116                return;
117            }
118        }
119
120        $updated = $dom->createElement('updated');
121        $root->appendChild($updated);
122        $text = $dom->createTextNode(
123            $this->getDataContainer()->getDateModified()->format(DateTime::ATOM)
124        );
125        $updated->appendChild($text);
126    }
127
128    /**
129     * Set feed generator string
130     *
131     * @param  DOMDocument $dom
132     * @param  DOMElement $root
133     * @return void
134     */
135    // @codingStandardsIgnoreStart
136    protected function _setGenerator(DOMDocument $dom, DOMElement $root)
137    {
138        // @codingStandardsIgnoreEnd
139        if (! $this->getDataContainer()->getGenerator()) {
140            $this->getDataContainer()->setGenerator(
141                'Laminas_Feed_Writer',
142                Version::VERSION,
143                'https://getlaminas.org'
144            );
145        }
146
147        $gdata     = $this->getDataContainer()->getGenerator();
148        $generator = $dom->createElement('generator');
149        $root->appendChild($generator);
150        $text = $dom->createTextNode($gdata['name']);
151        $generator->appendChild($text);
152        if (array_key_exists('uri', $gdata)) {
153            $generator->setAttribute('uri', $gdata['uri']);
154        }
155        if (array_key_exists('version', $gdata)) {
156            $generator->setAttribute('version', $gdata['version']);
157        }
158    }
159
160    /**
161     * Set link to feed
162     *
163     * @param  DOMDocument $dom
164     * @param  DOMElement $root
165     * @return void
166     */
167    // @codingStandardsIgnoreStart
168    protected function _setLink(DOMDocument $dom, DOMElement $root)
169    {
170        // @codingStandardsIgnoreEnd
171        if (! $this->getDataContainer()->getLink()) {
172            return;
173        }
174        $link = $dom->createElement('link');
175        $root->appendChild($link);
176        $link->setAttribute('rel', 'alternate');
177        $link->setAttribute('type', 'text/html');
178        $link->setAttribute('href', $this->getDataContainer()->getLink());
179    }
180
181    /**
182     * Set feed links
183     *
184     * @param  DOMDocument $dom
185     * @param  DOMElement $root
186     * @return void
187     * @throws Writer\Exception\InvalidArgumentException
188     */
189    // @codingStandardsIgnoreStart
190    protected function _setFeedLinks(DOMDocument $dom, DOMElement $root)
191    {
192        // @codingStandardsIgnoreEnd
193        $flinks = $this->getDataContainer()->getFeedLinks();
194        if (! $flinks || ! array_key_exists('atom', $flinks)) {
195            $message   = 'Atom 1.0 feed elements SHOULD contain one atom:link '
196                . 'element with a rel attribute value of "self".  This is the '
197                . 'preferred URI for retrieving Atom Feed Documents representing '
198                . 'this Atom feed but a feed link has not been set';
199            $exception = new Writer\Exception\InvalidArgumentException($message);
200            if (! $this->ignoreExceptions) {
201                throw $exception;
202            } else {
203                $this->exceptions[] = $exception;
204                return;
205            }
206        }
207
208        foreach ($flinks as $type => $href) {
209            $mime  = 'application/' . strtolower($type) . '+xml';
210            $flink = $dom->createElement('link');
211            $root->appendChild($flink);
212            $flink->setAttribute('rel', 'self');
213            $flink->setAttribute('type', $mime);
214            $flink->setAttribute('href', $href);
215        }
216    }
217
218    /**
219     * Set feed authors
220     *
221     * @param  DOMDocument $dom
222     * @param  DOMElement $root
223     * @return void
224     */
225    // @codingStandardsIgnoreStart
226    protected function _setAuthors(DOMDocument $dom, DOMElement $root)
227    {
228        // @codingStandardsIgnoreEnd
229        $authors = $this->container->getAuthors();
230        if (! $authors || empty($authors)) {
231            /**
232             * Technically we should defer an exception until we can check
233             * that all entries contain an author. If any entry is missing
234             * an author, then a missing feed author element is invalid
235             */
236            return;
237        }
238        foreach ($authors as $data) {
239            $author = $this->dom->createElement('author');
240            $name   = $this->dom->createElement('name');
241            $author->appendChild($name);
242            $root->appendChild($author);
243            $text = $dom->createTextNode($data['name']);
244            $name->appendChild($text);
245            if (array_key_exists('email', $data)) {
246                $email = $this->dom->createElement('email');
247                $author->appendChild($email);
248                $text = $dom->createTextNode($data['email']);
249                $email->appendChild($text);
250            }
251            if (array_key_exists('uri', $data)) {
252                $uri = $this->dom->createElement('uri');
253                $author->appendChild($uri);
254                $text = $dom->createTextNode($data['uri']);
255                $uri->appendChild($text);
256            }
257        }
258    }
259
260    /**
261     * Set feed identifier
262     *
263     * @param  DOMDocument $dom
264     * @param  DOMElement $root
265     * @return void
266     * @throws Writer\Exception\InvalidArgumentException
267     */
268    // @codingStandardsIgnoreStart
269    protected function _setId(DOMDocument $dom, DOMElement $root)
270    {
271        // @codingStandardsIgnoreEnd
272        if (! $this->getDataContainer()->getId()
273            && ! $this->getDataContainer()->getLink()
274        ) {
275            $message   = 'Atom 1.0 feed elements MUST contain exactly one '
276                . 'atom:id element, or as an alternative, we can use the same '
277                . 'value as atom:link however neither a suitable link nor an '
278                . 'id have been set';
279            $exception = new Writer\Exception\InvalidArgumentException($message);
280            if (! $this->ignoreExceptions) {
281                throw $exception;
282            } else {
283                $this->exceptions[] = $exception;
284                return;
285            }
286        }
287
288        if (! $this->getDataContainer()->getId()) {
289            $this->getDataContainer()->setId(
290                $this->getDataContainer()->getLink()
291            );
292        }
293        $id = $dom->createElement('id');
294        $root->appendChild($id);
295        $text = $dom->createTextNode($this->getDataContainer()->getId());
296        $id->appendChild($text);
297    }
298
299    /**
300     * Set feed copyright
301     *
302     * @param  DOMDocument $dom
303     * @param  DOMElement $root
304     * @return void
305     */
306    // @codingStandardsIgnoreStart
307    protected function _setCopyright(DOMDocument $dom, DOMElement $root)
308    {
309        // @codingStandardsIgnoreEnd
310        $copyright = $this->getDataContainer()->getCopyright();
311        if (! $copyright) {
312            return;
313        }
314        $copy = $dom->createElement('rights');
315        $root->appendChild($copy);
316        $text = $dom->createTextNode($copyright);
317        $copy->appendChild($text);
318    }
319
320    /**
321     * Set feed level logo (image)
322     *
323     * @param DOMDocument $dom
324     * @param DOMElement $root
325     * @return void
326     */
327    // @codingStandardsIgnoreStart
328    protected function _setImage(DOMDocument $dom, DOMElement $root)
329    {
330        // @codingStandardsIgnoreEnd
331        $image = $this->getDataContainer()->getImage();
332        if (! $image) {
333            return;
334        }
335        $img = $dom->createElement('logo');
336        $root->appendChild($img);
337        $text = $dom->createTextNode($image['uri']);
338        $img->appendChild($text);
339    }
340
341    /**
342     * Set date feed was created
343     *
344     * @param  DOMDocument $dom
345     * @param  DOMElement $root
346     * @return void
347     */
348    // @codingStandardsIgnoreStart
349    protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
350    {
351        // @codingStandardsIgnoreEnd
352        if (! $this->getDataContainer()->getDateCreated()) {
353            return;
354        }
355        if (! $this->getDataContainer()->getDateModified()) {
356            $this->getDataContainer()->setDateModified(
357                $this->getDataContainer()->getDateCreated()
358            );
359        }
360    }
361
362    /**
363     * Set base URL to feed links
364     *
365     * @param  DOMDocument $dom
366     * @param  DOMElement $root
367     * @return void
368     */
369    // @codingStandardsIgnoreStart
370    protected function _setBaseUrl(DOMDocument $dom, DOMElement $root)
371    {
372        // @codingStandardsIgnoreEnd
373        $baseUrl = $this->getDataContainer()->getBaseUrl();
374        if (! $baseUrl) {
375            return;
376        }
377        $root->setAttribute('xml:base', $baseUrl);
378    }
379
380    /**
381     * Set hubs to which this feed pushes
382     *
383     * @param  DOMDocument $dom
384     * @param  DOMElement $root
385     * @return void
386     */
387    // @codingStandardsIgnoreStart
388    protected function _setHubs(DOMDocument $dom, DOMElement $root)
389    {
390        // @codingStandardsIgnoreEnd
391        $hubs = $this->getDataContainer()->getHubs();
392        if (! $hubs) {
393            return;
394        }
395        foreach ($hubs as $hubUrl) {
396            $hub = $dom->createElement('link');
397            $hub->setAttribute('rel', 'hub');
398            $hub->setAttribute('href', $hubUrl);
399            $root->appendChild($hub);
400        }
401    }
402
403    /**
404     * Set feed categories
405     *
406     * @param  DOMDocument $dom
407     * @param  DOMElement $root
408     * @return void
409     */
410    // @codingStandardsIgnoreStart
411    protected function _setCategories(DOMDocument $dom, DOMElement $root)
412    {
413        // @codingStandardsIgnoreEnd
414        $categories = $this->getDataContainer()->getCategories();
415        if (! $categories) {
416            return;
417        }
418        foreach ($categories as $cat) {
419            $category = $dom->createElement('category');
420            $category->setAttribute('term', $cat['term']);
421            if (isset($cat['label'])) {
422                $category->setAttribute('label', $cat['label']);
423            } else {
424                $category->setAttribute('label', $cat['term']);
425            }
426            if (isset($cat['scheme'])) {
427                $category->setAttribute('scheme', $cat['scheme']);
428            }
429            $root->appendChild($category);
430        }
431    }
432}
433