Tutorial: Como crear un componente para Joomla!1.5 IV

Índice de la serie: desarrollo de extensiones con Joomla

  1. Hacer componentes en Joomla!
    1. Patrón MVC
    2. Concepto de Front-End y Back-End
    3. Primer componente MVC simple con Joomla!
    4. Segundo componente, Back-End y acceso a datos.
    5. Crear el xml del componente de joomla y generar instalable.
  2. Hacer Módulos para Joomla!
  3. Hacer Plugins para Joomla!

El tutorial anterior fue una introducción a la creación de componentes en Joomla 1.5, pero aun faltan muchas cosas.

Faltan cosas como el acceso a datos mediante el framework de Joomla, los tasks y más cosas que se me escapan he iré completando más adelante.

Para la parte de back-end, el sistema es el mismo, lo único que deberemos de ubicar el componente en la carpeta administrator/components . El acceso al componente es por la URL …tuSitio/administrator/index.php?option=com_prueba .

El api de Joomla! nos provee de unos objetos específicos para operar con bases de datos.Siempre que se pueda es recomendable usar estos objetos, en lugar de conectar directamente con las funciones de mysql que tiene php, ya que el API de Joomla! hace mucho trabajo por debajo, como protección contra inyección Sql, optimización, etc… En ocasiones , necesitaremos un acceso a datos mas profundo, y no nos podremos conformar con lo que nos ofrece el api de Joomla!, en estos casos no queda mas remedio que utilizar el acceso a datos de toda la vida. En este tutorial el componente se va llamar prueba. Por lo tanto accederemos a el mediante la URL …/administrator/index?option=com_prueba. Nuestro componente es muy simple: muestra una lista con los mensajes existentes y un formulario de introducción de datos en el que se presenta un campo de texto y un botón para enviar el formulario. Al enviarse el formulario se introduce en una tabla de la base de datos que hemos creado previamente el mensaje y nos lleva a la misma pagina que muestra todos los mensajes insertados y te da la opción de seguir insertando mensajes.

Vamos a crear la base de datos, esta es la sentencia SQL que yo he usado:

CREATE TABLE 'jos_prueba' (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`mensaje` VARCHAR( 30 ) NOT NULL DEFAULT 'mensaje'
) ENGINE = innodb;

Como puedes observar son dos campos; una tabla muy simple. Vamos a crear la estructura principal de nuestro componente como en el tutorial anterior, si tienes dudas, pégale un vistazo . La estructura principal del componente es esta:

Vista por defecto de admin

A continuación puedes observar el diagrama del componente que vamos a crear:

Esquema de la aplicación

La vista Prueba Admin es la que se muestra por defecto en nuestro componente, en ella se hará un listado de todos los mensajes creados en la base de datos, y al fina pondré un enlace que redirija a la vista IntroduceNuevo.

En la vista IntroduceNuevo, se presenta un formulario con una caja de texto y un botón de submit. Este boton de submit redirige al task IntroduceMensaje, donde introduciremos el mensaje en la base de datos y redirigiremos a la vista PruebaAdmin de nuevo para que se muestren todos los mensajes insertados y te da la opción de seguir insertando.

Lo primero que necesitamos es un modelo para nuestra vista PruebaAdmin, creamos la carpeta models, y dentro un archivo con nombre pruebaAdmin.php , dentro de este archivo crearemos la clase que contiene el modelo.

El modelo tiene que recuperar todos los datos de la base de datos y devolverlos para que la vista pueda mostrarlos.

Dentro de la carpeta models crea el fichero pruebaAdmin.php . De momento vamos a agregar el código necesario para recuperar los datos de la tabla. Este es el código que he usado:

defined('_JEXEC') or die();
jimport( 'joomla.application.component.model' );
class PruebaAdminModelPruebaAdmin extends JModel
{
    var $datos;
    function getData()
    {
        if (empty( $this->datos ))
        {
            $query = ' SELECT * '
            . ' FROM #__prueba ';

            $this->datos = $this->_getList( $query );
        }

        return $this->datos;
    }

}

Como siempre la primera línea hace una comprobación para ver si se esta accediendo desde Joomla! o se esta haciendo un acceso directo, esta medida de seguridad debe de estar siempre presente.

La segunda línea se utiliza la función jimport del api de Joomla!, esta función importa la clase abstracta para el modelo.

Observa que la nomenclatura sigue la norma descrita:

Nombre de la Vista– Model – Nombre del modelo

Al tener este nombre , el controaldor PruebaAdminController podra acceder directamente a los métodos de este modelo.

La función getData() comprueba si la variable $datos esta vacia, y si lo esta, entonces almacena en ella los datos de la tabla jos_prueba en la variable.Para ello utiliza el metodo getList()

. Este método es heredado por la clase padre y lo que hace es devolver una lista de objetos con los resultados de la consulta. Cada objeto de

la lista tendrá tantas propiedades como campos tenga la tabla consultada.Por lo tanto en la variable $datos se almacena

una lista de objetos con los resultados de la consulta.

Lo siguiente es mostrar estos datos en la vista PruebaAdmin.

Introduce el siguiente código en el fichero views/pruebaAdmin/view.html.php :

defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view');
class PruebaAdminViewPruebaadmin extends JView
{
    function display($tpl = null)
    {
        $model =& $this->getModel();
        $datos = $model->getData();
        $this->assignRef( 'mensajes',	$datos );
        parent::display($tpl);
    }
}

Las dos primeras líneas ya no necesitan explicación.

La nomenclatura de la Vista sigue el patrón descrito.

Se sobrescribe el método display() , lo primero es obtener el modelo, al seguir las nombras de nombrado no hace falta especificar el nombre del modelo en el método getModel().

Almacenamos en la variable $datos la lista de objetos que devuelve el método que hemos creado anteriormente en el modelo, y se la pasamos al layout mediante el método assignRef.

Código para el layout default.php de la vista :


<?php
    $n =count( $this->mensajes );
    for ($i=0; $i < $n; $i++)
    {
        $row =& $this->mensajes[$i];
        ?>



<?php
 
    }
?>
ID Mensaje
<?php echo $row->id; ?> <?php echo $row->mensaje; ?>
  Nuevo Mensaje

Recorremos la lista de objetos "mensajes" y creamos un elemento "tr" por cada mensaje, observa que estamos accediendo a la propiedad id y mensaje de cada objeto de la lista, esto es por que como he explicado antes se crea tantas propiedades como campos tenga el resultado de la consulta.

Al final de la tabla, he agregado un enlace que redirige a la vista que crearemos luego y que permitirá introducir un nuevo mensaje. El método estático JURI::base() devuelve la url base del sitio, para realizar la petición correctamente.

Introduce algunos datos en tu tabla y comprueba que todo funciona correctamente.

Vamos a crear la vista introduceNuevo.

Crea el directorio introduceNuevo dentro de la carpeta views , crea el directorio tmpl y los archivos view.html.php y tmpl/default.php correspondientes .

Introduce el siguiente código en view.html.php:

defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.application.component.view');
class PruebaAdminViewIntroduceNuevo extends JView
{
    function display($tpl = null)
    {
        parent::display($tpl);
    }
}

No se realiza ningún acceso a datos , simplemente se ejecuta el método display() y se visualiza el layout por defecto (“tmpl/default.php”) .La nomenclatura de la vista ha de seguir el patrón que ya se ha explicado anteriormente :

Nombre componente – View – Nombre de la vista .

Ahora vamos a ver el código del layout :

ID Mensaje
 

Como puedes observar, he creado un formulario que envía la información a index.php ,

y le he puesto una caja de texto para introducir el mensaje y otra para el id, la del id permanece bloqueada ya que se trata de un campo autoincremental y se ira incrementando automáticamente en la base de datos.

Esta información la tiene que procesar el task introduceMensaje . La forma de indicar que la información ha de ser procesada por este task es poniendo un input de tipo hidden con atributo name igual a task y un valor igual al nombre del task que deseamos que procese el formulario. En el otro input de tipo hidden se se indica el option para indicar a Joomla! que el task se encuentra dentro del componente com_prueba.

Los nombre de los campos input deben de coincidir con los nombres de los campos de la tabla en la que introduciremos los datos.

Vamos a crear el task introduceMensaje :

En la clase controlador PruebaAdminController que debes haber creado anteriormente introduce el siguiente método:

function introduceMensaje(){

    	$option = JRequest::getCmd('option');
    	$modelo = $this->getModel('pruebaAdmin');
    	 $res = $modelo->introduce(JRequest::get('post'));
    	 if($res == 1){
    	 	$this->setMessage('Mensage introducido!');
        	$this->setRedirect('index.php?option=' . $option. '&view=pruebaAdmin');
    	 }else{
    	 	$this->setMessage('Error al introducir!');
        	$this->setRedirect('index.php?option=' . $option. '&view=Error');
    	 }
}

Al pulsar submit en el formulario anterior , los datos son enviados a index.php, el marco de trabajo Joomla! lee los parámetros de entrada y detecta que hay un parámetro que indica el componente de destino , el componente com_prueba recibe la petición y el controlador detecta que existe un parámetro task, este parámetro es un parámetro especial que se usa en Joomla! para procesar acciones de formularios, Joomla! buscara en la clase controlador un metodo que tenga el mismo nombre que el valor del parámetro task y le concedera el control. Es por eso que el nombre del método ha de coincidir con el nombre del task que pusimos en el formulario. Se pueden mapear task’s a métodos diferentes, pero esto queda pendiente para otro articulo.

En este task volvemos a utilizar el API de Joomla! para acceder a datos, pero en este caso vamos a usar el objeto JTable, para introducir datos.

Podríamos utilizar funciones como mysql_query() para realizar consultas de tipo insert y update, sin embargo estas funciones son mas difíciles de generar, requieren de conocimientos de lenguaje SQL y probablemente nos dejemos huecos de seguridad que dan lugar a inyecciones SQL y otros fallos.

El API de Joomla! proporciona el objeto JTable para crear, leer , actualizar y borrar registros de una tabla.

Crea la carpeta tables, y dentro de esta carpeta crea el archivo Mensajes.php , El nombre del archivo a de ser igual que el nombre de la clase JTable,

es decir si el archivo se llama Mensajes.php, la clase se llamara

TableMensajes. Si no se hace así, Joomla! tendra problemas para

encontrar el objeto JTable.

Introduce el siguiente código en el archivo:

defined( '_JEXEC' ) or die( 'Restricted access' );
class TableMensajes extends JTable
{
	 var $id = null;
 	 var $mensaje = null;
   function __construct(&$db)
  {
    parent::__construct( '#__prueba', 'id', $db );
  }
}

Se declaran tantas propiedades como campos tenga la tabla sobre la que se quiere trabajar, el nombre de las propiedades debe ser igual que el nombre de los campos.

En el constructor se le pasa como primer parámetro el nombre de la tabla, como segundo parámetro la clave primaria y en el tercer parámetro la referencia al objeto base de datos del marco de trabajo Joomla!, el nombre de este tercer parámetro es siempre igual.

Ya tenemos el objeto JTable necesario para utilizar desde el modelo pruebaAdmin, por lo tanto cuando ejecutemos el task introduceMensaje, se instanciara el modelo pruebaAdmin y se ejecutara el método introduce de este. Es en el método introduce del modelo pruebaAdmin donde se usa el objeto JTable que acabamos de crear.

Vamos a implementar el método introduce del modelo pruebaAdmin , introduce el siguiente método en el modelo:

function introduce($post){

  $row =& JTable::getInstance('Mensajes', 'Table');
  	 if (!$row->bind($post)) {
     	 return JError::raiseWarning(500, $row->getError());
   	 }
  	 if (!$row->store()) {
      	return JError::raiseWarning(500, $row->getError());
  	 }
  return 1;
    }

Observa que acepta como parámetro una variable a la que llama $post.

En esta variable almacenaremos la petición entera que previamente hemos obtenido en el controlador mediante la instrucción : JRequest::get(’post’)

Esta instrucción recoge los parámetros de entrada de la petición, es como acceder al array $_POST de php, pero mediante el API de Joomla!, lo que nos provee de protección contra inyección de código, etc…

Es importante saber que si se intenta pasar el valor de los parámetros post mediante el objeto JRequest desde otro sitio que no sea el controlador, por ejemplo desde una vista, el objeto JTable no recibirá los parámetros correctamente y generará un error al intentar obtener los valores de la petición.

En la primera línea del método se obtiene una instancia del objeto TableMensajes que hemos creado antes , si no pones los nombre correctamente no se instanciará el objeto.

Después se ejecuta el método bin() del objeto TableMensajes que lo que hace es buscar en los parámetros post de entrada parámetros con el mismo nombre que los campos de la tabla y enlazarlos, por eso es importante que en el formulario hayamos escrito correctamente los nombres de los inputs.

Acto seguido se ejecuta el método store() , que almacena en la base de datos los datos provenientes del formulario. Busca la clave primaria, y si ya existe un un registro con la misma clave primaria ejecuta una consulta update, si aun no esta creada la clave primaria, ejecuta una consulta insert.

Si alguno de estos dos métodos no se ejecuta correctamente se lanza un error el método mediante el código : return JError::raiseWarning(500, $row->getError()) .

De vuelta al task introduce mensaje, obtenemos la devolución del metodo introduce y la procesamos con este código :

if($res == 1){
    	 	$this->setMessage('Mensage introducido!');
        	$this->setRedirect('index.php?option=' . $option. '&view=pruebaAdmin');
    	 }else{
    	 	$this->setMessage('Error al introducir!');
        	$this->setRedirect('index.php?option=' . $option. '&view=Error');
    	 }

Este código ya lo hemos introducido antes en el task introduceMensaje.

Si todo ha funcionado correctamente , se redirección a la vista pruebaAdmin mediante el método de controlador setRedirect(),en la cual se volverán a mostrar todos los mensajes insertados y un enlace para insertar mas mensajes. Si no, se redirecciona a una vista con nombre error en la cual crearemos un mensaje de error a gusto de cada cual.

El método del controlador setMessage() establece el mensaje que aparecerá en la parte superior izquierda de la pantalla por defecto, o donde este definido en el template de back-end, y hace que se muestre como en la foto : set message

estructura final

Si has leido todo, enhorabuena.

Proximamente hablaré sobre como usar el editor wysiwyg de Joomla, sobre como usar AJAX en nuestros componentes y también Google Maps.

También escribiré algo de módulos.

Comments

  1. says

    espero el tutorial de google maps en joomla con impaciencia! Gracias por este completo tutorial de fabricacion de componentes.

  2. says

    Saludos gente, de verdad que está muy bueno este tutorial. Tengo la siguiente duda: Deseo desarrollar un plugin que me permita integrar el easySlider 1.7 de jQuery a Joomla 1.5 y que éste sea lógicamente configurable con ciertos parámetros, por ejemplo los estilos y la carpeta de las imágenes. ¿Cuál sería más o menos la estructura de ese plugin? Gracias de antemano…

  3. says

    Hola.

    bueno agradecerte de nuevo el tutorial, me vino de perlas para no colocar por todos lados insert y update. ;)

    Por otro lado y con tu permiso me permito contestar a kreikol, aunque un poco tarde…

    A mi me paso lo mismo cuando colocaba ¡ en esta linea del php del controlador:

    if($res == 1){
    $this->setMessage(‘¡ok!’);

    el ¡ primero del ¡ok! es el que me daba problemas… me guardaba pero me desconectaba el usuario, si alguien lo puede explicar bien, si no pues no colocando el ¡ despues del ‘ todo solucionado.

    Un saludo a todos.

  4. kuroro says

    david:

    solucione mi problema, me ayudo lo que dijiste y tambien puede funcionar de la siguiente manera

    function display($tpl = null){
    global $mainframe;
    $filtro =$mainframe->getUserStateFromRequest( $option.’filtro’, ‘filtro’, ‘Pendiente’);
    $model =& $this->getModel();
    if ($filtro==’Bloqueado’){
    $mensaje = $model->ListadoBloqueadas();
    $this->assignRef(‘row’,$mensaje);
    $tpl=’agregar’;
    }

    donde $tpl hace que vaya a default_agregar.

    ahora mi duda es como puedo crear multiples controler y como los llamo a cada uno.

  5. Gabriel says

    Hola a todos.

    David muy buen blog, te felicito sinceramente, de verdad que el tiempo que le dedicas para ayudar a los que estamos empezando es muy apreciado. El primer ejemplo del componente me salió perfecto y en el segundo realizando los cambios que citó Sebas:

    Para crear el controlador en el modelo:
    $classname = ‘pruebaAdminController’.$controller;

    Y en el controller.php el class debe ser:
    class PruebaAdminController extends JController

    con estos cambios que agradezco a Sebas haber publicado tambn funcionó.

    Quiero también colaborar con un .zip del componente para quien quiera revisarlo, incluye la vista error funcionando. Un saludo a todos y mil gracias.

    http://www.megaupload.com/?d=FPO0FC33

  6. Mike says

    Hola, tenia un pequeño problema con la declaración:

    $res = $modelo->introduce(JRequest::get(‘post’));

    Me aparecía un mensaje de error al tratar de introducir un nuevo mensaje, algo referente a que no podía encontrar la declaración del método introduce(). En mi desesperación, reemplacé el código que escribí siguiendo este tutorial por el zip subido por Gabriel. Así que ya perdí la pista de dónde declaro el método introducce… esa es mi pregunta, ¿en dónde se declara?

  7. says

    Gracias David.
    No he probado el componente, he usado el tutorial para entender la estructura y el funcionamiento y la verdad, ha quedado muy claro.
    Muchas gracias.

  8. Jhonathan says

    Simplemente tengo que decirle que su explicacion es una bendicion, gracias por aportan sus conocimientos a la comunidad.