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