Browse Source

Patch to enforce Atom Tombstones fully in Zend_Feed_Writer

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@20518 44c647ce-9c0f-0410-b52a-842ac1e357ba
padraic 16 năm trước cách đây
mục cha
commit
b805e8ba23

+ 202 - 0
library/Zend/Feed/Writer/Deleted.php

@@ -0,0 +1,202 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Feed_Writer
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Feed.php 20096 2010-01-06 02:05:09Z bkarwin $
+ */
+
+require_once 'Zend/Feed/Writer/Feed/FeedAbstract.php';
+ 
+ /**
+ * @category   Zend
+ * @package    Zend_Feed_Writer
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Feed_Writer_Deleted
+{
+
+    /**
+     * Internal array containing all data associated with this entry or item.
+     *
+     * @var array
+     */
+    protected $_data = array();
+    
+    /**
+     * Holds the value "atom" or "rss" depending on the feed type set when
+     * when last exported.
+     *
+     * @var string
+     */
+    protected $_type = null;
+    
+    /**
+     * Set the feed character encoding
+     *
+     * @return string|null
+     */
+    public function setEncoding($encoding)
+    {
+        if (empty($encoding) || !is_string($encoding)) {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Invalid parameter: parameter must be a non-empty string');
+        }
+        $this->_data['encoding'] = $encoding;
+    }
+
+    /**
+     * Get the feed character encoding
+     *
+     * @return string|null
+     */
+    public function getEncoding()
+    {
+        if (!array_key_exists('encoding', $this->_data)) {
+            return 'UTF-8';
+        }
+        return $this->_data['encoding'];
+    }
+    
+    /**
+     * Unset a specific data point
+     *
+     * @param string $name
+     */
+    public function remove($name)
+    {
+        if (isset($this->_data[$name])) {
+            unset($this->_data[$name]);
+        }
+    }
+    
+    /**
+     * Set the current feed type being exported to "rss" or "atom". This allows
+     * other objects to gracefully choose whether to execute or not, depending
+     * on their appropriateness for the current type, e.g. renderers.
+     *
+     * @param string $type
+     */
+    public function setType($type)
+    {
+        $this->_type = $type;
+    }
+    
+    /**
+     * Retrieve the current or last feed type exported.
+     *
+     * @return string Value will be "rss" or "atom"
+     */
+    public function getType()
+    {
+        return $this->_type;
+    }
+    
+    public function setReference($reference)
+    {
+        if (empty($reference) || !is_string($reference)) {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Invalid parameter: reference must be a non-empty string');
+        }
+        $this->_data['reference'] = $reference;
+    }
+    
+    public function getReference()
+    {
+        if (!array_key_exists('reference', $this->_data)) {
+            return null;
+        }
+        return $this->_data['reference'];
+    }
+    
+    public function setWhen($date = null)
+    {
+        $zdate = null;
+        if (is_null($date)) {
+            $zdate = new Zend_Date;
+        } elseif (ctype_digit($date) && strlen($date) == 10) {
+            $zdate = new Zend_Date($date, Zend_Date::TIMESTAMP);
+        } elseif ($date instanceof Zend_Date) {
+            $zdate = $date;
+        } else {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Invalid Zend_Date object or UNIX Timestamp passed as parameter');
+        }
+        $this->_data['when'] = $zdate;
+    }
+    
+    public function getWhen()
+    {
+        if (!array_key_exists('when', $this->_data)) {
+            return null;
+        }
+        return $this->_data['when'];
+    }
+    
+    public function setBy(array $by)
+    {
+        $author = array();
+        if (!array_key_exists('name', $by) 
+            || empty($by['name']) 
+            || !is_string($by['name'])
+        ) {
+            require_once 'Zend/Feed/Exception.php';
+            throw new Zend_Feed_Exception('Invalid parameter: author array must include a "name" key with a non-empty string value');
+        }
+        $author['name'] = $by['name'];
+        if (isset($by['email'])) {
+            if (empty($by['email']) || !is_string($by['email'])) {
+                require_once 'Zend/Feed/Exception.php';
+                throw new Zend_Feed_Exception('Invalid parameter: "email" array value must be a non-empty string');
+            }
+            $author['email'] = $by['email'];
+        }
+        if (isset($by['uri'])) {
+            if (empty($by['uri']) 
+                || !is_string($by['uri']) 
+                || !Zend_Uri::check($by['uri'])
+            ) {
+                require_once 'Zend/Feed/Exception.php';
+                throw new Zend_Feed_Exception('Invalid parameter: "uri" array value must be a non-empty string and valid URI/IRI');
+            }
+            $author['uri'] = $by['uri'];
+        }
+        $this->_data['by'] = $author;
+    }
+    
+    public function getBy()
+    {
+        if (!array_key_exists('by', $this->_data)) {
+            return null;
+        }
+        return $this->_data['by'];
+    }
+    
+    public function setComment($comment)
+    {
+        $this->_data['comment'] = $comment;
+    }
+    
+    public function getComment()
+    {
+        if (!array_key_exists('comment', $this->_data)) {
+            return null;
+        }
+        return $this->_data['comment'];
+    }
+
+}

+ 4 - 0
library/Zend/Feed/Writer/Entry.php

@@ -109,6 +109,10 @@ class Zend_Feed_Writer_Entry
                 }
                 $author['uri'] = $name['uri'];
             }
+        /**
+         * @deprecated
+         * Array notation (above) is preferred and will be the sole supported input from ZF 2.0
+         */
         } else {
             if (empty($name['name']) || !is_string($name['name'])) {
                 require_once 'Zend/Feed/Exception.php';

+ 33 - 0
library/Zend/Feed/Writer/Feed.php

@@ -40,6 +40,11 @@ require_once 'Zend/Feed/Writer.php';
 require_once 'Zend/Feed/Writer/Entry.php';
 
 /**
+ * @see Zend_Feed_Writer_Deleted
+ */
+require_once 'Zend/Feed/Writer/Deleted.php';
+
+/**
  * @see Zend_Feed_Writer_Renderer_Feed_Atom
  */
 require_once 'Zend/Feed/Writer/Renderer/Feed/Atom.php';
@@ -93,6 +98,34 @@ implements Iterator, Countable
     }
 
     /**
+     * Appends a Zend_Feed_Writer_Deleted object representing a new entry tombstone
+     * to the feed data container's internal group of entries.
+     *
+     * @param Zend_Feed_Writer_Deleted $entry
+     */
+    public function addTombstone(Zend_Feed_Writer_Deleted $deleted)
+    {
+        $this->_entries[] = $deleted;
+    }
+    
+    /**
+     * Creates a new Zend_Feed_Writer_Deleted data container for use. This is NOT
+     * added to the current feed automatically, but is necessary to create a
+     * container with some initial values preset based on the current feed data.
+     *
+     * @return Zend_Feed_Writer_Deleted
+     */
+    public function createTombstone()
+    {
+        $deleted = new Zend_Feed_Writer_Deleted;
+        if ($this->getEncoding()) {
+            $deleted->setEncoding($this->getEncoding());
+        }
+        $deleted->setType($this->getType());
+        return $deleted;
+    }
+
+    /**
      * Appends a Zend_Feed_Writer_Entry object representing a new entry/item
      * the feed data container's internal group of entries.
      *

+ 121 - 0
library/Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php

@@ -0,0 +1,121 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Feed_Writer
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Atom.php 20506 2010-01-21 22:19:05Z padraic $
+ */
+
+/**
+ * @see Zend_Feed_Writer_Renderer_RendererAbstract
+ */
+require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Feed_Writer
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Feed_Writer_Renderer_Entry_Atom_Deleted
+    extends Zend_Feed_Writer_Renderer_RendererAbstract
+    implements Zend_Feed_Writer_Renderer_RendererInterface
+{
+    /**
+     * Constructor
+     * 
+     * @param  Zend_Feed_Writer_Deleted $container 
+     * @return void
+     */
+    public function __construct (Zend_Feed_Writer_Deleted $container)
+    {
+        parent::__construct($container);
+    }
+
+    /**
+     * Render atom entry
+     * 
+     * @return Zend_Feed_Writer_Renderer_Entry_Atom
+     */
+    public function render()
+    {
+        $this->_dom = new DOMDocument('1.0', $this->_container->getEncoding());
+        $this->_dom->formatOutput = true;
+        $entry = $this->_dom->createElement('at:deleted-entry');
+        $this->_dom->appendChild($entry);
+        
+        $entry->setAttribute('ref', $this->_container->getReference());
+        $entry->setAttribute('when', $this->_container->getWhen()->get(Zend_Date::ISO_8601));
+        
+        $this->_setBy($this->_dom, $entry);
+        $this->_setComment($this->_dom, $entry);
+        
+        return $this;
+    }
+    
+    /**
+     * Set tombstone comment
+     * 
+     * @param  DOMDocument $dom 
+     * @param  DOMElement $root 
+     * @return void
+     */
+    protected function _setComment(DOMDocument $dom, DOMElement $root)
+    {
+        if(!$this->getDataContainer()->getComment()) {
+            return;
+        }
+        $c = $dom->createElement('at:comment');
+        $root->appendChild($c);
+        $c->setAttribute('type', 'html');
+        $cdata = $dom->createCDATASection($this->getDataContainer()->getComment());
+        $c->appendChild($cdata);
+    }
+    
+    /**
+     * Set entry authors 
+     * 
+     * @param  DOMDocument $dom 
+     * @param  DOMElement $root 
+     * @return void
+     */
+    protected function _setBy(DOMDocument $dom, DOMElement $root)
+    {
+        $data = $this->_container->getBy();
+        if ((!$data || empty($data))) {
+            return;
+        }
+        $author = $this->_dom->createElement('at:by');
+        $name = $this->_dom->createElement('name');
+        $author->appendChild($name);
+        $root->appendChild($author);
+        $text = $dom->createTextNode($data['name']);
+        $name->appendChild($text);
+        if (array_key_exists('email', $data)) {
+            $email = $this->_dom->createElement('email');
+            $author->appendChild($email);
+            $text = $dom->createTextNode($data['email']);
+            $email->appendChild($text);
+        }
+        if (array_key_exists('uri', $data)) {
+            $uri = $this->_dom->createElement('uri');
+            $author->appendChild($uri);
+            $text = $dom->createTextNode($data['uri']);
+            $uri->appendChild($text);
+        }
+    }
+    
+}

+ 13 - 1
library/Zend/Feed/Writer/Renderer/Feed/Atom.php

@@ -31,6 +31,9 @@ require_once 'Zend/Feed/Writer/Renderer/RendererInterface.php';
 /** @see Zend_Feed_Writer_Renderer_Entry_Atom */
 require_once 'Zend/Feed/Writer/Renderer/Entry/Atom.php';
 
+/** @see Zend_Feed_Writer_Renderer_Entry_Atom_Deleted */
+require_once 'Zend/Feed/Writer/Renderer/Entry/Atom/Deleted.php';
+
 /** @see Zend_Feed_Writer_Renderer_RendererAbstract */
 require_once 'Zend/Feed/Writer/Renderer/RendererAbstract.php';
 
@@ -100,7 +103,16 @@ class Zend_Feed_Writer_Renderer_Feed_Atom
             if ($this->getDataContainer()->getEncoding()) {
                 $entry->setEncoding($this->getDataContainer()->getEncoding());
             }
-            $renderer = new Zend_Feed_Writer_Renderer_Entry_Atom($entry);
+            if ($entry instanceof Zend_Feed_Writer_Entry) {
+                $renderer = new Zend_Feed_Writer_Renderer_Entry_Atom($entry);
+            } else {
+                if (!$this->_dom->documentElement->hasAttribute('xmlns:at')) {
+                    $this->_dom->documentElement->setAttribute(
+                        'xmlns:at', 'http://purl.org/atompub/tombstones/1.0'
+                    );
+                }
+                $renderer = new Zend_Feed_Writer_Renderer_Entry_Atom_Deleted($entry);
+            }
             if ($this->_ignoreExceptions === true) {
                 $renderer->ignoreExceptions();
             }

+ 5 - 1
library/Zend/Feed/Writer/Renderer/Feed/Rss.php

@@ -98,7 +98,11 @@ class Zend_Feed_Writer_Renderer_Feed_Rss
             if ($this->getDataContainer()->getEncoding()) {
                 $entry->setEncoding($this->getDataContainer()->getEncoding());
             }
-            $renderer = new Zend_Feed_Writer_Renderer_Entry_Rss($entry);
+            if ($entry instanceof Zend_Feed_Writer_Entry) {
+                $renderer = new Zend_Feed_Writer_Renderer_Entry_Rss($entry);
+            } else {
+                continue;
+            }
             if ($this->_ignoreExceptions === true) {
                 $renderer->ignoreExceptions();
             }

+ 2 - 0
tests/Zend/Feed/AllTests.php

@@ -53,6 +53,7 @@ require_once 'Zend/Feed/Reader/Integration/H-OnlineComAtom10Test.php';
 
 require_once 'Zend/Feed/Writer/FeedTest.php';
 require_once 'Zend/Feed/Writer/EntryTest.php';
+require_once 'Zend/Feed/Writer/DeletedTest.php';
 require_once 'Zend/Feed/Writer/Renderer/Feed/AtomTest.php';
 require_once 'Zend/Feed/Writer/Renderer/Feed/RssTest.php';
 require_once 'Zend/Feed/Writer/Renderer/Entry/AtomTest.php';
@@ -120,6 +121,7 @@ class Zend_Feed_AllTests
         
         $suite->addTestSuite('Zend_Feed_Writer_FeedTest');
         $suite->addTestSuite('Zend_Feed_Writer_EntryTest');
+        $suite->addTestSuite('Zend_Feed_Writer_DeletedTest');
         $suite->addTestSuite('Zend_Feed_Writer_Renderer_Feed_AtomTest');
         $suite->addTestSuite('Zend_Feed_Writer_Renderer_Feed_RssTest');
         $suite->addTestSuite('Zend_Feed_Writer_Renderer_Entry_AtomTest');

+ 163 - 0
tests/Zend/Feed/Writer/DeletedTest.php

@@ -0,0 +1,163 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Feed
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/TestHelper.php';
+
+require_once 'Zend/Feed/Writer/Deleted.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Exception
+ * @subpackage UnitTests
+ * @group      Zend_Feed
+ * @group      Zend_Feed_Writer
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Feed_Writer_DeletedTest extends PHPUnit_Framework_TestCase
+{
+
+    public function testSetsReference()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setReference('http://www.example.com/id');
+        $this->assertEquals('http://www.example.com/id', $entry->getReference());
+    }
+
+    public function testSetReferenceThrowsExceptionOnInvalidParameter()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setReference('');
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+
+    public function testGetReferenceReturnsNullIfNotSet()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $this->assertTrue(is_null($entry->getReference()));
+    }
+    
+    public function testSetWhenDefaultsToCurrentTime()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setWhen();
+        $dateNow = new Zend_Date;
+        $this->assertTrue($dateNow->isLater($entry->getWhen()) || $dateNow->equals($entry->getWhen()));
+    }
+
+    public function testSetWhenUsesGivenUnixTimestamp()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setWhen(1234567890);
+        $myDate = new Zend_Date('1234567890', Zend_Date::TIMESTAMP);
+        $this->assertTrue($myDate->equals($entry->getWhen()));
+    }
+
+    public function testSetWhenUsesZendDateObject()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setWhen(new Zend_Date('1234567890', Zend_Date::TIMESTAMP));
+        $myDate = new Zend_Date('1234567890', Zend_Date::TIMESTAMP);
+        $this->assertTrue($myDate->equals($entry->getWhen()));
+    }
+    
+    public function testSetWhenThrowsExceptionOnInvalidParameter()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setWhen('abc');
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+    
+    public function testGetWhenReturnsNullIfDateNotSet()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $this->assertTrue(is_null($entry->getWhen()));
+    }
+    
+    public function testAddsByNameFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setBy(array('name'=>'Joe'));
+        $this->assertEquals(array('name'=>'Joe'), $entry->getBy());
+    }
+
+    public function testAddsByEmailFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setBy(array('name'=>'Joe','email'=>'joe@example.com'));
+        $this->assertEquals(array('name'=>'Joe', 'email' => 'joe@example.com'), $entry->getBy());
+    }
+
+    public function testAddsByUriFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        $entry->setBy(array('name'=>'Joe','uri'=>'http://www.example.com'));
+        $this->assertEquals(array('name'=>'Joe', 'uri' => 'http://www.example.com'), $entry->getBy());
+    }
+
+    public function testAddByThrowsExceptionOnInvalidNameFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setBy(array('name'=>''));
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+
+    public function testAddByThrowsExceptionOnInvalidEmailFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setBy(array('name'=>'Joe','email'=>''));
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+
+    public function testAddByThrowsExceptionOnInvalidUriFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setBy(array('name'=>'Joe','uri'=>'notauri'));
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+
+    public function testAddByThrowsExceptionIfNameOmittedFromArray()
+    {
+        $entry = new Zend_Feed_Writer_Deleted;
+        try {
+            $entry->setBy(array('uri'=>'notauri'));
+            $this->fail();
+        } catch (Zend_Feed_Exception $e) {
+        }
+    }
+
+}

+ 1 - 1
tests/Zend/Feed/Writer/EntryTest.php

@@ -426,7 +426,7 @@ class Zend_Feed_Writer_EntryTest extends PHPUnit_Framework_TestCase
         }
     }
 
-    public function testGetIdReturnsNullIfDateNotSet()
+    public function testGetIdReturnsNullIfNotSet()
     {
         $entry = new Zend_Feed_Writer_Entry;
         $this->assertTrue(is_null($entry->getId()));