Mercurial > hg > isophonics-drupal-site
comparison vendor/zendframework/zend-feed/src/Writer/Renderer/Entry/Atom.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
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\Entry; | |
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\Validator; | |
19 | |
20 class Atom extends Renderer\AbstractRenderer implements Renderer\RendererInterface | |
21 { | |
22 /** | |
23 * Constructor | |
24 * | |
25 * @param Writer\Entry $container | |
26 */ | |
27 public function __construct(Writer\Entry $container) | |
28 { | |
29 parent::__construct($container); | |
30 } | |
31 | |
32 /** | |
33 * Render atom entry | |
34 * | |
35 * @return Atom | |
36 */ | |
37 public function render() | |
38 { | |
39 $this->dom = new DOMDocument('1.0', $this->container->getEncoding()); | |
40 $this->dom->formatOutput = true; | |
41 $entry = $this->dom->createElementNS(Writer\Writer::NAMESPACE_ATOM_10, 'entry'); | |
42 $this->dom->appendChild($entry); | |
43 | |
44 $this->_setSource($this->dom, $entry); | |
45 $this->_setTitle($this->dom, $entry); | |
46 $this->_setDescription($this->dom, $entry); | |
47 $this->_setDateCreated($this->dom, $entry); | |
48 $this->_setDateModified($this->dom, $entry); | |
49 $this->_setLink($this->dom, $entry); | |
50 $this->_setId($this->dom, $entry); | |
51 $this->_setAuthors($this->dom, $entry); | |
52 $this->_setEnclosure($this->dom, $entry); | |
53 $this->_setContent($this->dom, $entry); | |
54 $this->_setCategories($this->dom, $entry); | |
55 | |
56 foreach ($this->extensions as $ext) { | |
57 $ext->setType($this->getType()); | |
58 $ext->setRootElement($this->getRootElement()); | |
59 $ext->setDOMDocument($this->getDOMDocument(), $entry); | |
60 $ext->render(); | |
61 } | |
62 | |
63 return $this; | |
64 } | |
65 | |
66 /** | |
67 * Set entry title | |
68 * | |
69 * @param DOMDocument $dom | |
70 * @param DOMElement $root | |
71 * @return void | |
72 * @throws Writer\Exception\InvalidArgumentException | |
73 */ | |
74 protected function _setTitle(DOMDocument $dom, DOMElement $root) | |
75 { | |
76 if (!$this->getDataContainer()->getTitle()) { | |
77 $message = 'Atom 1.0 entry elements MUST contain exactly one' | |
78 . ' atom:title element but a title has not been set'; | |
79 $exception = new Writer\Exception\InvalidArgumentException($message); | |
80 if (!$this->ignoreExceptions) { | |
81 throw $exception; | |
82 } else { | |
83 $this->exceptions[] = $exception; | |
84 return; | |
85 } | |
86 } | |
87 $title = $dom->createElement('title'); | |
88 $root->appendChild($title); | |
89 $title->setAttribute('type', 'html'); | |
90 $cdata = $dom->createCDATASection($this->getDataContainer()->getTitle()); | |
91 $title->appendChild($cdata); | |
92 } | |
93 | |
94 /** | |
95 * Set entry description | |
96 * | |
97 * @param DOMDocument $dom | |
98 * @param DOMElement $root | |
99 * @return void | |
100 */ | |
101 protected function _setDescription(DOMDocument $dom, DOMElement $root) | |
102 { | |
103 if (!$this->getDataContainer()->getDescription()) { | |
104 return; // unless src content or base64 | |
105 } | |
106 $subtitle = $dom->createElement('summary'); | |
107 $root->appendChild($subtitle); | |
108 $subtitle->setAttribute('type', 'html'); | |
109 $cdata = $dom->createCDATASection( | |
110 $this->getDataContainer()->getDescription() | |
111 ); | |
112 $subtitle->appendChild($cdata); | |
113 } | |
114 | |
115 /** | |
116 * Set date entry was modified | |
117 * | |
118 * @param DOMDocument $dom | |
119 * @param DOMElement $root | |
120 * @return void | |
121 * @throws Writer\Exception\InvalidArgumentException | |
122 */ | |
123 protected function _setDateModified(DOMDocument $dom, DOMElement $root) | |
124 { | |
125 if (!$this->getDataContainer()->getDateModified()) { | |
126 $message = 'Atom 1.0 entry elements MUST contain exactly one' | |
127 . ' atom:updated element but a modification date has not been set'; | |
128 $exception = new Writer\Exception\InvalidArgumentException($message); | |
129 if (!$this->ignoreExceptions) { | |
130 throw $exception; | |
131 } else { | |
132 $this->exceptions[] = $exception; | |
133 return; | |
134 } | |
135 } | |
136 | |
137 $updated = $dom->createElement('updated'); | |
138 $root->appendChild($updated); | |
139 $text = $dom->createTextNode( | |
140 $this->getDataContainer()->getDateModified()->format(DateTime::ATOM) | |
141 ); | |
142 $updated->appendChild($text); | |
143 } | |
144 | |
145 /** | |
146 * Set date entry was created | |
147 * | |
148 * @param DOMDocument $dom | |
149 * @param DOMElement $root | |
150 * @return void | |
151 */ | |
152 protected function _setDateCreated(DOMDocument $dom, DOMElement $root) | |
153 { | |
154 if (!$this->getDataContainer()->getDateCreated()) { | |
155 return; | |
156 } | |
157 $el = $dom->createElement('published'); | |
158 $root->appendChild($el); | |
159 $text = $dom->createTextNode( | |
160 $this->getDataContainer()->getDateCreated()->format(DateTime::ATOM) | |
161 ); | |
162 $el->appendChild($text); | |
163 } | |
164 | |
165 /** | |
166 * Set entry authors | |
167 * | |
168 * @param DOMDocument $dom | |
169 * @param DOMElement $root | |
170 * @return void | |
171 */ | |
172 protected function _setAuthors(DOMDocument $dom, DOMElement $root) | |
173 { | |
174 $authors = $this->container->getAuthors(); | |
175 if ((!$authors || empty($authors))) { | |
176 /** | |
177 * This will actually trigger an Exception at the feed level if | |
178 * a feed level author is not set. | |
179 */ | |
180 return; | |
181 } | |
182 foreach ($authors as $data) { | |
183 $author = $this->dom->createElement('author'); | |
184 $name = $this->dom->createElement('name'); | |
185 $author->appendChild($name); | |
186 $root->appendChild($author); | |
187 $text = $dom->createTextNode($data['name']); | |
188 $name->appendChild($text); | |
189 if (array_key_exists('email', $data)) { | |
190 $email = $this->dom->createElement('email'); | |
191 $author->appendChild($email); | |
192 $text = $dom->createTextNode($data['email']); | |
193 $email->appendChild($text); | |
194 } | |
195 if (array_key_exists('uri', $data)) { | |
196 $uri = $this->dom->createElement('uri'); | |
197 $author->appendChild($uri); | |
198 $text = $dom->createTextNode($data['uri']); | |
199 $uri->appendChild($text); | |
200 } | |
201 } | |
202 } | |
203 | |
204 /** | |
205 * Set entry enclosure | |
206 * | |
207 * @param DOMDocument $dom | |
208 * @param DOMElement $root | |
209 * @return void | |
210 */ | |
211 protected function _setEnclosure(DOMDocument $dom, DOMElement $root) | |
212 { | |
213 $data = $this->container->getEnclosure(); | |
214 if ((!$data || empty($data))) { | |
215 return; | |
216 } | |
217 $enclosure = $this->dom->createElement('link'); | |
218 $enclosure->setAttribute('rel', 'enclosure'); | |
219 if (isset($data['type'])) { | |
220 $enclosure->setAttribute('type', $data['type']); | |
221 } | |
222 if (isset($data['length'])) { | |
223 $enclosure->setAttribute('length', $data['length']); | |
224 } | |
225 $enclosure->setAttribute('href', $data['uri']); | |
226 $root->appendChild($enclosure); | |
227 } | |
228 | |
229 protected function _setLink(DOMDocument $dom, DOMElement $root) | |
230 { | |
231 if (!$this->getDataContainer()->getLink()) { | |
232 return; | |
233 } | |
234 $link = $dom->createElement('link'); | |
235 $root->appendChild($link); | |
236 $link->setAttribute('rel', 'alternate'); | |
237 $link->setAttribute('type', 'text/html'); | |
238 $link->setAttribute('href', $this->getDataContainer()->getLink()); | |
239 } | |
240 | |
241 /** | |
242 * Set entry identifier | |
243 * | |
244 * @param DOMDocument $dom | |
245 * @param DOMElement $root | |
246 * @return void | |
247 * @throws Writer\Exception\InvalidArgumentException | |
248 */ | |
249 protected function _setId(DOMDocument $dom, DOMElement $root) | |
250 { | |
251 if (!$this->getDataContainer()->getId() | |
252 && !$this->getDataContainer()->getLink()) { | |
253 $message = 'Atom 1.0 entry elements MUST contain exactly one ' | |
254 . 'atom:id element, or as an alternative, we can use the same ' | |
255 . 'value as atom:link however neither a suitable link nor an ' | |
256 . 'id have been set'; | |
257 $exception = new Writer\Exception\InvalidArgumentException($message); | |
258 if (!$this->ignoreExceptions) { | |
259 throw $exception; | |
260 } else { | |
261 $this->exceptions[] = $exception; | |
262 return; | |
263 } | |
264 } | |
265 | |
266 if (!$this->getDataContainer()->getId()) { | |
267 $this->getDataContainer()->setId( | |
268 $this->getDataContainer()->getLink() | |
269 ); | |
270 } | |
271 if (!Uri::factory($this->getDataContainer()->getId())->isValid() | |
272 && !preg_match( | |
273 "#^urn:[a-zA-Z0-9][a-zA-Z0-9\-]{1,31}:([a-zA-Z0-9\(\)\+\,\.\:\=\@\;\$\_\!\*\-]|%[0-9a-fA-F]{2})*#", | |
274 $this->getDataContainer()->getId() | |
275 ) | |
276 && !$this->_validateTagUri($this->getDataContainer()->getId()) | |
277 ) { | |
278 throw new Writer\Exception\InvalidArgumentException('Atom 1.0 IDs must be a valid URI/IRI'); | |
279 } | |
280 $id = $dom->createElement('id'); | |
281 $root->appendChild($id); | |
282 $text = $dom->createTextNode($this->getDataContainer()->getId()); | |
283 $id->appendChild($text); | |
284 } | |
285 | |
286 /** | |
287 * Validate a URI using the tag scheme (RFC 4151) | |
288 * | |
289 * @param string $id | |
290 * @return bool | |
291 */ | |
292 protected function _validateTagUri($id) | |
293 { | |
294 if (preg_match( | |
295 '/^tag:(?P<name>.*),(?P<date>\d{4}-?\d{0,2}-?\d{0,2}):(?P<specific>.*)(.*:)*$/', | |
296 $id, | |
297 $matches | |
298 )) { | |
299 $dvalid = false; | |
300 $date = $matches['date']; | |
301 $d6 = strtotime($date); | |
302 if ((strlen($date) == 4) && $date <= date('Y')) { | |
303 $dvalid = true; | |
304 } elseif ((strlen($date) == 7) && ($d6 < strtotime("now"))) { | |
305 $dvalid = true; | |
306 } elseif ((strlen($date) == 10) && ($d6 < strtotime("now"))) { | |
307 $dvalid = true; | |
308 } | |
309 $validator = new Validator\EmailAddress; | |
310 if ($validator->isValid($matches['name'])) { | |
311 $nvalid = true; | |
312 } else { | |
313 $nvalid = $validator->isValid('info@' . $matches['name']); | |
314 } | |
315 return $dvalid && $nvalid; | |
316 } | |
317 return false; | |
318 } | |
319 | |
320 /** | |
321 * Set entry content | |
322 * | |
323 * @param DOMDocument $dom | |
324 * @param DOMElement $root | |
325 * @return void | |
326 * @throws Writer\Exception\InvalidArgumentException | |
327 */ | |
328 protected function _setContent(DOMDocument $dom, DOMElement $root) | |
329 { | |
330 $content = $this->getDataContainer()->getContent(); | |
331 if (!$content && !$this->getDataContainer()->getLink()) { | |
332 $message = 'Atom 1.0 entry elements MUST contain exactly one ' | |
333 . 'atom:content element, or as an alternative, at least one link ' | |
334 . 'with a rel attribute of "alternate" to indicate an alternate ' | |
335 . 'method to consume the content.'; | |
336 $exception = new Writer\Exception\InvalidArgumentException($message); | |
337 if (!$this->ignoreExceptions) { | |
338 throw $exception; | |
339 } else { | |
340 $this->exceptions[] = $exception; | |
341 return; | |
342 } | |
343 } | |
344 if (!$content) { | |
345 return; | |
346 } | |
347 $element = $dom->createElement('content'); | |
348 $element->setAttribute('type', 'xhtml'); | |
349 $xhtmlElement = $this->_loadXhtml($content); | |
350 $deep = version_compare(PHP_VERSION, '7', 'ge') ? 1 : true; | |
351 $xhtml = $dom->importNode($xhtmlElement, $deep); | |
352 $element->appendChild($xhtml); | |
353 $root->appendChild($element); | |
354 } | |
355 | |
356 /** | |
357 * Load a HTML string and attempt to normalise to XML | |
358 */ | |
359 protected function _loadXhtml($content) | |
360 { | |
361 if (class_exists('tidy', false)) { | |
362 $tidy = new \tidy; | |
363 $config = [ | |
364 'output-xhtml' => true, | |
365 'show-body-only' => true, | |
366 'quote-nbsp' => false | |
367 ]; | |
368 $encoding = str_replace('-', '', $this->getEncoding()); | |
369 $tidy->parseString($content, $config, $encoding); | |
370 $tidy->cleanRepair(); | |
371 $xhtml = (string) $tidy; | |
372 } else { | |
373 $xhtml = $content; | |
374 } | |
375 $xhtml = preg_replace([ | |
376 "/(<[\/]?)([a-zA-Z]+)/" | |
377 ], '$1xhtml:$2', $xhtml); | |
378 $dom = new DOMDocument('1.0', $this->getEncoding()); | |
379 $dom->loadXML( | |
380 '<xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">' | |
381 . $xhtml | |
382 . '</xhtml:div>' | |
383 ); | |
384 return $dom->documentElement; | |
385 } | |
386 | |
387 /** | |
388 * Set entry categories | |
389 * | |
390 * @param DOMDocument $dom | |
391 * @param DOMElement $root | |
392 * @return void | |
393 */ | |
394 protected function _setCategories(DOMDocument $dom, DOMElement $root) | |
395 { | |
396 $categories = $this->getDataContainer()->getCategories(); | |
397 if (!$categories) { | |
398 return; | |
399 } | |
400 foreach ($categories as $cat) { | |
401 $category = $dom->createElement('category'); | |
402 $category->setAttribute('term', $cat['term']); | |
403 if (isset($cat['label'])) { | |
404 $category->setAttribute('label', $cat['label']); | |
405 } else { | |
406 $category->setAttribute('label', $cat['term']); | |
407 } | |
408 if (isset($cat['scheme'])) { | |
409 $category->setAttribute('scheme', $cat['scheme']); | |
410 } | |
411 $root->appendChild($category); | |
412 } | |
413 } | |
414 | |
415 /** | |
416 * Append Source element (Atom 1.0 Feed Metadata) | |
417 * | |
418 * @param DOMDocument $dom | |
419 * @param DOMElement $root | |
420 * @return void | |
421 */ | |
422 protected function _setSource(DOMDocument $dom, DOMElement $root) | |
423 { | |
424 $source = $this->getDataContainer()->getSource(); | |
425 if (!$source) { | |
426 return; | |
427 } | |
428 $renderer = new Renderer\Feed\AtomSource($source); | |
429 $renderer->setType($this->getType()); | |
430 $element = $renderer->render()->getElement(); | |
431 $imported = $dom->importNode($element, true); | |
432 $root->appendChild($imported); | |
433 } | |
434 } |