web/lib/Zend/Feed/Reader/Extension/Atom/Entry.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Feed_Reader
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Entry.php 23170 2010-10-19 18:29:24Z mabe $
       
    20  */
       
    21 
       
    22 /**
       
    23  * @see Zend_Feed_Reader
       
    24  */
       
    25 require_once 'Zend/Feed/Reader.php';
       
    26 
       
    27 /**
       
    28  * @see Zend_Feed_Reader_Extension_EntryAbstract
       
    29  */
       
    30 require_once 'Zend/Feed/Reader/Extension/EntryAbstract.php';
       
    31 
       
    32 /**
       
    33  * @see Zend_Date
       
    34  */
       
    35 require_once 'Zend/Date.php';
       
    36 
       
    37 /**
       
    38  * @see Zend_Uri
       
    39  */
       
    40 require_once 'Zend/Uri.php';
       
    41 
       
    42 /**
       
    43  * @see Zend_Feed_Reader_Collection_Category
       
    44  */
       
    45 require_once 'Zend/Feed/Reader/Collection/Category.php';
       
    46 
       
    47 /**
       
    48  * @see Zend_Feed_Reader_Feed_Atom_Source
       
    49  */
       
    50 require_once 'Zend/Feed/Reader/Feed/Atom/Source.php';
       
    51 
       
    52 /**
       
    53  * @category   Zend
       
    54  * @package    Zend_Feed_Reader
       
    55  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    56  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    57  */
       
    58 class Zend_Feed_Reader_Extension_Atom_Entry
       
    59     extends Zend_Feed_Reader_Extension_EntryAbstract
       
    60 {
       
    61     /**
       
    62      * Get the specified author
       
    63      *
       
    64      * @param  int $index
       
    65      * @return string|null
       
    66      */
       
    67     public function getAuthor($index = 0)
       
    68     {
       
    69         $authors = $this->getAuthors();
       
    70 
       
    71         if (isset($authors[$index])) {
       
    72             return $authors[$index];
       
    73         }
       
    74 
       
    75         return null;
       
    76     }
       
    77 
       
    78     /**
       
    79      * Get an array with feed authors
       
    80      *
       
    81      * @return array
       
    82      */
       
    83     public function getAuthors()
       
    84     {
       
    85         if (array_key_exists('authors', $this->_data)) {
       
    86             return $this->_data['authors'];
       
    87         }
       
    88 
       
    89         $authors = array();
       
    90         $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:author');
       
    91 
       
    92         if (!$list->length) {
       
    93             /**
       
    94              * TODO: Limit query to feed level els only!
       
    95              */
       
    96             $list = $this->getXpath()->query('//atom:author');
       
    97         }
       
    98 
       
    99         if ($list->length) {
       
   100             foreach ($list as $author) {
       
   101                 $author = $this->_getAuthor($author);
       
   102                 if (!empty($author)) {
       
   103                     $authors[] = $author;
       
   104                 }
       
   105             }
       
   106         }
       
   107 
       
   108         if (count($authors) == 0) {
       
   109             $authors = null;
       
   110         } else {
       
   111             $authors = new Zend_Feed_Reader_Collection_Author(
       
   112                 Zend_Feed_Reader::arrayUnique($authors)
       
   113             );
       
   114         }
       
   115 
       
   116         $this->_data['authors'] = $authors;
       
   117         return $this->_data['authors'];
       
   118     }
       
   119 
       
   120     /**
       
   121      * Get the entry content
       
   122      *
       
   123      * @return string
       
   124      */
       
   125     public function getContent()
       
   126     {
       
   127         if (array_key_exists('content', $this->_data)) {
       
   128             return $this->_data['content'];
       
   129         }
       
   130         
       
   131         $content = null;
       
   132         
       
   133         $el = $this->getXpath()->query($this->getXpathPrefix() . '/atom:content');
       
   134         if($el->length > 0) {
       
   135             $el = $el->item(0);
       
   136             $type = $el->getAttribute('type');
       
   137             switch ($type) {
       
   138                 case '':
       
   139                 case 'text':
       
   140                 case 'text/plain':
       
   141                 case 'html':
       
   142                 case 'text/html':
       
   143                     $content = $el->nodeValue;
       
   144                 break;
       
   145                 case 'xhtml':
       
   146                     $this->getXpath()->registerNamespace('xhtml', 'http://www.w3.org/1999/xhtml');
       
   147                     $xhtml = $this->getXpath()->query(
       
   148                         $this->getXpathPrefix() . '/atom:content/xhtml:div'
       
   149                     )->item(0);
       
   150                     //$xhtml->setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
       
   151                     $d = new DOMDocument('1.0', $this->getEncoding());
       
   152                     $xhtmls = $d->importNode($xhtml, true);
       
   153                     $d->appendChild($xhtmls);
       
   154                     $content = $this->_collectXhtml(
       
   155                         $d->saveXML(),
       
   156                         $d->lookupPrefix('http://www.w3.org/1999/xhtml')
       
   157                     );
       
   158                 break;
       
   159             }
       
   160         }
       
   161         
       
   162         //var_dump($content); exit;
       
   163 
       
   164         if (!$content) {
       
   165             $content = $this->getDescription();
       
   166         }
       
   167 
       
   168         $this->_data['content'] = trim($content);
       
   169 
       
   170         return $this->_data['content'];
       
   171     }
       
   172     
       
   173     /**
       
   174      * Parse out XHTML to remove the namespacing
       
   175      */
       
   176     protected function _collectXhtml($xhtml, $prefix)
       
   177     {
       
   178         if (!empty($prefix)) $prefix = $prefix . ':';
       
   179         $matches = array(
       
   180             "/<\?xml[^<]*>[^<]*<" . $prefix . "div[^<]*/",
       
   181             "/<\/" . $prefix . "div>\s*$/"
       
   182         );
       
   183         $xhtml = preg_replace($matches, '', $xhtml);
       
   184         if (!empty($prefix)) {
       
   185             $xhtml = preg_replace("/(<[\/]?)" . $prefix . "([a-zA-Z]+)/", '$1$2', $xhtml);
       
   186         }
       
   187         return $xhtml;
       
   188     }
       
   189 
       
   190     /**
       
   191      * Get the entry creation date
       
   192      *
       
   193      * @return string
       
   194      */
       
   195     public function getDateCreated()
       
   196     {
       
   197         if (array_key_exists('datecreated', $this->_data)) {
       
   198             return $this->_data['datecreated'];
       
   199         }
       
   200 
       
   201         $date = null;
       
   202 
       
   203         if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) {
       
   204             $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:created)');
       
   205         } else {
       
   206             $dateCreated = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:published)');
       
   207         }
       
   208 
       
   209         if ($dateCreated) {
       
   210             $date = new Zend_Date;
       
   211             $date->set($dateCreated, Zend_Date::ISO_8601);
       
   212         }
       
   213 
       
   214         $this->_data['datecreated'] = $date;
       
   215 
       
   216         return $this->_data['datecreated'];
       
   217     }
       
   218 
       
   219     /**
       
   220      * Get the entry modification date
       
   221      *
       
   222      * @return string
       
   223      */
       
   224     public function getDateModified()
       
   225     {
       
   226         if (array_key_exists('datemodified', $this->_data)) {
       
   227             return $this->_data['datemodified'];
       
   228         }
       
   229 
       
   230         $date = null;
       
   231 
       
   232         if ($this->_getAtomType() === Zend_Feed_Reader::TYPE_ATOM_03) {
       
   233             $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:modified)');
       
   234         } else {
       
   235             $dateModified = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:updated)');
       
   236         }
       
   237 
       
   238         if ($dateModified) {
       
   239             $date = new Zend_Date;
       
   240             $date->set($dateModified, Zend_Date::ISO_8601);
       
   241         }
       
   242 
       
   243         $this->_data['datemodified'] = $date;
       
   244 
       
   245         return $this->_data['datemodified'];
       
   246     }
       
   247 
       
   248     /**
       
   249      * Get the entry description
       
   250      *
       
   251      * @return string
       
   252      */
       
   253     public function getDescription()
       
   254     {
       
   255         if (array_key_exists('description', $this->_data)) {
       
   256             return $this->_data['description'];
       
   257         }
       
   258 
       
   259         $description = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:summary)');
       
   260 
       
   261         if (!$description) {
       
   262             $description = null;
       
   263         }
       
   264 
       
   265         $this->_data['description'] = $description;
       
   266 
       
   267         return $this->_data['description'];
       
   268     }
       
   269 
       
   270     /**
       
   271      * Get the entry enclosure
       
   272      *
       
   273      * @return string
       
   274      */
       
   275     public function getEnclosure()
       
   276     {
       
   277         if (array_key_exists('enclosure', $this->_data)) {
       
   278             return $this->_data['enclosure'];
       
   279         }
       
   280 
       
   281         $enclosure = null;
       
   282 
       
   283         $nodeList = $this->getXpath()->query($this->getXpathPrefix() . '/atom:link[@rel="enclosure"]');
       
   284 
       
   285         if ($nodeList->length > 0) {
       
   286             $enclosure = new stdClass();
       
   287             $enclosure->url    = $nodeList->item(0)->getAttribute('href');
       
   288             $enclosure->length = $nodeList->item(0)->getAttribute('length');
       
   289             $enclosure->type   = $nodeList->item(0)->getAttribute('type');
       
   290         }
       
   291 
       
   292         $this->_data['enclosure'] = $enclosure;
       
   293 
       
   294         return $this->_data['enclosure'];
       
   295     }
       
   296 
       
   297     /**
       
   298      * Get the entry ID
       
   299      *
       
   300      * @return string
       
   301      */
       
   302     public function getId()
       
   303     {
       
   304         if (array_key_exists('id', $this->_data)) {
       
   305             return $this->_data['id'];
       
   306         }
       
   307 
       
   308         $id = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:id)');
       
   309 
       
   310         if (!$id) {
       
   311             if ($this->getPermalink()) {
       
   312                 $id = $this->getPermalink();
       
   313             } elseif ($this->getTitle()) {
       
   314                 $id = $this->getTitle();
       
   315             } else {
       
   316                 $id = null;
       
   317             }
       
   318         }
       
   319 
       
   320         $this->_data['id'] = $id;
       
   321 
       
   322         return $this->_data['id'];
       
   323     }
       
   324 
       
   325     /**
       
   326      * Get the base URI of the feed (if set).
       
   327      *
       
   328      * @return string|null
       
   329      */
       
   330     public function getBaseUrl()
       
   331     {
       
   332         if (array_key_exists('baseUrl', $this->_data)) {
       
   333             return $this->_data['baseUrl'];
       
   334         }
       
   335 
       
   336         $baseUrl = $this->getXpath()->evaluate('string('
       
   337             . $this->getXpathPrefix() . '/@xml:base[1]'
       
   338         . ')');
       
   339 
       
   340         if (!$baseUrl) {
       
   341             $baseUrl = $this->getXpath()->evaluate('string(//@xml:base[1])');
       
   342         }
       
   343 
       
   344         if (!$baseUrl) {
       
   345             $baseUrl = null;
       
   346         }
       
   347 
       
   348         $this->_data['baseUrl'] = $baseUrl;
       
   349 
       
   350         return $this->_data['baseUrl'];
       
   351     }
       
   352 
       
   353     /**
       
   354      * Get a specific link
       
   355      *
       
   356      * @param  int $index
       
   357      * @return string
       
   358      */
       
   359     public function getLink($index = 0)
       
   360     {
       
   361         if (!array_key_exists('links', $this->_data)) {
       
   362             $this->getLinks();
       
   363         }
       
   364 
       
   365         if (isset($this->_data['links'][$index])) {
       
   366             return $this->_data['links'][$index];
       
   367         }
       
   368 
       
   369         return null;
       
   370     }
       
   371 
       
   372     /**
       
   373      * Get all links
       
   374      *
       
   375      * @return array
       
   376      */
       
   377     public function getLinks()
       
   378     {
       
   379         if (array_key_exists('links', $this->_data)) {
       
   380             return $this->_data['links'];
       
   381         }
       
   382 
       
   383         $links = array();
       
   384 
       
   385         $list = $this->getXpath()->query(
       
   386             $this->getXpathPrefix() . '//atom:link[@rel="alternate"]/@href' . '|' .
       
   387             $this->getXpathPrefix() . '//atom:link[not(@rel)]/@href'
       
   388         );
       
   389 
       
   390         if ($list->length) {
       
   391             foreach ($list as $link) {
       
   392                 $links[] = $this->_absolutiseUri($link->value);
       
   393             }
       
   394         }
       
   395 
       
   396         $this->_data['links'] = $links;
       
   397 
       
   398         return $this->_data['links'];
       
   399     }
       
   400 
       
   401     /**
       
   402      * Get a permalink to the entry
       
   403      *
       
   404      * @return string
       
   405      */
       
   406     public function getPermalink()
       
   407     {
       
   408         return $this->getLink(0);
       
   409     }
       
   410 
       
   411     /**
       
   412      * Get the entry title
       
   413      *
       
   414      * @return string
       
   415      */
       
   416     public function getTitle()
       
   417     {
       
   418         if (array_key_exists('title', $this->_data)) {
       
   419             return $this->_data['title'];
       
   420         }
       
   421 
       
   422         $title = $this->getXpath()->evaluate('string(' . $this->getXpathPrefix() . '/atom:title)');
       
   423 
       
   424         if (!$title) {
       
   425             $title = null;
       
   426         }
       
   427 
       
   428         $this->_data['title'] = $title;
       
   429 
       
   430         return $this->_data['title'];
       
   431     }
       
   432 
       
   433     /**
       
   434      * Get the number of comments/replies for current entry
       
   435      *
       
   436      * @return integer
       
   437      */
       
   438     public function getCommentCount()
       
   439     {
       
   440         if (array_key_exists('commentcount', $this->_data)) {
       
   441             return $this->_data['commentcount'];
       
   442         }
       
   443 
       
   444         $count = null;
       
   445 
       
   446         $this->getXpath()->registerNamespace('thread10', 'http://purl.org/syndication/thread/1.0');
       
   447         $list = $this->getXpath()->query(
       
   448             $this->getXpathPrefix() . '//atom:link[@rel="replies"]/@thread10:count'
       
   449         );
       
   450 
       
   451         if ($list->length) {
       
   452             $count = $list->item(0)->value;
       
   453         }
       
   454 
       
   455         $this->_data['commentcount'] = $count;
       
   456 
       
   457         return $this->_data['commentcount'];
       
   458     }
       
   459 
       
   460     /**
       
   461      * Returns a URI pointing to the HTML page where comments can be made on this entry
       
   462      *
       
   463      * @return string
       
   464      */
       
   465     public function getCommentLink()
       
   466     {
       
   467         if (array_key_exists('commentlink', $this->_data)) {
       
   468             return $this->_data['commentlink'];
       
   469         }
       
   470 
       
   471         $link = null;
       
   472 
       
   473         $list = $this->getXpath()->query(
       
   474             $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="text/html"]/@href'
       
   475         );
       
   476 
       
   477         if ($list->length) {
       
   478             $link = $list->item(0)->value;
       
   479             $link = $this->_absolutiseUri($link);
       
   480         }
       
   481 
       
   482         $this->_data['commentlink'] = $link;
       
   483 
       
   484         return $this->_data['commentlink'];
       
   485     }
       
   486 
       
   487     /**
       
   488      * Returns a URI pointing to a feed of all comments for this entry
       
   489      *
       
   490      * @return string
       
   491      */
       
   492     public function getCommentFeedLink($type = 'atom')
       
   493     {
       
   494         if (array_key_exists('commentfeedlink', $this->_data)) {
       
   495             return $this->_data['commentfeedlink'];
       
   496         }
       
   497 
       
   498         $link = null;
       
   499 
       
   500         $list = $this->getXpath()->query(
       
   501             $this->getXpathPrefix() . '//atom:link[@rel="replies" and @type="application/'.$type.'+xml"]/@href'
       
   502         );
       
   503 
       
   504         if ($list->length) {
       
   505             $link = $list->item(0)->value;
       
   506             $link = $this->_absolutiseUri($link);
       
   507         }
       
   508 
       
   509         $this->_data['commentfeedlink'] = $link;
       
   510 
       
   511         return $this->_data['commentfeedlink'];
       
   512     }
       
   513     
       
   514     /**
       
   515      * Get all categories
       
   516      *
       
   517      * @return Zend_Feed_Reader_Collection_Category
       
   518      */
       
   519     public function getCategories()
       
   520     {
       
   521         if (array_key_exists('categories', $this->_data)) {
       
   522             return $this->_data['categories'];
       
   523         }
       
   524 
       
   525         if ($this->_getAtomType() == Zend_Feed_Reader::TYPE_ATOM_10) {
       
   526             $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom:category');
       
   527         } else {
       
   528             /**
       
   529              * Since Atom 0.3 did not support categories, it would have used the
       
   530              * Dublin Core extension. However there is a small possibility Atom 0.3
       
   531              * may have been retrofittied to use Atom 1.0 instead.
       
   532              */
       
   533             $this->getXpath()->registerNamespace('atom10', Zend_Feed_Reader::NAMESPACE_ATOM_10);
       
   534             $list = $this->getXpath()->query($this->getXpathPrefix() . '//atom10:category');
       
   535         }
       
   536 
       
   537         if ($list->length) {
       
   538             $categoryCollection = new Zend_Feed_Reader_Collection_Category;
       
   539             foreach ($list as $category) {
       
   540                 $categoryCollection[] = array(
       
   541                     'term' => $category->getAttribute('term'),
       
   542                     'scheme' => $category->getAttribute('scheme'),
       
   543                     'label' => $category->getAttribute('label')
       
   544                 );
       
   545             }
       
   546         } else {
       
   547             return new Zend_Feed_Reader_Collection_Category;
       
   548         }
       
   549 
       
   550         $this->_data['categories'] = $categoryCollection;
       
   551 
       
   552         return $this->_data['categories'];
       
   553     }
       
   554     
       
   555     /**
       
   556      * Get source feed metadata from the entry
       
   557      *
       
   558      * @return Zend_Feed_Reader_Feed_Atom_Source|null
       
   559      */
       
   560     public function getSource()
       
   561     {
       
   562         if (array_key_exists('source', $this->_data)) {
       
   563             return $this->_data['source'];
       
   564         }
       
   565         
       
   566         $source = null;
       
   567         // TODO: Investigate why _getAtomType() fails here. Is it even needed?
       
   568         if ($this->getType() == Zend_Feed_Reader::TYPE_ATOM_10) {
       
   569             $list = $this->getXpath()->query($this->getXpathPrefix() . '/atom:source[1]');
       
   570             if ($list->length) {
       
   571                 $element = $list->item(0);
       
   572                 $source = new Zend_Feed_Reader_Feed_Atom_Source($element, $this->getXpathPrefix());
       
   573             }
       
   574         }
       
   575         
       
   576         $this->_data['source'] = $source;
       
   577         return $this->_data['source']; 
       
   578     }
       
   579 
       
   580     /**
       
   581      *  Attempt to absolutise the URI, i.e. if a relative URI apply the
       
   582      *  xml:base value as a prefix to turn into an absolute URI.
       
   583      */
       
   584     protected function _absolutiseUri($link)
       
   585     {
       
   586         if (!Zend_Uri::check($link)) {
       
   587             if ($this->getBaseUrl() !== null) {
       
   588                 $link = $this->getBaseUrl() . $link;
       
   589                 if (!Zend_Uri::check($link)) {
       
   590                     $link = null;
       
   591                 }
       
   592             }
       
   593         }
       
   594         return $link;
       
   595     }
       
   596 
       
   597     /**
       
   598      * Get an author entry
       
   599      *
       
   600      * @param DOMElement $element
       
   601      * @return string
       
   602      */
       
   603     protected function _getAuthor(DOMElement $element)
       
   604     {
       
   605         $author = array();
       
   606 
       
   607         $emailNode = $element->getElementsByTagName('email');
       
   608         $nameNode  = $element->getElementsByTagName('name');
       
   609         $uriNode   = $element->getElementsByTagName('uri');
       
   610         
       
   611         if ($emailNode->length && strlen($emailNode->item(0)->nodeValue) > 0) {
       
   612             $author['email'] = $emailNode->item(0)->nodeValue;
       
   613         }
       
   614 
       
   615         if ($nameNode->length && strlen($nameNode->item(0)->nodeValue) > 0) {
       
   616             $author['name'] = $nameNode->item(0)->nodeValue;
       
   617         }
       
   618 
       
   619         if ($uriNode->length && strlen($uriNode->item(0)->nodeValue) > 0) {
       
   620             $author['uri'] = $uriNode->item(0)->nodeValue;
       
   621         }
       
   622 
       
   623         if (empty($author)) {
       
   624             return null;
       
   625         }
       
   626         return $author;
       
   627     }
       
   628 
       
   629     /**
       
   630      * Register the default namespaces for the current feed format
       
   631      */
       
   632     protected function _registerNamespaces()
       
   633     {
       
   634         switch ($this->_getAtomType()) {
       
   635             case Zend_Feed_Reader::TYPE_ATOM_03:
       
   636                 $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_03);
       
   637                 break;
       
   638             default:
       
   639                 $this->getXpath()->registerNamespace('atom', Zend_Feed_Reader::NAMESPACE_ATOM_10);
       
   640                 break;
       
   641         }
       
   642     }
       
   643 
       
   644     /**
       
   645      * Detect the presence of any Atom namespaces in use
       
   646      */
       
   647     protected function _getAtomType()
       
   648     {
       
   649         $dom = $this->getDomDocument();
       
   650         $prefixAtom03 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_03);
       
   651         $prefixAtom10 = $dom->lookupPrefix(Zend_Feed_Reader::NAMESPACE_ATOM_10);
       
   652         if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_03)
       
   653         || !empty($prefixAtom03)) {
       
   654             return Zend_Feed_Reader::TYPE_ATOM_03;
       
   655         }
       
   656         if ($dom->isDefaultNamespace(Zend_Feed_Reader::NAMESPACE_ATOM_10)
       
   657         || !empty($prefixAtom10)) {
       
   658             return Zend_Feed_Reader::TYPE_ATOM_10;
       
   659         }
       
   660     }
       
   661 }