Actions

User

Rvsjoen/tutorial/Developing an MVC Component/Part 14

From Joomla! Documentation

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

Contents

Adding ACL

The time has come to add some access control to our component, we don't want nasty critters playing with our greetings now do we. So we will start by writing a relatively simple access.xml file in order to define which actions we want available for our component and the messages.

Creating the access XML

With your favorite editor, create the following file

admin/access.xml

<?xml version="1.0" encoding="utf-8"?>
<access component="com_helloworld">
        <section name="component">
                <action name="core.admin" title="JACTION_ADMIN" description="JACTION_ADMIN_COMPONENT_DESC" />
                <action name="core.manage" title="JACTION_MANAGE" description="JACTION_MANAGE_COMPONENT_DESC" />
                <action name="core.create" title="JACTION_CREATE" description="JACTION_CREATE_COMPONENT_DESC" />
                <action name="core.delete" title="JACTION_DELETE" description="JACTION_DELETE_COMPONENT_DESC" />
                <action name="core.edit" title="JACTION_EDIT" description="JACTION_EDIT_COMPONENT_DESC" />
        </section>
        <section name="message">
                <action name="core.delete" title="JACTION_DELETE" description="COM_HELLOWORLD_ACCESS_DELETE_DESC" />
                <action name="core.edit" title="JACTION_EDIT" description="COM_HELLOWORLD_ACCESS_EDIT_DESC" />
        </section>
</access>

Adding access configuration

Now that we have declared ourselves some actions that may or may not be performed on certain objects, we need a way for the user to be able to configure which groups get to perform what actions and which do not. This already exists for us, all we have to do it to add it to config.xml

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

admin/config.xml

<?xml version="1.0" encoding="utf-8"?>
<config>
        <fieldset
                name="greetings"
                label="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL"
                description="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC">
                <field
                        name="show_category"
                        type="radio"
                        label="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL"
                        description="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC"
                        default="0">
                        <option value="0">JHIDE</option>
                        <option value="1">JSHOW</option>
                </field>
        </fieldset>
        <fieldset
                name="permissions"
                label="JCONFIG_PERMISSIONS_LABEL"
                description="JCONFIG_PERMISSIONS_DESC">
                <field
                        name="rules"
                        type="rules"
                        label="JCONFIG_PERMISSIONS_LABEL"
                        class="inputbox"
                        validate="rules"
                        filter="rules"
                        component="com_helloworld"
                        section="component" 
                />
        </fieldset>
</config>

Enforcing permissions

Now that we have a set of actions, and a way to configure who gets to perform them, the next natural step is actually enforcing these actions, so let us start with the simplest one.

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

admin/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.application.component.controller');
 
// Set some global property
$document = JFactory::getDocument();
$document->addStyleDeclaration('.icon-48-helloworld {background-image: url(../media/com_helloworld/images/tux-48x48.png);}');
 
// Access check.
if (!JFactory::getUser()->authorise('core.manage', 'com_helloworld')) 
{
        return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));
}
 
// Require helper file
JLoader::register('HelloWorldHelper', dirname(__FILE__) . DS . 'helpers' . DS . 'helloworld.php');
 
// Get an instance of the controller prefixed by HelloWorld
$controller = JController::getInstance('HelloWorld');
 
// Perform the Request task
$controller->execute(JRequest::getCmd('task'));
 
// Redirect if set by the controller
$controller->redirect();

Implementing an access check on the component-wide action 'core.manage' in the entry point of the backend makes sure that nobody can perform any actions or view any data in the backend of your component unless they have this privilege.

We also implement a helper function getActions() to help us return which actions are available for the current user on a given message id.

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

admin/helpers/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
class HelloWorldHelper
{
        public static function addSubmenu($submenu) 
        {
                JSubMenuHelper::addEntry(JText::_('COM_HELLOWORLD_SUBMENU_MESSAGES'), 
                        'index.php?option=com_helloworld', $submenu == 'messages');
                JSubMenuHelper::addEntry(JText::_('COM_HELLOWORLD_SUBMENU_CATEGORIES'), 
                        'index.php?option=com_categories&view=categories&extension=com_helloworld', $submenu == 'categories');
                $document = JFactory::getDocument();
                if ($submenu == 'categories'){ 
                        $document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION_CATEGORIES'));
                }
        }
 
        public static function getActions($messageId = 0)
        {
                $user   = JFactory::getUser();
                $result = new JObject;
 
                if (empty($messageId)) {
                        $assetName = 'com_helloworld';
                }
                else {
                        $assetName = 'com_helloworld.message.'.(int) $messageId;
                }
 
                $actions = array(
                        'core.admin', 'core.manage', 'core.create', 'core.edit', 'core.delete'
                );
 
                foreach ($actions as $action) {
                        $result->set($action,   $user->authorise($action, $assetName));
                }
 
                return $result;
        }
}


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

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);
        }
 
        protected function allowEdit($data = array(), $key = 'id')
        {
                // Check specific edit permission then general edit permission.
                return JFactory::getUser()->authorise('core.edit', 
                        'com_helloworld.message.'.((int) isset($data[$key]) ? $data[$key] : 0)) 
                        || parent::allowEdit($data, $key);
        }
}

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

admin/tables/helloworld.php

<?php
// No direct access to this file
defined('_JEXEC') or die;
 
jimport('joomla.database.table');
 
class HelloWorldTableHelloWorld extends JTable
{
        function __construct(&$db) 
        {
                parent::__construct('#__helloworld', 'id', $db);
        }
 
        public function bind($array, $ignore = '') 
        {
                if (isset($array['params']) && is_array($array['params'])) 
                {
                        // Convert the params field to a string.
                        $parameter = new JRegistry;
                        $parameter->loadArray($array['params']);
                        $array['params'] = (string)$parameter;
                }
                return parent::bind($array, $ignore);
        }
 
        public function load($pk = null, $reset = true) 
        {
                if (parent::load($pk, $reset)) 
                {
                        // Convert the params field to a registry.
                        $params = new JRegistry;
                        $params->loadJSON($this->params);
                        $this->params = $params;
                        return true;
                }
                else
                {
                        return false;
                }
        }
 
        protected function _getAssetName()
        {
                $k = $this->_tbl_key;
                return 'com_helloworld.message.'.(int) $this->$k;
        }
 
        protected function _getAssetTitle()
        {
                return $this->greeting;
        }
 
        protected function _getAssetParentId()
        {
                $asset = JTable::getInstance('Asset');
                $asset->loadByName('com_helloworld');
                return $asset->id;
        }
}

Assets are object on which there are stored permission information, in order to enable saving permissions on individual items we need to make our JTable class aware that it needs to keep things in sync with the assets table. We do this by implementing these three protected functions.

Updating the toolbars

Now all that remains, is to implement some logic in the code building the toolbars for the backend views in order to only show the buttons for the tasks that are available to the current user.

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

admin/views/helloworld/view.html.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);
 
                // Set the document
                $this->setDocument();
        }
 
        protected function addToolBar() 
        {
                JRequest::setVar('hidemainmenu', true);
                $isNew = ($this->item->id == 0);
                $user = JFactory::getUser();
                $userId = $user->id;
                $canDo = HelloWorldHelper::getActions($this->item->id);
                JToolBarHelper::title($isNew ? JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW') 
                        : JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT'), 'helloworld');
                // Built the actions for new and existing records.
                if ($isNew) 
                {
                        // For new records, check the create permission.
                        if ($canDo->get('core.create')) 
                        {
                                JToolBarHelper::apply('helloworld.apply', 'JTOOLBAR_APPLY');
                                JToolBarHelper::save('helloworld.save', 'JTOOLBAR_SAVE');
                                JToolBarHelper::custom('helloworld.save2new', 'save-new.png', 
                                        'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false);
                        }
                        JToolBarHelper::cancel('helloworld.cancel', 'JTOOLBAR_CANCEL');
                }
                else
                {
                        if ($canDo->get('core.edit'))
                        {
                                // We can save the new record
                                JToolBarHelper::apply('helloworld.apply', 'JTOOLBAR_APPLY');
                                JToolBarHelper::save('helloworld.save', 'JTOOLBAR_SAVE');
 
                                // We can save this record, but check the create permission to 
                                // see if we can return to make a new one.
                                if ($canDo->get('core.create')) 
                                {
                                        JToolBarHelper::custom('helloworld.save2new', 'save-new.png', 
                                                'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false);
                                }
                        }
                        if ($canDo->get('core.create')) 
                        {
                                JToolBarHelper::custom('helloworld.save2copy', 'save-copy.png', 
                                        'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false);
                        }
                        JToolBarHelper::cancel('helloworld.cancel', 'JTOOLBAR_CLOSE');
                }
        }
 
        protected function setDocument() 
        {
                $isNew = ($this->item->id < 1);
                $document = JFactory::getDocument();
                $document->setTitle($isNew ? JText::_('COM_HELLOWORLD_HELLOWORLD_CREATING') 
                        : JText::_('COM_HELLOWORLD_HELLOWORLD_EDITING'));
                $document->addScript(JURI::root() . "media/com_helloworld/js/helloworld.js");
        }
}

admin/views/helloworlds/view.html.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);
 
                // Set the document
                $this->setDocument();
        }
 
        protected function addToolBar() 
        {
                $canDo = HelloWorldHelper::getActions();
                JToolBarHelper::title(JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS'), 'helloworld');
                if ($canDo->get('core.create')) 
                {
                        JToolBarHelper::addNew('helloworld.add', 'JTOOLBAR_NEW');
                }
                if ($canDo->get('core.edit')) 
                {
                        JToolBarHelper::editList('helloworld.edit', 'JTOOLBAR_EDIT');
                }
                if ($canDo->get('core.delete')) 
                {
                        JToolBarHelper::deleteList('', 'helloworld.delete', 'JTOOLBAR_DELETE');
                }
                if ($canDo->get('core.admin')) 
                {
                        JToolBarHelper::divider();
                        JToolBarHelper::preferences('com_helloworld');
                }
        }
 
        protected function setDocument() 
        {
                $document = JFactory::getDocument();
                $document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION'));
        }
}

Installation manifest

In the installation manifest, we have updated the version number and added access.xml

helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="2.5.0" method="upgrade">
 
        <name>COM_HELLOWORLD</name>
        <!-- The following elements are optional and free of formatting constraints -->
        <creationDate>June 2011</creationDate>
        <author>John Doe</author>
        <authorEmail>john.doe@example.org</authorEmail>
        <authorUrl>http://www.example.org</authorUrl>
        <copyright>Copyright Info</copyright>
        <license>License Info</license>
        <!--  The version string is stored in the components table -->
        <version>0.0.14</version>
        <!-- The description is optional and defaults to the name -->
        <description>COM_HELLOWORLD_DESCRIPTION</description>
 
        <install>
                <sql>
                        <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
                </sql>
        </install>
        <uninstall>
                <sql>
                        <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
                </sql>
        </uninstall>
 
        <!-- Note the folder attribute: This attribute describes the folder
                to copy FROM in the package to install therefore files copied
                in this section are copied from "site/" in the package -->
        <files folder="site">
                <filename>index.html</filename>
                <filename>helloworld.php</filename>
                <filename>controller.php</filename>
                <folder>views</folder>
                <folder>models</folder>
                <folder>language</folder>
        </files>
 
        <media destination="com_helloworld" folder="media">
                <filename>index.html</filename>
                <folder>images</folder>
                <folder>js</folder>
        </media>
 
        <administration>
                <menu img="../media/com_helloworld/images/tux-16x16.png">COM_HELLOWORLD_MENU</menu>
                <submenu>
                        <menu view="helloworlds">COM_HELLOWORLD_SUBMENU_MESSAGES</menu>
                        <menu link="option=com_categories&amp;view=categories&amp;extension=com_helloworld">COM_HELLOWORLD_SUBMENU_CATEGORIES</menu>
                </submenu>
                <!-- Note the folder attribute: This attribute describes the folder
                        to copy FROM in the package to install therefore files copied
                        in this section are copied from "admin/" in the package -->
                <files folder="admin">
                        <filename>index.html</filename>
                        <filename>access.xml</filename>
                        <filename>helloworld.php</filename>
                        <filename>controller.php</filename>
                        <filename>config.xml</filename>
                        <folder>sql</folder>
                        <folder>tables</folder>
                        <folder>models</folder>
                        <folder>views</folder>
                        <folder>language</folder>
                        <folder>controllers</folder>
                        <folder>helpers</folder>
                </files>
        </administration>
 
</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