Principales flujos en Yii

Secuencia del procesamiento de un requerimiento.

El típico flujo de datos
El típico flujo de datos
  1. El usuario realiza un requerimiento al sistema mediante la construcción de un URL de la forma:
    http://hostname/index.php?r=post/show&id=1.
  2. El script de inicio (index.php) es interpretado, se crea la instancia de la aplicación y esta es ejecutada.
  3. La aplicación construye el objeto request a partir de la información suministrada por el usuario.
  4. La aplicación, gracias al componente urlManager, determina cual es el controlador relacionado en el request.
    En este caso, el controlador es post cuya clase es PostController y la acción es show junto con el atributo id cuyo valor es de 1.
  5. La aplicación crea una instancia del controlador específico, determina el tipo y modo de ejecutar la acción y determina los filtros asociados.  Ejecuta los filtros y si es permitido por ellos, invoca la acción.
  6. La implementación de la acción se ejecuta.  El modelo Post lee de la base de datos el registro cuyo id es 1.
  7. La acción prepara la vista show con la información del modelo Post.
  8. La vista ejecuta los wigets que se incluyan en su interior.
  9. La vista resultante se incluye en el layout general.
  10. La acción envía la vista para que sea mostrada al usuario final.

Secuencia de desarrollo de una aplicación en Yii.

  1. Crear el esqueleto de la aplicación: yiic webapp.
  2. Configurar la aplicación.
  3. Crear un modelo para cada tipo de datos manipulado.  yiic model para las tablas de la base de datos.
  4. Crear un controlador para cada tipo de requerimientos de usuario.  “Si un modelo necesita ser accedido por el usuario, se debe crear su correspondiente controlador”.  yiic crud para los modelos de base de datos.
  5. Implementar las acciones y sus correspondientes vistas.
  6. Configurar los filtros necesarios sobre las acciones de los controladores.
  7. Crear el tema de la aplicación si es necesario.
  8. Crear los mensajes traducidos para la internacionalización si es necesaria.
  9. Aplicar las técnicas de caché según los requerimientos.
  10. Realizar ajustes menores y desplegar la aplicación final.

Enlaces.

Convenciones en Yii

Alias de rutas.

  • Permite establecer nombres cortos para ciertas rutas de uso frecuente.
  • Utiliza el punto como separador de ruta: AliasRuta.directorio1.directorio2.objetivo.
  • Es posible definir nuevos alias invocando YiiBase::setPathOfAlias().
  • El proceso contrario, convertir un alias en su correspondiente ruta, puede realizarse invocando YiiBase::getPathOfAlias().
  • Yii define los siguientes alias de manera predefinida.
    • system: directorio del framework.
    • application: directorio base de aplicaciones.
    • webroot: directorio donde se encuentra el script de entrada.
  • Los alias se pueden utilizar en múltiples situaciones.
    Yii::import(‘system.web.CController’);

    Inclusive referenciando grupos de clases.
    Yii::import(‘system.web.*’);

Código.

  • PHP soporta el uso de namespaces a partir de su versión 5.3.0.
  • Las clases nativas de Yii inician siempre con la letra C.
  • Para evitar colisiones de nombres se recomienda que las clases definidas por el usuario inicien por una determinada letra (diferente de la anterior).
  • Los nombres de las variables, funciones y clases deben estar en camel case, es decir, en mayúsculas la primera letra de cada palabra.
    • Los nombres de las variables/atributos y métodos empiezan por minúsculas.
    • Los nombres de las clases empiezan por mayúsculas.
    • Los atributos privados empiezan por underscore (‘_‘).

Rutas.

  • Por defecto se utiliza el siguiente formato.
    http://hostname/index.php?r=ControladorId/AcciónId

  • Es posible reescribir esta ruta a una mas amigable con SEO.
    http://hostname/ControladorId/AcciónId.html

  • Si se obvia la acción se utilizará la acción por defecto: index.
  • Si se obvian el controlador y la acción se utilizarán sus versiones por defecto: main/index.

Archivos.

  • Los nombres de los archivos de clases dependen de la clase pública que contienen y la nomenclatura para esa entidad.
  • Cada archivo debe contener una única clase pública y cero o mas clases privadas.
  • Los archivos de configuración pueden tener un nombre arbitrario.

Directorios.

  • Esta es la estructura general de directorios de Yii.
    • WebRoot/protected: es el directorio base de las aplicaciones.
      • A él le hace referencia el alias application.
      • Debe ser protegido en contra del acceso directo por los usuarios con un .htaccess.
      • Se puede personalizar a través de CWebApplication::basePath.
    • WebRoot/protected/runtime: archivos temporales generados durante la ejecución.
      • Debe tener privilegios de lectura/escritura por parte del servidor web.
      • Se puede personalizar a través de CApplication::runtimePath.
    • WebRoot/protected/extensions: almacena extensiones desarrolladas por terceros.
      • Se puede personalizar a través de CApplication::extensionPath.
    • WebRoot/protected/modules: almacena los módulos de la aplicación.
    • WebRoot/protected/controllers: almacena las clases de los controladores.
      • Se puede personalizar a través de CWebApplication::controllerPath.
    • WebRoot/protected/views: almacena los archivos de las vistas.
      • Se puede personalizar a través de CWebApplication::viewPath.
    • WebRoot/protected/views/ControladorId: almacena las vistas de un controlador específico.
      • Se puede personalizar a través de CController::getViewPath.
    • WebRoot/protected/views/layouts: almacena los archivos del layout de las vistas.
      • Se puede personalizar a través de CWebApplication::layoutPath.
    • WebRoot/protected/views/system: almacena las vistas del sistema.
      • Se puede personalizar a través de CWebApplication::systemViewPath.
    • WebRoot/assets: almacena los assets publicados.
      • Debe tener privilegios de lectura/escritura por parte del servidor web.
      • Se puede personalizar a través de CAssetManager::basePath.
    • WebRoot/themes: almacena los temas de la aplicación.
      • Cada subdirectorio representa un tema diferente.
      • Se puede personalizar a través de CThemeManager::basePath.

Enlaces.

Introducción al MVC de Yii – Parte II

Vista.

  • Es un archivo de PHP con elementos de interfaz de usuario.
  • Su implementación no debe alterar el estado de los modelos.
  • Sólo debe dedicarse a generar la presentación de la respuesta al usuario, así los modelos deberán ser gordos y los controladores delgados.
  • El nombre del archivo que la contiene es “{VistaId}.php” y se ubica bajo la ruta protected/controllers/{ControladorId}.
  • La generación de la vista se realiza con la instrucción CController::render(‘VistaId’, array(‘var’ => $valor)).  De esta manera $var se convierte en una variable local para la vista.
  • Desde la Vista es posible acceder al controlador a través del objeto $this y consecuentemente a sus atributos: $this -> atributo.

Layout.

  • Es un tipo especial de Vista cuya funcionalidad permite componer la presentación a partir de varias vistas para generar un contenido estandarizado.  Por ejemplo, mantener secciones de cabecera, pies, menú izquierdo y contenido.
  • El contenido de la Vista se incluye en el Layout a través de la variable $content.
  • Se incluye automáticamente durante la ejecución de CController::render().  Si se desea evitar este comportamiento se debe utilizar CController::renderPartial().
  • Por defecto su contenido se toma desde protected/views/layouts/main.php.  Esto se puede personalizar modificando CWebApplication::layout (a nivel de toda la aplicación) o CController::layout (a nivel del controlador actual unicamente).

Widget.

  • Su clase base es CWidget.
  • Son componentes autocontenidos de interfaz de usuario y su utilidad es la de permitir crear con ellos interfaces mas completas.  Por ejemplo un calendario y un campo de autocompletar.
  • Su utilización se puede realizar de dos maneras según su contenido.
    • Sin cuerpo.
      <?php this -> widget('ruta.al.Widget', array('atributo' => $valor)); ?>
    • Con cuerpo.
      <?php this -> beginWidget('ruta.al.Widget', array('atributo' => $valor)); ?>
      ... Cuerpo del Widget ...
      <?php this -> endWidget(); ?>
  • Su implementación se basa en dos métodos: init y run que son invocados por beginWidget y endWidget respectivamente.
  • Los Widgets cuentan con sus propias Vistas almacenadas en /views bajo el directorio donde se encuentra su clase.

Vistas del sistema.

  • Se utilizan para presentar errores del sistema o información de registro.
  • Su nombre corresponde con el formato errorXXX donde XXX es el código HTTP del error al que corresponden.
  • Las vistas predefinidas se localizan en framework/views y pueden personalizarse desplegando versiones nuevas bajo protected/views/system.

Módulo.

  • Su clase base es CWebModule.
  • Es una unidad autocontenida de software con sus propios modelos, vistas, controladores y demás componentes.
  • Permite desarrollar funcionalidades independientes (manejo de usuarios, manejo de contenido, etc.) que pueden reutilizarse fácilmente entre varias aplicaciones.
  • A diferencia de las Aplicaciones, un Módulo no puede ser desplegado por si mismo.
  • El nombre de la clase es “ucfirst({MóduloId})Module” y se ubica bajo la ruta protected/modules/{MóduloId}.
  • El esquelo del Módulo se puede crear a partir del comando “module MóduloId“de yiic.
  • Para utilizarse en una Aplicación debe ser declarado en la propiedad modules de protected/config/main.php de la siguiente manera.
    • Sin valores iniciales para sus propiedades.
      return array(
          ...
          'modules' => array('miModulo', ... ),
          ...
      );
    • Especificando valores iniciales para las propiedades de los módulos.
      return array(
          ...
          'modules' => array('miModulo' => array
                                           (
                                              'titulo' => 'Hola Mundo',
                                              'lontigud' => 50
                                           ),
                             ... ),
          ...
      );
  • Puede accederse a través del controlador de la siguiente manera: Yii::app() -> controlador -> modulo -> propiedades.
  • La ruta del requerimiento se complementa con el módulo: MóduloId/ControladorId/AcciónId.
  • Los Módulos puede contener a otros Módulos en su interior: MóduloExternoId/MóduloInternoId/ControladorId/AcciónId.

Enlaces.

Introducción al MVC de Yii – Parte I

Introducción.

MVC es un patrón de diseño que separa de manera clara y precisa los tres componentes de una aplicación: el modelo, la vista y el controlador.  Su objetivo principal es el de separar la lógica del negocio de la lógica de la presentación para darle estructura a la implementación y facilitar con esto su posterior mantenimiento.

Como se mencionó anteriormente, el modelo consta de tres partes de acuerdo con la siguiente descripción.

  • El modelo representa la lógica de la aplicación, que se encuentra inmersa en los datos y en las reglas del negocio.
  • La vista hace referencia a la interfaz de usuario, a la presentación de la información.
  • El controlador actúa como mediador entre la solicitud del usuario y los modelos y vistas involucrados en la ejecución.
Estructura de una aplicación Yii.
Estructura de una aplicación Yii.

Aplicación.

  • Yii utiliza adicionalmente el patrón de diseño del controlador frontal.
  • Representado por el index.php y es el único punto de acceso del usuario a la aplicación web.
  • En el controlador frontal se crea la instancia de la Aplicación cuya función es la de recibir los requerimientos del usuario y remitirlos a los controladores apropiados para su posterior procesamiento.
  • Representa el contexto de ejecución del procesamiento de los requerimientos del usuario.
  • Puede accederse en cualquier momento a través del singleton Yii::app().
  • Su configuración se realiza en la ruta protected/config, especialmente en el archivo main.php.

Componente.

  • Su clase base es CComponent.
  • Implementan funcionalidades específicas con la suficiente flexibilidad para poderse compartir con otras aplicaciones.
  • Se pueden incluír y configurar facilmente en el archivo de configuración de la aplicación (arreglo components).
  • Se acceden a través de Yii::app() -> ComponenteId.
  • Su creación es perezosa, es decir, sus instancias sólo son creadas cuando son invocados por primera vez.  Es posible evitar este comportamiento listando los componentes bajo la sección preload de la configuración de la aplicación.
  • Sus propiedades pueden definirse de dos maneras.
    • Como atributos públicos de la instancia.
      • Su nombre es sensible a mayúsculas.
      • Su acceso es directo.
      • No permite definir restricciones sobre su modificación.
    • A través de los métodos de consulta y modificadores.
      • Su nombre no es sensible a mayúsculas.
      • Se deben definir los métodos getAtributo y setAtributo según se requiera el acceso.
      • La implementación de estos métodos permite filtrar el acceso a la propiedad.
  • Yii incluye en su distribución múltiples componentes listos para ser utilizados.

Controlador.

  • Su clase base es CController.
  • Su misión es la de dirigir la interacción entre los modelos (lógica del negocio) y las vistas (presentación) para producir el resultado que el usuario desea a partir de su requerimiento.
  • Contiene las acciones.
  • Determina la acción por defecto: index.  Es posible modificar su valor mediante CController::defaultAction.
  • El nombre de la clase es “{ControladorId}Controller“.
  • El nombre del archivo que lo contiene es “{ControladorId}Controller.php” y se ubica bajo la ruta protected/controllers.
  • La búsqueda para localizar una clase de un controlador se rige por las siguientes reglas.
    1. Si la aplicación define a CWebApplication::catchAllRequest se rige por esta propiedad y el controlador especificado en el requerimiento es obviado.
    2. Si se encuentra un alias para este controlador en CWebApplication::controllerMap es utilizado.
    3. Si para el requerimiento ruta/ControladorId se encuentra el archivo protected/controllers/ruta/ControladorIdController.php es utilizada la clase contenida en él.
    4. Si hay módulos definidos en la aplicación la búsqueda incluye sus rutas de manera similar a la regla anterior.
    5. El controlador no fue encontrado y se lanza una excepción CHttpException.

Acciones.

  • Corresponden a las actividades que el controlador puede realizar.
  • Pueden definirse de dos maneras.
    • Como un método de la clase controlador.
      • El nombre del método debe corresponder con el formato “action{AcciónId}”.
      • De esta manera, la acción agregar se encuentra implementada en el método actionAgregar.
    • Como una subclase de la clase CAction.
      • Se define una clase por cada acción.
      • El nombre de la clase corresponde con el formato “{AcciónId}Action“.
      • El nombre del archivo donde se almacena la acción tiene el formato “{AcciónId}Action.php” y se almacena bajo protected/controllers/{ControladorId}.
      • De esta manera, la acción agregar se encuentra implementada en la clase AgregarAction.
      • La clase debe implementar el método run donde se implementa la lógica de la acción.
        class AgregarAction extends CAction
        {
            public function run()
            {
                // Lógica de la acción.
            }
        }
      • Es necesario sobreescribir el método actions() del controlador para hacerle saber de la existencia de la acción.
        class UsuarioController extends CController
        {
            public function actions()
            {
                return array(
                    'adicionar' => 'application.controllers.usuario.AgregarAction'
                );
            }
        }
      • En el ejemplo anterior se le especificó al controlador de Usuario que la acción adicionar se relaciona con la clase AgregarAction definida anteriormente y que se encuentra ubicada bajo protected/controllers/usuario.

Filtros.

  • Se ejecutan antes y/o después de una acción.
  • Su finalidad es la de realizar verificaciones o adecuaciones antes y/o después de procesar la solicitud del usuario.  Como es el caso de verificar la autenticación del usuario antes de realizar cualquier acción administrativa.
  • Una acción puede tener múltiples filtros.
  • El orden de ejecución de los filtros corresponde con el orden de aparición en la lista.
  • Un filtro puede evitar que los siguientes filtros se ejecuten.
  • De manera similar a las Acciones, los Filtros pueden definirse de dos maneras.
    • Como un método de la clase Controlador.
      • El nombre del método debe corresponder con el formato “filter{FiltroId}”.
      • De esta manera, el filtro verificarAutenticacion se encuentra implementado en el método filterVerificarAutenticacion.
        public function filterVerificarAutenticacion($filterChain)
        {
            // El llamado a $filterChain -> run() continúa con la invocación del siguiente filtro.
        }
    • Como una subclase de la clase CFilter.
      • Se define una clase por cada filtro.
      • El nombre de la clase corresponde con el formato “{FiltroId}Filter“.
      • El nombre del archivo donde se almacena el filtro tiene el formato “{FiltroId}Filter.php” y se almacena bajo protected/filters.
      • De esta manera, el filtro estadisticas se encuentra implementado en la clase EstadisticasFilter.
      • La clase debe implementar los métodos preFilter y postFilter donde se implementa la lógica del filtro antes y después de la ejecución de la acción respectivamente.
        class EstadisticasFilter extends CFilter
        {
            public function preFilter($filterChain)
            {
                // Lógica del filtro previo a la ejecución de la acción.
        
                // Si $respuesta es 'true' se continúa con la ejecución de los filtros
                // y eventualmente con la ejecución de la acción.  Si es 'false' la
                // la ejecución de la acción es abortada.
        
                return $respuesta;
            }
        
            public function postFilter($filterChain)
            {
                // Lógica del filtro posterior a la ejecución de la acción.
            }
        }
  • En ambos casos es necesario indicarle al controlador la existencia del filtro.  Para esto se debe sobreescribir el método CController::filters() de manera que retorne la lista de filtros a ejecutarse por cada acción.
    class UsuarioController extends CController
    {
        // ...
    
        public function filters()
        {
            return array(
                'verificarAutenticacion + crear, editar',
    
                array(
                    'application.filters.EstadisticasFilter - crear, editar',
                    'activado' => true,
                    'frecuencia' => 'diaria'
                )
            );
        }
    }
  • El ejemplo anterior especifica dos filtros para el controlador Usuario con las siguientes características.
    • El filtro verificarAutenticacion esta basado en un método mientras que el filtro estadisticas está basado en una clase.
    • Se establecieron valores iniciales para la configuración del filtro de estadisticas.  Estos valores (activado = true y frecuencia = ‘diaria’) se asignan a los atributos del filtro en el momento de su construcción.
    • Los modificadores + y determinan sobre cuales acciones se ejecutan efectivamente los filtros.
      • El filtro verificarAutenticacion se le aplicará UNICAMENTE a las acciones crear y editar.
      • El filtro estadisticas se le aplicará a TODAS las acciones EXCEPTUANDO a las acciones de crear y editar.
      • Si no se especifica ningún modificador se sobreentiende que aplica a TODAS las acciones.

Modelo.

  • Su clase base es CModel.
  • Representa una unica fuente de datos como una fila de una tabla de una base de datos o un formulario con información provista por el usuario.
  • Cada campo de la fuente de datos se convierte en un atributo del modelo.
  • Cada atributo tiene una etiqueta y puede ser validado a partir de un conjunto de reglas.
  • Hay dos tipos de modelo según la fuente de datos que representan.
    • El modelo de formularios se representa con la clase CFormModel.
      • Mantiene información recibida a partir de un formulario del usuario para ser procesada y posteriormente descartada.
    • El modelo de registro activo se representa con la clase CActiveRecord.
      • Se basa en el patrón de diseño de Active Record.
      • Representa un registro de una tabla de una base de datos.
      • Permite su manipulación de una manera orientada a objetos.
      • Los campos del registro se convierten en atributos del modelo.

Enlaces.