File indexing completed on 2024-12-22 05:36:40

0001 <?php
0002 
0003 /**
0004  * Zend Framework
0005  *
0006  * LICENSE
0007  *
0008  * This source file is subject to the new BSD license that is bundled
0009  * with this package in the file LICENSE.txt.
0010  * It is also available through the world-wide-web at this URL:
0011  * http://framework.zend.com/license/new-bsd
0012  * If you did not receive a copy of the license and are unable to
0013  * obtain it through the world-wide-web, please send an email
0014  * to license@zend.com so we can send you a copy immediately.
0015  *
0016  * @category   Zend
0017  * @package    Zend_Feed
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Feed_Abstract
0026  */
0027 // require_once 'Zend/Feed/Abstract.php';
0028 
0029 /**
0030  * @see Zend_Feed_Entry_Atom
0031  */
0032 // require_once 'Zend/Feed/Entry/Atom.php';
0033 
0034 
0035 /**
0036  * Atom feed class
0037  *
0038  * The Zend_Feed_Atom class is a concrete subclass of the general
0039  * Zend_Feed_Abstract class, tailored for representing an Atom
0040  * feed. It shares all of the same methods with its abstract
0041  * parent. The distinction is made in the format of data that
0042  * Zend_Feed_Atom expects, and as a further pointer for users as to
0043  * what kind of feed object they have been passed.
0044  *
0045  * @category   Zend
0046  * @package    Zend_Feed
0047  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0048  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0049  */
0050 class Zend_Feed_Atom extends Zend_Feed_Abstract
0051 {
0052 
0053     /**
0054      * The classname for individual feed elements.
0055      *
0056      * @var string
0057      */
0058     protected $_entryClassName = 'Zend_Feed_Entry_Atom';
0059 
0060     /**
0061      * The element name for individual feed elements (Atom <entry>
0062      * elements).
0063      *
0064      * @var string
0065      */
0066     protected $_entryElementName = 'entry';
0067 
0068     /**
0069      * The default namespace for Atom feeds.
0070      *
0071      * @var string
0072      */
0073     protected $_defaultNamespace = 'atom';
0074 
0075 
0076     /**
0077      * Override Zend_Feed_Abstract to set up the $_element and $_entries aliases.
0078      *
0079      * @return void
0080      * @throws Zend_Feed_Exception
0081      */
0082     public function __wakeup()
0083     {
0084         parent::__wakeup();
0085 
0086         // Find the base feed element and create an alias to it.
0087         $element = $this->_element->getElementsByTagName('feed')->item(0);
0088         if (!$element) {
0089             // Try to find a single <entry> instead.
0090             $element = $this->_element->getElementsByTagName($this->_entryElementName)->item(0);
0091             if (!$element) {
0092                 /**
0093                  * @see Zend_Feed_Exception
0094                  */
0095                 // require_once 'Zend/Feed/Exception.php';
0096                 throw new Zend_Feed_Exception('No root <feed> or <' . $this->_entryElementName
0097                                               . '> element found, cannot parse feed.');
0098             }
0099 
0100             $doc = new DOMDocument($this->_element->version,
0101                                    $this->_element->actualEncoding);
0102             $feed = $doc->appendChild($doc->createElement('feed'));
0103             $feed->appendChild($doc->importNode($element, true));
0104             $element = $feed;
0105         }
0106 
0107         $this->_element = $element;
0108 
0109         // Find the entries and save a pointer to them for speed and
0110         // simplicity.
0111         $this->_buildEntryCache();
0112     }
0113 
0114 
0115     /**
0116      * Easy access to <link> tags keyed by "rel" attributes.
0117      *
0118      * If $elt->link() is called with no arguments, we will attempt to
0119      * return the value of the <link> tag(s) like all other
0120      * method-syntax attribute access. If an argument is passed to
0121      * link(), however, then we will return the "href" value of the
0122      * first <link> tag that has a "rel" attribute matching $rel:
0123      *
0124      * $elt->link(): returns the value of the link tag.
0125      * $elt->link('self'): returns the href from the first <link rel="self"> in the entry.
0126      *
0127      * @param  string $rel The "rel" attribute to look for.
0128      * @return mixed
0129      */
0130     public function link($rel = null)
0131     {
0132         if ($rel === null) {
0133             return parent::__call('link', null);
0134         }
0135 
0136         // index link tags by their "rel" attribute.
0137         $links = parent::__get('link');
0138         if (!is_array($links)) {
0139             if ($links instanceof Zend_Feed_Element) {
0140                 $links = array($links);
0141             } else {
0142                 return $links;
0143             }
0144         }
0145 
0146         foreach ($links as $link) {
0147             if (empty($link['rel'])) {
0148                 continue;
0149             }
0150             if ($rel == $link['rel']) {
0151                 return $link['href'];
0152             }
0153         }
0154 
0155         return null;
0156     }
0157 
0158 
0159     /**
0160      * Make accessing some individual elements of the feed easier.
0161      *
0162      * Special accessors 'entry' and 'entries' are provided so that if
0163      * you wish to iterate over an Atom feed's entries, you can do so
0164      * using foreach ($feed->entries as $entry) or foreach
0165      * ($feed->entry as $entry).
0166      *
0167      * @param  string $var The property to access.
0168      * @return mixed
0169      */
0170     public function __get($var)
0171     {
0172         switch ($var) {
0173             case 'entry':
0174                 // fall through to the next case
0175             case 'entries':
0176                 return $this;
0177 
0178             default:
0179                 return parent::__get($var);
0180         }
0181     }
0182 
0183     /**
0184      * Generate the header of the feed when working in write mode
0185      *
0186      * @param  array $array the data to use
0187      * @return DOMElement root node
0188      */
0189     protected function _mapFeedHeaders($array)
0190     {
0191         $feed = $this->_element->createElement('feed');
0192         $feed->setAttribute('xmlns', 'http://www.w3.org/2005/Atom');
0193 
0194         $id = $this->_element->createElement('id', $array->link);
0195         $feed->appendChild($id);
0196 
0197         $title = $this->_element->createElement('title');
0198         $title->appendChild($this->_element->createCDATASection($array->title));
0199         $feed->appendChild($title);
0200 
0201         if (isset($array->author)) {
0202             $author = $this->_element->createElement('author');
0203             $name = $this->_element->createElement('name', $array->author);
0204             $author->appendChild($name);
0205             if (isset($array->email)) {
0206                 $email = $this->_element->createElement('email', $array->email);
0207                 $author->appendChild($email);
0208             }
0209             $feed->appendChild($author);
0210         }
0211 
0212         $updated = isset($array->lastUpdate) ? $array->lastUpdate : time();
0213         $updated = $this->_element->createElement('updated', date(DATE_ATOM, $updated));
0214         $feed->appendChild($updated);
0215 
0216         if (isset($array->published)) {
0217             $published = $this->_element->createElement('published', date(DATE_ATOM, $array->published));
0218             $feed->appendChild($published);
0219         }
0220 
0221         $link = $this->_element->createElement('link');
0222         $link->setAttribute('rel', 'self');
0223         $link->setAttribute('href', $array->link);
0224         if (isset($array->language)) {
0225             $link->setAttribute('hreflang', $array->language);
0226         }
0227         $feed->appendChild($link);
0228 
0229         if (isset($array->description)) {
0230             $subtitle = $this->_element->createElement('subtitle');
0231             $subtitle->appendChild($this->_element->createCDATASection($array->description));
0232             $feed->appendChild($subtitle);
0233         }
0234 
0235         if (isset($array->copyright)) {
0236             $copyright = $this->_element->createElement('rights', $array->copyright);
0237             $feed->appendChild($copyright);
0238         }
0239 
0240         if (isset($array->image)) {
0241             $image = $this->_element->createElement('logo', $array->image);
0242             $feed->appendChild($image);
0243         }
0244 
0245         $generator = !empty($array->generator) ? $array->generator : 'Zend_Feed';
0246         $generator = $this->_element->createElement('generator', $generator);
0247         $feed->appendChild($generator);
0248 
0249         return $feed;
0250     }
0251 
0252     /**
0253      * Generate the entries of the feed when working in write mode
0254      *
0255      * The following nodes are constructed for each feed entry
0256      * <entry>
0257      *    <id>url to feed entry</id>
0258      *    <title>entry title</title>
0259      *    <updated>last update</updated>
0260      *    <link rel="alternate" href="url to feed entry" />
0261      *    <summary>short text</summary>
0262      *    <content>long version, can contain html</content>
0263      * </entry>
0264      *
0265      * @param  array      $array the data to use
0266      * @param  DOMElement $root  the root node to use
0267      * @return void
0268      */
0269     protected function _mapFeedEntries(DOMElement $root, $array)
0270     {
0271         foreach ($array as $dataentry) {
0272             $entry = $this->_element->createElement('entry');
0273 
0274             $id = $this->_element->createElement('id', isset($dataentry->guid) ? $dataentry->guid : $dataentry->link);
0275             $entry->appendChild($id);
0276 
0277             $title = $this->_element->createElement('title');
0278             $title->appendChild($this->_element->createCDATASection($dataentry->title));
0279             $entry->appendChild($title);
0280 
0281             $updated = isset($dataentry->lastUpdate) ? $dataentry->lastUpdate : time();
0282             $updated = $this->_element->createElement('updated', date(DATE_ATOM, $updated));
0283             $entry->appendChild($updated);
0284 
0285             $link = $this->_element->createElement('link');
0286             $link->setAttribute('rel', 'alternate');
0287             $link->setAttribute('href', $dataentry->link);
0288             $entry->appendChild($link);
0289 
0290             $summary = $this->_element->createElement('summary');
0291             $summary->appendChild($this->_element->createCDATASection($dataentry->description));
0292             $entry->appendChild($summary);
0293 
0294             if (isset($dataentry->content)) {
0295                 $content = $this->_element->createElement('content');
0296                 $content->setAttribute('type', 'html');
0297                 $content->appendChild($this->_element->createCDATASection($dataentry->content));
0298                 $entry->appendChild($content);
0299             }
0300 
0301             if (isset($dataentry->category)) {
0302                 foreach ($dataentry->category as $category) {
0303                     $node = $this->_element->createElement('category');
0304                     $node->setAttribute('term', $category['term']);
0305                     if (isset($category['scheme'])) {
0306                         $node->setAttribute('scheme', $category['scheme']);
0307                     }
0308                     $entry->appendChild($node);
0309                 }
0310             }
0311 
0312             if (isset($dataentry->source)) {
0313                 $source = $this->_element->createElement('source');
0314                 $title = $this->_element->createElement('title', $dataentry->source['title']);
0315                 $source->appendChild($title);
0316                 $link = $this->_element->createElement('link', $dataentry->source['title']);
0317                 $link->setAttribute('rel', 'alternate');
0318                 $link->setAttribute('href', $dataentry->source['url']);
0319                 $source->appendChild($link);
0320             }
0321 
0322             if (isset($dataentry->enclosure)) {
0323                 foreach ($dataentry->enclosure as $enclosure) {
0324                     $node = $this->_element->createElement('link');
0325                     $node->setAttribute('rel', 'enclosure');
0326                     $node->setAttribute('href', $enclosure['url']);
0327                     if (isset($enclosure['type'])) {
0328                         $node->setAttribute('type', $enclosure['type']);
0329                     }
0330                     if (isset($enclosure['length'])) {
0331                         $node->setAttribute('length', $enclosure['length']);
0332                     }
0333                     $entry->appendChild($node);
0334                 }
0335             }
0336 
0337             if (isset($dataentry->comments)) {
0338                 $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/',
0339                                                              'wfw:comment',
0340                                                              $dataentry->comments);
0341                 $entry->appendChild($comments);
0342             }
0343             if (isset($dataentry->commentRss)) {
0344                 $comments = $this->_element->createElementNS('http://wellformedweb.org/CommentAPI/',
0345                                                              'wfw:commentRss',
0346                                                              $dataentry->commentRss);
0347                 $entry->appendChild($comments);
0348             }
0349 
0350             $root->appendChild($entry);
0351         }
0352     }
0353 
0354     /**
0355      * Override Zend_Feed_Element to allow formated feeds
0356      *
0357      * @return string
0358      */
0359     public function saveXml()
0360     {
0361         // Return a complete document including XML prologue.
0362         $doc = new DOMDocument($this->_element->ownerDocument->version,
0363                                $this->_element->ownerDocument->actualEncoding);
0364         $doc->appendChild($doc->importNode($this->_element, true));
0365         $doc->formatOutput = true;
0366 
0367         return $doc->saveXML();
0368     }
0369 
0370     /**
0371      * Send feed to a http client with the correct header
0372      *
0373      * @return void
0374      * @throws Zend_Feed_Exception if headers have already been sent
0375      */
0376     public function send()
0377     {
0378         if (headers_sent()) {
0379             /**
0380              * @see Zend_Feed_Exception
0381              */
0382             // require_once 'Zend/Feed/Exception.php';
0383             throw new Zend_Feed_Exception('Cannot send ATOM because headers have already been sent.');
0384         }
0385 
0386         header('Content-Type: application/atom+xml; charset=' . $this->_element->ownerDocument->actualEncoding);
0387 
0388         echo $this->saveXML();
0389     }
0390 }