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