Forráskód Böngészése

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 éve
szülő
commit
9c8d4bbf21

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

@@ -382,11 +382,19 @@ $feed = Zend_Feed_Reader::import(
         <para>
         <para>
             This method calls any <acronym>URI</acronym> and searches for the location of
             This method calls any <acronym>URI</acronym> and searches for the location of
             <acronym>RSS</acronym>, <acronym>RDF</acronym>
             <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
             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>.
             <acronym>RSS</acronym>, <acronym>RDF</acronym> or Atom feed <acronym>URI</acronym>.
         </para>
         </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[
         <programlisting language="php"><![CDATA[
 $links = Zend_Feed_Reader::findFeedLinks('http://www.planet-php.net');
 $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
             Based on these links, you can then import from whichever source you
             wish in the usual manner.
             wish in the usual manner.
         </para>
         </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>
 
 
   <sect2 id="zend.feed.reader.retrieve-info">
   <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';
 require_once 'Zend/Feed/Reader/Feed/Atom.php';
 
 
 /**
 /**
+ * @see Zend_Feed_Reader_FeedSet
+ */
+require_once 'Zend/Feed/Reader/FeedSet.php';
+
+/**
  * @category   Zend
  * @category   Zend
  * @package    Zend_Feed_Reader
  * @package    Zend_Feed_Reader
  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  * @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());
             throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
         }
         }
         $responseHtml = $response->getBody();
         $responseHtml = $response->getBody();
-        @ini_set('track_errors', 1);
+        $libxml_errflag = libxml_use_internal_errors(true);
         $dom = new DOMDocument;
         $dom = new DOMDocument;
-        $status = @$dom->loadHTML($responseHtml);
-        @ini_restore('track_errors');
+        $status = $dom->loadHTML($responseHtml);
+        libxml_use_internal_errors($libxml_errflag);
         if (!$status) {
         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';
             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');
         $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);
         $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()
     public function testAddsPrefixPath()
     {
     {
         Zend_Feed_Reader::addPrefixPath('A_B_C', '/A/B/C');
         Zend_Feed_Reader::addPrefixPath('A_B_C', '/A/B/C');