22ebe763639ce5cdbd214f27ab462e173ba1e502
[yaffs-website] / vendor / zendframework / zend-feed / src / Writer / Renderer / Feed / Rss.php
1 <?php
2 /**
3  * Zend Framework (http://framework.zend.com/)
4  *
5  * @link      http://github.com/zendframework/zf2 for the canonical source repository
6  * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7  * @license   http://framework.zend.com/license/new-bsd New BSD License
8  */
9
10 namespace Zend\Feed\Writer\Renderer\Feed;
11
12 use DateTime;
13 use DOMDocument;
14 use DOMElement;
15 use Zend\Feed\Uri;
16 use Zend\Feed\Writer;
17 use Zend\Feed\Writer\Renderer;
18 use Zend\Feed\Writer\Version;
19
20 /**
21 */
22 class Rss extends Renderer\AbstractRenderer implements Renderer\RendererInterface
23 {
24     /**
25      * Constructor
26      *
27      * @param  Writer\Feed $container
28      */
29     public function __construct(Writer\Feed $container)
30     {
31         parent::__construct($container);
32     }
33
34     /**
35      * Render RSS feed
36      *
37      * @return self
38      */
39     public function render()
40     {
41         $this->dom = new DOMDocument('1.0', $this->container->getEncoding());
42         $this->dom->formatOutput = true;
43         $this->dom->substituteEntities = false;
44         $rss = $this->dom->createElement('rss');
45         $this->setRootElement($rss);
46         $rss->setAttribute('version', '2.0');
47
48         $channel = $this->dom->createElement('channel');
49         $rss->appendChild($channel);
50         $this->dom->appendChild($rss);
51         $this->_setLanguage($this->dom, $channel);
52         $this->_setBaseUrl($this->dom, $channel);
53         $this->_setTitle($this->dom, $channel);
54         $this->_setDescription($this->dom, $channel);
55         $this->_setImage($this->dom, $channel);
56         $this->_setDateCreated($this->dom, $channel);
57         $this->_setDateModified($this->dom, $channel);
58         $this->_setLastBuildDate($this->dom, $channel);
59         $this->_setGenerator($this->dom, $channel);
60         $this->_setLink($this->dom, $channel);
61         $this->_setAuthors($this->dom, $channel);
62         $this->_setCopyright($this->dom, $channel);
63         $this->_setCategories($this->dom, $channel);
64
65         foreach ($this->extensions as $ext) {
66             $ext->setType($this->getType());
67             $ext->setRootElement($this->getRootElement());
68             $ext->setDOMDocument($this->getDOMDocument(), $channel);
69             $ext->render();
70         }
71
72         foreach ($this->container as $entry) {
73             if ($this->getDataContainer()->getEncoding()) {
74                 $entry->setEncoding($this->getDataContainer()->getEncoding());
75             }
76             if ($entry instanceof Writer\Entry) {
77                 $renderer = new Renderer\Entry\Rss($entry);
78             } else {
79                 continue;
80             }
81             if ($this->ignoreExceptions === true) {
82                 $renderer->ignoreExceptions();
83             }
84             $renderer->setType($this->getType());
85             $renderer->setRootElement($this->dom->documentElement);
86             $renderer->render();
87             $element = $renderer->getElement();
88             $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true;
89             $imported = $this->dom->importNode($element, $deep);
90             $channel->appendChild($imported);
91         }
92         return $this;
93     }
94
95     /**
96      * Set feed language
97      *
98      * @param DOMDocument $dom
99      * @param DOMElement $root
100      * @return void
101      */
102     // @codingStandardsIgnoreStart
103     protected function _setLanguage(DOMDocument $dom, DOMElement $root)
104     {
105         // @codingStandardsIgnoreEnd
106         $lang = $this->getDataContainer()->getLanguage();
107         if (! $lang) {
108             return;
109         }
110         $language = $dom->createElement('language');
111         $root->appendChild($language);
112         $language->nodeValue = $lang;
113     }
114
115     /**
116      * Set feed title
117      *
118      * @param  DOMDocument $dom
119      * @param  DOMElement $root
120      * @return void
121      * @throws Writer\Exception\InvalidArgumentException
122      */
123     // @codingStandardsIgnoreStart
124     protected function _setTitle(DOMDocument $dom, DOMElement $root)
125     {
126         // @codingStandardsIgnoreEnd
127         if (! $this->getDataContainer()->getTitle()) {
128             $message = 'RSS 2.0 feed elements MUST contain exactly one'
129             . ' title element but a title has not been set';
130             $exception = new Writer\Exception\InvalidArgumentException($message);
131             if (! $this->ignoreExceptions) {
132                 throw $exception;
133             } else {
134                 $this->exceptions[] = $exception;
135                 return;
136             }
137         }
138
139         $title = $dom->createElement('title');
140         $root->appendChild($title);
141         $text = $dom->createTextNode($this->getDataContainer()->getTitle());
142         $title->appendChild($text);
143     }
144
145     /**
146      * Set feed description
147      *
148      * @param  DOMDocument $dom
149      * @param  DOMElement $root
150      * @return void
151      * @throws Writer\Exception\InvalidArgumentException
152      */
153     // @codingStandardsIgnoreStart
154     protected function _setDescription(DOMDocument $dom, DOMElement $root)
155     {
156         // @codingStandardsIgnoreEnd
157         if (! $this->getDataContainer()->getDescription()) {
158             $message = 'RSS 2.0 feed elements MUST contain exactly one'
159             . ' description element but one has not been set';
160             $exception = new Writer\Exception\InvalidArgumentException($message);
161             if (! $this->ignoreExceptions) {
162                 throw $exception;
163             } else {
164                 $this->exceptions[] = $exception;
165                 return;
166             }
167         }
168         $subtitle = $dom->createElement('description');
169         $root->appendChild($subtitle);
170         $text = $dom->createTextNode($this->getDataContainer()->getDescription());
171         $subtitle->appendChild($text);
172     }
173
174     /**
175      * Set date feed was last modified
176      *
177      * @param  DOMDocument $dom
178      * @param  DOMElement $root
179      * @return void
180      */
181     // @codingStandardsIgnoreStart
182     protected function _setDateModified(DOMDocument $dom, DOMElement $root)
183     {
184         // @codingStandardsIgnoreEnd
185         if (! $this->getDataContainer()->getDateModified()) {
186             return;
187         }
188
189         $updated = $dom->createElement('pubDate');
190         $root->appendChild($updated);
191         $text = $dom->createTextNode(
192             $this->getDataContainer()->getDateModified()->format(DateTime::RSS)
193         );
194         $updated->appendChild($text);
195     }
196
197     /**
198      * Set feed generator string
199      *
200      * @param  DOMDocument $dom
201      * @param  DOMElement $root
202      * @return void
203      */
204     // @codingStandardsIgnoreStart
205     protected function _setGenerator(DOMDocument $dom, DOMElement $root)
206     {
207         // @codingStandardsIgnoreEnd
208         if (! $this->getDataContainer()->getGenerator()) {
209             $this->getDataContainer()->setGenerator(
210                 'Zend_Feed_Writer',
211                 Version::VERSION,
212                 'http://framework.zend.com'
213             );
214         }
215
216         $gdata = $this->getDataContainer()->getGenerator();
217         $generator = $dom->createElement('generator');
218         $root->appendChild($generator);
219         $name = $gdata['name'];
220         if (array_key_exists('version', $gdata)) {
221             $name .= ' ' . $gdata['version'];
222         }
223         if (array_key_exists('uri', $gdata)) {
224             $name .= ' (' . $gdata['uri'] . ')';
225         }
226         $text = $dom->createTextNode($name);
227         $generator->appendChild($text);
228     }
229
230     /**
231      * Set link to feed
232      *
233      * @param  DOMDocument $dom
234      * @param  DOMElement $root
235      * @return void
236      * @throws Writer\Exception\InvalidArgumentException
237      */
238     // @codingStandardsIgnoreStart
239     protected function _setLink(DOMDocument $dom, DOMElement $root)
240     {
241         // @codingStandardsIgnoreEnd
242         $value = $this->getDataContainer()->getLink();
243         if (! $value) {
244             $message = 'RSS 2.0 feed elements MUST contain exactly one'
245             . ' link element but one has not been set';
246             $exception = new Writer\Exception\InvalidArgumentException($message);
247             if (! $this->ignoreExceptions) {
248                 throw $exception;
249             } else {
250                 $this->exceptions[] = $exception;
251                 return;
252             }
253         }
254         $link = $dom->createElement('link');
255         $root->appendChild($link);
256         $text = $dom->createTextNode($value);
257         $link->appendChild($text);
258         if (! Uri::factory($value)->isValid()) {
259             $link->setAttribute('isPermaLink', 'false');
260         }
261     }
262
263     /**
264      * Set feed authors
265      *
266      * @param  DOMDocument $dom
267      * @param  DOMElement $root
268      * @return void
269      */
270     // @codingStandardsIgnoreStart
271     protected function _setAuthors(DOMDocument $dom, DOMElement $root)
272     {
273         // @codingStandardsIgnoreEnd
274         $authors = $this->getDataContainer()->getAuthors();
275         if (! $authors || empty($authors)) {
276             return;
277         }
278         foreach ($authors as $data) {
279             $author = $this->dom->createElement('author');
280             $name = $data['name'];
281             if (array_key_exists('email', $data)) {
282                 $name = $data['email'] . ' (' . $data['name'] . ')';
283             }
284             $text = $dom->createTextNode($name);
285             $author->appendChild($text);
286             $root->appendChild($author);
287         }
288     }
289
290     /**
291      * Set feed copyright
292      *
293      * @param  DOMDocument $dom
294      * @param  DOMElement $root
295      * @return void
296      */
297     // @codingStandardsIgnoreStart
298     protected function _setCopyright(DOMDocument $dom, DOMElement $root)
299     {
300         // @codingStandardsIgnoreEnd
301         $copyright = $this->getDataContainer()->getCopyright();
302         if (! $copyright) {
303             return;
304         }
305         $copy = $dom->createElement('copyright');
306         $root->appendChild($copy);
307         $text = $dom->createTextNode($copyright);
308         $copy->appendChild($text);
309     }
310
311     /**
312      * Set feed channel image
313      *
314      * @param  DOMDocument $dom
315      * @param  DOMElement $root
316      * @return void
317      * @throws Writer\Exception\InvalidArgumentException
318      */
319     // @codingStandardsIgnoreStart
320     protected function _setImage(DOMDocument $dom, DOMElement $root)
321     {
322         // @codingStandardsIgnoreEnd
323         $image = $this->getDataContainer()->getImage();
324         if (! $image) {
325             return;
326         }
327
328         if (! isset($image['title']) || empty($image['title'])
329             || ! is_string($image['title'])
330         ) {
331             $message = 'RSS 2.0 feed images must include a title';
332             $exception = new Writer\Exception\InvalidArgumentException($message);
333             if (! $this->ignoreExceptions) {
334                 throw $exception;
335             } else {
336                 $this->exceptions[] = $exception;
337                 return;
338             }
339         }
340
341         if (empty($image['link']) || ! is_string($image['link'])
342             || ! Uri::factory($image['link'])->isValid()
343         ) {
344             $message = 'Invalid parameter: parameter \'link\''
345             . ' must be a non-empty string and valid URI/IRI';
346             $exception = new Writer\Exception\InvalidArgumentException($message);
347             if (! $this->ignoreExceptions) {
348                 throw $exception;
349             } else {
350                 $this->exceptions[] = $exception;
351                 return;
352             }
353         }
354
355         $img   = $dom->createElement('image');
356         $root->appendChild($img);
357
358         $url   = $dom->createElement('url');
359         $text  = $dom->createTextNode($image['uri']);
360         $url->appendChild($text);
361
362         $title = $dom->createElement('title');
363         $text  = $dom->createTextNode($image['title']);
364         $title->appendChild($text);
365
366         $link  = $dom->createElement('link');
367         $text  = $dom->createTextNode($image['link']);
368         $link->appendChild($text);
369
370         $img->appendChild($url);
371         $img->appendChild($title);
372         $img->appendChild($link);
373
374         if (isset($image['height'])) {
375             if (! ctype_digit((string) $image['height']) || $image['height'] > 400) {
376                 $message = 'Invalid parameter: parameter \'height\''
377                          . ' must be an integer not exceeding 400';
378                 $exception = new Writer\Exception\InvalidArgumentException($message);
379                 if (! $this->ignoreExceptions) {
380                     throw $exception;
381                 } else {
382                     $this->exceptions[] = $exception;
383                     return;
384                 }
385             }
386             $height = $dom->createElement('height');
387             $text   = $dom->createTextNode($image['height']);
388             $height->appendChild($text);
389             $img->appendChild($height);
390         }
391         if (isset($image['width'])) {
392             if (! ctype_digit((string) $image['width']) || $image['width'] > 144) {
393                 $message = 'Invalid parameter: parameter \'width\''
394                          . ' must be an integer not exceeding 144';
395                 $exception = new Writer\Exception\InvalidArgumentException($message);
396                 if (! $this->ignoreExceptions) {
397                     throw $exception;
398                 } else {
399                     $this->exceptions[] = $exception;
400                     return;
401                 }
402             }
403             $width = $dom->createElement('width');
404             $text  = $dom->createTextNode($image['width']);
405             $width->appendChild($text);
406             $img->appendChild($width);
407         }
408         if (isset($image['description'])) {
409             if (empty($image['description']) || ! is_string($image['description'])) {
410                 $message = 'Invalid parameter: parameter \'description\''
411                          . ' must be a non-empty string';
412                 $exception = new Writer\Exception\InvalidArgumentException($message);
413                 if (! $this->ignoreExceptions) {
414                     throw $exception;
415                 } else {
416                     $this->exceptions[] = $exception;
417                     return;
418                 }
419             }
420             $desc = $dom->createElement('description');
421             $text = $dom->createTextNode($image['description']);
422             $desc->appendChild($text);
423             $img->appendChild($desc);
424         }
425     }
426
427     /**
428      * Set date feed was created
429      *
430      * @param  DOMDocument $dom
431      * @param  DOMElement $root
432      * @return void
433      */
434     // @codingStandardsIgnoreStart
435     protected function _setDateCreated(DOMDocument $dom, DOMElement $root)
436     {
437         // @codingStandardsIgnoreEnd
438         if (! $this->getDataContainer()->getDateCreated()) {
439             return;
440         }
441         if (! $this->getDataContainer()->getDateModified()) {
442             $this->getDataContainer()->setDateModified(
443                 $this->getDataContainer()->getDateCreated()
444             );
445         }
446     }
447
448     /**
449      * Set date feed last build date
450      *
451      * @param  DOMDocument $dom
452      * @param  DOMElement $root
453      * @return void
454      */
455     // @codingStandardsIgnoreStart
456     protected function _setLastBuildDate(DOMDocument $dom, DOMElement $root)
457     {
458         // @codingStandardsIgnoreEnd
459         if (! $this->getDataContainer()->getLastBuildDate()) {
460             return;
461         }
462
463         $lastBuildDate = $dom->createElement('lastBuildDate');
464         $root->appendChild($lastBuildDate);
465         $text = $dom->createTextNode(
466             $this->getDataContainer()->getLastBuildDate()->format(DateTime::RSS)
467         );
468         $lastBuildDate->appendChild($text);
469     }
470
471     /**
472      * Set base URL to feed links
473      *
474      * @param  DOMDocument $dom
475      * @param  DOMElement $root
476      * @return void
477      */
478     // @codingStandardsIgnoreStart
479     protected function _setBaseUrl(DOMDocument $dom, DOMElement $root)
480     {
481         // @codingStandardsIgnoreEnd
482         $baseUrl = $this->getDataContainer()->getBaseUrl();
483         if (! $baseUrl) {
484             return;
485         }
486         $root->setAttribute('xml:base', $baseUrl);
487     }
488
489     /**
490      * Set feed categories
491      *
492      * @param  DOMDocument $dom
493      * @param  DOMElement $root
494      * @return void
495      */
496     // @codingStandardsIgnoreStart
497     protected function _setCategories(DOMDocument $dom, DOMElement $root)
498     {
499         // @codingStandardsIgnoreEnd
500         $categories = $this->getDataContainer()->getCategories();
501         if (! $categories) {
502             return;
503         }
504         foreach ($categories as $cat) {
505             $category = $dom->createElement('category');
506             if (isset($cat['scheme'])) {
507                 $category->setAttribute('domain', $cat['scheme']);
508             }
509             $text = $dom->createTextNode($cat['term']);
510             $category->appendChild($text);
511             $root->appendChild($category);
512         }
513     }
514 }