RSS delivery with the APF

This article deals with RSS streams and the APF tools, that help you to publish your own streams. For this reason, this page contains two main sections: the first section describes, how the page controller can be used to generate XML using a document controller and the second part demonstrates the front controller's capability of delivering RSS streams dynamically.


1. Introduction

By default, RSS streams are just simple xml documents, that follow the RSS specification. A common RSS may contain the following content (taken from http://www.weather.com/weather/rss/subscription):
APF template
<?xml version="1.0" encoding="ISO-8859-1" ?> <rss version="2.0"> <channel> <title>The Weather Channel: National Weather Outlook</title> <link><![CDATA[http://www.weather.com/newscenter/fcstsummary.html?cm_ven=NWF&cm_pla=news&cm_ite=fcstsummary&site=news&cm_cat=rss&par=NWF_rss]]></link> <description> Since 1982, The Weather Channel has brought timely weather information to the world. Now via our National Weather Outlook RSS feed we can keep you up-to-date on the latest weather affecting the nation, including severe weather alerts and video forecasts with expert commentary, delivered right to your desktop. The Weather Channel...Bringing Weather To Life </description> <language>en-us</language> <copyright>Copyright © 2006, The Weather Channel Interactive, Inc.</copyright> <pubDate>Tue, 11 Nov 2008 16:44:01 EST</pubDate> <docs>http://blogs.law.harvard.edi/tech/rss</docs> <ttl>60</ttl> <image> <title>The Weather Channel: National Weather Outlook</title> <url><![CDATA[http://image.weather.com/web/common/logos/twci_logo_110x104.jpg?cm_ven=NWF&site=logo&cm_pla=logo&cm_ite=homepage&cm_cat=rss&par=NWF_rss]]></url> <link><![CDATA[http://www.weather.com?cm_ven=NWF&site=logo&cm_pla=logo&cm_ite=homepage&cm_cat=rss&par=NWF_rss]]></link> <description>National Weather Outlook from The Weather Channel</description> </image> <item> <title><![CDATA[ Current Weather Conditions Across The 48 Contiguous United States ]]></title> <link><![CDATA[ http://www.weather.com/maps/maptype/currentweatherusnational/index_large.html?cm_ven=NWF&cm_cat=rss&cm_pla=map&cm_ite=cc_us&par=NWF_rss&site=map ]]></link> <description><![CDATA[ Northwest Flood; Central Storm. For more details... ]]></description> <pubDate>Tue, 11 Nov 2008 16:44:01 EST</pubDate> </item> ... </channel> </rss>
Analyzing the document's structure, the weather forecast channel presented here, contains some static and some dynamic sections. The latter ones have to be filled dynamically to guarantee best actuality.

To be compatible with most of the readers, please have a look at to get a detailed idea about the content presented via rss.


2. Dynamic rss generation

Due to the fact, that XML documents are similar to HTML files, the page controller and it's mechanisms can also be used to generate XML output. As we have seen above, the rss content can be devided into two main sections: the header including the channel definition and the channel's items. This seems to be like a web page with a design template and a content area created by an included template.


2.1. Definition of the base document

So let us first of all define the base document. To do so, we create a rss base template and fill it with the necessary structural elements mentioned in the of rss specification:
APF template
<?xml version="1.0"?> <rss version="2.0"> <channel> <title></title> <link></link> <description></description> <language></language> <pubDate></pubDate> <lastBuildDate></lastBuildDate> <docs>http://blogs.law.harvard.edu/tech/rss</docs> <generator>The Adventure PHP Framework's page controller</generator> <managingEditor></managingEditor> <webMaster></webMaster> ... </channel> </rss>

2.2. Dynamic content generation

To be flexible with the values presented in the stream we add some place holders and a document controller, that is instructed to fill them as desired. The template now looks like this:
APF template
<@controller namespace="..." class="RssController" @> <?xml version="1.0"?> <rss version="2.0"> <channel> <title><html:placeholder name="title" /></title> <link><html:placeholder name="link" /></link> <description><html:placeholder name="description" /></description> <language><html:placeholder name="language" /></language> <pubDate><html:placeholder name="pubdate" /></pubDate> <lastBuildDate><html:placeholder name="lastbuilddate" /></lastBuildDate> <docs>http://blogs.law.harvard.edu/tech/rss</docs> <generator>The Adventure PHP Framework's page controller</generator> <managingEditor><html:placeholder name="editor" /></managingEditor> <webMaster>The name of the great webmaster</webMaster> ... </channel> </rss>
Before we are going to create the document controller, let me talk about application design in common. Typically, your application design features a three layer architecture, where the data layer is intended to care about persistent data, the business layer, that controls the application and the presentation tier to generate the user interface. In case of good designs, the presentation layer is convertible with other implementations or output formats. Despite the powerful HTML and XML implementation of the Adventure PHP Framework you are free to choose and deploy tools for generating other output formats such as PDF. In this case, we can use the built-in mechanisms to generate dynamical rss streams.

Let us now define the document controller's functionality. As mentioned before, the items of the channel are going to be presented by a sub template, that we are discussing later on. So the controller's logic filling the place holder looks quite simple:
PHP code
import('namespace::of:my::business::component','BusinessComp'); class RssController extends BaseDocumentController { public function transformContent(){ // create / get the business layer as a service object $bC = &$this->getServiceObject('namespace::of:my::business::component','BusinessComp'); // read the channel information $channel = $bC->getChannelInformation('desired_channel'); // fill the place holders $this->setPlaceHolder('title',$channel->getAttribute('...')); $this->setPlaceHolder('link',$channel->getAttribute('...')); $this->setPlaceHolder('description',$channel->getAttribute('...')); $this->setPlaceHolder('language',$channel->getAttribute('...')); $this->setPlaceHolder('pubdate',$channel->getAttribute('...')); $this->setPlaceHolder('lastbuilddate',$channel->getAttribute('...')); $this->setPlaceHolder('editor',$channel->getAttribute('...')); } }
As you can see in the code box, our current application features a business layer, that we use to gather the desired data. Please note, that we will use this component for the items as well.


2.3. Loading the items

Next, we care about the channel's items. As already mentioned before, we can use the business layer to load the items for the desired channel and we can use subtemplates to include the item list into the main template.

For this reason, we update the template definition above like this:
APF template
<@controller namespace="..." class="RssController" @> <?xml version="1.0"?> <rss version="2.0"> <channel> <title><html:placeholder name="title" /></title> <link><html:placeholder name="link" /></link> <description><html:placeholder name="description" /></description> <language><html:placeholder name="language" /></language> <pubDate><html:placeholder name="pubdate" /></pubDate> <lastBuildDate><html:placeholder name="lastbuilddate" /></lastBuildDate> <docs>http://blogs.law.harvard.edu/tech/rss</docs> <generator>The Adventure PHP Framework's page controller</generator> <managingEditor><html:placeholder name="editor" /></managingEditor> <webMaster>The name of the great webmaster</webMaster> <strong><core:importdesign namespace="..." template="items" /></strong> </channel> </rss>
The items template then contains an iterator tag, that is intended to display the list of available items. Do fill the iterator's data container a second document controller is defined at the top of the template:
APF template
<@controller namespace="..." class="rss_items_controller" @> <core:addtaglib namespace="tools::html::taglib" class="HtmlIteratorTag" prefix="html" name="iterator" /> <html:iterator name="items"> <iterator:item getter="getAttribute"> <item> <title><item:placeholder name="title" /></title> <link><item:placeholder name="link" /></link> <description><item:placeholder name="content" /></description> <author><item:placeholder name="author" /></author> <pubDate><item:placeholder name="date" /></pubDate> </item> </iterator:item> </html:iterator>
The content of the document controller class looks like this:
PHP code
import('namespace::of:my::business::component','BusinessComp'); class RssItemsController extends BaseDocumentController { public function transformContent(){ // create / get the business layer as a service object $bC = &$this->getServiceObject('namespace::of:my::business::component','BusinessComp'); // read the channel information $channel = $bC->getChannelInformation('desired_channel'); // get the channel's items $items = $channel->getItems(); // reference the iterator template $iterator = &$this->getIterator('items'); // fill the data container $iterator->fillDataContainer($items); // display the item list $iterator->transformOnPlace(); } }

2.4. Conclusion

To sum things up, the page controller's functionality can also be used to generate XML output instead of HTML content. Second, the framework contains various tools, that can help to generate an rss stream out of existing content and with help of an application's business component. But please be aware, that good software design is a central condition to be able to exchange the presentation! To be a bit more explicitly: good software design should be independent of tools or frameworks. :)


3. Rss delivery

Chapter 3 now describes, how the rss stream generated through the APF page controller can be presented to the user in a convenient way. For this reason, each content page should get a rss tag. When the user clicks on that tag, the content should be presented as an rss stream in a new window.

To achieve this, a front controller action can be used to deliver the rss document generated in chapter 2. To keep things simple, the action definition contains no input parameters, but reads the page id from the "normal" GET params. As an example, the rss stream URL may then look like this:
Code
http://adventure-php-framework.org/Page/082-RSS-delivery-with-the-APF/~/my_namespace-action/deliverRSS
In order to execute the action described before, we have to ensure, that the bootstrap file uses the front controller to create the page output. If this is not the case, please take a look at the Front controller documentation. After having done that, we can define the action configuration for the current context of our application and the action implementation. If you are not yet familiar with the implementation of front controller actions, take a short break and read about this topic on the Front controller page.

As we have already implemented the major part of the functionality of the action and the action has not input params by definition, the implementation of the action is quite easy. The only thing it has to do is to extract the page id from the url, create the page and flush the output to the user.

You might expect, that this job is not as easy as it sounds. :) This is because the implementation above does not contain a page configuration parameter, that is applied to the business component. But don't be afraid, there's a very elegant way of injecting this parameter into the DOM tree. To get a better understanding, let me say a few words about the DOM tree, the page controller creates:

Every template file is searched for known tags. Every tag is then extracted, the taglib implementation is executet and the object created in this way is stored as a child node of the current DOM node. Due to the fact, that the importdesign tags include functionality to include another template file as a new DOM node and parse the tags within that template in the same way, a tree containing objects derived from the Document class. After the loadDesign() method is called in the bootstrap file, the complete DOM tree exists in memory and can be manipulated using the API functions of the Page and Document classes. This fact enables the developer to subsequently "inject" attributes into the DOM document objects as desired. In this simple case, we exactly know the structure of the DOM tree. I consists of the Page object, the root Document and it's child - the items template.


3.1. Parameter injection
Now, that we know about the characteristics of the DOM tree created by the templates described in chapter 2, the parameter injection can be done by the following code snippet:
PHP code
// declare page id $id = '001'; // create the DOM tree $page = new Page(); $page->loadDesign('namespace::to::the::desired::template','template_name'); // get the root node of the tree and add attribute $doc = &$page->getRootDocument(); $doc->setAttribute('page_id',$id);

3.2. Adaption of the RssController
Now the RssController must be adapted to use the Document's attribute instead of the static channel name. This can be achieved by changing
PHP code
$channel = $bC->getChannelInformation('desired_channel');
to
PHP code
$channel = $bC->getChannelInformation($this->getDocument()->getAttribute('page_id'));

3.3. Adaption of the rss_items_controller
In case of the item controller, the parent document must be asked for the page id. Here,
PHP code
$channel = $bC->getChannelInformation('desired_channel');
must be changed to
PHP code
$channel = $bC->getChannelInformation($this->getDocument()->getAttribute('page_id'));
because the document referenced within the items controller is the child of the document node we added the secondary attribute to.


3.4. Action definition
The action implementation now contains to following code:
PHP code
class DeliverRSSAction extends AbstractFrontcontrollerAction { public function run(){ // get page id (to keep it simple) $id = $_REQUEST['id']; // create the DOM tree $page = new Page(); $page->loadDesign('namespace::to::the::desired::template','template_name'); // get the root node of the tree and add attribute $doc = &$page->getRootDocument(); $doc->setAttribute('page_id',$id); // transform and display rss stream header('Content-Type: text/xml'); echo $page->transform(); // exit execution, because we're done exit(0); } }

3.5. Conclusion

Thanks to the clean DOM structure and the capabilities of the front controller it is easy to create an rss stream within an existing application. Moreover, the developer is - also thanks to the front controller - not forced to create and maintain several bootstrap or rss.php files to deliver the rss content.

Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.
« 1   »
Entries/Page: | 5 | 10 | 15 | 20 |
1
cialis 18.10.2016, 10:25:17
Too Amazon before your nails would often directed meds buy cialis usa and I started looking for my!
2
cialis 12.09.2016, 11:12:13
Hello!
cialis ,