Guía rápida de TEAM

Publicado en Blog · 08 August 2016.
Introducción a TEAM Framework

NOTA: Esta guía será actualizada constantemente hasta su finalización. Por lo mismo, te recomiendo regresar cada cierto tiempo para ver los últimos cambios.

Última actualización 22 de Sept 2016

¿ Qué es TEAM ?

TEAM es un framework PHP minimalista que tiene la finalidad de proporcionarte una buena forma de estructurar tus proyectos y ... nada más( es minimalista, ¿ recuerdas ? ). El framework viene de serie con unas pocas herramientas a bajo nivel y espera que si necesitas más, aunque normalmente no hagan falta, uses librerías de terceros que te proporcionen la funcionalidad que necesitas( no esperes que nuevas versiones del framework puedan traerlas ).

TEAM es la versión publica de Trasweb Framework, que es un desarrollo propio para la construción de los proyectos de mis clientes( el último sitio en hacer uso de él es https://www.elseptimoarte.net/ ).

El código está disponible bajo licencia nueva BSD en github: https://github.com/trasweb/TEAM

Los componentes y paquetes

Un componente, o component, es una pequeña parte de la funcionalidad y/o apariencia del sitio web que esperas construir. El sitio web finalizado será, por tanto, un gran número de componentes que pueden interactuar entre ellos( de ahí el nombre de TEAM ) y con el exterior. Estos componentes están contenidos y agrupados en paquetes( o packages ). A nivel de sistema de archivo los componentes y los paquetes son directorios. Hay un componente especial llamado 'commons' que mantiene el código y los recursos comunes a los componentes pertenecientes a un paquete. A su vez hay un paquete especial también llamado 'commons' ( aunque normalmente denominado 'root' ) que mantiene el código y recursos comunes a todos los paquetes.

Si te has bajado el código de TEAM con git clone, seguramente ya te hayas percatado que de seríe venía con los paquetes: 'commons' y 'package' y el componente 'welcome' que pertenece a este último.

Tienes que tener en cuenta que, como los componentes pueden interactuar entre ellos y también desde el exterior, al componente ,y a la petción hacia este componente, desde el exterior la distinguiremos como main. Mientras que a los componentes llamados desde otro componente normalmente se le llamará widget. Esto no es siempre fijo para cada componente. A veces un componente actuará como main y otras veces lo hará como widget. Esta distinción es importante porque nos permitirá, si así lo deseamos, cambiar aspectos o funcionalidades del componente ya sea que la petición la haga el navegador u otro componente. Veamoslo con un ejemplo.

Tu web puede necesitar una sección de noticias. La representación y funcionalidad de esta sección puede ser resuelta mediante un componente llamado 'noticias'. Cuando un naegador pide un listado de noticias, la petición de ese listado de noticias( así como el mismo componente ) es main( porque es la primera o principal ). Sin embargo, puede pasar que en portada, se muestre también un pequeño listado de últimas noticias además de otras cosas como eventos o últimos posts. En este caso, portada -ya que es la petición lanzada por el navegador- será el componente main. Portada llamará a los componentes de noticias( para que muestre las últimas noticias ), blog( para que muestre las últimas entradas de blog ) o eventos( para que muestre los últimos eventos ) que serán considerados componentes widgets.

Controladores o controllers

En el mundo físico, a cada acción le viene asociada una reacción. En el mundo de internet, por cada acción del usuario sobre un sitio web, se genera una petición( request ). Esta petición o request es procesada por un componente que devuelve la información pedida en el formato solicitado por el origen de la petición.

Mundo físico Accion ----- Reacción

Mundo internet Acción usuario/Request ----- Componente/Response

Esto es como funcionan las peticiones main. En el caso de peticiones incrustadas o embebed ( las realizadas entre componentes ) , el funcionamiento como se puede ver es parecido:

Petición componente/Request ------ Componente/Response

Hemos dicho que un componente devuelve la información que se le pide en el formato solicitado. Esto, a pesar de ser lo más lógico, contrasta con el desarrollo de otros frameworks en los que la aplicación debe determinar el formato de respuesta. Aclaremos esto de los formatos con unos ejemplos:

  • Un navegador hace un request al servidor de la sección de noticias de la web. Por tanto, el formato. que espera el navegador para el response desde el servidor, es HTML.
  • Un script javascript hace un request al servidor para solicitar más noticias. Este javascript puede que necesite los datos en JSON, XML o HTML. Por tanto, el mismo especificará el formato que necesita.
  • Un componente 'portada' hace un request a un componente 'noticias' solicitando un listado y lo quiere en HTML, pero un HTML para ser incrustado( sin metatags, ni migas, ... ).
  • Un agregador de noticias hace un request al servidor, más concretamente al componente noticias, porque quiere un XML en formato RSS.

Queda claro que el solicitante en su petición, o request, también debe determinar el formato que desea para la respuesta.

Los mecanismos que tiene TEAM framework para responder a las peticiones se conocen como controladores. Los controladores se distinguien según el formato que debe tener la respuesta:

  • Gui: Cuando la petición o request soliciita una respuesta HTML
  • Actions: Cuando la petición o request solicita una respuesta diferente a HTML
  • Commands: Cuando la petición o request es desde línea de comandos y, por tanto, la respuesta debe de ser visualizable en el terminal.

A nivel de sistema de archivos un controlador es una clase PHP llamada 'Gui'( en un archivo Gui.php ), 'Actions'( en un archivo Actions.php ) o 'Commands'( en un archivo Commands.php ) en el raíz del directorio de cada componente

¡ ...Sí, exacto, la clase Gui.php que hay dentro de /package/welcome al bajarte el framework es un controlador Gui !

Los responses

Los response son métodos de las clases controladoras. Un response da respuesta a una o varias peticiones. Atendiendo a lo siguiente:

  • Si a la hora de hacer una petición concreta, se especificó una respuesta concreta y existía un response( no estático ) con el mismo nombre, se lamará a ese response para genere la respuesta.
  • Si a la hora de hacer una petición concreta, se especificó una respuesta concreta, pero esta no estaba en el controller. La respuestá la dará el response 'main'
  • Si a la hora de hacer una petición concreta, no se especifico que respuesta concreta se quería, la respuesta la dará el response 'index'

De nuevo, algunos ejemplos para clarificarlo:

  • Un navegador hace la petición /noticias . Esto internamente al framework representa una llamada al componente llamado 'noticias' perteneciente al paquete por defecto. Esta petición del navegador no solicita ninguna respuesta concreta. Por lo que la respuesta será generada por el método 'index'( que es la response por defecto) de la clase Gui( ya que lo que se requiere es un HTML ) del componente 'noticias' como hemos dicho.
  • Un navegador hace la petición /noticias/deportes. Esto internamente al framework representa una llamada al componente llamado 'noticias' perteneciente al paquete por defecto. También se solicita una respuesta concreta 'deportes', por tanto, la respuesta será generada por el método 'deportes' de la clase Gui del componente 'noticias'. Si no existiera el método 'deportes' se llamará al método 'main'( response usado cuando no se encuentra el pedido ) pasándole como un argumento un string con valor 'deportes'
  • Un navegador hace la petición /noticias/politica solicitando un JSON. Esto internamente al framework representa una llamada al componente llamado 'noticias' perteneciente al paquete por defecto. También se solicita una respuesta concreta 'politica', por tanto, la respuesta será generada por el método 'politica' de la clase Actions( ya que queremos que la salida sea JSON ) del componente 'noticias'. Si no existiera el método 'politica' se llamará al método 'main' pasándole como un argumento un string con valor 'politica'
  • Una tarea CRON hace la petición /cli . Esto internamente al framework representa una llamada al componente llamado 'cli' perteneciente al paquete por defecto. Esta petición del navegador no solicita ninguna respuesta concreta. Por lo que la respuesta será generada por el método 'index'( que es la response por defecto) de la clase Commands( ya que lo que se requiere es una salida de terminal ) del componente 'cli'.

Creo que ya nos hemos hecho una idea de como se selecciona un 'response' ( que es un método ) para que de respuesta a una request.

Hemos dicho que un request puede venir desde el exterior( petición llamada 'main', generada por un usuario o llamada desde línea de comandos ) como de otro componente( petición llamada 'embebed' o incrustada ) . Por tanto, esto podría crear un problema de seguridad. Ya que podría pasar que tuvieramos un response que diera respuesta a una petición embebed(desde otro componente) pero no quisiéramos que se diera respuesta a una main( a un navegador, por ejemplo). Estos problemas de visibilidad se pueden resolver poniendo como 'protected' a aquellos métodos response que sólo queramos que respondan a peticiones embebed y poniéndo como 'public' aquellos métodos response que puedan responder tanto peticiones main como embebed. Finalmente, podremos poner como 'private' aquellos response que sean helpers a peticiones del mismo componente y, por tanto, no queremos que respondan a ningún request.

No todos los métodos de un controlador son response, también existen los llamados métodos modificadores y los llamados métodos eventos. Los métodos modificadores son dos:

  • 'commons' que se ejecuta antes de llamar al 'response' que le correspoda
  • 'custom' que se ejecuta después del evento que le corresponda.

Como no, otro ejemplo:

Un navegador hace la petición HTML /noticias/deportes. Esta petición llegaría a la Gui del componente 'noticias' y se lanzaría lo siguiente:

  • En primer lugar se llamaría al método 'commons'
  • En segundo lugar se llamaría al método 'deportes' si existiera, sino se llamaría al método 'main'
  • En tercer lugar se llamaría al método 'custom'

En caso de no existir ni el método 'deportes' ni el 'main' no se llamaría a ninguno de los tres métodos y se generaría un crítico de ACTION_NOT_FOUND. Al no ser ni 'commons' ni 'custom' métodos response se recomienda que se pongan como 'private' o 'protected'

Los métodos eventos los veremos en la versión extendida de la documentación

URL

Aunque se ha puesto de moda el uso generalizado de routeadores, estos ralentizan la web debido al tener que comparar la url de entrada contra decenas o cientos de urls modelos. TEAM proporciona un parseador de url de serie( aunque reemplazable o modificable ). El esquema más básico según parsea es el siguiente: /:componente:/:response:/:id:

El componente y el response se refiere al paquete por defecto( ya hablaremos de ello más adelante ) y el id es el primer subpath numérico que encuentre entre los tres primeros elementos.

No hay nada mejor que ejemplos:

  • /noticias/estrenos: corresponde al response 'estrenos' del componente 'noticias' del paquete por defecto.
  • /noticias/10: corresponde al componente 'noticias' del paquete por defecto. id es igual a 10 y al no especificarse un response se considerará 'index'( como ya se vió en el apartado de response )
  • /notlicias/10?out=JSON: corresponde a lo mismo que en el anterior pero en este caso se quiere en formato JSON( por tanto, el controlador a lanzar será Actions y no Gui )
  • /peliculas/editar/150: corresponde al response 'editar' del componente 'películas' del paquete por defecto, id es igual a 150
  • /usuarios/login: corresponde al response 'login' del componente 'usuarios' del paquete por defecto
  • /usuarios/logout: corresponde al response 'logout' del componente 'usuarios' del paquete por defecto

También es posible seleccionar items. Consideraremos un item a la llamada a una entidad especifica de nuestra web. Ejemplos:

  • /noticias/manual-de-team.xml
  • /noticias/linux-triunfa-en-el-escritorio.html
  • /noticias/linux-triunfa-en-el-escritorio-10.html

En todos los casos se llama al componente noticias, pero con la siguiente diferencias respectivamente:

  • Se especifica un item_name( con valor 'manual-de-team') y un item_ext( con valor 'xml' ). Los item_ext, si no se ha especificado un out expllícitamente, suelen usarse, tras un proceso de filtrado, como argumento out.
  • Se especifica un item_name( con valor 'linux-triunfa-en-el-escritorio' ) y un item_ext( con valor 'html' )
  • Se especifica un item_name( con valor 'linux-triunfa-en-el-escritorio' ), un item_id( con valor 10 ) y un item_ext( con valor 'html' ). Los item_id, si no se ha especificado un id expllícitamente, se usan como id.

Parámetros

Los componentes son entidades encapsuladas como lo son las funciones en los lenguajes de programación. Es decir, tienen unos argumentos de entrada, hacen lo que tienen que hacer y generan una salida. Poco nos importa de dónde se realice la llamada( desde el exterior o desde otro componente ) ésta debería de ser, y de hecho lo es, homogenea( es decir, da igual que los datos se envían por POST, GET o vengan desde otro componente, que se accede a ellos de igual manera ).

Para acceder a los argumentos de llamada basta con acceder al atributo params en cualquiera de los controladores.

  • Desde el navegador se lanza /noticias/listado?order=ASC&type=1
  • En una de las página de nuestro sitio web se lanza un formulario con action igual a /noticias/listado y con los select 'order'( con valor 'ASC') y 'type'( con valor de 1 ).
  • Se llama desde otro componente al response 'listado' del componente 'noticias' pasándole como argumentos: 'order'( con valor 'ASC') y 'type'( con valor de 1 ).

En cualquier de los tres casos anteriores corresponde podríamos acceder a ellos desde params con $this->params así:

<?php 
 
 
function listado() {
 echo 
'Elegiste el orden: '.$this->params->order;
 echo 
'Elegiste el tipo: '.$this->params->type;
 }
 

¡ Compártelo !
Este sitio utiliza cookies propias y de terceros para mejorar tu experiencia con el sitio web. Al continuar con la navegación consideramos que acepta su uso.