PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/concrete/vendor/zendframework/zend-feed/src/Writer/Renderer/Entry/Atom.php

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