Переглянути джерело

Added Zend_Feed_Reader_FeedSet class extending ArrayObject
Added support for lazy loading detected feeds from Zend_Feed_Reader::findFeedLinks() method result (FeedSet)
Added support for retaining all links detected as a FeedSet Array Object
Maintains backwards compatibility with previous API as a "quick method" when other features not required.
Implements (among other things) the improvement suggested in ZF-7870


git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@18318 44c647ce-9c0f-0410-b52a-842ac1e357ba

padraic 16 роки тому
батько
коміт
9c8d4bbf21

+ 35 - 1
documentation/manual/en/module_specs/Zend_Feed_Reader.xml

@@ -382,11 +382,19 @@ $feed = Zend_Feed_Reader::import(
         <para>
             This method calls any <acronym>URI</acronym> and searches for the location of
             <acronym>RSS</acronym>, <acronym>RDF</acronym>
-            and Atom feeds assuming the wlebsite's <acronym>HTML</acronym> contains the relevant
+            and Atom feeds assuming the website's <acronym>HTML</acronym> contains the relevant
             links. It then returns a value object where you can check for the existence of a
             <acronym>RSS</acronym>, <acronym>RDF</acronym> or Atom feed <acronym>URI</acronym>.
         </para>
 
+        <para>
+            The returned object is an <classname>ArrayObject</classname>
+            called <classname>Zend_Feed_Reader_FeedSet</classname> so you can cast
+            it to an array, or iterate over it, to access all the detected links.
+            However, as a simple shortcut, you can just grab the first RSS, RDF
+            or Atom link using its public properties as in the example below.
+        </para>
+
         <programlisting language="php"><![CDATA[
 $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
 
@@ -405,6 +413,32 @@ if(isset($links->atom)) {
             Based on these links, you can then import from whichever source you
             wish in the usual manner.
         </para>
+
+        <para>
+            This quick method only gives you one link for each feed type, but
+            websites may indicate many links of any type. Perhaps it's a news
+            site with a RSS feed for each news category. You can iterate over
+            all links using the ArrayObject's iterator.
+        </para>
+
+                <programlisting language="php"><![CDATA[
+$links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
+
+foreach ($links as $link) {
+    echo $link['href'], "\n";
+}
+]]></programlisting>
+
+        <para>The available keys are <emphasis>href</emphasis>, <emphasis>rel</emphasis>
+        which will always be 'alternate', <emphasis>type</emphasis> which will
+        be one of <code>application/rss+xml</code>, <code>application/rdf+xml</code>
+        or <code>application/atom+xml</code> and <emphasis>feed</emphasis>.
+        <emphasis>feed</emphasis> is only available if you preserve the
+        <classname>ArrayObject</classname> (i.e. do not cast it to an array)
+        and using it triggers an attempt to load the feed into a
+        <classname>Zend_Feed_Reader_FeedAbstract</classname> instance. This
+        is a lazy loaded attempt - feeds are never loaded until you try to
+        access them using this method.</para>
   </sect2>
 
   <sect2 id="zend.feed.reader.retrieve-info">

+ 19 - 28
library/Zend/Feed/Reader.php

@@ -35,6 +35,11 @@ require_once 'Zend/Feed/Reader/Feed/Rss.php';
 require_once 'Zend/Feed/Reader/Feed/Atom.php';
 
 /**
+ * @see Zend_Feed_Reader_FeedSet
+ */
+require_once 'Zend/Feed/Reader/FeedSet.php';
+
+/**
  * @category   Zend
  * @package    Zend_Feed_Reader
  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
@@ -378,40 +383,26 @@ class Zend_Feed_Reader
             throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
         }
         $responseHtml = $response->getBody();
-        @ini_set('track_errors', 1);
+        $libxml_errflag = libxml_use_internal_errors(true);
         $dom = new DOMDocument;
-        $status = @$dom->loadHTML($responseHtml);
-        @ini_restore('track_errors');
+        $status = $dom->loadHTML($responseHtml);
+        libxml_use_internal_errors($libxml_errflag);
         if (!$status) {
-            if (!isset($php_errormsg)) {
-                if (function_exists('xdebug_is_enabled')) {
-                    $php_errormsg = '(error message not available, when XDebug is running)';
-                } else {
-                    $php_errormsg = '(error message not available)';
-                }
+            // Build error message
+            $error = libxml_get_last_error();
+            if ($error && $error->message) {
+                $errormsg = "DOMDocument cannot parse HTML: {$error->message}";
+            } else {
+                $errormsg = "DOMDocument cannot parse HTML: Please check the XML document's validity";
             }
+
             require_once 'Zend/Feed/Exception.php';
-            throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg");
+            throw new Zend_Feed_Exception($errormsg);
         }
-        $feedLinks = new stdClass;
+        $feedSet = new Zend_Feed_Reader_FeedSet;
         $links = $dom->getElementsByTagName('link');
-        foreach ($links as $link) {
-            if (strtolower($link->getAttribute('rel')) !== 'alternate'
-                || !$link->getAttribute('type') || !$link->getAttribute('href')) {
-                continue;
-            }
-            if (!isset($feedLinks->rss) && $link->getAttribute('type') == 'application/rss+xml') {
-                $feedLinks->rss = $link->getAttribute('href');
-            } elseif(!isset($feedLinks->atom) && $link->getAttribute('type') == 'application/atom+xml') {
-                $feedLinks->atom = $link->getAttribute('href');
-            } elseif(!isset($feedLinks->rdf) && $link->getAttribute('type') == 'application/rdf+xml') {
-                $feedLinks->rdf = $link->getAttribute('href');
-            }
-            if (isset($feedLinks->rss) && isset($feedLinks->atom) && isset($feedLinks->rdf)) {
-                break;
-            }
-        }
-        return $feedLinks;
+        $feedSet->addLinks($links);
+        return $feedSet;
     }
 
     /**

+ 40 - 0
tests/Zend/Feed/ReaderTest.php

@@ -174,6 +174,46 @@ class Zend_Feed_ReaderTest extends PHPUnit_Framework_TestCase
         $this->assertEquals('http://www.planet-php.org/rss/', $links->rss);
     }
 
+    public function testCompilesLinksAsArrayObject()
+    {
+        if (!defined('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+            || !constant('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+        ) {
+            $this->markTestSkipped('testGetsFeedLinksAsValueObject() requires a network connection');
+            return;
+        }
+        $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
+        $this->assertTrue($links instanceof Zend_Feed_Reader_FeedSet);
+        $this->assertEquals(array(
+            'rel' => 'alternate', 'type' => 'application/rss+xml', 'href' => 'http://www.planet-php.org/rss/'
+        ), (array) $links->getIterator()->current());
+    }
+
+    public function testFeedSetLoadsFeedObjectWhenFeedArrayKeyAccessed()
+    {
+        if (!defined('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+            || !constant('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+        ) {
+            $this->markTestSkipped('testGetsFeedLinksAsValueObject() requires a network connection');
+            return;
+        }
+        $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
+        $link = $links->getIterator()->current();
+        $this->assertTrue($link['feed'] instanceof Zend_Feed_Reader_Feed_Rss);
+    }
+
+    public function testZeroCountFeedSetReturnedFromEmptyList()
+    {
+        if (!defined('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+            || !constant('TESTS_ZEND_FEED_READER_ONLINE_ENABLED')
+        ) {
+            $this->markTestSkipped('testGetsFeedLinksAsValueObject() requires a network connection');
+            return;
+        }
+        $links = Zend_Feed_Reader::findFeedLinks('http://www.example.com');
+        $this->assertEquals(0, count($links));
+    }
+
     public function testAddsPrefixPath()
     {
         Zend_Feed_Reader::addPrefixPath('A_B_C', '/A/B/C');