J3.x

Difference between revisions of "Developing an MVC Component/Adding ACL/es"

From Joomla! Documentation

< J3.x:Developing an MVC Component
(Created page with "Con el fin de almacenar los permisos para cada uno de los mensajes en la tabla assets de base de datos, tenemos que instruir a la clase de la tabla asociada con el modelo para...")
(Created page with "JTable no sólo proporciona una interfaz para el almacenamiento de los datos del registro mismo en el elemento de la tabla de base de datos, también almacena los permisos par...")
Line 794: Line 794:
 
Con el fin de almacenar los permisos para cada uno de los mensajes en la tabla assets de base de datos, tenemos que instruir a la clase de la tabla asociada con el modelo para salvar esos permisos en la tabla assets.
 
Con el fin de almacenar los permisos para cada uno de los mensajes en la tabla assets de base de datos, tenemos que instruir a la clase de la tabla asociada con el modelo para salvar esos permisos en la tabla assets.
  
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 also  have to provide the asset name, asset title and the id of the asset parent via the helloworld JTable. Therefore we override 3 methods:
+
JTable no sólo proporciona una interfaz para el almacenamiento de los datos del registro mismo en el elemento de la tabla de base de datos, también almacena los permisos para este registro en la tabla assets de base de datos. Por lo tanto debemos agregar información al método bind() sobre los valores de los permisos. También tenemos que proporcionar el nombre, título y el id del asset padre a través de JTable de helloworld. Por lo tanto, reescribimos 3 métodos:
 
* _getAssetName(): a unique name for this asset, by which it can be retrieved
 
* _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)
 
* _getAssetTitle(): a more human-friendly way to identify the asset (not necessary unique)

Revision as of 17:25, 27 August 2015

Other languages:
English • ‎español • ‎français • ‎italiano • ‎العربية • ‎中文(台灣)‎
Copyedit.png
This Page Needs Your Help

This page is tagged because it NEEDS REVIEW. You can help the Joomla! Documentation Wiki by contributing to it.
More pages that need help similar to this one are here. NOTE-If you feel the need is satistified, please remove this notice.


Joomla! 
3.x
Tutorial
Desarrollo de un Componente MVC

Agregar una variable de petición en el tipo de menú

Utilizando la base de datos

Lado servidor básico

Agregar gestión de idioma

Agregar acciones del lado servidor

Agregar decoraciones del lado servidor

Agregar verificaciones

Agregar categorías

Agregar configuración

  1. Agregar ACL

Agregar un archivo de secuencia de comandos instalar-desinstalar-actualizar

Agregar un formulario del lado cliente

  1. Agregar una imagen
  2. Agregar un mapa
  3. Agregar AJAX
  4. Agregar un alias

Usar la facilidad filtro de idioma

  1. Agregar una Modal
  2. Agregar Asociaciones
  3. Agregar Comprobación
  4. Agregar Ordenamiento
  5. Agregar Niveles
  6. Agregar Control de Versiones
  7. Agregar Etiquetas
  8. Agregar Accesos
  9. Agregar procesos por lote
  10. Agregar Caché
  11. Agregar un Canal de Noticias

Agregar un servidor de actualización

  1. Agregar campos personalizados
  2. Upgrading to Joomla4



Esta es una serie multi-artículos de tutoriales sobre cómo desarrollar un Componente Modelo-Vista-Controlador para Joomla! VersiónJoomla 3.x.

Comenzar con la Introducción, y navegar por los artículos de esta serie usando el botón de navegación en la parte inferior o en el cuadro de la derecha (los "Artículos de esta serie").



Introducción

Este artículo es parte del tutorial Desarrollo de un Componente MVC para Joomla! 3.2. Te invitamos a leer las partes anteriores del tutorial antes de leer esto.

Agregar Control de Acceso

Con el Control de Acceso de Joomla! se puede definir a que grupos de usuarios se les permite o niega realizar acciones sobre el componente. En este ejemplo vamos a utilizar acciones que se definen en el núcleo. Para el componente en su conjunto: core.admin (acceso a la configuración) y core.manage (acceso al lado servidor). Y con varios niveles de acciones como crear, borrar y editar. Además de esas acciones puedes definir tus propias acciones, pero que a menudo no es necesario y no se muestran en este ejemplo. El Acceso a Ver/Leer no es gestionado a través de esas acciones, pero con la Vista de los Niveles de Acceso; para esto véase la documentación general sobre ACL de Joomla!.

En la tabla #__assets la lista actual almacena: a cuales grupos de usuarios se les permite o niega hacer qué acciones sobre cuales los recursos (assets). Se trata de la implementación de la Lista de Control de Acceso (ACL).

En este artículo vamos a mostrar cómo agregar y utilizar los permisos de acceso con diferentes niveles de granularidad: para el componente como un todo, para las categorías y para los elementos individuales.

Nota: en este ejemplo HelloWorld estamos trabajando en el lado servidor, por lo que los únicos niveles de acceso disponibles son administrador y superusuario. Para probar este tutorial primero crear un nuevo usuario administrador y a continuación, establecer sus permisos (trabajando como superusuario). Después al estar registrado en el sistema como administrador podrá ver los cambios.

Requerimientos mínimos de ACL a nivel del componente

Hay 2 acciones que deben ser definidas a nivel del componente para un componente Joomla! 2.5+ para ofrecer servicios básicos de soporte de ACL:

  • Configurar (core.admin): a cuales grupos se le permite configurar el nivel de permisos del componente a través del botón Opciones de la barra de herramientas?
  • Acceso al Componente (core.manage): a cuales grupos se les permite el acceso al lado servidor del componente?

Esta soporte ACL básico se realiza en 4 sencillos pasos:


Agregar las 2 acciones mínimas a nivel de componente a access.xml

Un mínimo ACL access.xml consistiría sólo de estas 2 acciones básicas:

Basic 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" />
	</section>
</access>

Ver admin/access.xml para el actual y una versión más elaborada.

Agregar los conjuntos de campo de permisos a config.xml

Agregue los siguientes conjuntos de campos de permisos a admin/config.xml con el fin de ser capaz de establecer nuestro nivel de permisos del componente.

	<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>

Consulte el ejemplo más elaborado de config.xml más abajo para el lugar exacto donde se inserta este código.

Agregar el botón 'Opciones' en la barra de herramientas cuando el usuario esta autorizado

En el archivo admin/views/helloworlds/view.html.php puedes agregar el siguiente código para comprobar si el usuario puede editar las preferencias:

    // Options button.
    if (JFactory::getUser()->authorise('core.admin', 'com_helloworld')) 
    {
	JToolBarHelper::preferences('com_helloworld');
    }

Véase más abajo para un ejemplo más elaborado admin/views/helloworlds/view.html.php donde esta JToolBarHelper::preferencias('com_helloworld'), se hace en un método addToolBar() junto con el resto de botones de la barra de herramientas y la comprobación JUser->authorise() se realiza con JHelperContent, lo que resulta de la propiedad $canDo.

Restringir el acceso al lado servidor del componente a grupos de usuarios autorizados

Para controlar el acceso al lado servidor del componente agrega las siguientes líneas al archivo de entrada admin/helloworld.php:

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

Véase más abajo para todo el código del archivo admin/helloworld.php.

Agregar más acciones, también a nivel de la categoría y nivel del elemento

Al agregar más acciones y más niveles, los 4 pasos anteriormente descriptos también se llevan a cabo:

Además también tenemos que hacer los siguientes pasos:

Describiendo las acciones sobre las que deseas controlar el acceso

Cada componente (o parte de el) tiene su propio conjunto de permisos que pueden ser controlados. Ellos son descriptos en el archivo access.xml que se encuentra en la raíz de la carpeta admin. En este ejemplo helloworld las acciones en las que el acceso es controlado se dividen en tres secciones: a nivel de componente, a nivel de categoría y a nivel de elemento. Un 'elemento' se llama un 'mensaje' en nuestro ejemplo de componente, de ahí el nombre de la tercera sección.

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="category">
		<action name="core.create" title="JACTION_CREATE" description="COM_CATEGORIES_ACCESS_CREATE_DESC" />
		<action name="core.delete" title="JACTION_DELETE" description="COM_CATEGORIES_ACCESS_DELETE_DESC" />
		<action name="core.edit" title="JACTION_EDIT" description="COM_CATEGORIES_ACCESS_EDIT_DESC" />
		<action name="core.edit.state" title="JACTION_EDITSTATE" description="COM_CATEGORIES_ACCESS_EDITSTATE_DESC" />
		<action name="core.edit.own" title="JACTION_EDITOWN" description="COM_CATEGORIES_ACCESS_EDITOWN_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>

Agregando la configuración de permisos en las Preferencias del componente

Puesto que ahora usamos permisos de Control de Acceso en nuestro componente, tenemos que ser capaces de ponerlos en el nivel del componente. Se hace en las Preferencias de este componente: la pantalla se puede ver después de hacer clic en el botón 'Opciones'. El archivo de configuración config.xml es un archivo de formulario con la definición de esas Preferencias. Podríamos definir el nivel de las acciones del componente aquí también, como un hijo de las "reglas" de la etiqueta del campo, pero ahora se prefiere también poner esas acciones en access.xml de esa manera todas las reglas de acceso para este componente están en un solo lugar.

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>

Mostrar sólo los botones correctos de la barra de herramientas

Que botones de la barra de herramientas se van a mostrar depende de los permisos de Control de Acceso del usuario. Ponemos todos los permisos de este usuario en la propiedad $canDo de la vista; por lo que, eventualmente, pueden referirse a ella en los diseños (en la edición del formulario, por ejemplo).

En el archivo admin/views/helloworlds/view.html.php coloca estas líneas:

admin/views/helloworlds/view.html.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
 * HelloWorlds View
 *
 * @since  0.0.1
 */
class HelloWorldViewHelloWorlds extends JViewLegacy
{
	/**
	 * Display the Hello World view
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  void
	 */
	function display($tpl = null)
	{
		
		// Get application
		$app = JFactory::getApplication();
		$context = "helloworld.list.admin.helloworld";
		// Get data from the model
		$this->items		= $this->get('Items');
		$this->pagination	= $this->get('Pagination');
		$this->state		= $this->get('State');
		$this->filter_order	= $app->getUserStateFromRequest($context.'filter_order', 'filter_order', 'greeting', 'cmd');
		$this->filter_order_Dir = $app->getUserStateFromRequest($context.'filter_order_Dir', 'filter_order_Dir', 'asc', 'cmd');
		$this->filterForm    	= $this->get('FilterForm');
		$this->activeFilters 	= $this->get('ActiveFilters');

		// What Access Permissions does this user have? What can (s)he do?
		$this->canDo = JHelperContent::getActions();

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Set the submenu
		HelloWorldHelper::addSubmenu('helloworlds');

		// Set the toolbar and number of found items
		$this->addToolBar();

		// Display the template
		parent::display($tpl);

		// Set the document
		$this->setDocument();
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	protected function addToolBar()
	{
		$title = JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLDS');

		if ($this->pagination->total)
		{
			$title .= "<span style='font-size: 0.5em; vertical-align: middle;'>(" . $this->pagination->total . ")</span>";
		}

		JToolBarHelper::title($title, 'helloworld');

		if ($this->canDo->get('core.create')) 
		{
			JToolBarHelper::addNew('helloworld.add', 'JTOOLBAR_NEW');
		}
		if ($this->canDo->get('core.edit')) 
		{
			JToolBarHelper::editList('helloworld.edit', 'JTOOLBAR_EDIT');
		}
		if ($this->canDo->get('core.delete')) 
		{
			JToolBarHelper::deleteList('', 'helloworlds.delete', 'JTOOLBAR_DELETE');
		}
		if ($this->canDo->get('core.admin')) 
		{
			JToolBarHelper::divider();
			JToolBarHelper::preferences('com_helloworld');
		}
	}
	/**
	 * Method to set up the document properties
	 *
	 * @return void
	 */
	protected function setDocument() 
	{
		$document = JFactory::getDocument();
		$document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION'));
	}
}

En el archivo admin/views/helloworld/view.html.php coloca estas líneas:

admin/views/helloworld/view.html.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
 * HelloWorld View
 *
 * @since  0.0.1
 */
class HelloWorldViewHelloWorld extends JViewLegacy
{
	protected $form;
	protected $item;
	protected $script;
	protected $canDo;

	/**
	 * Display the Hello World view
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  void
	 */
	public function display($tpl = null)
	{
		// Get the Data
		$this->form = $this->get('Form');
		$this->item = $this->get('Item');
		$this->script = $this->get('Script');

		// What Access Permissions does this user have? What can (s)he do?
		$this->canDo = JHelperContent::getActions($this->item->id);

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Set the toolbar
		$this->addToolBar();

		// Display the template
		parent::display($tpl);

		// Set the document
		$this->setDocument();
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	protected function addToolBar()
	{
		$input = JFactory::getApplication()->input;

		// Hide Joomla Administrator Main menu
		$input->set('hidemainmenu', true);

		$isNew = ($this->item->id == 0);

		JToolBarHelper::title($isNew ? JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW')
		                             : JText::_('COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT'), 'helloworld');
		// Build the actions for new and existing records.
		if ($isNew)
		{
			// For new records, check the create permission.
			if ($this->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 ($this->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 ($this->canDo->get('core.create')) 
				{
					JToolBarHelper::custom('helloworld.save2new', 'save-new.png', 'save-new_f2.png',
					                       'JTOOLBAR_SAVE_AND_NEW', false);
				}
			}
			if ($this->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');
		}
	}
	/**
	 * Method to set up the document properties
	 *
	 * @return void
	 */
	protected function setDocument() 
	{
		$isNew = ($this->item->id == 0);
		$document = JFactory::getDocument();
		$document->setTitle($isNew ? JText::_('COM_HELLOWORLD_HELLOWORLD_CREATING')
		                           : JText::_('COM_HELLOWORLD_HELLOWORLD_EDITING'));
		$document->addScript(JURI::root() . $this->script);
		$document->addScript(JURI::root() . "/administrator/components/com_helloworld"
		                                  . "/views/helloworld/submitbutton.js");
		JText::script('COM_HELLOWORLD_HELLOWORLD_ERROR_UNACCEPTABLE');
	}
}

Estos dos archivos usan el método getActions definido en el archivo admin/helpers/helloworld.php.

En el archivo helper, poner este código:

admin/helpers/helloworld.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
 * HelloWorld component helper.
 *
 * @param   string  $submenu  The name of the active view.
 *
 * @return  void
 *
 * @since   1.6
 */
abstract class HelloWorldHelper
{
	/**
	 * Configure the Linkbar.
	 */
	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'
		);

		// set some global property
		$document = JFactory::getDocument();
		$document->addStyleDeclaration('.icon-48-helloworld ' .
		                               '{background-image: url(../media/com_helloworld/images/tux-48x48.png);}');
		if ($submenu == 'categories') 
		{
			$document->setTitle(JText::_('COM_HELLOWORLD_ADMINISTRATION_CATEGORIES'));
		}
	}

	/**
	 * Get the actions
	 */
	public static function getActions($messageId = 0)
	{	
		$result	= new JObject;

		if (empty($messageId)) {
			$assetName = 'com_helloworld';
		}
		else {
			$assetName = 'com_helloworld.message.'.(int) $messageId;
		}

		$actions = JAccess::getActions('com_helloworld', 'component');

		foreach ($actions as $action) {
			$result->set($action->name, JFactory::getUser()->authorise($action->name, $assetName));
		}

		return $result;
	}
}

Restringir el acceso al componente

La idea principal en ACL es restringir las acciones de los grupos de usuarios. La primera acción a ser restringida, es el acceso a la administración del lado servidor del propio componente. Con tu editor de archivos favorito, modifica el archivo admin/helloworld.php y agrega las líneas con la comprobación de acceso.

admin/helloworld.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');

// Set some global property
$document = JFactory::getDocument();
$document->addStyleDeclaration('.icon-helloworld {background-image: url(../media/com_helloworld/images/tux-16x16.png);}');

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

// Require helper file
JLoader::register('HelloWorldHelper', JPATH_COMPONENT . '/helpers/helloworld.php');

// Get an instance of the controller prefixed by HelloWorld
$controller = JControllerLegacy::getInstance('HelloWorld');

// Perform the Request task
$controller->execute(JFactory::getApplication()->input->get('task'));;

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

Agregar un asset_id a la tabla de la base de datos

Con el fin de ser capaz de trabajar con JTable una columna asset_id tiene que ser agregada a la tabla #__helloworld de la base de datos.

Así, admin/sql/instalar.mysql.utf8.sql se convierte en:

admin/sql/install.mysql.utf8.sql

DROP TABLE IF EXISTS `#__helloworld`;

CREATE TABLE `#__helloworld` (
	`id`       INT(11)     NOT NULL AUTO_INCREMENT,
	`asset_id` INT(10)     NOT NULL DEFAULT '0',
	`greeting` VARCHAR(25) NOT NULL,
	`published` tinyint(4) NOT NULL,
	`catid`	    int(11)    NOT NULL DEFAULT '0',
	`params`   VARCHAR(1024) NOT NULL DEFAULT '',
	PRIMARY KEY (`id`)
)
	ENGINE =MyISAM
	AUTO_INCREMENT =0
	DEFAULT CHARSET =utf8;

INSERT INTO `#__helloworld` (`greeting`) VALUES
('Hello World!'),
('Good bye World!');

Para actualizaciones añadimos un archivo sql de actualización:

admin/sql/updates/mysql/0.0.14.sql

ALTER TABLE`#__helloworld` ADD COLUMN `asset_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `id`;

Restringir el acceso a los mensajes

Hasta ahora hemos restringido el acceso al componente en sí, pero también tenemos que hacerlo a nivel mensaje.

Para comprobar los permisos del "core.delete" es necesario modificar la clase del modelo: admin/models/helloworld.php al agregar estas líneas:

admin/models/helloworld.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
 * HelloWorld Model
 *
 * @since  0.0.1
 */
class HelloWorldModelHelloWorld extends JModelAdmin
{
	/**
	 * Method to get a table object, load it if necessary.
	 *
	 * @param   string  $type    The table name. Optional.
	 * @param   string  $prefix  The class prefix. Optional.
	 * @param   array   $config  Configuration array for model. Optional.
	 *
	 * @return  JTable  A JTable object
	 *
	 * @since   1.6
	 */
	public function getTable($type = 'HelloWorld', $prefix = 'HelloWorldTable', $config = array())
	{
		return JTable::getInstance($type, $prefix, $config);
	}

	/**
	 * Method to get the record form.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
	 *
	 * @return  mixed    A JForm object on success, false on failure
	 *
	 * @since   1.6
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm(
			'com_helloworld.helloworld',
			'helloworld',
			array(
				'control' => 'jform',
				'load_data' => $loadData
			)
		);

		if (empty($form))
		{
			return false;
		}

		return $form;
	}
	/**
	 * Method to get the script that have to be included on the form
	 *
	 * @return string	Script files
	 */
	public function getScript() 
	{
		return 'administrator/components/com_helloworld/models/forms/helloworld.js';
	}
	/**
	 * Method to get the data that should be injected in the form.
	 *
	 * @return  mixed  The data for the form.
	 *
	 * @since   1.6
	 */
	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;
	}
	/**
	 * Method to check if it's OK to delete a message. Overwrites JModelAdmin::canDelete
	 */
	protected function canDelete($record)
	{
		if( !empty( $record->id ) )
		{
			return JFactory::getUser()->authorise( "core.delete", "com_helloworld.message." . $record->id );
		}
	}
}

Para comprobar "core.edit" (y core.add si lo deseas) necesitas actualizar el sub-controlador (no el modelo). No estoy seguro por qué esto es así, pero es la forma estándar de hacerlo en los componentes de Joomla. Necesitas agregar las siguientes líneas en el archivo: admin/controllers/helloworld.php

admin/controllers/helloworld.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

/**
 * HelloWorld Controller
 *
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 * @since       0.0.9
 */
class HelloWorldControllerHelloWorld extends JControllerForm
{
	/**
	* Implement to allowAdd or not
	*
	* Not used at this time (but you can look at how other components use it....)
	* Overwrites: JControllerForm::allowAdd
	*
	* @param array $data
	* @return bool
	*/
	protected function allowAdd($data = array())
	{
		return parent::allowAdd($data);
	}
	/**
	* Implement to allow edit or not
	* Overwrites: JControllerForm::allowEdit
	*
	* @param array $data
	* @param string $key
	* @return bool
	*/
	protected function allowEdit($data = array(), $key = 'id')
	{
		$id = isset( $data[ $key ] ) ? $data[ $key ] : 0;
		if( !empty( $id ) )
		{
			return JFactory::getUser()->authorise( "core.edit", "com_helloworld.message." . $id );
		}
	}
}

Por favor, ten en cuenta que allowAdd simplemente llama a su padre. Lo he puesto aquí en caso de que desees utilizarlo en tu componente. Si miras tu archivo admin/access.xml, te darás cuenta que no hay una acción core.add definida para "mensajes", por lo que será necesario agregarla, así que si eres capaz puedes configurar la interfaz.

Configuración de los valores de permisos en la tabla assets

Con el fin de almacenar los permisos para cada uno de los mensajes en la tabla assets de base de datos, tenemos que instruir a la clase de la tabla asociada con el modelo para salvar esos permisos en la tabla assets.

JTable no sólo proporciona una interfaz para el almacenamiento de los datos del registro mismo en el elemento de la tabla de base de datos, también almacena los permisos para este registro en la tabla assets de base de datos. Por lo tanto debemos agregar información al método bind() sobre los valores de los permisos. También tenemos que proporcionar el nombre, título y el id del asset padre a través de JTable de helloworld. Por lo tanto, reescribimos 3 métodos:

  • _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)

admin/tables/helloworld.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_helloworld
 *
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
// No direct access
defined('_JEXEC') or die('Restricted access');

/**
 * Hello Table class
 *
 * @since  0.0.1
 */
class HelloWorldTableHelloWorld extends JTable
{
	/**
	 * Constructor
	 *
	 * @param   JDatabaseDriver  &$db  A database connector object
	 */
	function __construct(&$db)
	{
		parent::__construct('#__helloworld', 'id', $db);
	}
	/**
	 * Overloaded bind function
	 *
	 * @param       array           named array
	 * @return      null|string     null is operation was satisfactory, otherwise returns an error
	 * @see JTable:bind
	 * @since 1.5
	 */
	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;
		}

		// Bind the rules.
		if (isset($array['rules']) && is_array($array['rules']))
		{
			$rules = new JAccessRules($array['rules']);
			$this->setRules($rules);
		}

		return parent::bind($array, $ignore);
	}

	/**
	 * Overloaded load function
	 *
	 * @param       int $pk primary key
	 * @param       boolean $reset reset data
	 * @return      boolean
	 * @see JTable:load
	 */
	public function load($pk = null, $reset = true)
	{
		if (parent::load($pk, $reset))
		{
			// Convert the params field to a registry.
			$params = new JRegistry;
			$params->loadString($this->params, 'JSON');

			$this->params = $params;
			return true;
		}
		else
		{
			return false;
		}
	}
	/**
	 * Method to compute the default name of the asset.
	 * The default name is in the form `table_name.id`
	 * where id is the value of the primary key of the table.
	 *
	 * @return	string
	 * @since	2.5
	 */
	protected function _getAssetName()
	{
		$k = $this->_tbl_key;
		return 'com_helloworld.message.'.(int) $this->$k;
	}
	/**
	 * Method to return the title to use for the asset table.
	 *
	 * @return	string
	 * @since	2.5
	 */
	protected function _getAssetTitle()
	{
		return $this->greeting;
	}
	/**
	 * Method to get the asset-parent-id of the item
	 *
	 * @return	int
	 */
	protected function _getAssetParentId(JTable $table = NULL, $id = NULL)
	{
		// We will retrieve the parent-asset from the Asset-table
		$assetParent = JTable::getInstance('Asset');
		// Default: if no asset-parent can be found we take the global asset
		$assetParentId = $assetParent->getRootId();

		// Find the parent-asset
		if (($this->catid)&& !empty($this->catid))
		{
			// The item has a category as asset-parent
			$assetParent->loadByName('com_helloworld.category.' . (int) $this->catid);
		}
		else
		{
			// The item has the component as asset-parent
			$assetParent->loadByName('com_helloworld');
		}

		// Return the found asset-parent-id
		if ($assetParent->id)
		{
			$assetParentId=$assetParent->id;
		}
		return $assetParentId;
	}
}

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.

Mostrar la configuración de permisos a nivel de elemento

Adding the rules field to the form-definition of the edit-form.

admin/models/forms/helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<form
				addrulepath="/administrator/components/com_helloworld/models/rules"
>
	<fieldset
				name="details"
				label="COM_HELLOWORLD_HELLOWORLD_DETAILS"
	>
		<field
				name="id"
				type="hidden"
				/>
		<field
				name="greeting"
				type="text"
				label="COM_HELLOWORLD_HELLOWORLD_GREETING_LABEL"
				description="COM_HELLOWORLD_HELLOWORLD_GREETING_DESC"
				size="40"
				class="inputbox validate-greeting"
				validate="greeting"
				required="true"
				default=""
				/>
		<field
				name="catid"
				type="category"
				extension="com_helloworld"
				class="inputbox"
				default=""
				label="COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_LABEL"
				description="COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_DESC"
				required="true"
		>
			<option value="0">JOPTION_SELECT_CATEGORY</option>
		</field>
	</fieldset>
	<fields name="params">
		<fieldset
				name="params"
				label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS"
		>
			<field
					name="show_category"
					type="list"
					label="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL"
					description="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC"
					default=""
			>
				<option value="">JGLOBAL_USE_GLOBAL</option>
				<option value="0">JHIDE</option>
				<option value="1">JSHOW</option>
			</field>
		</fieldset>
	</fields>
	<fieldset
			name="accesscontrol"
			label="COM_HELLOWORLD_FIELDSET_RULES"
	>
    	<field
				name="asset_id"
				type="hidden"
				filter="unset"
				/>
    	<field
				name="rules"
				type="rules"
				label="COM_HELLOWORLD_FIELD_RULES_LABEL"
				filter="rules"
				validate="rules"
				class="inputbox"
				component="com_helloworld"
				section="message"
				/>
    </fieldset>
</form>

Now the ACL interface is displayed at the bottom of the Helloworld editform too (the edit.php file automatically get the fieldsets from the above xml).

Agregar cadenas de idioma

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

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

; Joomla! Project
; Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

COM_HELLOWORLD_ADMINISTRATION="HelloWorld - Administration"
COM_HELLOWORLD_ADMINISTRATION_CATEGORIES="HelloWorld - Categories"
COM_HELLOWORLD_NUM="#"
COM_HELLOWORLD_HELLOWORLDS_FILTER="Filters"
COM_HELLOWORLD_PUBLISHED="Published"
COM_HELLOWORLD_HELLOWORLDS_NAME="Name"
COM_HELLOWORLD_ID="Id"

COM_HELLOWORLD_HELLOWORLD_CREATING="HelloWorld - Creating"
COM_HELLOWORLD_HELLOWORLD_DETAILS="Details"
COM_HELLOWORLD_HELLOWORLD_EDITING="HelloWorld - Editing"
COM_HELLOWORLD_HELLOWORLD_ERROR_UNACCEPTABLE="Some values are unacceptable"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_DESC="The category the messages belongs to"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_LABEL="Category"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC="This message will be displayed"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL="Message"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL="Show category"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC="If set to Show, the title of the message&rsquo;s category will show."
COM_HELLOWORLD_HELLOWORLD_HEADING_GREETING="Greeting"
COM_HELLOWORLD_HELLOWORLD_HEADING_ID="Id"
COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT="HelloWorld manager: Edit Message"
COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW="HelloWorld manager: New Message"
COM_HELLOWORLD_MANAGER_HELLOWORLDS="HelloWorld manager"
COM_HELLOWORLD_EDIT_HELLOWORLD="Edit message"
COM_HELLOWORLD_N_ITEMS_DELETED_1="One message deleted"
COM_HELLOWORLD_N_ITEMS_DELETED_MORE="%d messages deleted"
COM_HELLOWORLD_N_ITEMS_PUBLISHED="%d message(s) published"
COM_HELLOWORLD_N_ITEMS_UNPUBLISHED="%d message(s) unpublished"
COM_HELLOWORLD_HELLOWORLD_GREETING_LABEL="Greeting"
COM_HELLOWORLD_HELLOWORLD_GREETING_DESC="Add Hello World Greeting"
COM_HELLOWORLD_SUBMENU_MESSAGES="Messages"
COM_HELLOWORLD_SUBMENU_CATEGORIES="Categories"
COM_HELLOWORLD_CONFIGURATION="HelloWorld Configuration"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL="Messages settings"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC="Settings that will be applied to all messages by default"
COM_HELLOWORLD_FIELDSET_RULES="Message Permissions"
COM_HELLOWORLD_FIELD_RULES_LABEL="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:

Deprecated classes

For the moment we leave the deprecated JError-references as they are. They will probably 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 numerous 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 get the same functionality without using JError at all, 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 now primarily focused on Joomla! 3.x. So: we notice the upcoming change, but leave it there for the moment.

Since Joomla! 2.5.5 the MVC-base-classes JController, JModel and JView got proxies JControllerLegacy, JModelLegacy and JViewLegacy. You are recommended to use those proxies instead of the original classes to be forward compatibility with Joomla! CMS 3.x legacy classes.

Packaging the component

Content of your code directory

Create a compressed file of this directory or directly download the archive 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

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.2.0" method="upgrade">

	<name>COM_HELLOWORLD</name>
	<!-- The following elements are optional and free of formatting constraints -->
	<creationDate>February 2015</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>
			<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
		</sql>
	</install>
	<uninstall> <!-- Runs on uninstall -->
		<sql>
			<file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
		</sql>
	</uninstall>
	<update> <!-- Runs on update; New since J2.5 -->
		<schemas>
			<schemapath type="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 -->
	<files folder="site">
		<filename>index.html</filename>
		<filename>helloworld.php</filename>
		<filename>controller.php</filename>
		<folder>views</folder>
		<folder>models</folder>
	</files>

        <languages folder="site/language">
		<language tag="en-GB">en-GB/en-GB.com_helloworld.ini</language>
        </languages>

	<media destination="com_helloworld" folder="media">
		<filename>index.html</filename>
		<folder>images</folder>
	</media>

	<administration>
		<!-- Administration Menu Section -->
		<menu link='index.php?option=com_helloworld' img="../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 -->
		<files folder="admin">
			<!-- Admin Main File Copy Section -->
			<filename>index.html</filename>
			<filename>config.xml</filename>
			<filename>helloworld.php</filename>
			<filename>controller.php</filename>
			<filename>access.xml</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>
		<languages folder="admin/language">
        		<language tag="en-GB">en-GB/en-GB.com_helloworld.ini</language>
                        <language tag="en-GB">en-GB/en-GB.com_helloworld.sys.ini</language>
		</languages>
	</administration>

</extension>

Contributors