This tutorial is part of the [[Developing a Model-View-Controller (MVC) Component for Joomla!2.5]] tutorial. You are encouraged to read the previous parts of the tutorial before reading this.

This tutorial is part of the [[Developing a Model-View-Controller (MVC) Component for Joomla!2.5]] tutorial. You are encouraged to read the previous parts of the tutorial before reading this.

−

For the moment we leave the deprecated JError-references as they are. They will still be available in Joomla! 3.x. We cannot just change them to JLog::add() statements because in Joomla! 2.5 the messages will then not be enqueued (as there is no messagequeue-logger added as is in /libraries/cms.php in Joomla! 3.0). Other solutions, like using $app->enqueueMessage() or directly throwing PHP-exceptions as showstopper are also possible, but then there would still be numurous references to JError throughout the application. For instance in the view, we now check for errors raised in the model with: <span style="color:#900">count($errors = $this->get('Errors'))</span>, which uses JError from the JOBject that was the base for JModel. To be able to use a check like <span style="color:#900">$result instanceof Exception</span> there, we would have to change the way the Model raises those errors and warnings now. If we want to make an application that would work in Joomla! 2.5 and 3.x we can continue using JError. The moment we want to use our 3.x extensions also in 4.x we will have to change this (and probably a lot more too). This tutorial is primarily focussed on Joomla! 2.5 for the moment. So: we notice the upcoming change, but leave it there for the moment.

+

For the moment we leave the '''deprecated JError'''-references as they are. They will still be available in Joomla! 3.x. We cannot just change them to JLog::add() statements because in Joomla! 2.5 the messages will then not be enqueued (as there is no messagequeue-logger added as is in /libraries/cms.php in Joomla! 3.0). Other solutions, like using $app->enqueueMessage() or directly throwing PHP-exceptions as showstopper are also possible, but then there would still be numurous references to JError throughout the application. For instance in the view, we now check for errors raised in the model with: <span style="color:#900">count($errors = $this->get('Errors'))</span>, which uses JError from the JOBject that was the base for JModel. To be able to use a check like <span style="color:#900">$result instanceof Exception</span> there, we would have to change the way the Model raises those errors and warnings now. If we want to make an application that would work in Joomla! 2.5 and 3.x we can continue using JError. The moment we want to use our 3.x extensions also in 4.x we will have to change this (and probably a lot more too). This tutorial is primarily focussed on Joomla! 2.5 for the moment. So: we notice the upcoming change, but leave it there for the moment.

The MVC-base-classes JController, JModel and JView have been changed to JControllerLegacy, JModelLegacy and JViewLegacy to be forward compatibility with Joomla! CMS 3.x legacy classes.

The MVC-base-classes JController, JModel and JView have been changed to JControllerLegacy, JModelLegacy and JViewLegacy to be forward compatibility with Joomla! CMS 3.x legacy classes.

Introduction

For the moment we leave the deprecated JError-references as they are. They will still be available in Joomla! 3.x. We cannot just change them to JLog::add() statements because in Joomla! 2.5 the messages will then not be enqueued (as there is no messagequeue-logger added as is in /libraries/cms.php in Joomla! 3.0). Other solutions, like using $app->enqueueMessage() or directly throwing PHP-exceptions as showstopper are also possible, but then there would still be numurous references to JError throughout the application. For instance in the view, we now check for errors raised in the model with: count($errors = $this->get('Errors')), which uses JError from the JOBject that was the base for JModel. To be able to use a check like $result instanceof Exception there, we would have to change the way the Model raises those errors and warnings now. If we want to make an application that would work in Joomla! 2.5 and 3.x we can continue using JError. The moment we want to use our 3.x extensions also in 4.x we will have to change this (and probably a lot more too). This tutorial is primarily focussed on Joomla! 2.5 for the moment. So: we notice the upcoming change, but leave it there for the moment.

The MVC-base-classes JController, JModel and JView have been changed to JControllerLegacy, JModelLegacy and JViewLegacy to be forward compatibility with Joomla! CMS 3.x legacy classes.

Adding Access Control

With Joomla!'s Access Control we can define which user groups are allowed or denied to do which actions in your component. In this example we use actions that are defined in the core. For the component as a whole: core.admin (access to the configuration) and core.manage (access to the backend). And at various levels actions like create, delete and edit. Besides those core actions you can define your own actions, but that is often not necessary and is not shown in this example. View/Read Access is not managed via those actions but with View Access Levels; see general documentation about Joomla!'s ACL for that.

In the #__assets table the actual list is stored: which user groups are allowed or denied to do which actions on which resources (assets). This is the implementation of the Access Control List (ACL).

In this article we will show how to add and use access permissions at several levels of granularity: for your component as a whole, for the categories and for the individual items.

Minimal ACL requirements at the component level

There are 2 actions that need to be defined at the component level for a Joomla! 2.5 component to offer basic ACL support:

Add the 'Options' toolbar button when user is authorised for it

See further downwards for a more elaborated example of admin/views/helloworlds/view.html.php where this JToolBarHelper::preferences('com_helloworld') is done in an addToolBar()-method together with the other toolbar buttons and the JUser->authorise()-check is done in the admin/helpers/helloworld.php helper file, resulting in the $canDo-property.

Restrict the access to the component's backend to authorised usergroups

To control the access to the backend of the component add the following lines to the admin/helloworld.php entry-file:

// Access check: is this user allowed to access the backend of this component?if(!JFactory::getUser()->authorise('core.manage','com_helloworld')){return JError::raiseWarning(404, JText::_('JERROR_ALERTNOAUTHOR'));}

Describing the actions you want to control the access to

Each component (or part of it) has its own set of permissions that can be controlled. They are described in an access.xml file located at the root of the admin folder. In this helloworld-example the actions to which access is controlled are divided in three sections: at the component level, the category level and the item level. An 'item' is called a 'message' in our example component, hence the name of the third section.

Adding the setting of permissions in the component's Preferences

Since we now use Access Control permissions in our component, we need to be able to set them at the component level. That is done in the Preferences of this component: the screen you see after clicking the 'Options' button. The config.xml-file is a form-definition for those Preferences. We could define the component level actions here too, as a child of the "rules" field-tag, but it is now preferred to also put those actions in access.xml: in that way all access rules for this component are on one spot.

Displaying only the right toolbar buttons

Which toolbar buttons to display depends on the Access Control permissions for the user. We put all permissions for this user in the $canDo property of the view; so we can eventually refer to it in layouts (in the edit-form for example).

Restricting access to the component

The main idea in ACL is to restrict actions to groups of users. The first action to be restricted is access to the administrative backend of the component itself. With your favorite file editor, edit the admin/helloworld.php file and add the lines with the access check.

admin/helloworld.php

<?php// No direct access to this filedefined('_JEXEC') or die('Restricted access');// Access check: is this user allowed to access the backend of this component?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');// import joomla controller library
jimport('joomla.application.component.controller');// Get an instance of the controller prefixed by HelloWorld$controller= JController::getInstance('HelloWorld');// Perform the Request task$input= JFactory::getApplication()->input;$controller->execute($input->getCmd('task'));// Redirect if set by the controller$controller->redirect();

Add the asset_id column to the database table

In order to be able to work with JTable an asset_id column has to be added to the database #__helloworld table.

Setting the permission values in the assets table

In order to store permissions for each message in the assets database table, we have to do two things.

First, in the HelloWorld model we check the 'core.edit' ACL permission: is this user allowed to edit this record? The JUser->autorise() method checks the permission of the record itself and if not set: of it's parent in the assets table.

Second, we store the item permissions in the assets database table. JTable not only provides an interface for storing the data of the record itself in the item's database table, but also for storing the permissions for that record in the assets database table. Therefore we must add information to the bind()-method about the permission-values. We alsop have to provide the asset name, asset title and the id of the asset parent via the helloworld JTable. Therefore we override 3 methods:

_getAssetName(): a unique name for this asset, by which it can be retrieved

_getAssetTitle(): a more human-friendly way to identify the asset (not necessary unique)

_getAssetParentId(): the asset_id of the parent in the asset database table (from whom permissions are inherited)

This code for _getAssetParentId() above uses JTableAsset to retrieve the asset_id of the asset-parent. This is different from the code in the current version of com_content, where the asset_id of the category is retrieved from the #__categories database table. That is another possibility; many ways leading to Rome. In com_content however, if an item would not be under a category, then the asset_id of the global asset is returned. That would of course not be right, but is fixed there by providing a default category "uncategorised", so that an article is always under a category. That is why you cannot just copy the code of _getAssetParentId() in com_content to your own component. The code above is more general.

Adding language strings

We used 3 language strings that have to be added to the backend language-file.

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

COM_HELLOWORLD_FIELDSET_RULES="Message Permissions"
COM_HELLOWORLD_ACCESS_DELETE_DESC="Is this group allowed to edit this message?"
COM_HELLOWORLD_ACCESS_DELETE_DESC="Is this group allowed to delete this message?"

Further reading

More information on actions, assets and ACL can be found on the following pages:

Create a compressed file of this directory or directly download the archive (TODO: zip has to be updated! Will be done coming days...) and install it using the extension manager of Joomla. You can add a menu item of this component using the menu manager in the backend.

helloworld.xml

<?xmlversion="1.0"encoding="utf-8"?><extensiontype="component"version="2.5.0"method="upgrade"><name>COM_HELLOWORLD</name><!-- The following elements are optional and free of formatting constraints --><creationDate>November 2009</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 recorded in the components table --><version>0.0.14</version><!-- The description is optional and defaults to the name --><description>COM_HELLOWORLD_DESCRIPTION</description><install><!-- Runs on install --><sql><filedriver="mysql"charset="utf8">sql/install.mysql.utf8.sql</file></sql></install><uninstall><!-- Runs on uninstall --><sql><filedriver="mysql"charset="utf8">sql/uninstall.mysql.utf8.sql</file></sql></uninstall><update><!-- Runs on update; New in 2.5 --><schemas><schemapathtype="mysql">sql/updates/mysql</schemapath></schemas></update><!-- Site Main File Copy Section --><!-- 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 --><filesfolder="site"><filename>index.html</filename><filename>helloworld.php</filename><filename>controller.php</filename><folder>views</folder><folder>models</folder><folder>language</folder></files><mediadestination="com_helloworld"folder="media"><filename>index.html</filename><folder>images</folder></media><administration><!-- Administration Menu Section --><menuimg="../media/com_helloworld/images/tux-16x16.png">COM_HELLOWORLD_MENU</menu><!-- Administration Main File Copy Section --><!-- 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 --><filesfolder="admin"><!-- Admin Main File Copy Section --><filename>index.html</filename><filename>config.xml</filename><filename>access.xml</filename><filename>helloworld.php</filename><filename>controller.php</filename><!-- SQL files section --><folder>sql</folder><!-- tables files section --><folder>tables</folder><!-- models files section --><folder>models</folder><!-- views files section --><folder>views</folder><!-- controllers files section --><folder>controllers</folder><!-- helpers files section --><folder>helpers</folder></files><languagesfolder="admin"><languagetag="en-GB">language/en-GB/en-GB.com_helloworld.ini</language><languagetag="en-GB">language/en-GB/en-GB.com_helloworld.sys.ini</language></languages></administration></extension>

Zips

Download the zip file for this Part: [1]= 404!!!, TODO: make new zip available