Saturday, August 1, 2015

Joomla componenet: Article generator from RSS feeds - part 1

     I took a break from the "myFrontController" project. A friend of mine who is using Joomla to develop some websites told me "There was a good free extension called Feedgator which
is not developed anymore. Why don't you program something like that?". Basically he needs a Joomla component able to generate articles in the database from some RSS feeds.

    I started reading about Joomla component development with the tutorial from the Joomla! official documentation: J3.x:Developing_an_MVC_Component which can be found at this link:
https://docs.joomla.org/J3.x:Developing_an_MVC_Component/Introduction


It's a good point to start, but is not talking too much about the magic that happens behind. I found some explanations on stackoverflow:

From http://stackoverflow.com/questions/9573570/joomla-getitems-and-how-it-works
------------------------------------------------------------------------
Q:      I am looking at line 34 of /administrator/components/com_contact/views/contacts/view.html.php where is says $this->items = $this->get('Items'); What I don't understand is how that is actually calling the protected function getListQuery() on line 123 of /administrator/components/com_contact/models/contacts.php
There are also some other things I don't understand how are working... like
$this->pagination   = $this->get('Pagination');
$this->state        = $this->get('State');
What are these calling? I looked at the documentation for "get()" but it doesn't say what these are actually calling because I don't see any methods called getPagination, getState or getItems... It appears the get('Items') is somehow magically calling getListQuery().
------------------------------------------------------------------------
A:     I'm presuming 1.7/2.5+ here...
In Joomla!'s MVC the view contacts (ContactViewContacts which extends JView) automatically loads the model contacts (or in J! terminology ContactModelContacts) which as a class extends JModelList.
The get() looks in the view to get data from a registered model or a property of the view.
So:
    $this->items = $this->get('Items');
is actually a call to the model ContactModelContacts which has a matching getItems() in it's parent.
The model file com_contact/models/contacts.php doesn't implement it's own getItems(), so the getItems() from the JModelList class is used (found in /libraries/joomla/application/component/modellist.php).
This in turn calls getListQuery() - no magic just inheritance.
The $this->get('Pagination') is doing the same thing, ie. accessing the implementation in the models parent.
The $this->get('State') is probably going all the way back to the JModel implementation.
------------------------------------------------------------------------

Some other links from where I tried to understand how the Joomla component works:





  
       In order to accelerate the process and create all the files structure I used the free service from: http://www.component-creator.com (I would not called it  cheating, rather increasing productivity)
and generated a Joomla component. This component has just some backend logic and one DB table. There is a view from where you can enter  RSS feed linka, name and  number of posts.

To this structure I added in the "/site" part of the component, the logic for reading the RSS feeds and just display them.

I added a simple view which contains a display() method  :

/com_rssagregator/site/views/rssagregator/view.html.php

            function display($tpl = null)
            {
                // Assign data to the view
                $this->msg = $this->get('Msg');
               
                // Check for errors.
                if (count($errors = $this->get('Errors')))
                {
                    JLog::add(implode('<br />', $errors), JLog::WARNING, 'jerror');
       
                    return false;
                }
       
                // Display the view
                parent::display($tpl);
            }


In the corresponded model class I implemented the getMsg() method.
 /com_rssagregator/site/models/rssagregator.php.
The logic is :
1. read the list of feeds from the database (which were previously added in back end - administrator view)
2. read the the number of posts to be displayed for each feed from the database (which also were previously added in back end - administrator view)
3. require_once the "RSSReader.php" file in which I implemented the logic for reading feed posts
4. call getContent($feedsList,$noOfFeeds);
5. in the RSSReader.php each feed is read entirely and then only the first "noOfPosts" are returned in the output. The output is formatted and ready to be sent to the view for displaying it.

    public function parseData($feedObj,$limit)
    {
   
        $rss = new DOMDocument();
        $rss->loadXML($feedObj);
       
        $feed = array();
        foreach ($rss->getElementsByTagName('item') as $node) {
            $item = array (
                'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
                'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
                'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
                'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue,
                );
            array_push($feed, $item);
        }
       
        $output='';
        for($x=0;$x<$limit;$x++) {
            $title = str_replace(' & ', ' &amp; ', $feed[$x]['title']);
            $link = $feed[$x]['link'];
            $description = $feed[$x]['desc'];
            $date = date('l F d, Y', strtotime($feed[$x]['date']));
            ///////////////////////////////////////////////////////////
           
            $output.= '<p><strong><a href="'.$link.'" title="'.$title.'">'.$title.'</a></strong><br />';
            $output.= '<small><em>Posted on '.$date.'</em></small></p>';
            $output.= '<p>'.$description.'</p><br/><br/>';
           
           
        }
        return $output;
    }

6. In order to visualize the result, from backend add a menu item pointing to this newly created view. This is possible only if
in the "view/<view_name>/tmpl/" exists a an xml file contianing a layout title and description like this one:

    <?xml version="1.0" encoding="utf-8"?>
    <metadata>
        <layout title="COM_RSSAGREGATOR_CPANARSS_VIEW_DEFAULT">
            <message>link menu catre RSSAGREGATOR default view</message>
        </layout>
    </metadata>

   
The result of my work can be downloaded from here.

Instead of directly displaying the feed posts this  component should be further developed to add the feed posts to the database as articles.

No comments:

Post a Comment