JoomaDevUser

JoomaDevUser

Component Develompment With Example - Part II: The Backend
User Rating: / 35
PoorBest 
Written by Administrator   
Friday, 09 May 2008 15:31

PART II: The Backend

Now that we’ve created the frontend of our component that allows us to view a list of greetings, stored in the database, we have to do the backend, which will allow us to manage our greetings: List, Add, Edit and Remove them.


Section 1: The entry point

Once again the first thing we have to do is the entry point. But for the backend the naming convention for the file that will contain the code of the entry point is different. Instead of being just the component name followed by “.php”, in the backend it’s: admin.[ComponentName].php. So in our case that will be: admin.greetings.php and it should be located in:

place where  you’ve installed joomla/administrator/components/com_greetings/admin.greetings.php
The entry’s point code in the backend is exactly the same as the frontend’s, here it is again:

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

// Require the controller
require_once( JPATH_COMPONENT.DS.'greetingsController.php' );

// Create the controller
$controller   = new GreetingsController();

// Perform the Request task
$controller->execute( JRequest::getVar( 'task' ) );

// Redirect if set by the controller
$controller->redirect();

?>

Please note that JPATH_COMPONENT now gives you the path to the backend of our component, in this case: place where you’ve installed joomla/administrator/components/com_greetings

You can see from the code above that I decided to give our backend’s controller the same name as the frontend’s. If you understood the first part of the tutorial you should be confident enough to give it another name and know what you have to change in the rest of the tutorial. If you don’t read section: “2.2 – The controller” from part I of this tutorial.


Section 2 – The backend tasks –The default task

Section 2.1 The default controller task (display)

Our backend controller will be more complex than our frontend’s. It will have to deal with more tasks: add, edit, remove and display the list of greetings.  I think the easiest way to do this is iteratively. What I mean is that it is easier if we handle each task at a time. For example, if we want to start with the display task, that will list the greetings, we do the code for the controller, then do the model, do the view and test, and then do the other tasks (this way it is easier to test if everything is going well). It is easier to explain it this way than post all the code from the controller here, describe it, and then do the same for the models and views.

So, let’s start with the controller. We’ve called the file greetingsController.php  again, but now we have to put it in the backend folder, so put the file here:

folder where you’ve installed joomla/administrator/components/com_greetings/greetingsController.php

Here’s the code that handles the default task (display):

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
      
       /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
       //This sets the default view (second argument)       
             $viewName    = JRequest::getVar( 'view', 'list' );
             //This sets the default layout/template for the view
             $viewLayout  = JRequest::getVar( 'layout', 'listlayout' );        

             $view = & $this->getView($viewName);
                   
             // Get/Create the model
             if ($model = & $this->getModel('greetings')) {
                    //Push the model into the view (as default)
                    //Second parameter indicates that it is the default model for the view
                    $view->setModel($model, true);
             }
                          
             $view->setLayout($viewLayout);
             $view->display();

    }
}

?>

The default task for the controller is display, so we redefine the display method. This time we want to load a view named list and a model called greetings.  Now, if you read the first part of this tutorial carefully you already know how the classes and files for the model and view should be named (if not, see DETAIL NOTE 2.2.3 from Part I). The file and class names:

  • view file: folder where you’ve installed joomla/administrator/com_greetings/views/list/view.php
  • view class name: GreetingsViewList
  • view layout/template file:  folder where you’ve installed joomla/administrator/com_greetings/views/list/tmpl/listlayout.php (Remember that the file name is lowercase)
  • model file:  folder where you’ve installed joomla/administrator/com_greetings/models/greetings.php (Remember, that even if you name your model with uppercase character, the file name has to be all lowercase)
  • model class name: GreetingsModelGreetings

DETAIL 2.1.1: You don’t really have to use the JRequest::getVar to read the view name and layout from the request (url). You can assume that when the task is display you’ll use a view named list.  Reading the view name from the request is only useful if you have more than one view for the same controller task which won’t be our case.

DETAIL 2.1.2: I’ve used the default task name, display, in the code above, remember that you can change the default task name in the Controller’s contructor(see detail note 2.2.2 from part I of the tutorial).

 

Section 2.2 The model - Getting the greetings from the DB

Let’s create our model with a method to load all the greetings in the database and return them in an array, so that we can display them in the view. Remember, the model is named greetings.

file name: folder where you’ve installed joomla/administrator/components/com_greetings/models/greetings.php

class name: GreetingsModelGreetings

The code is almost the same as what we did in Part I of the tutorial, here it is:

<?php

//No direct acesss
defined('_JEXEC') or die();

jimport('joomla.application.component.model');

class GreetingsModelGreetings extends JModel {
      
      
       function getGreetings(){
             $db = $this->getDBO();
            
             $db->setQuery('SELECT * from #__greetings');
             $greetings = $db->loadObjectList();

            
             if ($greetings === null)
                    JError::raiseError(500, 'Error reading db');
                   
             return $greetings;
       }
}
?>

The differences here are the query that now selects all the fields from our greetings database table and that we used $db->loadObjectList(); instead of using loadResultList. The loadObjectList returns an array of objects, each one represents a row of the results returned by our query. In our case, it will be an array where each element is an object with the attributes id and greeting, which are the fields of our greetings table in the database.

We’ll get back to this file later because we’ll have to add more methods to fulfill our controller’s other tasks.

Section 2.3 - The view - Listing the greetings

This view will access the model to get the list of greetings, then make that list of greetings available for the view’s layout/template and then use the JView default display method to output the html generated by the layout/template.

Note that this time we will be returning from the model not a list of strings like we did in the frontend, but a list of objects created from what was returned from the database. I’ll call those objects row and you’ll see that each attribute they have corresponds to a database field from the table we’ve created for our component. The attributes will be id and greeting.

The files and classnames for the view:

view file: folder where you’ve installed joomla/administrator/components/com_greetings/views/list/view.php

(Remember that the view file is not called view.html.php because we use the getView method in the controller without specifying its second parameter, the view type).

view class name: GreetingsViewList

layout file: folder where you’ve installed joomla/administrator/components/com_greetings/views/list/tmpl/listlayout.php

Here’s the view:

<?php
// no direct access

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.application.component.view');

/**
 * HTML View class for the Greetings Component (List)
 *
 * @package    Greetings
 */

class GreetingsViewList extends JView
{
            
    function display()
    {
       JToolBarHelper::title('Greetings Manager', 'generic.png');
       JToolBarHelper::deleteList();   
       JToolBarHelper::editListX();     
       JToolBarHelper::addNewX();       
      
       $model = $this->getModel();
       $greetings = $model->getGreetings();
       $this->assignRef('greetings', $greetings);
       parent::display();

    }
}
?>

Some new things here: the toolbar code. The first four lines in the display method output the javascript/html that will make up the toolbar for our component (Figure 1).

 

Figure 1 - Toolbar
Toolbar

 

At the time I wrote these lines (20th May 2008) there was no doc. page in the Joomla Framework API page (http://dev.joomla.org/content/view/16/59/) about the JToolBarHelper class.

But it is not too hard to use, so don’t worry, the first line (JToolBarHelper::title) sets the title you’ll see in the toolbar, and the image (generic.png that you can find in folder where you’ve installed joomla/administrator/images).

The JToolBarHelper::deleteList(),JToolBarHelper::editListX(),JToolBarHelper::addNewX() add a delete, edit and add buttons to the toolbar. When you press these buttons some javascript is executed that will eventually submit the form we will define in layout/template file for this view. There are a few naming conventions used here that will become clear as soon as I show you an example of the html and javascript generated for one of those buttons. For example the editListX:

 

<td class="button" id="toolbar-edit">
<a href="#" onclick="javascript:if(document.adminForm.boxchecked.value==0){alert('Please make a selection from the list to edit');}else{ hideMainMenu(); submitbutton('edit')}" class="toolbar">
<span class="icon-32-edit" title="Edit">
</span>
Edit
</a>
</td>

First, the html form (defined in the layout/template we’ll do next) has to be named adminForm.  This is always true for all forms that you do in the backend. They are always assumed to be named adminForm.

Some buttons, like the button generated with editListX, assume you have a hidden field named boxchecked that contains the number of selected items. For example, in our component, this view we’re doing right now will display a list of greetings, so boxchecked will contain the number of greetings selected (you don’t have to worry about updating boxchecked, it just has to be defined in the form, and it will be updated automatically. I’ll tell you how that happens when we see the form in the layout/template file).

We used editListX (and addNewX), which are alternative versions of editList and addNew. The difference between them is that the X versions also calls a javascript function named hideMainMenu that will set the value of a hidden input in the form (if that input exists) named hidemainmenu to 1. When the form is submitted and if hidemainmenu is in the request and has a value of 1, joomla makes the administrator menu (Site Menus Content Components … ) inactive. This is useful when you’re adding or editing (in our case greetings) because the user will have to click on one of the buttons you put in the toolbar (typically Save and Cancel), because all the other buttons will be inactive.

Finally, the buttons call a joomla javascript function named submitbutton that has one parameter called pressbutton. For example, when we press the edit button created by the JToolBarHelper::editListX the submitform will be called with the parameter edit: submitbutton(‘edit’); What this javascript function does is it sets a hidden field named task in the adminForm form (in this example with ‘edit’), and then submits the adminForm. So you see that we also have to have a hidden field named task in our form.

We’ll also have to add a hidden field name option that contains the name of the component prefixed by “com_”. This is necessary so that when the form is submitted you get an url equivalent to this (using our component as an example and the edit task): index.php?option=com_greetings&task=edit (This is not actually true, because we’ll POST the form but the important thing here to remember is that joomla needs to know which component is being executed, hence the option hidden field, and which task is going to be executed for that component, hence the task hidden field).

So now, you know that we have to do a layout/template for this view with a form named adminForm and 4 hidden fields named boxchecked, option, task and hidemainmenu. You also know that we have to list the greetings, and that there are a few naming conventions that we’ll have to follow, we’ll see all that next.

DETAIL NOTE 2.3.1:
You can check the code of JToolBarHelper here:
folder where you’ve installed joomla/administrator/includes/toolbar.php.


Here’s a list of the most common button generator methods from JToolBarHelper and what they do to the form (see the toolbar code for all the buttons):
back($alt = 'Back', $href = 'javascript:history.back();') – Generates a button that when you click on it makes the browser go to the previous page.
addNew($task = 'add', $alt = 'New') – Generates a Add button. (the $alt is the text that is displayed below the button).
  Fields that have to be defined in the form: task.
addNewX($task = 'add', $alt = 'New') same as above. But causes the menu to stay inactive.
  Fields that have to be defined in the form: task, hidemainmenu.
publish($task = 'publish', $alt = 'Publish')
  Fields that have to be defined in the form: task.
publishList($task = 'publish', $alt = 'Publish') – Note that the task string used in this one is the same as the one above.
  Fields that have to be defined in the form: task, boxchecked.
unpublish($task = 'unpublish', $alt = 'Unpublish')
  Fields that have to be defined in the form: task.
unpublishList($task = 'unpublish', $alt = 'Unpublish')
    Fields that have to be defined in the form: task, boxchecked.
editList($task = 'edit', $alt = 'Edit')
    Fields that have to be defined in the form: task, boxchecked.
editListX($task = 'edit', $alt = 'Edit')
    Fields that have to be defined in the form: task, boxchecked, hidemainmenu.
deleteList($msg = '', $task = 'remove', $alt = 'Delete')- When$msg is not empty, a confirm box will display the message $msg.
save($task = 'save', $alt = 'Save')
    Fields that have to be defined in the form: task.
cancel($task = 'cancel', $alt = 'Cancel')
    Fields that have to be defined in the form: task.

DETAIL NOTE 2.3.2:
You can check the joomla javascript (hideMainMenu, submitbutton, submitform) in here:
folder where you’ve installed joomla/includes/js/joomla.javascript.js

Here it is: the view’s layout/template. It displays the list of greetings read from the DB (Figure 2). The file should be here: folder where you’ve installed joomla/administrator/components/com_greetings/views/list/tmpl/listlayout.php

<?php // no direct access
defined('_JEXEC') or die('Restricted access'); ?>
<form action="index.php" method="POST" name="adminForm">
       <table class="adminlist">
             <thead>
                    <tr>
                           <th width="10">ID</th>
                           <th width="10"><input type="checkbox" name="toggle" value="" onclick="checkAll(<?php echo count($this->items); ?>)" /></th>
                           <th>Greeting</th>
                    </tr>              
             </thead>
             <tbody>
                    <?php
                    $k = 0;
                    $i = 0;
                    foreach ($this->greetings as $row){
                           $checked = JHTML::_('grid.id', $i, $row->id);
                           $link = JRoute::_( 'index.php?option='.JRequest::getVar('option').'&task=edit&cid[]='. $row->id.'&hidemainmenu=1' );                      ?>
                           <tr class="<?php echo "row$k";?>">
                                  <td><?php echo $row->id;?></td>
                                  <td><?php echo $checked; ?></td>
                                  <td><a href="<?php echo $link;?>"><?php echo $row->greeting;?></a></td>
                           </tr>
                    <?php
                    $k = 1 - $k;
                    $i++;
                    }
                    ?>
             </tbody>
       </table>
      
       <input type="hidden" name="option" value="<?php echo JRequest::getVar( 'option' );?>"/>
       <input type="hidden" name="task" value=""/>
       <input type="hidden" name="boxchecked" value="0"/>   
       <input type="hidden" name="hidemainmenu" value="0"/> 
</form>

Figure 2 - List the greetings
Listing

 

There are a few things you have to know. First, the form action is index.php and the name of the form has to be adminForm.

The html table’s css class: adminlist is a css class name used in joomla. The css classes are defined by joomla templates. In this case, because we’re working in the backend, the adminlist css class is defined in a backend template. I don’t think template details are very important here, so just trust me about using that css class, and a few more that I’ll mention. Joomla templates have sufficient material for several tutorials. If you want, have a look at the css from the default template for the backend that comes with joomla 1.5 (named khepri), the css is in folder where you’ve installed jooma/administrator/templates/khepri/css, the files that define the class adminlist are general.css and general_rt.css.

The table header will display something like this: ID [checkbox] Greeting (Figure 2). There are a few things you need to know about that checkbox. Its behaviour is that when you click on it, you select/deselect all items (in our case greetings). This will work if we respect joomla’s naming conventions for the checkboxes. First, this checkbox has to be named toggle, and it’s onclick event handler has to be checkAll([Number of items listed]) (in our case, the number of items are the greetings). The checkAll javascript method is defined in folder where you’ve installed joomla/includes/js/joomla.javascript.js, and what it does is that it checks to see if a checkbox named toggle inside a form named adminForm is checked or not, and then it goes through the checkboxes with id cbX, where X goes from 0 to the number you pass as argument to checkAll-1, and checks or unchecks them depending on the of checkbox named toggle being checked or not. So now you know that the checkboxes to select each individual item have to have an id: cb0, cb1, cb2, etc. But fortunately, since joomla 1.5, you don’t have to worry about that because the code: JHTML::_('grid.id', $i, $row->id); generates that for you.  JHTML is used to generate the html for several html elements, check the api page for more information about JHTML: http://dev.joomla.org/component/option,com_jd-wiki/Itemid,/id,references:joomla.framework:html:jhtml/.

The checkboxes created with JHTML like we did, are named cid and have an id cb0, cb1, cb2, etc.

DETAIL NOTE 2.3.3: If you see the actual HTML generated when you do JHTML::_('grid.id', $i, $row->id); you’ll see that the name of the checkboxes is actually cid[]. This is a php thing: when you add ‘[]’ to the name of a checkbox and you have several checkboxes with that same name followed by ‘[]’ you can read an array from the request with the value of the checked checkboxes. In our case, when we read cid from the request we’ll get an array that contains the values of the checked checkboxes.

Each of the greetings displayed is a link, that when you click on it redirects you to the url: index.php?option=com_greetings&task=edit&cid[]=ID_OF_THE_ROW_WE_WANT_TO_EDIT&hidemainmenu=1. We’re using JRoute’s ‘_’ function to build the url. We should do that because the ‘_’ method from JRoute rewrites the url to a Search Engine Friendly(SEF) form if SEF is enabled in Joomla (To enable SEF go to Site->Global Configuration). However, SEF doesn’t work on the backend so you won’t see any difference in the url, but still it’s good practice to use it because if you want to reuse some of the code in the frontend you won’t have to worry about the urls .The hidemainmenu parameter is set to 1 in the url so that the joomla’s administrator menu stays disabled when editing (remember, that also happens when we click the edit button because we use JToolBar::editListX : the X version of editList).

About the actual listing of the greetings (the foreach’s code), we’re using a trick to change the css class of every <TR>.  The css classes row0 and row1 have different background colors making it easier for you to distinguish between each item in the list (in our case, each greeting). The rest is each table row displays the greeting’s id, followed by a checkbox that was generated by JHTML::_('grid.id', $i, $row->id); and then the actual greeting, in the form of a link that, when pressed will create a request for our backend’s component with the task edit and with the parameter cid (that will be an array) with the value of the id of the greeting we want to edit (we still have to code the edit task). 

DETAIL NOTE 2.3.4: This note is about how the boxchecked hidden field is updated. The code generated by JHTML::_('grid.id', $i, $row->id); is something like this: <input id="cb0" name="cid[]" value="1" onclick="isChecked(this.checked);" type="checkbox"> . The javascript isChecked method is the one that updated boxchecked hidden input field. What it does is if the checkbox is being checked it adds 1 to the boxchecked adminForm’s hidden input, if it is being unchecked it subtracts 1. You can see the code for isChecked here:  folder where you’ve installed joomla/includes/js/joomla.javascript.js.

You can test this task now. In the backend go to Components->Greetings and you should see something like Figure 2.


Section 3 – The backend tasks – The edit task

Section 3.1 – The controller task: edit

Now let’s do the edit task. To do that we just have to add a method named edit to our controller that will load a view named greetingForm, with a layout/template named greetingformlayout. We will use the same model we used for listing the greetings although we’ll add a new method that will return an object that represents a row in the greetings table in the database (we’ll look at that in Section 3.2).  I’m not reading the viewname and layout from the request in this task, I just make the view name and layout fixed to greetingForm and greetingformlayout respectively.

In this task we’ll read the id of the greeting we want to edit. There is a detail about reading the id from the request. Remember that when we listed the greetings we put a link in each one: index.php?option=com_greetings&task=edit&cid[]=ID. Where ID is the actual ID for the greeting we want to edit. You might be asking yourself right now why did I used cid[] as a parameter. Especially because if we’re just editing one greeting, why do we need to put it in an array? The answer to that is: it’s because of the Edit button in the toolbar. When you click on it, it submits the form that has the list of greetings, and the selected greetings will go in the request in the cid[] parameter. So, that’s why we called the parameter with the id of the greeting cid[] , so that we could handle both cases (clicking on the link and clicking the edit button in the toolbar) the same way.

We’ll call a method named displayEdit in the view and pass the id of the greeting as a parameter to it (we’ll do the view’s displayEdit method in Section 3.3).

Remember that our controller file is named greetingsController.php, and it should be located in folder where you’ve installed joomla/administrator/components/com_greetings/greetingsController.php.

Here it is an updated version of it (new parts are in red):

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
      
       /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
       //This sets the default view (second argument)       
             $viewName    = JRequest::getVar( 'view', 'list' );
             //This sets the default layout/template for the view
             $viewLayout  = JRequest::getVar( 'layout', 'listlayout' );        

             $view = & $this->getView($viewName);
                   
             // Get/Create the model
             if ($model = & $this->getModel('greetings')) {
                    //Push the model into the view (as default)
                    //Second parameter indicates that it is the default model for the view
                    $view->setModel($model, true);
             }
                          
             $view->setLayout($viewLayout);
             $view->display();

    }
   
    function edit(){
      
       //getVar(PARAMETER_NAME, DEFAULT_VALUE, HASH, TYPE)
       //The HASH is where to read the parameter from:
       //The default is its default value:  getVar will look for the parameter in
       //GET, then POST and then FILE  
       $cids = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
      
       if($cids === null){ //Make sure the cid parameter was in the request
             JError::raiseError(500, 'cid parameter missing from the request');
       }
      
       $greetingId = (int)$cids[0]; //get the first id from the list (we can only edit one greeting at a time)

       $view = & $this->getView('greetingForm');
            
       // Get/Create the model
       if ($model = & $this->getModel('greetings')) {
             //Push the model into the view (as default)
             //Second parameter indicates that it is the default model for the view
             $view->setModel($model, true);
       }
            
            
                          
       $view->setLayout('greetingformlayout');
       $view->displayEdit($greetingId);       
    }
}

?>

Section 3.2 The model – Getting a greeting through its id

We have to add a method to our model that gets a greeting from the database based on its id. If you remember the code that we did for the default task (display) that displays a list of the greetings read from the database, you’ll remember that in that list each greeting has a link. Something like this: index.php?option=com_greetings&task=edit&cid[]=1. Where, in this example the 1 is the id of the greeting we want to edit. So our new method for the model will do just that: get the greeting from the database with a specific id. Let’s call that method getGreeting.

Remember that our model file is named greetings.php and that it is located in folder where you’ve installed joomla/administrator/components/com_greetings/models/greetings.php

Here’s the code (new parts in red):

<?php

//No direct acesss
defined('_JEXEC') or die();

jimport('joomla.application.component.model');

class GreetingsModelGreetings extends JModel {
      
      
       function getGreetings(){
             $db = $this->getDBO();
            
             $db->setQuery('SELECT * from #__greetings');
             $greetings = $db->loadObjectList();

            
             if ($greetings === null)
                    JError::raiseError(500, 'Error reading db');
                   
             return $greetings;
       }
      
       function getGreeting($id){
             $query = ' SELECT * FROM #__greetings '.
                            ' WHERE id = '.$id;
             $db = $this->getDBO();
             $db->setQuery($query);
             $greeting = $db->loadObject();         
            
             if ($greeting === null)
                    JError::raiseError(500, 'Greeting with ID: '.$id.' not found.');
             else
                    return $greeting;         
       }
}
?>

Section 3.3 The view – form to edit the greeting

This view we’re about to do will display a form that will allow us to edit a greeting (Figure 3) . We’ll create a method named displayEdit that gets as a parameter the id of the greeting we want to edit, then we use the getGreeting method from the model associated with this view to get the actual greeting from the database and then display it in the form in the layout/template.

This view will have two buttons on its toolbar: Save and Cancel.

This view will have to be located in: folder where you’ve installed joomla/administrator/components/com_greetings/views/greetingform/view.php (please notice the lowercase 'l' in 'greetingform', you should always use lowercase letters in folder names)

The view’s class name is: GreetingsViewGreetingForm

And the layout/template file: joomla/administrator/components/com_greetings/views/greetingform/tmpl/greetingformlayout.php (please notice the lowercase 'l' in 'greetingform', you should always use lowercase letters in folder names)

Here’s the code for the view:

<?php
// no direct access

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.application.component.view');

/**
 * HTML View class for the backend of the Greetings Component edit task
 *
 * @package    Greetings
 */

class GreetingsViewGreetingForm extends JView
{
            
    function displayEdit($greetingId)
    {                           
                   
       JToolBarHelper::title('Greeting'.': [<small>Edit</small>]');
       JToolBarHelper::save();
       JToolBarHelper::cancel(); 
            
       $model = $this->getModel();
       $greeting = $model->getGreeting($greetingId);
       $this->assignRef('greeting', $greeting);
                                     
        parent::display();
    }
}
?>   

Remember that the layout/template for this view is named greetingformlayout and should be located in: folder where you’ve installed joomla/administrator/com_greetings/views/greetingform/tmpl/greetingformlayout.php

Here it is:

<?php // no direct access
defined('_JEXEC') or die('Restricted access'); ?>

<form action="index.php" method="POST" name="adminForm" id="adminForm">
       <fieldset class="adminform">
             <legend>Details</legend>
             <table class="admintable">
                    <tr>
                           <td class="key">Greeting</td>
                           <td>
                                  <input type="text" name="greeting" id="greeting" size="32" maxlength="250" value="<?php echo $this->greeting->greeting; ?>" />
                           </td>
                    </tr>
             </table>
       </fieldset>

       <input type="hidden" name="option" value="<?php echo JRequest::getVar( 'option' );?>"/>
       <input type="hidden" name="id" value="<?php echo $this->greeting->id; ?>"/>     
       <input type="hidden" name="task" value=""/>   
</form>

Figure 3 - The Edit Form
Edit Form

 

Remember that we used the Save and Cancel buttons in the toolbar, the Save button causes this form to be submitted with the hidden field task with value ‘save’ and the Cancel button submits the form with the hidden field task with value ‘cancel’.

There is an important detail here, which is: the form has to have inputs with the same name as the fields in our greetings table, that’s why there is a hidden field named id. When we do the save task it will be clear why.

You can now test the Edit task, but remember, we still have to do the Save task for it to work properly. That comes next!


Section 4: The backend tasks - Save

Section 4.1 – The controller task: save

When we edit a greeting and click on the save button the form we just did before is going to be submitted with the task parameter set to save. That will cause the save task to be executed in the controller. So we need to do the method to handle that task, and that method has to be named save.

So let’s add that method to our backend controller, it will read the data posted by the form we did for the greetingForm view. Then it will use a method in the model that will get that post data as a parameter and will use it to update the database record that corresponds to the greeting we’re editing (we’ll add that method to our model later, just assume it works now and it is named saveGreeting).

Finally, after using the model to save the edited greeting we’ll use the JController’s method setRedirect to make joomla redirect to the page we’re the greetings are listed (our components default task, display).

DETAIL NOTE 4.1.1: If you’re wondering how setRedirect will redirect you to the link you pass as a parameter look at our entry point file, and you’ll see that at the end a method named redirect from the controller is executed. That method is what actually causes the browser to redirect to the link we supply as a parameter to setRedirect.

We are editing controller file, located in: folder where you’ve installed joomla/administrator/com_greetings/greetingsController.php

Here’s the code (new parts in red):

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
      
       /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
       //This sets the default view (second argument)       
             $viewName    = JRequest::getVar( 'view', 'list' );
             //This sets the default layout/template for the view
             $viewLayout  = JRequest::getVar( 'layout', 'listlayout' );        

             $view = & $this->getView($viewName);
                   
             // Get/Create the model
             if ($model = & $this->getModel('greetings')) {
                    //Push the model into the view (as default)
                    //Second parameter indicates that it is the default model for the view
                    $view->setModel($model, true);
             }
                          
             $view->setLayout($viewLayout);
             $view->display();

    }
   
    function edit(){
       //getVar(PARAMETER_NAME, DEFAULT_VALUE, HASH, TYPE)
       //The HASH is where to read the parameter from:
       //The default is its default value: getVar will look for the parameter in
       //GET, then POST and then FILE  
       $cids = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
      
       if($cids === null){ //Make sure the cid parameter was in the request
             JError::raiseError(500, 'cid parameter missing from the request');
       }
             
             $greetingId = (int)$cids[0]; //get the first id from the list (we can only edit one greeting at a time) 
      
             $view = & $this->getView('greetingForm');
                   
             // Get/Create the model
             if ($model = & $this->getModel('greetings')) {
                    //Push the model into the view (as default)
                    //Second parameter indicates that it is the default model for the view
                    $view->setModel($model, true);
             }
                          
             $view->setLayout('greetingformlayout');
             $view->displayEdit($greetingId);        
    }
   
    function save(){      
       $greeting = JRequest::get( 'POST' );
      
       $model = & $this->getModel('greetings');
       $model->saveGreeting($greeting);
      
       $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option').'&task=display');
       $this->setRedirect($redirectTo, 'Greeting Saved!');               
    }
}

?>

Section 4.2 JTABLE

To do our saveGreeting method in the model we’re going to use an instance of a class we’ll do that extends JTABLE. JTABLE is a class we can extend that has methods that help us interact with the database, especially if we want to update or add records to a database table.

Doc. Page for JTABLE here: http://dev.joomla.org/component/option,com_jd-wiki/Itemid,/id,references:joomla.framework:table:jtable/

To use the functionalities that JTABLE has we have to create a class that extends JTABLE and has a direct correspondence between the names of its attributes and the names of the fields in the database table we’re dealing with. Using our greetings table as an example, the class that we’re going to write that extends JTABLE has two attributes, named id and greeting which correspond to the greetings database table fields with the same name. We also have to specify in the constructor which of the fields is the key for the database and also the table’s name.

The JModel specifies methods to get instances of JTABLE following some naming conventions. First, the default location for JTABLE files is, in the backend: folder where you’ve installed joomla/admistrator/components/com_greetings/tables; in the frontend it’s the same without administrator (you can change the default location in the model’s constructor).

You can use a JModel’s method named getTable without parameters to get the class that extends JTABLE following JModel’s naming conventions for table classes.

The convention is:

  • The class extending JTABLE should be named Table[ModelName], where [ModelName] is the model’s name from where we’re using the JModel’s gettable method without parameters. Remember that the model’s class name is build by: [ControllerName]Model[ModelName].
  • The class that extends JTable should be located in folder where you’ve installed joomla/administrator/components/[COMPONENT_NAME]/tables where [COMPONENT_NAME] is the name of the component where our model is. And should be named [ModelName].php (the file name has to be in lowercase).

If you want, you can specify a name in the JModel’s getTable method, for example getTable(‘Mytable’), this tries to get an instance for a class named TableMyTable located in joomla/administrator/components/[COMPONENT_NAME]/tables/mytable.php for the backend (the same for the frontend without administrator.)

DETAIL NOTE 4.2.1: To change the default location of the classes that extend JTable you have to override the default constructor ofthe model class you’re using, and specify in the config array, that the constructor gets as argument, a parameter named table_path. For example, if we want to change the tables folder in our model for the greetings (in the backend) we would add this code to our model file located in:

folder where you’ve installed joomla/administrator/components/com_greetings/models/greetings.php

function __construct(){
parent::__construct(array('table_path'=>JPATH_COMPONENT.DS.'myTablesFolder'));
}

Here’s the code for the class that will extend JTable that we will be using to add and update greetings in our greetings’ database table, it has to be located in:

folder where you’ve installed joomla/administrator/components/com_greetings/tables

and the file will be named greetings.php:

<?php

defined('_JEXEC') or die('Restricted Access');

class TableGreetings extends JTable {
       public $id = null;
       public $greeting = null;
      
       function TableGreetings(&$db){
             parent::__construct('#__greetings', 'id', $db);
       }
}

?>

Section 4.3 The Model – Adding the save functionality

We’re adding a new method to our model named saveGreeting that, if you remember from the controller’s code, we’re invoking there and passing a parameter to it with the data we’re getting from the request (that will contain the values from the inputs of the from that is outputted by the greetingForm view).

This is where we’ll use the functionalities offered by JTable. I’ll show you the code and then talk a little bit about the methods we’re using from JTable.

Remember, this file is located in:

folder where you’ve installed joomla/administrator/com_greetings/models/greetings.php

New the code is in red:

<?php

//No direct acesss
defined('_JEXEC') or die();

jimport('joomla.application.component.model');

class GreetingsModelGreetings extends JModel {
      
      
       function getGreetings(){
             $db = $this->getDBO();
            
             $db->setQuery('SELECT * from #__greetings');
             $greetings = $db->loadObjectList();

            
             if ($greetings === null)
                    JError::raiseError(500, 'Error reading db');
                   
             return $greetings;
       }
      
       function getGreeting($id){
             $query = ' SELECT * FROM #__greetings '.
                            ' WHERE id = '.$id;
             $db = $this->getDBO();
             $db->setQuery($query);
             $greeting = $db->loadObject();         
            
             if ($greeting === null)
                    JError::raiseError(500, 'Greeting with ID: '.$id.' not found.');
             else
                    return $greeting;         
       }
      
      
       /**
       * Method to store a greeting in the DB
       *
       * @access    public       
       */
       function saveGreeting($greeting)
       {
             //Parameter not necessary because our model is named GreetingsModelGreetings (used to ilustrate that you can specify an alternative name to the JTable extending class)
           $greetingTableRow =& $this->getTable('greetings');
          
           // Bind the form fields to the greetings table
           if (!$greetingTableRow->bind($greeting)) {
             JError::raiseError(500, 'Error binding data');             
       }     

       // Make sure the greetings record is valid
       if (!$greetingTableRow->check()) {
             JError::raiseError(500, 'Invalid data');                          
       }
      
       // Insert/update this record in the db
        if (!$greetingTableRow->store()) {
             $errorMessage = $greetingTableRow->getError();
                    JError::raiseError(500, 'Error binding data: '.$errorMessage);                          
       }
             //If we get here and with no raiseErrors, then everythign went well
       }
      

}
?>

The $greeting parameter will be an array that will contain the values from the input fields from the form (that we did in the greetingForm view) indexed by the names of the inputs.

The JTable’s bind method we’re using ($greetingTableRow->bind($greeting)) uses reflection to get all the attributes from the class, and then sets them with the values from the array passed as a parameter that have a key with the same name as the attributes in the class.  This gets really simple with an example. Imagine our TableGreetings class that extends JTable. It has 2 attributes: id and greeting. And remember that the form from the greetingForm view has among other form inputs, an input named id and greeting. What bind does is it sets the attribute id with the value from the form input id, and the same for greeting.

DETAIL 4.3.1: Doc. page for JTable::bind:

http://dev.joomla.org/component/option,com_jd-wiki/Itemid,/id,references:joomla.framework:table:jtable-bind/

If you look at bind’s signature: boolean bind ( $from, $ignore ) you’ll notice that it has a second parameter. What it’s for is to specify a list of attributes to be ignored in the binding process. If for some reason you have attributes in your table class that you don’t want to update with the values from $from, you put them in $ignore.

Also note that if an attribute is in the table class, but not in $from, no error is produced and bind still returns true.

After the bind we do the check. What the JTable’s check method does is … well it just returns true. I just put it there so I could tell you about it. The idea behind the check method is that you should override it when you extend JTable, and make it return true if the attributes are valid and false otherwise (doc page for check is: http://dev.joomla.org/component/option,com_jd-wiki/Itemid,/id,references:joomla.framework:table:jtable-check/).

Finally, we store. What store does is it inserts a new record in the database if the attribute that represents the table key is 0 (in our case if the TableGreeting id attribute is 0 a new record is inserted), or it updates the record whose primary key has the same value as the value of the attribute we specify as key in the JTable’s class constructor (in our case, TableGreeting id attribute with value X not 0, will cause an update to the greeting with id X).

If there is an error you can access an error message through JTable’s getError method.

DETAIL NOTE 4.3.2: getError and setError are methods that are actually implemented in the JObject class (that is extended by JTable). At this date (27th May 2008) there is no documentation about those methods, but you can have a look at JObject’s code here:

Folder where you’ve installed joomla/libraries/joomla/base/object.php

By now you can edit and save greetings, so if you have added some greetings to the database table in phpmyadmin or using MySQL command line client, you can test the edit and save tasks.


Section 5: The backend tasks – The add task

Section 5.1: The controller task: add

For the add task we’re doing something very similar to the edit task. This is the task that will be executed when you click on the toolbar’s Add button when our component is displaying the list of greetings (default display task).

What we will do in the controller code is we will add a method named add that will get the model named greetings and the view named greetingForm and call a method from that view named disaplyAdd that we’ll do later.

We’re editing our controller file located in folder where you’ve installed joomla/administrator/com_greetings/greetingsController.php

Here’s the controller code (new parts in red):

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
        
         /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
         //This sets the default view (second argument)         
                   $viewName = JRequest::getVar( 'view', 'list' );
                   //This sets the default layout/template for the view
                   $viewLayout        = JRequest::getVar( 'layout', 'listlayout' );          

                   $view = & $this->getView($viewName);
                           
                   // Get/Create the model
                   if ($model = & $this->getModel('greetings')) {
                            //Push the model into the view (as default)
                            //Second parameter indicates that it is the default model for the view
                            $view->setModel($model, true);
                   }
                                     
                   $view->setLayout($viewLayout);
                   $view->display();

    }
   
    function edit(){
         //getVar(PARAMETER_NAME, DEFAULT_VALUE, HASH, TYPE)
         //The HASH is where to read the parameter from:
         //The default is its default value: getVar will look for the parameter in
         //GET, then POST and then FILE       
         $cids = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
        
         if($cids === null){ //Make sure the cid parameter was in the request
                   JError::raiseError(500, 'cid parameter missing from the request');
         }
                 
                   $greetingId = (int)$cids[0]; //get the first id from the list (we can only edit one greeting at a time)         
        
                   $view = & $this->getView('greetingForm');
                           
                   // Get/Create the model
                   if ($model = & $this->getModel('greetings')) {
                            //Push the model into the view (as default)
                            //Second parameter indicates that it is the default model for the view
                            $view->setModel($model, true);
                   }
                                     
                   $view->setLayout('greetingformlayout');
                   $view->displayEdit($greetingId);     
    }
   
    function save(){       
         $greeting = JRequest::get( 'POST' );
        
         $model = & $this->getModel('greetings');
         $model->saveGreeting($greeting);
        
         $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option').'&task=display');
         $this->setRedirect($redirectTo, 'Greeting Saved!');            
    }
   
         function add(){
                   $view = & $this->getView('greetingForm');
                   $model = & $this->getModel('greetings');
                  
                   if (!$model){
                            JError::raiseError(500, 'Model named greetings not found');
                   }
                   $view->setModel($model, true);
                   $view->setLayout('greetingformlayout');
         $view->displayAdd();                 
         }
       
}

?>

Easy, right? Now let’s do add the displayAdd method to the view named greetingForm.

Section 5.2: The view - Form to edit the greeting (revisited)

We have to add a method named displayAdd that has no arguments to the view named greetingForm.

What this method will do is, it will call a method from the model named getNewGreeting (that we’ll do later) that returns an “empty” greeting with id 0, and then it’s the same thing as we did for editing a greeting. The only difference is that we will be editing a greeting with id 0, and the actual greeting will be an empty string.

We’re editing the view named greetingForm which is located here:

folder where you’ve installed joomla/administrator/components/com_greetings/views/greetingform/view.php

Here’s the code (new parts in red):

<?php
// no direct access

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.application.component.view');

/**
 * HTML View class for the backend of the Greetings Component edit task
 *
 * @package    HelloWorld
 */

class GreetingsViewGreetingForm extends JView
{
            
    function displayEdit($greetingId)
    {                                                                    
             JToolBarHelper::title('Greeting'.': [<small>Edit</small>]');
             JToolBarHelper::save();
             JToolBarHelper::cancel(); 
            
             $model = $this->getModel();
             $greeting = $model->getGreeting($greetingId);
             $this->assignRef('greeting', $greeting);                               
                                     
        parent::display();
    }
   
    function displayAdd(){
             JToolBarHelper::title('Greeting'.': [<small>Add</small>]');
             JToolBarHelper::save();
             JToolBarHelper::cancel(); 
            
             $model = $this->getModel();
             $greeting = $model->getNewGreeting();
             $this->assignRef('greeting', $greeting);
            
             parent::display();
    }
}
?>   

That’s it for the view, now let’s do the model.

Section 5.3: The model – New greetings

We have to add the getNewGreeting method to the greetings model. What this method will do is it will get an instance form the table class (the one that implements JTBALE) and set that instance’s id attribute to 0 and the greeting attribute to the empty string.

We’re editing the greetings model file located in: folder where you’ve installed joomla/administrator/components/com_greetings/models/greetings.php

Here’s the code (new parts in red):

<?php

//No direct acesss
defined('_JEXEC') or die();

jimport('joomla.application.component.model');

class GreetingsModelGreetings extends JModel {
        
        
         function getGreetings(){
                   $db = $this->getDBO();
                  
                   $db->setQuery('SELECT * from #__greetings');
                   $greetings = $db->loadObjectList();

                  
                   if ($greetings === null)
                            JError::raiseError(500, 'Error reading db');
                           
                   return $greetings;
         }
        
         function getGreeting($id){
                   $query = ' SELECT * FROM #__greetings '.
                                       ' WHERE id = '.$id;
                   $db = $this->getDBO();
                   $db->setQuery($query);
                   $greeting = $db->loadObject();                
                  
                   if ($greeting === null)
                            JError::raiseError(500, 'Greeting with ID: '.$id.' not found.');
                   else
                            return $greeting;          
         }
                  
        
         /**
         * Method to store a greeting in the DB
         *
         * @access    public        
         */
         function saveGreeting($greeting)
         {
                   //Parameter not necessary because our model is named GreetingsModelGreetings (used to ilustrate that you can specify an alternative name to the JTable extending class)
             $greetingTableRow =& $this->getTable('greetings');
            
             // Bind the form fields to the greetings table
             if (!$greetingTableRow->bind($greeting)) {
                   JError::raiseError(500, 'Error binding data');         
         }       

         // Make sure the greetings record is valid
         if (!$greetingTableRow->check()) {
                   JError::raiseError(500, 'Invalid data');                        
         }
        
             // Insert/update this record in the db
             if (!$greetingTableRow->store()) {
        $errorMessage = $greetingTableRow->getError();
                            JError::raiseError(500, 'Error binding data: '.$errorMessage);                     
         }
                   //If we get here and with no raiseErrors, then everythign went well
         }
        
  /**
         * Method that returns an empty greeting with id 0
         *
         * @access    public        
         */
         function getNewGreeting(){
                   $greetingTableRow =& $this->getTable('greetings');
                   $greetingTableRow->id = 0;
                   $greetingTableRow->greeting = '';
                   return $greetingTableRow;
         }
}

?>

Why are we doing this? Remember when I explained how the JTable’s store method worked? That when the attribute associated with the table’s primary key was 0 the store method would insert a new record in the database. That’s what happening here, it is like you’re editing a greeting with id 0, but when you click the save button, and the save task is executed, you get a new record in the database.


Section 6: The backend tasks: The remove task

Section 6.1: The controller task: remove

To do the remove task we have to get the id of the greeting we want to remove (like we did for the greeting to edit, in the edit task). Then we’ll call a method from the model named deleteGreetings to which we will supply the array with the ids of the greeting as a parameter (we’ll do deleteGreetings later), and then use the JController’s setRedirect method to redirect to the list of the greetings.

We’re editing the controller’s class located in:

folder where you’ve installed joomla/administrator/com_greetings/greetingsController.php

New code is in red:

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
        
         /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
         //This sets the default view (second argument)         
                   $viewName = JRequest::getVar( 'view', 'list' );
                   //This sets the default layout/template for the view
                   $viewLayout        = JRequest::getVar( 'layout', 'listlayout' );          

                   $view = & $this->getView($viewName);
                           
                   // Get/Create the model
                   if ($model = & $this->getModel('greetings')) {
                            //Push the model into the view (as default)
                            //Second parameter indicates that it is the default model for the view
                            $view->setModel($model, true);
                   }
                                     
                   $view->setLayout($viewLayout);
                   $view->display();

    }
   
    function edit(){
         //getVar(PARAMETER_NAME, DEFAULT_VALUE, HASH, TYPE)
         //The HASH is where to read the parameter from:
         //The default is its default value: getVar will look for the parameter in
         //GET, then POST and then FILE       
         $cids = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
        
         if($cids === null){ //Make sure the cid parameter was in the request
                   JError::raiseError(500, 'cid parameter missing from the request');
         }
                 
                   $greetingId = (int)$cids[0]; //get the first id from the list (we can only edit one greeting at a time)         
        
                   $view = & $this->getView('greetingForm');
                           
                   // Get/Create the model
                   if ($model = & $this->getModel('greetings')) {
                            //Push the model into the view (as default)
                            //Second parameter indicates that it is the default model for the view
                            $view->setModel($model, true);
                   }
                                     
                   $view->setLayout('greetingformlayout');
                   $view->displayEdit($greetingId);     
    }
   
    function save(){       
         $greeting = JRequest::get( 'POST' );
        
         $model = & $this->getModel('greetings');
         $model->saveGreeting($greeting);
        
         $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option').'&task=display');
         $this->setRedirect($redirectTo, 'Greeting Saved!');            
    }
   
         function add(){
                   $view = & $this->getView('greetingForm');
                   $model = & $this->getModel('greetings');
                  
                   if (!$model){
                            JError::raiseError(500, 'Model named greetings not found');
                   }
                   $view->setModel($model, true);
                   $view->setLayout('greetingformlayout');       
         $view->displayAdd();                 
         }
        
         function remove(){
             $arrayIDs = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
        
             if($arrayIDs === null){ //Make sure the cid parameter was in the request
                   JError::raiseError(500, 'cid parameter missing from the request');
             }
        
             $model = & $this->getModel('greetings');
             $model->deleteGreetings($arrayIDs);
        
             $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option'));
             $this->setRedirect($redirectTo, 'Deleted...');               
         }
        
}

?>

Section 6.2: The model – Deleting greetings

Where doing the deleteGreetings method in our greetings model that gets an array with the id’s of the greetings to be deleted as input.

We’re using php’s implode method (http://php.net/implode) that has two arguments, the separator and the array. Imagine you use implode with arguments (‘,’, array(‘a’,’b’,’c’)) you’d get a string like this: ‘a,b,c’.

We’re editing the model named greetings’ file, located in:

folder where you’ve installed joomla/administrator/com_greetings/models/greetings.php

New code is in red:

<?php

//No direct acesss
defined('_JEXEC') or die();

jimport('joomla.application.component.model');

class GreetingsModelGreetings extends JModel {
        
        
         function getGreetings(){
                   $db = $this->getDBO();
                  
                   $db->setQuery('SELECT * from #__greetings');
                   $greetings = $db->loadObjectList();

                  
                   if ($greetings === null)
                            JError::raiseError(500, 'Error reading db');
                           
                   return $greetings;
         }
        
         function getGreeting($id){
                   $query = ' SELECT * FROM #__greetings '.
                                       ' WHERE id = '.$id;
                   $db = $this->getDBO();
                   $db->setQuery($query);
                   $greeting = $db->loadObject();                
                  
                   if ($greeting === null)
                            JError::raiseError(500, 'Greeting with ID: '.$id.' not found.');
                   else
                            return $greeting;          
         }
        
        
  /**
         * Method that returns an empty greeting with id 0
         *
         * @access    public        
         */
         function getNewGreeting(){
                   $greetingTableRow =& $this->getTable('greetings');
                   $greetingTableRow->id = 0;
                   $greetingTableRow->greeting = '';
                   return $greetingTableRow;
         }
        
         /**
         * Method to store a greeting in the DB
         *
         * @access    public        
         */
         function saveGreeting($greeting)
         {
                   //Parameter not necessary because our model is named GreetingsModelGreetings (used to ilustrate that you can specify an alternative name to the JTable extending class)
             $greetingTableRow =& $this->getTable('greetings');
            
             // Bind the form fields to the greetings table
             if (!$greetingTableRow->bind($greeting)) {
                   JError::raiseError(500, 'Error binding data');         
         }       

         // Make sure the greetings record is valid
         if (!$greetingTableRow->check()) {
                   JError::raiseError(500, 'Invalid data');                        
         }
        
             // Insert/update this record in the db
             if (!$greetingTableRow->store()) {
        $errorMessage = $greetingTableRow->getError();
                            JError::raiseError(500, 'Error binding data: '.$errorMessage);                     
         }
                   //If we get here and with no raiseErrors, then everythign went well
         }
        
         function deleteGreetings($arrayIDs)
         {
                   $query = "DELETE FROM #__greetings WHERE id IN (".implode(',', $arrayIDs).")";
                   $db = $this->getDBO();
                   $db->setQuery($query);
                   if (!$db->query()){
                            $errorMessage = $this->getDBO()->getErrorMsg();
                            JError::raiseError(500, 'Error deleting greetings: '.$errorMessage); 
                   }                 
         }

}
?>

Note that we’re using the getErrorMsg method from JDatabase to get the error message. If there’s an error while the query is being executed (query method) getErrorMsg returns the SQL error that describes what happened (doc. page here: http://dev.joomla.org/component/option,com_jd-wiki/Itemid,/id,references:joomla.framework:database:jdatabase-geterrormsg/)


Section 7: The backend tasks – The cancel task

Section 7.1: The controller task: cancel

We really didn’t have to do this one, but we will just so that when you click cancel when you’re adding or editing a greeting you’ll see a “Cancelled…” message.

And we’re doing this because it creates the opportunity for me to tell you how the tasks are mapped to the controller’s methods and why if you press the toolbar’s Cancel button there’s no error.

When the controller’s constructor is executed, it will use reflection to get a list of all the methods in the controller’s class. Each method is registered as a task with the same name as the method, that’s why in our greetings component when you have, for example, an url like this: index.php?option=com_greetings&task=save the save method from the GreetingsControllerGreetings class is executed.

The JController’s method to register a task is named registerTask and has two parameters, the first one is the task name and the second one is the name of the controller’s method that should be executed when the execute method from JController gets called with that task name as its parameter. For example, in our greetings controller, if we override the constructor to something like this:

       function __construct(){
             parent::__construct();
             $this->registerTask('insert', 'add');
       }

And we supply write the url: index.php?option=com_greetings&task=insert, it will execute the add method in the controller.

JController’s  registerTask doc. Page here.

There is a method in JController named registerDefaultTask that allows you to specify which method from the controller’s class should be executed if no task is specified. This allows you to change the default method to be executed (the default is display). The doc. page for registerDefaultTask is here.

There is a peculiarity about the default task which is the default task is executed, not only when you don’t specify which task is to be executed (for example, that happens with the url: index.php?option=com_greetings where there’s no task parameter) but also when no mapping is found for the task you’ve specified, so if you write an url like this: index.php?option=com_greetings&task=fictional_task that specifies a task that doesn’t exist for our component, the default task (display method) is executed.

And this is why we don’t need to put a cancel method in our controller (the mapping for cancel doesn’t exist so the display gets executed, which is what cancel should do). Although my opinion is, if a task is specified and it doesn’t have a mapping, an error should be produced. So that if you, for some reason, hardcode a link somewhere (like we did in the list view to edit the greetings (display task) ) and you mistype the task name you’d know that you had made a mistake immediately. If you don’t know about this peculiarity of the default task you might end up banging your head before you realize you’ve mistyped the name of the task.

Anyway, this is getting way too long, so... (finally) here’s the last piece of code.

We’re editing the controller’s class located in:

folder where you’ve installed joomla/administrator/com_greetings/greetingsController.php

New code is in red:

<?php

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

jimport('joomla.application.component.controller');

/**
 * Greetings Component Administrator Controller
 */
class GreetingsController extends JController
{
           
            /**
     * Method to display the view
     *
     * @access    public
     */
    function display()
    {
            //This sets the default view (second argument)            
                        $viewName   = JRequest::getVar( 'view', 'list' );
                        //This sets the default layout/template for the view
                        $viewLayout = JRequest::getVar( 'layout', 'listlayout' );             

                        $view = & $this->getView($viewName);
                                  
                        // Get/Create the model
                        if ($model = & $this->getModel('greetings')) {
                                   //Push the model into the view (as default)
                                   //Second parameter indicates that it is the default model for the view
                                   $view->setModel($model, true);
                        }
                                              
                        $view->setLayout($viewLayout);
                        $view->display();

    }
   
    function edit(){
            //getVar(PARAMETER_NAME, DEFAULT_VALUE, HASH, TYPE)
            //The HASH is where to read the parameter from:
            //The default is its default value: getVar will look for the parameter in
            //GET, then POST and then FILE    
            $cids = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
           
            if($cids === null){ //Make sure the cid parameter was in the request
                        JError::raiseError(500, 'cid parameter missing from the request');
            }
                       
                        $greetingId = (int)$cids[0]; //get the first id from the list (we can only edit one greeting at a time) 
           
                        $view = & $this->getView('greetingForm');
                                  
                        // Get/Create the model
                        if ($model = & $this->getModel('greetings')) {
                                   //Push the model into the view (as default)
                                   //Second parameter indicates that it is the default model for the view
                                   $view->setModel($model, true);
                        }
                                              
                        $view->setLayout('greetingformlayout');
                        $view->displayEdit($greetingId);              
    }
   
    function save(){              
            $greeting = JRequest::get( 'POST' );
           
            $model = & $this->getModel('greetings');
            $model->saveGreeting($greeting);
           
            $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option').'&task=display');
            $this->setRedirect($redirectTo, 'Greeting Saved!');                   
    }
   
            function add(){
                        $view = & $this->getView('greetingForm');
                        $model = & $this->getModel('greetings');
                       
                        if (!$model){
                                   JError::raiseError(500, 'Model named greetings not found');
                        }
                        $view->setModel($model, true);
                        $view->setLayout('greetingformlayout');       
            $view->displayAdd();              
            }
           
            function remove(){
            $arrayIDs = JRequest::getVar('cid', null, 'default', 'array' ); //Reads cid as an array
           
            if($arrayIDs === null){ //Make sure the cid parameter was in the request
                        JError::raiseError(500, 'cid parameter missing from the request');
            }
           
            $model = & $this->getModel('greetings');
            $model->deleteGreetings($arrayIDs);
           
            $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option'));
            $this->setRedirect($redirectTo, 'Deleted...');             }
           
            function cancel(){
            $redirectTo = JRoute::_('index.php?option='.JRequest::getVar('option'));
            $this->setRedirect($redirectTo, 'Cancelled...');                      
            }
}

?>

And that’s it. Part III explains how to create the installation package for the component.

Click here to download the code from discussed in part of the tutorial(if you want to try it, unzip the file to folder where you've installed joomla/administrator/components [Remember, this won't work if you haven't set the database tables for the component properly]).

For questions or comments go here.

Last Updated ( Saturday, 21 June 2008 20:34 )
 
Comments (15)
Error in the save function
15 Thursday, 13 May 2010 00:14
Gregory Martin
Found an error with the redirect code in the save function. This code:

$redirectTo = JRoute::_('index.php?
option='.JRequest::getVar('option').'&task=display');

should be

$redirectTo = JRoute::_('index.php?
option='.JRequest::getVar('option').'&task=display', false);

Otherwise the ampersand in &task=display will be rendered as & amp; in the address bar. This doesn't cause any problems in the tutorial because 'display' is the default task anyway. But if you want to redirect anywhere else besides the display list, it won't work.
love it! ... minor correction
14 Saturday, 16 January 2010 00:21
vimentis
Thank you very very much for this great tutorial!!!!

One minor correction:
in joomla/administrator/components/com_greetings/views/list/tmpl/listlayout.php
you use $this->items to select all items at once but it has to be $this->greetings

Greetz!
Simply Great !!!!!!!!!!!!
13 Sunday, 03 January 2010 05:40
tazz
Simply Great !!!!!!!!!!!!
Best tutorial I've seen
12 Tuesday, 24 November 2009 20:32
Nels
Thank you so much. The explanation is simple and easy to understand. Best tutorial I've found so far for a newbie like myself.
awesome
11 Tuesday, 03 November 2009 22:17
wrociu
This what i read here is awesome.
This is something amazing.

Thank You and greetings from Warsaw.
Re: Working with binary data
10 Wednesday, 30 September 2009 13:54
b1ix
Hi Bob,

Email me (b1ix(at)joomladevuser.com) and I'll send you some code samples on how to do that.

Right now, I really don't have any spare time to write more stuff for the site.
Working with binary data
9 Monday, 28 September 2009 14:16
Bob
Excellent tutorial. I haven't seen anything nearly as good anywhere else on the web.

I have the front-end working and am about to start the back-end. My question - would it be terribly difficult to add an image field to the mix? In other words, upload an image, associate it with my 'greeting', have Joomla! save its path in the DB, and correctly display the image?

This is quite easy with other MVC frameworks but within the context of Joomla, since Joomla makes you upload your files into some kind of 'image pool' first, before being able to use them (in articles, for example) I am not sure how to go about it.

Many thanks and kudos once again on the excellent tutorial!
Bob
Thank you
8 Wednesday, 12 August 2009 23:17
R0nn1e
I have toiled over this tutorial for nearly a week but at last understand the structure and format of MVC and joomla
select form
7 Thursday, 11 June 2009 08:44
dennis
hi...great tutorial...
i have one question..i want to make an html select drop-down menu with 4 options, in views/greetingsform/view.php...my database field has 4 ENUM values...
could you help me or send me a useful link?
Thank you.
6 Sunday, 05 April 2009 21:23
Patrick
Excellent information. Very helpful. Thank you.
Would like to know how to add another view
5 Saturday, 07 March 2009 17:05
John
i would like to know how to add another model and view -- how do i set that up on the controller? so that thec controller can sellect the task that i need and the model that i need
New and improved tutorials
4 Tuesday, 27 January 2009 11:08
b1ix
Hi Prabhu Patil,

Thanks!

I would like to improve and add new content to the site. For example, as you said a tutorial that covers adding, deleting and editing records in the frontend.
But I've been having so little free time recently that I haven't even been able to write the tutorials for how to create modules and plugins... (it has been months since the last time I updated the site)

If you want to contribute, you can write a draft or something and send me, I'll put it online and give you credit for it ;)

Contributions are welcome
Cheers,
Rui
deleteGreetings
3 Tuesday, 27 January 2009 11:01
b1ix
Hi Max,

From what I understood you are trying to use $this->getDBO() directly instead
of using the local variable $db in the deleteGreetings function...

you should be ok doing that...

If you want post your code in the forum and I'll have a look at it.

Cheers,
Rui
Great Tutor!
2 Thursday, 22 January 2009 10:51
Max Kurilov
Thank you very much for this tutor.
I have one question: is there a reason to get error message through $this->getDBO() instead of using already defined reference in $db at the deleteGreetings function?
Joomla Developer
1 Friday, 16 January 2009 15:37
Prabhu Patil
Thank you. Tutorial is simply superb, provided lot of information, top to bottom. Thanks once again.
Request: In next addition please cover topic 'how to add, delete, edit records from frontend'. If u add pagination info for frontend that would be much better.

Add your comment

Your name:
Subject:
Comment:
Joomla 1.5 Templates by Joomlashack