Actions

User

Rvsjoen/tutorial/Developing an MVC Component/Part 09

From Joomla! Documentation

< User:Rvsjoen‎ | tutorial/Developing an MVC Component

Contents

Adding actions to backend

Now, we don't want to only be able to see a table with all the greetings in the backend. We also want to be able to manage them by editing, adding new greetings, deleting greetings and so on. This means we are going to have to add some more logic to the backend. We will implement a controller to handle these task and an editing view to make them available for the user.

Creating the controllers

In fact, we are going to implement not only one, but two controllers. One controller will be responsible for handling the actions taken in the view we already have (the table listing the messages). And one controller will be responsible for handling the actions taken when we are in the editing view of a single message.

With your favorite editor, create the following file

admin/controllers/helloworlds.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.controlleradmin');
 
class HelloWorldControllerHelloWorlds extends JControllerAdmin
{
        public function getModel($name = 'HelloWorld', $prefix = 'HelloWorldModel')         {
                $model = parent::getModel($name, $prefix, array('ignore_request' => true));
                return $model;
        }
}

The important thing to notice about this controller is that it extends from JControllerAdmin and not from JController, this means that it has a lot of builtin functionality for handling lists of items like you would normally see in the backend. We override the default getModel() function in order to use the HelloWorldModelHelloWorld instead of HelloWorldModelHellos for these actions so we don't have to duplicate functionality in two different controllers.

Now that we have the controller to handle the list view, we also need to create the controller to handle the single item editing view, this will be handled by a controller extending JControllerForm.

With your favorite editor, create the following file

admin/controllers/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.controllerform');
 
class HelloWorldControllerHelloWorld extends JControllerForm
{
 
}

We do not have to add any functionality to this controller for our component since JControllerForm has everything that we need.

Creating the model

As we previously said, we also need a model for our components to work with to perform options on the individual messages. We already have a controller.

With your favorite editor, create the following file

admin/models/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.modeladmin');
 
class HelloWorldModelHelloWorld extends JModelAdmin
{
        public function getForm($data = array(), $loadData = true) 
        {
                // Get the form.
                $form = $this->loadForm('com_helloworld.helloworld', 'helloworld', array('control' => 'jform', 'load_data' => $loadData));
                return $form;
        }
 
        protected function loadFormData() 
        {
                // Check the session for previously entered form data.
                $data = JFactory::getApplication()->getUserState('com_helloworld.edit.helloworld.data', array());
                if(empty($data)){
                        $data = $this->getItem();
                }
                return $data;
        }
 
        public function getTable($name = '', $prefix = 'HelloWorldTable', $options = array())
        {
                return parent::getTable($name, $prefix, $options);
        }
}


In the model there are two functions that we need to create. getForm() is declared abstract in JModelForm so we have no choice whether or not to implement this if we want to extend from JModelAdmin, and it is basically used to get the form from the XML form definition (which we will create in a minute) using the protected function loadForm().

The call to loadForm() takes several important parameters, the first parameter is the name of the form as Joomla! sees it once it is created, the second parameter is the form source (where to load the form from). This can either be an XML string, or the name of the XML form definition file. Our form definition file will be named helloworld.xml and therefore we pass helloworld as the second parameter. The third parameter is an array containing two items, load_data is used to tell the form that it needs to load data into the form elements since we want to be able to edit existing messages and not just create new ones. control is used to control the name and id attributes of the form elements. Passing a control value of jform will cause the form element with name and id greeting in the XML, to have name="jform[greeting]" and id="jform_greeting" in the html, making it easy to distinguish which fields belong to which form and to get all the fields of a certain form from the request variables.

The second function we implement is loadFormData() and this function will be called by loadForm() when we tell it that it needs to load the form data. As you can see from the code, the function will first check the user state of the application to see if we have data available to populate the form, alternatively it will get the item from the database.

In addition we need to override the function call to getTable() in order to make it use our HelloWorldTable class prefix. This is a workaround for behavior in 1.7.0 and older and will not be required in newer versions.

Updating the list view

We have created the necessary models and controllers, now we need to make the functionality available to the users. We will start by adding a toolbar to the view that lists the messages and modify it so that clicking a message will open up the editing view for that message.

With your favorite editor, modify the following file to look like this

admin/views/helloworlds/view.html.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.view');
 
class HelloWorldViewHelloWorlds extends JView
{
        function display($tpl = null) 
        {
                // Get data from the model
                $items = $this->get('Items');
                $pagination = $this->get('Pagination');
 
                // Assign data to the view
                $this->items = $items;
                $this->pagination = $pagination;
 
                // Set the toolbar
                $this->addToolBar();
 
                // Display the template
                parent::display($tpl);
        }
 
        protected function addToolBar() 
        {
                JToolBarHelper::title(JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS'));
                JToolBarHelper::deleteListX('', 'helloworlds.delete');
                JToolBarHelper::editListX('helloworld.edit');
                JToolBarHelper::addNewX('helloworld.add');
        }
}

As you can see, we have added a new function addToolBar() which is responsible for building the toolbar, and then this function is called from the display() function. We use the JToolBarHelper to help us make the buttons since that is what it is for, so no magic here, move along.

With your favorite editor, modify the following files to look like this

admin/views/helloworlds/tmpl/default.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
JHtml::_('behavior.tooltip');
?>
<form action="<?php echo JRoute::_('index.php?option=com_helloworld'); ?>" method="post" name="adminForm">
        <table class="adminlist">
                <thead><?php echo $this->loadTemplate('head');?></thead>
                <tfoot><?php echo $this->loadTemplate('foot');?></tfoot>
                <tbody><?php echo $this->loadTemplate('body');?></tbody>
        </table>
        <div>
                <input type="hidden" name="task" value="" />
                <input type="hidden" name="boxchecked" value="0" />
                <?php echo JHtml::_('form.token'); ?>
        </div>
</form>

admin/views/helloworlds/tmpl/default_body.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
?>
<?php foreach($this->items as $i => $item): ?>
        <tr class="row<?php echo $i % 2; ?>">
                <td>
                        <?php echo $item->id; ?>
                </td>
                <td>
                        <?php echo JHtml::_('grid.id', $i, $item->id); ?>
                </td>
                <td>
                        <a href="<?php echo JRoute::_('index.php?option=com_helloworld&task=helloworld.edit&id=' . $item->id); ?>">                                <?php echo $item->greeting; ?>
                        </a>
                </td>
        </tr>
<?php endforeach; ?>

We have made two changes to the view template, first we added some hidden input fields to the form, this is to make the toolbar buttons capable of executing the tasks with the items which are checked in the list. Secondly we added a link to the greeting in the table, which executes the edit task for that particular greeting. The functionality of the HelloWorldControllerHelloWorld controller will take care of opening up the editing view.

Creating the form for editing

We do want to be able to edit the greetings, so we need an XML form definition that makes this possible, after all we already told the model to load the form and what the form is called, so now we have to create it.

With your favorite editor, create the following file

admin/models/forms/helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<form>
        <fieldset>
                <field
                        name="id"
                        type="hidden"
                />
                <field
                        name="greeting"
                        type="text"
                        label="COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL"
                        description="COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC"
                        size="40"
                        class="inputbox"
                        default=""
                />
        </fieldset>
</form>

In the form definition we declare each property of the greeting. In addition we give the field a name and a type, the id field is hidden since we only need to pass it in the form, the user does not have to see or change it, and the greeting field is of type text since we want the user to be able to edit this field. There are a lot of other options to apply to field elements, but they will not be covered here.

Creating the editing view

The last piece of this puzzle, is to actually create the view that we will be able to use to edit each individual greeting.

With your favorite editor, create the following file

admin/views/helloworld/view.html.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.view');
 
class HelloWorldViewHelloWorld extends JView
{
        public function display($tpl = null) 
        {
                // get the Data
                $form = $this->get('Form');
                $item = $this->get('Item');
 
                // Assign the Data
                $this->form = $form;
                $this->item = $item;
 
                // Set the toolbar
                $this->addToolBar();
 
                // Display the template
                parent::display($tpl);
        }
 
        protected function addToolBar() 
        {
                JRequest::setVar('hidemainmenu', true);
                $isNew = ($this->item->id == 0);
                JToolBarHelper::title($isNew ? JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW') 
                        : JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT'));
                JToolBarHelper::save('helloworld.save');
                JToolBarHelper::cancel('helloworld.cancel', $isNew ? 'JTOOLBAR_CANCEL' : 'JTOOLBAR_CLOSE');
        }
}

This view is pretty similar to the HelloWorldViewHelloWorlds that we already have, except for the fact that it is meant to display only a single greeting and not a list. As you can see, all it pretty much does is load the form and item from the model and create a toolbar.

With your favorite editor, create the following file

admin/views/helloworld/tmpl/edit.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
JHtml::_('behavior.tooltip');
?>
<form action="<?php echo JRoute::_('index.php?option=com_helloworld&layout=edit&id='.(int) $this->item->id); ?>" 
        method="post" name="adminForm" id="helloworld-form">
        <fieldset class="adminform">
                <legend><?php echo JText::_('COM_HELLOWORLD_HELLOWORLD_DETAILS'); ?></legend>
                <ul class="adminformlist">
                <?php foreach($this->form->getFieldset() as $field): ?>
                        <li><?php echo $field->label;echo $field->input;?></li>
                <?php endforeach; ?>
                </ul>
        </fieldset>
        <div>
                <input type="hidden" name="task" value="helloworld.edit" />
                <?php echo JHtml::_('form.token'); ?>
        </div>
</form>

This is the edit view template, and it is responsible for displaying the editing form for the item the user has selected. Here the power of JForm really becomes apparent, since we have a form that we dynamically render using the foreach loop, all we need to do if we want to add fields to this form, is to simply update the form XML definition.

Updating language files

Since we added a couple of new language strings, we need to translate these and put them in the proper language file

With your favorite editor, modify the following file to look like this

admin/language/en-GB/en-GB.com_helloworld.ini

COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC="This message will be displayed"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL="Message"
COM_HELLOWORLD_HELLOWORLD_HEADING_GREETING="Greeting"
COM_HELLOWORLD_HELLOWORLD_HEADING_ID="ID"
COM_HELLOWORLD_HELLOWORLD_DETAILS="Details"
COM_HELLOWORLD_MANAGER_HELLOWORLDS="HelloWorld manager"
COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW="HelloWorld manager: New Message"
COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT="HelloWorld manager: Edit Message"
COM_HELLOWORLD_N_ITEMS_DELETED_1="One message deleted"
COM_HELLOWORLD_N_ITEMS_DELETED_MORE="%d messages deleted"

Installation manifest

The changes to the installation manifest are the version number and the addition of the controller folder in the administrator file copy section.

helloworld.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <extension type="component" version="2.5.0" method="upgrade">
  3.  
  4.         <name>COM_HELLOWORLD</name>
  5.         <!-- The following elements are optional and free of formatting constraints -->
  6.         <creationDate>June 2011</creationDate>
  7.         <author>John Doe</author>
  8.         <authorEmail>john.doe@example.org</authorEmail>
  9.         <authorUrl>http://www.example.org</authorUrl>
  10.         <copyright>Copyright Info</copyright>
  11.         <license>License Info</license>
  12.         <!--  The version string is stored in the components table -->
  13.         <version>0.0.9</version>
  14.         <!-- The description is optional and defaults to the name -->
  15.         <description>COM_HELLOWORLD_DESCRIPTION</description>
  16.  
  17.         <install>
  18.                 <sql>
  19.                         <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
  20.                 </sql>
  21.         </install>
  22.         <uninstall>
  23.                 <sql>
  24.                         <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
  25.                 </sql>
  26.         </uninstall>
  27.  
  28.         <!-- Note the folder attribute: This attribute describes the folder
  29.                 to copy FROM in the package to install therefore files copied
  30.                 in this section are copied from "site/" in the package -->
  31.         <files folder="site">
  32.                 <filename>index.html</filename>
  33.                 <filename>helloworld.php</filename>
  34.                 <filename>controller.php</filename>
  35.                 <folder>views</folder>
  36.                 <folder>models</folder>
  37.                 <folder>language</folder>
  38.         </files>
  39.  
  40.         <administration>
  41.                 <menu>COM_HELLOWORLD_MENU</menu>
  42.                 <!-- Note the folder attribute: This attribute describes the folder
  43.                         to copy FROM in the package to install therefore files copied
  44.                         in this section are copied from "admin/" in the package -->
  45.                 <files folder="admin">
  46.                         <filename>index.html</filename>
  47.                         <filename>helloworld.php</filename>
  48.                         <filename>controller.php</filename>
  49.                         <folder>sql</folder>
  50.                         <folder>tables</folder>
  51.                         <folder>models</folder>
  52.                         <folder>views</folder>
  53.                         <folder>language</folder>
  54.                         <folder>controllers</folder>
  55.                 </files>
  56.         </administration>
  57.  
  58. </extension>

Testing your component

For details on how to install the component into your Joomla! site, refer to the information provided in Part 01.

File listing

Download this part

Download example package

Articles in this series

This tutorial is supported by the following versions of Joomla!

Joomla 2.5