Actions

Difference between revisions of "Adding ACL rules to your component"

From Joomla! Documentation

m (Put Action Control In Action)
(Edit bug in _getAssetName)
 
(12 intermediate revisions by 7 users not shown)
Line 1: Line 1:
This tutorial will demonstrate how to add custom action permission to your component down to object level. Normally we familiar with ACL in global configuration level, category level and component level. Now we will learn how to add action permission control in our component.
+
{{version/tutor|2.5,3.1}}{{incomplete}}
{{JVer|1.6}} {{JVer|1.7}}
+
This tutorial will demonstrate how to add custom action permissions to your component down to object level. Normally we are familiar with ACL in global configuration level, category level and component level. Now we will learn how to add action permission control in our component.
 +
 
 
== ACL Architecture Overview ==
 
== ACL Architecture Overview ==
Action permissions for component in Joomla! 1.6 can be defined at up to 3 levels
+
Action permissions for components in Joomla! 2.5 can be defined at up to 3 levels:
 
# '''Global Configuration''': determines the default permissions for each action and group.  
 
# '''Global Configuration''': determines the default permissions for each action and group.  
 
# '''Component Options->Permissions''': can override the default permissions for our component
 
# '''Component Options->Permissions''': can override the default permissions for our component
 
# '''Record Options->Permissions''': this is what we discuss in this tutorial.  
 
# '''Record Options->Permissions''': this is what we discuss in this tutorial.  
  
The other level that you will see is '''Category''' which can override the default permissions for objects assigned to category. We can use this if we use category in our component. I separate this one from others as its parent is '''Global Configuration'''.
+
The other level that you will see is '''Category''' which can override the default permissions for objects assigned to category. We can use this if we use category in our component. I separate this one from others as it's parent is '''Global Configuration'''.
 +
== Modify own database table ==
 +
The own database table needs to have a column with an asset-ID. If this kind of column is missing in your own database table structure, then add something like this:
 +
<source lang="sql">
 +
ALTER TABLE `#__asterman_units` ADD `asset_id` INT(255) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`;
 +
</source>
  
 
== Using JTable To Handle Action Control Saving and Loading ==
 
== Using JTable To Handle Action Control Saving and Loading ==
JTable class has some built-in support for ACL, to use this you have to add one integer field in your table named 'asset_id'. This field will be used to perform action control for your object. Do not confused with 'access' field, that is only for access permission (read side) as Joomla! separates other actions from read acess.
+
The JTable class has some built-in support for ACL, to use this you have to add one integer field in your table named 'asset_id'. This field will be used to perform action control for your object. Do not confuse this with the 'access' field, which is only for access permission (read side) as Joomla! separates other actions from read access.
  
Normally, we have to override __construct() method in our descendant class. We may also override check() method to validate our data before saving to database. For ACL action support we have to override these methods:-
+
Normally, we have to override the __construct() method in our descendant class. We may also override the check() method to validate our data before saving to the database. For ACL action support we have to override these methods:-
  
 
* <code>public function bind($array, $ignore = '')</code> to let JTable save rule data to Joomla's assets table.
 
* <code>public function bind($array, $ignore = '')</code> to let JTable save rule data to Joomla's assets table.
* <code>protected function _getAssetName()</code> to give asset name for our asset.
+
* <code>protected function _getAssetName()</code> to give an asset name to our asset.
* <code>protected function _getAssetParentId($table = null, $id = null)</code> to give parent id of our asset, normally Joomla! uses root (1) as a parent. Generally we will change parent of node to our component. Doing all of these made JTable handles storing and loading action controll setting for us.
+
* <code>protected function _getAssetParentId($table = null, $id = null)</code> to give a parent id to our asset. Normally Joomla! uses root (1) as a parent. Generally we will change parent of node to our component. Doing all of these makes JTable handle storing and loading action control settings for us.
  
 
== JTable Example ==
 
== JTable Example ==
Line 58: Line 64:
 
}
 
}
 
</source>
 
</source>
 +
 
== Add Rules Field to Your Form ==
 
== Add Rules Field to Your Form ==
Next, we have to add two fields to our form so we will have action control setting input in the view. The first one is 'asset_id' and its type is hidden. This is same name as we provide in our table. The second one is 'rules' and its type is rules. We have to provide this name as it will be processed by JTable descendant class. Please see JTable class for more detail.
+
Next, we have to add two fields to our form so we will have action control setting input in the view. The first one is 'asset_id' and it's type is hidden. This is same name as we provided in our table. The second one is 'rules' and it's type is rules. We have to provide this name as it will be processed by JTable's descendant class. Please see the JTable class for more detail.
  
 
<source>
 
<source>
Line 79: Line 86:
 
</source>
 
</source>
  
For rules field type, we have to provide '''component attribute''' as our component name and '''section attribute''' according to section defined in our access.xml. Please see the example below.
+
For the rules field type, we have to provide the '''component attribute''' as our component name and '''section attribute''' according to the section defined in our access.xml. Please see the example below.
 
<source>
 
<source>
 
<?xml version="1.0" encoding="UTF-8"?>
 
<?xml version="1.0" encoding="UTF-8"?>
Line 96: Line 103:
 
         <!-- Actions to be used in for unit -->
 
         <!-- Actions to be used in for unit -->
 
<action name="core.create" title="JACTION_CREATE" description="COM_ASTERMAN_ACTION_CREATE_UNIT_DESC" />
 
<action name="core.create" title="JACTION_CREATE" description="COM_ASTERMAN_ACTION_CREATE_UNIT_DESC" />
<action name="core.delete" title="JACTION_DELETE" description="COM_ASTERMAN_ACTION_CREATE_UNIT_DESC" />
+
<action name="core.delete" title="JACTION_DELETE" description="COM_ASTERMAN_ACTION_DELETE_UNIT_DESC" />
 
<action name="core.edit" title="JACTION_EDIT" description="COM_ASTERMAN_ACTION_EDIT_UNIT_DESC" />
 
<action name="core.edit" title="JACTION_EDIT" description="COM_ASTERMAN_ACTION_EDIT_UNIT_DESC" />
 
<action name="asterman.edit.basic" title="COM_ASTERMAN_ACTION_EDITBASIC" description="COM_ASTERMAN_ACTION_EDITBASIC_DESC" />
 
<action name="asterman.edit.basic" title="COM_ASTERMAN_ACTION_EDITBASIC" description="COM_ASTERMAN_ACTION_EDITBASIC_DESC" />
Line 104: Line 111:
 
</access>
 
</access>
 
</source>
 
</source>
You will see that I have also create new action for my component. The "asterman.edit.basic" action is to control if user has right to edit some part of the record or not.
+
You will see that I have also created a new action for my component. The "asterman.edit.basic" action controls whether the user has rights to edit some part of the record or not.
  
 
== Put Action Control In Action ==
 
== Put Action Control In Action ==
Using action control in your code is easy than you think, we use JUser 's method to do this. This method is authorise() which requires two parameters one is action and second one is assest name. Unlike our global component access control, here we refer to asset name per record, please JTable descendant class above.
+
Using action control in your code is easier than you think. We use JUser's method authorise() which requires two parameters; one is action and the second is asset name. Unlike our global component access control, here we refer to asset name per record, please see the JTable descendant class above.
 
<source lang="php">
 
<source lang="php">
 
       JFactory::getUser()->authorise($action, $assetName);
 
       JFactory::getUser()->authorise($action, $assetName);
 
</source>
 
</source>
This is example of JModelAdmin descendant class that use this function.
+
This is an example of a JModelAdmin descendant class that uses this function.
 
<source lang="php">
 
<source lang="php">
  
Line 183: Line 190:
 
}
 
}
 
</source>
 
</source>
And this is the output of action permission setting on unit object of my component.
+
And this is the output of the action permission setting on the unit object of my component.
  
 
== Conclusion ==
 
== Conclusion ==
Line 193: Line 200:
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]
 
[[Category:Access Control]]
 
[[Category:Access Control]]
[[Category:Joomla! 1.6]]
+
[[Category:Joomla! 2.5]]
[[Category:Joomla! 1.7]]
+
[[Category:Joomla! 3.1]]

Latest revision as of 16:21, 26 October 2014

Quill icon.png
Content is Incomplete

This article or section is incomplete, which means it may be lacking information. You are welcome to assist in its completion by editing it as well. If this article or section has not been edited in several days, please consider helping complete the content.
This article was last edited by Tjakes (talk| contribs) 32 days ago. (Purge)

This tutorial will demonstrate how to add custom action permissions to your component down to object level. Normally we are familiar with ACL in global configuration level, category level and component level. Now we will learn how to add action permission control in our component.

Contents

ACL Architecture Overview

Action permissions for components in Joomla! 2.5 can be defined at up to 3 levels:

  1. Global Configuration: determines the default permissions for each action and group.
  2. Component Options->Permissions: can override the default permissions for our component
  3. Record Options->Permissions: this is what we discuss in this tutorial.

The other level that you will see is Category which can override the default permissions for objects assigned to category. We can use this if we use category in our component. I separate this one from others as it's parent is Global Configuration.

Modify own database table

The own database table needs to have a column with an asset-ID. If this kind of column is missing in your own database table structure, then add something like this:

ALTER TABLE `#__asterman_units` ADD `asset_id` INT(255) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`;

Using JTable To Handle Action Control Saving and Loading

The JTable class has some built-in support for ACL, to use this you have to add one integer field in your table named 'asset_id'. This field will be used to perform action control for your object. Do not confuse this with the 'access' field, which is only for access permission (read side) as Joomla! separates other actions from read access.

Normally, we have to override the __construct() method in our descendant class. We may also override the check() method to validate our data before saving to the database. For ACL action support we have to override these methods:-

  • public function bind($array, $ignore = ) to let JTable save rule data to Joomla's assets table.
  • protected function _getAssetName() to give an asset name to our asset.
  • protected function _getAssetParentId($table = null, $id = null) to give a parent id to our asset. Normally Joomla! uses root (1) as a parent. Generally we will change parent of node to our component. Doing all of these makes JTable handle storing and loading action control settings for us.

JTable Example

class AstermanTableUnit extends JTable
{
        public function __construct($db)
        {
                parent::__construct('#__asterman_units', 'id', $db);
        }
 
        public function bind($array, $ignore = '')
        {
                // Bind the rules. 
                if (isset($array['rules']) && is_array($array['rules'])) { 
                        $rules = new JRules($array['rules']); 
                        $this->setRules($rules); 
                }
                return parent::bind($array, $ignore);
        }
 
        /**
         * Redefined asset name, as we support action control
         */
        protected function _getAssetName() {
                $k = $this->_tbl_key;
                return 'com_asterman.unit.'.(int) $this->$k;
        }
 
        /**
         * We provide our global ACL as parent
         * @see JTable::_getAssetParentId()
         */
        protected function _getAssetParentId($table = null, $id = null)
        {
                $asset = JTable::getInstance('Asset');
                $asset->loadByName('com_asterman');
                return $asset->id;
        }
 
}

Add Rules Field to Your Form

Next, we have to add two fields to our form so we will have action control setting input in the view. The first one is 'asset_id' and it's type is hidden. This is same name as we provided in our table. The second one is 'rules' and it's type is rules. We have to provide this name as it will be processed by JTable's descendant class. Please see the JTable class for more detail.

        <fieldset name="accesscontrol">
 
                <field name="asset_id" type="hidden" filter="unset" /> 
 
                <field
                        name="rules"
                        type="rules"
                        label="JFIELD_RULES_LABEL"
                        translate_label="false"
                        filter="rules"
                        validate="rules"
                        class="inputbox"
                        component="com_asterman"
                        section="unit" />
        </fieldset>

For the rules field type, we have to provide the component attribute as our component name and section attribute according to the section defined in our access.xml. Please see the example below.

<?xml version="1.0" encoding="UTF-8"?>
<access component="com_asterman">
        <section name="component">
        <!-- Actions to be used in our global 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" />
                <action name="core.edit.state" title="JACTION_EDITSTATE" description="JACTION_EDITSTATE_COMPONENT_DESC" />
                <action name="core.edit.own" title="JACTION_EDITOWN" description="JACTION_EDITOWN_COMPONENT_DESC" />
        </section>
        <section name="unit">
        <!-- Actions to be used in for unit -->
                <action name="core.create" title="JACTION_CREATE" description="COM_ASTERMAN_ACTION_CREATE_UNIT_DESC" />
                <action name="core.delete" title="JACTION_DELETE" description="COM_ASTERMAN_ACTION_DELETE_UNIT_DESC" />
                <action name="core.edit" title="JACTION_EDIT" description="COM_ASTERMAN_ACTION_EDIT_UNIT_DESC" />
                <action name="asterman.edit.basic" title="COM_ASTERMAN_ACTION_EDITBASIC" description="COM_ASTERMAN_ACTION_EDITBASIC_DESC" />
                <action name="core.edit.state" title="JACTION_EDITSTATE" description="COM_ASTERMAN_ACTION_EDITSTATE_UNIT_DESC" />
                <action name="core.edit.own" title="JACTION_EDITOWN" description="COM_ASTERMAN_ACTION_EDITOWN_UNIT_DESC" />
        </section>    
</access>

You will see that I have also created a new action for my component. The "asterman.edit.basic" action controls whether the user has rights to edit some part of the record or not.

Put Action Control In Action

Using action control in your code is easier than you think. We use JUser's method authorise() which requires two parameters; one is action and the second is asset name. Unlike our global component access control, here we refer to asset name per record, please see the JTable descendant class above.

      JFactory::getUser()->authorise($action, $assetName);

This is an example of a JModelAdmin descendant class that uses this function.

public function getForm($data = array(), $loadData = true)
{
    // Get the form.
    $form = $this->loadForm('com_asterman.extension', //form name
            'extension', //XML file name
            array(
                'control' => 'jform',
                'load_data' => $loadData
            ));
 
    if (empty($form)) {
        return false;
    }
 
    if ($this->getState('suffix') == '14') {
        // theses fields do not exists in Asterisk version 1.4
        $form->setFieldAttribute('call-limit', 'disabled', 'true');
        $form->setFieldAttribute('call-limit', 'filter', 'unset');
    }
 
    $user = JFactory::getUser();
 
    if (!empty($data['unit_id'])) {
        $assetName = $this->option . '.unit.' . $data['unit_id'];
 
        $canEdit = $user->authorise('core.edit', $assetName);
        $canEditBasic = $user->authorise('asterman.edit.basic', $assetName);
        $canEditState = $user->authorise('core.edit.state', $assetName);
    } else {
        $canEdit = $user->authorise('core.create', $this->option);
    }
 
    if (!$canEdit) {
 
        $form->setFieldAttribute('unit_id', 'disabled', 'true');
        $form->setFieldAttribute('unit_id', 'filter', 'unset');
 
        if (!$canEditBasic) {
            $form->setFieldAttribute('callerid', 'disabled', 'true');
            $form->setFieldAttribute('secret', 'disabled', 'true');
            $form->setFieldAttribute('allow', 'disabled', 'true');
            $form->setFieldAttribute('callgroup', 'disabled', 'true');
            $form->setFieldAttribute('pickupgroup', 'disabled', 'true');
            $form->setFieldAttribute('call-limit', 'disabled', 'true');
 
            $form->setFieldAttribute('callerid', 'filter', 'unset');
            $form->setFieldAttribute('secret', 'filter', 'unset');
            $form->setFieldAttribute('allow', 'filter', 'unset');
            $form->setFieldAttribute('callgroup', 'filter', 'unset');
            $form->setFieldAttribute('pickupgroup', 'filter', 'unset');
            $form->setFieldAttribute('call-limit', 'filter', 'unset');
        }
 
        // Modify the form based on access controls.
        if (!$canEditState) {
            // Disable fields for display.
            $form->setFieldAttribute('host', 'disabled', 'true');
            $form->setFieldAttribute('context', 'disabled', 'true');
 
            // Disable fields while saving.
            // The controller has already verified this is a record you can edit.
            $form->setFieldAttribute('host', 'filter', 'unset');
            $form->setFieldAttribute('context', 'filter', 'unset');
        }
    }
 
    return $form;
}

And this is the output of the action permission setting on the unit object of my component.

Conclusion

Contributors

Prasit Gebsaap