From f2486296a731732f177d068e0ac9d1e645f1b607 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Sun, 26 Dec 2010 23:31:47 +1300 Subject: [PATCH] A new AtomFeed class for building an Atom feed. Plus the change in rss.php to use it. Signed-off-by: Andrew McMillan --- htdocs/rss.php | 4 +- inc/AtomFeed.php | 232 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 inc/AtomFeed.php diff --git a/htdocs/rss.php b/htdocs/rss.php index ae50870c..c6e37dab 100644 --- a/htdocs/rss.php +++ b/htdocs/rss.php @@ -72,8 +72,8 @@ function caldav_get_rss( $request ) { * the timezones that are referred to by the events we have selected. * Library used: http://framework.zend.com/manual/en/zend.feed.writer.html */ - require_once('Zend/Feed/Writer/Feed.php'); - $feed = new Zend_Feed_Writer_Feed; + require_once('AtomFeed.php'); + $feed = new AtomFeed(); $feed->setTitle('CalDAV RSS Feed: '. $collection->GetProperty('displayname')); $url = $c->protocol_server_port . $collection->url(); diff --git a/inc/AtomFeed.php b/inc/AtomFeed.php new file mode 100644 index 00000000..e9e43a0d --- /dev/null +++ b/inc/AtomFeed.php @@ -0,0 +1,232 @@ + + * + */ + +class AtomXHTMLContent /* extends XMLElement */ { + private $content_string; + + function __construct($xhtml) { + $this->content_string = $xhtml; + } + + function Render( $ignore1, $ignore2, $ignore3 ) { + return $this->content_string . "\n"; + } +} + + +class AtomEntry { + /** + + <![CDATA[Woohoo! Time to Par-tay! (1/1)]]> + + + 2008-10-25T11:07:49+13:00 + 2010-12-27T06:49:16+13:00 + http://mycaldav/rss.php/rss.php/user1/home/MICROPARTY-77C6-4FB7-BDD3-6882E2F1BE74.ics#UID:MICROPARTY-77C6-4FB7-BDD3-6882E2F1BE74 + + Time: 2008-11-21 16:00:00Description:Have a microparty. All the best parties are monthly! + + + + */ + private $id; + private $title; + private $updated; + private $nodes; + + function __construct( $id, $title, $published, $updated ) { + $this->nodes = array( 'id', 'title', 'updated' ); // placeholders + } + + public function setId( $new_value ) { + $this->id = new XMLElement('id', rtrim($new_value,"\r\n")); + return $this->id; + } + + public function setTitle( $new_value, $type = 'text' ) { + $this->title = new XMLElement('title', $new_value, array( 'type' => $type )); + return $this->title; + } + + public static function setDate( $tagname, $epoch ) { + // e.g. 2010-12-26T17:49:16+13:00 + return new XMLElement($tagname, date('Y-m-d\TH:i:sP',$epoch)); + } + + public function setDateModified( $epoch ) { + $this->updated = self::setDate('updated', $epoch); + return $this->updated; + } + + public function setDateCreated( $epoch ) { + $node = self::setDate('published', $epoch); + $this->nodes[] = $node; + return $node; + } + + public function setLink( $new_value, $type="text/calendar", $rel='alternate' ) { + return $this->addNode('link', $new_value, array( 'rel' => $rel, 'type' => $type ) ); + } + + public function addAuthor( $new_value ) { + if ( is_array($new_value) && isset($new_value['name']) ) { + $author = $this->addNode('author' ); + foreach( $new_value AS $k => $v ) { + $author->NewElement($k, $v); + } + return $author; + } + throw new Exception("AtomFeed::addAuthor(\$new_value) the \$new_value MUST be an array with at leas a 'name' element. RFC4287-3.2"); + } + + + public function setDescription( $new_value, $type = 'text' ) { + return $this->addNode('summary', $new_value, array( 'type' => $type ) ); + } + + public function setContent( $new_value, $type = 'xhtml' ) { + $content = $this->addNode('content', null, array( 'type' => $type ) ); + if ( $type == 'xhtml' ) { + $content->NewElement('div', array( new AtomXHTMLContent($new_value) ), array('xmlns' => XHTML_XMLNS)); + } + else { + $content->SetContent($new_value); + } + return $content; + } + + public function addNode( $in_tag, $content=false, $attributes=false, $xmlns=null ) { + $node = new XMLElement($in_tag,$content,$attributes,$xmlns); + if ( !isset($node) ) return null; + $this->nodes[] = $node; + return $node; + } + + public function getXML() { + $this->nodes[0] = $this->id; + $this->nodes[1] = $this->title; + $this->nodes[2] = $this->updated; + return $this->nodes; + } +} + + +class AtomFeed extends XMLDocument { + + private $id; + private $title; + private $updated; + private $nodes; + + public function __construct() { + global $c; + parent::__construct( array( ATOM_XMLNS => null, XHTML_XMLNS => 'xhtml' ) ); + $this->title = 'DAViCal Atom Feed'; + $this->nodes = array( 'id', 'title', 'updated', // placeholders + new XMLElement('generator', 'DAViCal', array('uri' => 'http://www.davical.org/', 'version' => $c->version_string ) ) + ); + } + + /* + http://mycaldav/rss.php/user1/home.ics + CalDAV RSS Feed: User 1's Calendaranza + 2010-12-26T17:49:16+13:00 + Zend_Feed_Writer + + + + User 1 + user1@example.net + http://mycaldav/rss.php/caldav.php/user1/ + + */ + + public function setId( $new_value ) { + $this->id = $this->NewXMLElement('id', $new_value); + return $this->id; + } + + public function setTitle( $new_value, $type = 'text' ) { + $this->title = $this->NewXMLElement('title', $new_value, array( 'type' => $type )); + return $this->title; + } + + public function setDateModified( $epoch ) { + $this->updated = AtomEntry::setDate('updated', $epoch); + return $this->updated; + } + + public function setLink( $new_value, $type="text/calendar", $rel='alternate' ) { + return $this->addNode('link', $new_value, array( 'rel' => $rel, 'type' => $type ) ); + } + + + /** + * Sets the feed link (rel=self), ignoring the parameter which is for + * compatibility with the Zend library API, although we use this for + * the Id, whereas they use the first link that is set. + * @param uri $new_value The link target + * @return XMLElement the node that was added. + */ + public function setFeedLink( $new_value, $type = null ) { + $this->setId($new_value); + return $this->setLink($new_value , 'application/atom+xml', 'self' ); + } + + public function addAuthor( $new_value ) { + if ( is_array($new_value) && isset($new_value['name']) ) { + $author = $this->addNode('author' ); + foreach( $new_value AS $k => $v ) { + $this->NSElement($author, $k, $v); + } + return $author; + } + throw new Exception("AtomFeed::addAuthor(\$new_value) the \$new_value MUST be an array with at leas a 'name' element. RFC4287-3.2"); + } + + + public function setDescription( $new_value, $type = 'text' ) { + return $this->addNode('subtitle', $new_value, array( 'type' => $type ) ); + } + + public function addNode( $in_tag, $content=false, $attributes=false, $xmlns=null ) { + $node = $this->NewXMLElement($in_tag,$content,$attributes,$xmlns); + if ( !isset($node) ) return null; + $this->nodes[] = $node; + return $node; + } + + public function addEntry( $new_entry ) { + if ( !isset($new_entry) ) return; + $this->nodes[] = new XMLElement('entry', $new_entry->getXML() ); + } + + public function createEntry( $id=null, $title=null, $published=null, $updated=null ) { + return new AtomEntry($id,$title,$published,$updated); + } + + public function export( $format='atom' ) { + if ( $format != 'atom' ) throw new Exception("AtomFeed class only supports creation of Atom 1.0 format feeds."); + $this->nodes[0] = $this->id; + $this->nodes[1] = $this->title; + $this->nodes[2] = $this->updated; + return $this->Render('feed', $this->nodes ); + } +} +