SlideShare ist ein Scribd-Unternehmen logo
1 von 54
Yupp PHP Framework
  Tutorial “manos a la obra”



 Autor: Ing. Pablo Pazos Gutiérrez
    <pablo.swp@gmail.com>
          Fecha: Mayo 2011
             Versión: 1.1
Índice
1. Fundamentos de patrones MVC y ORM...........................................................................................4
   1.1 Model-View-Controller (MVC).....................................................................................................4
     1.1.1 Algunos conceptos a importantes de recordar:....................................................................5
   1.2 Object-Relational Mapping (ORM)..............................................................................................6
     1.2.1 Mapeo objeto-relacional.......................................................................................................6
       1.2.1.1 Mapeo de clase..............................................................................................................6
       1.2.1.2 Mapeo de relaciones......................................................................................................7
       1.2.1.3 Mapeos de herencia......................................................................................................8
2. Fundamentos de programación ágil y aplicaciones web.................................................................10
3. Instalación y configuración del framework......................................................................................12
   3.1 Descargar la liberación.............................................................................................................12
   3.2 Descargar del servidor de desarrollo........................................................................................13
   3.3 Configuración del framework....................................................................................................14
4. Estructura de Yupp Framework......................................................................................................15
5. URLs en Yupp................................................................................................................................18
6. Creando una aplicación simple.......................................................................................................19
7. Estructura de las aplicaciones Yupp...............................................................................................24
   7.1 Configuración de la base de datos por aplicación.....................................................................25
     7.1.1 Creando la configuración....................................................................................................25
   7.2 Script de bootstrap....................................................................................................................26
   7.3 Scripts de testing......................................................................................................................26
8. Model: funcionalidades avanzadas.................................................................................................28
   8.1 Gestionando relaciones hasOne...............................................................................................28
   8.2 Gestionando relaciones hasMany.............................................................................................30
     8.2.1 Tipos de relaciones hasMany.............................................................................................31
   8.3 Convenciones sobre nombrado de tablas.................................................................................32
     8.3.1 Nombrado implícito de tablas.............................................................................................32
     8.3.2 Nombrado explícito de tablas.............................................................................................32
     8.3.3 Nombrado de tablas de join................................................................................................33
   8.4 Creando restricciones sobre campos y relaciones....................................................................33
     8.4.1 Definiendo restricciones.....................................................................................................33
     8.4.2 Verificando restricciones....................................................................................................35
       8.4.2.1 Validando datos mediante restricciones.......................................................................35
       8.4.2.2 Validando datos previa a la persistencia......................................................................35
   8.5 Definiendo lógica pre-validación...............................................................................................36
   8.6 Usando belongsTo....................................................................................................................37
   8.7 Definiendo relaciones de muchos a muchos.............................................................................40
   8.8 Eliminación física vs. eliminación lógica....................................................................................40
9. Controladores.................................................................................................................................42
   9.1 Convenciones...........................................................................................................................42
   9.2 Acciones de infraestructura (scaffolded)...................................................................................44
   9.3 Recibiendo archivos..................................................................................................................44
   9.4 Devolviendo XML o JSON........................................................................................................46
     9.4.1 Programando una acción que devuelve JSON...................................................................46
     9.4.2 Programando una acción que devuelve XML.....................................................................47
10. Vistas...........................................................................................................................................48
   10.1 Fundamentos para la implementación de vistas.....................................................................48
10.2 Uso de helpers........................................................................................................................49
    10.2.1 Helper layout....................................................................................................................49
    10.2.2 Helper template................................................................................................................50
    10.2.3 Helper javascript...............................................................................................................52
    10.2.4 Helper ajax link.................................................................................................................52
  10.3 Vistas de infraestructura (scaffolded)......................................................................................53
11. Estado actual del proyecto...........................................................................................................54
  11.1 Hoja de ruta del proyecto........................................................................................................54
  11.2 Información administrativa......................................................................................................54
1. Fundamentos de patrones MVC y ORM
1.1 Model-View-Controller (MVC)
MVC es un patrón arquitectónico, que determina grandes componentes de software, a modo de
capas, que se dividen las responsabilidades funcionales de un sistema informático. Es frecuente la
asociación de MVC al modelo de 3 capas: interfaz de usuario, lógica de negocio y acceso a datos,
donde “view” se asocia a la interfaz de usuario, “controller” a la lógica de negocio, y “model” al
acceso a datos.

Existen múltiples implementaciones de MVC, en esta sección veremos la alternativa de
implementación elegida para Yupp Framework. En el siguiente diagrama se muestra un ciclo de
pedido, donde se pasa por los 3 componentes de MVC.




En el diagrama se muestra un modelo simplificado del MVC de Yupp Framewrok (YMVC), donde un
usuario que realiza un pedido desde su navegador web, y este es atendido por el componente
Controller. En Controller se ejecuta la lógica de negocio, se accede a los datos mediante el
componente Model, donde se hacen consultas y actualizaciones. Luego el componente View es el
que determina que respuesta se le dará al usuario. View también puede acceder a Model pero en
general no accede directamente, sino que usa el resultado de la ejecución de la lógica, provisto por
Controller. Luego Controller entrega la respuesta al usuario, en general es una página web con datos
de las entidades del Model.
1.1.1 Algunos conceptos a importantes de recordar:

   ●   Un controlador implementa cierta lógica que es ejecutada dependiendo del pedido recibido.
   ●   La lógica se implementa en forma de acciones, cada acción es un método dentro del
       controlador. Un controlador puede tener varias acciones.
   ●   Cada acción determina que vista se va a mostrar al usuario, lo que depende de los
       parámetros de entrada y la lógica que se ejecute.
   ●   Desde una acción, se pueden mostrar varias vistas distintas, solo una a la vez.
   ●   Cada acción determina que modelo pasarle a cada vista.


A continuación se muestra un diagrama más detallado que se aproxima mejor a la implementación
de YMVC.




1.1.2 Descripción de los componentes:

Routing: se encarga de recibir un pedido del usuario y determinar qué controller lo debe atender.
Una instancia de Yupp puede contener múltiples aplicaciones, cada una con múltiples controllers.

Filter: es un componente que sirve para realizar acciones previas a la ejecución de la lógica del
controller seleccionado. Es útil para realizar verificaciones de seguridad, por ejemplo verificar si el
usuario tiene permisos para ejecutar la lógica del controller o no.

Data Access Layer (DAL): componente que abstrae el acceso a distintos DBMS, de modo que el
framework pueda trabajar, con MySQL o Postgres de forma transparente para el usuario.
La clase RequestManager es la que se encarga de recibir los pedidos, procesar los parámetros,
utilizar routing para determinar el controller y acción a ejecutar, procesar el resultado, y devolver una
vista. También se encarga de procesar errores y mostrarlos de forma amigable al usuario.



1.2 Object-Relational Mapping (ORM)
ORM es un mecanismo que permite trabajar con objetos en lugar de registros, en el acceso a bases
de datos relacionales. Esto es de especial interés para quienes programamos usando Orientación a
Objetos, porque evita la complejidad de tener que trabajar con estructuras de registros relacionales.
Para ORM también existen múltiples alternativas de implementación, en esta sección nos
concentraremos en la implementación de ORM elegida para Yupp (YORM).

Objetivos principales de YORM:
   ● Definir modelos de datos complejos, completamente orientados a objetos
   ● Evitar al máximo trabajar con SQL
   ● Soportar múltiples gestores de bases de datos


El primer objetivo implica que se deben soportar el mapeo de clases a tablas, el mapeo de
relaciones entre clases, y el mapeo de herencia entre clases. El segundo objetivo implica que se
utilizarán estructuras de clases para crear las consultas a las bases de datos, en lugar de utilizar
SQL. Y el tercer objetivo implica que el framework se debe abstraer del gestor de bases datos. Como
vimos en el MVC, esto se hace con el componente DAL.



1.2.1 Mapeo objeto-relacional

1.2.1.1 Mapeo de clase

El primer problema a resolver es el de mapear una clase simple a una tabla en la base de datos
relacional. Esto es relativamente sencillo de hacer en general, pero con PHP existe un problema
agregado: PHP es dinámico y débilmente tipado, y las bases de datos utilizan registros fuértemente
tipados, por lo que para cada campo de una clase programada en PHP, es necesario contar con un
mecanismo de especificación del tipo, ya que PHP no lo tiene.

El siguiente diagrama muestra la correspondencia entre la definición de una clase y su
correspondiente mapeo a una tabla.
La implementación de esta clase en Yupp es similar a este código:

// Todas clas clases persistentes heredan de PersistentObject
class Usuario extends PersistentObject
{
   // Los campos se definen en el constructor
   function __construct($args = array (), $isSimpleInstance = false)
   {
      // Determina el nombre de la tabla
      $this->setWithTable("usuarios");

        // Campos de la clase
        $this->addAttribute("nombre", Datatypes :: TEXT);
        $this->addAttribute("email", Datatypes :: TEXT);
        $this->addAttribute("edad", Datatypes :: INT_NUMBER);
        $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        // Llamada al constructor de la superclase
        // Inyecta atributos útiles para ORM (id, class, deleted)
        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}



1.2.1.2 Mapeo de relaciones

Habiendo definido 2 clases, estas pueden relacionarse de múltiples formas. Las relaciones entre
clases pueden ser unidireccionales o bidireccionales, y pueden tener distintas cardinalidades. Para
las cardinalidades, diferenciaremos 2 casos: 1 y N. A continuación se muestra un diagrama con
todas las posibilidades de definición de relaciones entre 2 clases:




Para las relaciones con un lado N, aparte de las tablas que el YORM creará para las clases A y B,
creará una tabla intermedia (tabla de join) para mantener las relaciones. A continuación se muestra
un ejemplo. Si a es una instancia de A y b1, b2, b3 son instancias de B, y A tiene varios B (en este
caso b1, b2 y b3), las relaciones se mantienen de la siguiente forma:
tabla_a                          tabla_a_b                            tabla_b


id               id_a               id_a            id_b1             id               id_b1

                                    id_a            id_b2             id               id_b2

                                    id_a            id_b3             id               id_b3




A continuación se muestra el código PHP de la clase A con una relación unidireccional a un B:

class A extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->setWithTable("tabla_a");

         // Declaración de campos de la clase A omitidos ..

         $this->addHasOne("b", "B"); // Declaración de relación a un B

         // Llamada al constructor de la superclase
         // Inyecta atributos útiles para ORM (id, class, deleted)
         parent :: __construct($args, $isSimpleInstance);
     }

     // Métodos estáticos omitidos
}



En el caso de que la clase A tuviera relacionados varios B, la definición de la clase sería:

class A extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->setWithTable("tabla_a");

         // Declaración de campos de la clase A omitidos ..

         $this->addHasMany("b", "B"); // Declaración de relación a muchos B

         // Llamada al constructor de la superclase
         // Inyecta atributos útiles para ORM (id, class, deleted)
         parent :: __construct($args, $isSimpleInstance);
     }

     // Métodos estáticos omitidos
}

1.2.1.3 Mapeos de herencia
Las clases persistentes soportan la definición de herencia (especialización) como en cualquier
modelo orientado a objetos. Al conjunto de una clase y todas las clases que heredan de esta, directa
o indirectamente, se le llama “estructura de herencia” o “árbol de herencia”.

Por ejemplo, si se tienen 2 clases C y D, donde D hereda de C, hay dos opciones de ORM:

   ●   mapear las dos clases a la misma tabla, ó
   ●   que cada clase tenga su propia tabla.


Caso 1: D hereda de C y se mapean en la misma tabla.




Caso 2: D hereda de C y se mapean en tablas distintas:




En el caso 2 se puede apreciar que en la tabla_d se inyecta un nuevo atributo “super_id_c”, que
indica cual es el identificador de la parte de la clase D que se hereda de C, y sirve para hacer un join
entre las tablas, de modo de obtener una instancia completa de D, que incluye los valores de los
atributos declarados tanto en la clase C como en la clase D.

También para el caso 2 se debe notar que el identificador de las instancias de D será en que se
guarda en la tabla “tabla_d”, ya que es la tabla que corresponde con la clase concreta. Este
identificador puede ser distinto al que se guarda en la tabla “tabla_c” (por eso es necesaria la
columna “super_id_c”). Para una instancia de D persistita, en la columna “class” de ambas tablas
estará el valor “D”. Las instancias de C persistidas, no tendrán ningún registro ingresado en la tabla
“tabla_d”.
2. Fundamentos de programación ágil y
aplicaciones web
En general, el desarrollo ágil refiere a una característica de algunos procesos de desarrollo de
software, que permiten que un proyecto tenga:

   ●   Productos tangibles y funcionales en períodos de tiempo cortos
   ●   Mayor visibilidad del avance del proyecto para el cliente
   ●   Capacidad de adaptación rápida a cambios en los requerimientos


Que esto sea posible, también depende de las tecnologías que se empleen para los proyectos. En
particular los “frameworks ágiles”, como lo es Yupp, han propuesto tecnologías para acompañar y
ayudar a los procesos de desarrollo ágil de software. En este sentido, los objetivos de Yupp son:

   ●   Quitar de manos del programador las tareas repetitivas que agregan poco valor al proyecto
       (consultas a la BD, validación de datos, internacionalización, ajax, etc)
   ●   Seguir el paradigma “convención sobre configuración”, que marca reglas básicas o
       convenciones, que hacen que no se necesiten grandes y dificultosas configuraciones por
       cada proyecto.
   ●   Fácil de instalar y usar.
   ●   Minimalista, todo lo necesario, pero no más.
   ●   Permitir generar aplicaciones web funcionales sin necesidad de realizar una programación
       completa.
   ●   Curva de aprendizaje reducida.


Aplicaciones web

Principales características de las aplicaciones web:

   ●   Instaladas en la nube
   ●   No necesitan actualizaciones
   ●   Accedidas desde web browsers
   ●   Ejecución mixta, parte en el cliente, parte en el servidor (puede ser más de uno)


Las tendencias actuales muestran que en el futuro las aplicaciones basadas en web serán las únicas
aplicaciones, y que las aplicaciones de escritorio poco a poco van a desaparecer. Además existe una
tendencia de empresas como Google y Mozilla al desarrollo de sistemas operativos y aplicaciones
todo basado en web.

Por otro lado, con el desarrollo del nuevo estándar HTML5, que incluye de forma nativa soporte para
video, sonido, multi-threading, primitivas gráficas 2D y 3D, y otras características, lo que da una
infraestructura enorme para el desarrollo de aplicaciones web. En este sentido, Yupp está intentando
posicionarse como una opción competitiva entre los frameworks ágiles para el desarrollo de
aplicaciones para esta nueva realidad que está comenzando.

Algunos vínculos interesantes:

   ●   http://www.youtube.com/watch?v=42Gyy2xr5zA
   ●   http://www.youtube.com/watch?v=ErqCqwkwIDE
   ●   http://www.youtube.com/watch?v=jB5KFJULahs
   ●   http://www.youtube.com/watch?v=KMZLM2AhSE0
   ●   http://www.youtube.com/watch?v=ANMrzw7JFzA
3. Instalación y configuración del
framework
Los siguientes pasos suponen que se tiene un servidor web con soporte para PHP instalado. En
particular, se referenciará a la aplicación WAMP que es un paquete que trae Apache, MySQL y PHP
para Windows. Por más información: http://www.wampserver.com

El primer paso es obtener la última versión del framework, para esto hay dos opciones:

   ●   Descargar la liberación
   ●   Descargar del repositorio de desarrollo



3.1 Descargar la liberación
Desde la página de Google Code del proyecto [1], en el área de descargas, residen las últimas
liberaciones en archivos en formato ZIP.




[1] http://code.google.com/p/yupp/
3.2 Descargar del servidor de desarrollo
En Google Code también se encuentra el servidor de versiones (SVN) del proyecto. El código fuente
de desarrollo se puede descargar desde ahí [2] con cualquier cliente SVN.

[2] http://yupp.googlecode.com/svn/YuppPHPFramework

Una vez descargado el framework, se copia su contenido al directorio “www” del WAMP. Para
verificar que se ha copiado correctamente, se inicia el WAMP, en un navegador web se accede a
http://localhost, donde deberá aparecer una página del WAMP. En esa página, hay una zona de
proyectos, ahí debería aparecer el directorio descomprimido donde se ha copiado el framewok. Si se
ingresa al directorio del framework, se debería ver el escritorio de Yupp como se muestra en la
siguiente imagen:




En este escritorio aparecerán todas las aplicaciones instaladas en Yupp Framework. Podemos
comentar varios aspectos de Yupp:
   ● Soporta múltiples aplicaciones.
   ● Sirve para que el desarrollador tenga varios proyectos en los que está trabajando.
   ● Sirve para que el usuario final pueda usar varias aplicaciones.

Yupp es tanto un plataforma de desarrollo, como plataforma de ejecución de aplicaciones web.

Otros aspectos del escritorio son:
   ● Desde aquí se pueden crear nuevas aplicaciones
   ● Se pueden filtrar las aplicaciones (útil cuando se tiene una cantidad considerable)
   ● Se pueden ver novedades relacionadas con Yupp y publicadas en Twitter
   ● Se puede acceder al listado de aplicaciones (vista por defecto)
   ● Se puede acceder a la vista de Base de Datos (es necesaria la configuración previa)
   ● Se pueden ejecutar los tests de las aplicaciones
   ● Se pueden ejecutar los scripts de bootstrap de las aplicaciones
   ● Se pueden ejecutar las aplicaciones

Nota: si se intenta acceder a la vista de Bases de Datos se obtendrá un error que indicará que la
base de datos no existe. Esto se debe a que todavía no la hemos creado y configurado.
3.3 Configuración del framework
Yupp Framework fue diseñado para que la configuración sea mínima, representando una tarea muy
simple a realizar una sola vez. La única configuración necesaria es la de la base de datos a utilizar.

Al día de hoy, Yupp Framework soporta MySQL, Postgres y SQLite. Para configurar el gestor de
base de datos, es necesario editar el archivo yupp/core/config/core.config.YuppConfig.class.php. En
este archivo hay un campo $default_datasource, donde se realiza esta configuración en una
estructura como esta:

$default_datasource = array(
   self::MODE_DEV => array(
      'type'     => self::DB_MYSQL,
      'url'      => 'localhost',
      'user'     => 'root',
      'pass'     => '',
      'database' => 'yupp_dev'
   ),
   self::MODE_PROD => array(
      'type'     => self::DB_MYSQL,
      'url'      => 'localhost',
      'user'     => 'root',
      'pass'     => '',
      'database' => 'yupp_prod'
   ),
   self::MODE_TEST => array(
      'type'     => self::DB_MYSQL,
      'url'      => 'localhost',
      'user'     => 'root',
      'pass'     => '',
      'database' => 'yupp_test'
   )
);



En esta estructura se indica que configuración de base de datos usar para cada modo de ejecución.
Hoy el framework soporta los modos “desarrollo” y “producción”, en un futuro también soportará el
modo “testing”. Para cada modo de ejecución se indica:

   ●   tipo de gestor de bases de datos (MySQL, Postgres o SQLite)
   ●   ubicación del gestor de bases de datos
   ●   usuario y clave
   ●   nombre de la base de datos a utilizar
4. Estructura de Yupp Framework
La estructura (reducida) del framework es la siguiente:

   ●   apps
          ○   core
          ○   tests
                ■ app.xml
   ●   core
           ○ app
           ○ basic
           ○ config
           ○ db
           ○ http
           ○ layout
           ○ mvc
           ○ persistent
           ○ routing
           ○ support
           ○ testing
           ○ utils
           ○ validation
           ○ web
           ○ App
           ○ FileSystem
           ○ Yupp
           ○ YuppLoader
           ○ YuppSession
   ●   css
   ●   images
   ●   js
   ●   .htaccess
   ●   index.php


Explicación de la estructura

/apps: Este directorio contiene las aplicaciones instaladas en el framework

/apps/core: Esta aplicación es parte del framework. Todas las vistas y acciones como el escritorio
de Yupp, la vista de Bases de Datos, la creación de aplicaciones, etc, son parte de esta aplicación.

/apps/tests: Esta aplicación contiene algunos tests sobre el framework. Por un lado, los tests
automatizados que pueden ser ejecutados desde el escritorio de Yupp. Por otro lado, al ejecutar la
aplicación, se tienen algunas vistas con tests para ejecutar manualmente, que además sirven como
referencia para la programación.
/apps/tests/app.xml: Descriptor de aplicaciones, usado por Yupp para presentar correctamente la
aplicación en el escritorio. En el futuro servirá para gestionar aplicaciones.

/core: Es el núcleo del framework. Contiene todas las clases y scripts necesarios para el
funcionamiento del framework.

/core/app: Contiene recursos relacionados con el manejo de las aplicaciones.

/core/basic: Contiene clases útiles para manejar tipos básicos como String y DateTime.

/core/config: Contiene elementos de configuración y la implementación de muchas de las
convenciones de Yupp, como las de nombrado de los archivos.

/core/db: Contiene la implementación de la capa de acceso a datos, los conectores a los distintos
motores de bases de datos, y el paquete de creación de consultas.

/core/http: Contiene la implementación de HTTPRequest y HTTPResponse.

/core/layout: Contiene la clase que da soporte a la definición de layouts en las vistas.

/core/mvc: Contiene la implementación de los elementos básicos para soportar controladores,
vistas, helpers útiles para la generación de vistas, y para el pasaje del modelo desde el controlador a
la vista.

/core/persistent: Contiene la implementación del ORM de Yupp. y clases para la serialización a
JSON y XML.

/core/routing: Este directorio contiene las clases que implementan el ruteo de pedidos al framework,
y la ejecución de acciones de los controladores.

/core/support: Contiene algunas clases útiles para mantener el contexto de ejecución del
framework, para el manejo de medidas de tiempo y para soportar la internacionalización.

/core/testing: Contiene las clases necesarias para implementar tests automáticos.

/core/utils: Contiene clases utilitarias de uso interno del framework.

/core/validation: Contiene las clases que implementan la validación de campos para las clases
persistentes.

/core/web: Contiene las clases que se encargan de manejar los pedidos al framework, procesar urls,
parámetros, y coordinar toda la ejecución de acciones y devolución de vistas.

App: Clase que implementa operaciones útiles sobre las aplicaciones.

FileSystem: Clase que implementa métodos útiles para acceder al sistema de archivos.

Yupp: Clases que implementa operaciones útiles sobre el framework.

YuppLoader: Clase que implementa la carga controlada de clases y scripts.
YuppSession: Clase que implementa la gestión de la sesión.

css: En este directorio se colocan las hojas de estilo de uso global (útiles para varias aplicaciones).

images: En este directorio se ponen las imágenes de uso global.

js: En este directorio se ponen los archivos javascript para uso global.

.htaccess: Indica reglas de redirección de pedidos, todos los pedidos van al index.php.

index.php: Punto de entrada de los pedidos del usuario al framework.
5. URLs en Yupp
Como se mencionó antes, Yupp es un framework orientado a convenciones. La primer convención
que debe quedar clara es la del formato de las URLs que el framework puede recibir. Esto es muy
importante, porque toda la ejecución del framework y de sus aplicaciones dependerá de las URLs
que se reciban.

Antes de entrar en los formatos de las URLs, algunos comentarios:

   ●   Yupp soporta varias aplicaciones
   ●   Cada aplicación puede tener varios controladores
   ●   Cada controlador implementa varias acciones (métodos)
   ●   Dependiendo de los parámetros de entrada, una misma acción puede indicar que se
       muestren varias vistas, una a la vez.


Ejemplo de URL válida en Yupp:

   ●   http://localhost/yupp/app/controller/action?param1=value1&param2=value2


Si el framework fue copiado al directorio “yupp” dentro del directorio “www” del WAMP, esta debería
ser una URL válida para Yupp. A continuación se explica cada trozo de la misma:

   ●   http://localhost: acceso al “www” del WAMP, también conocido como “http root”.
   ●   yupp: directorio donde fue copiado el framework dentro del “www” del WAMP.
   ●   app: nombre de la aplicación que se desea ejecutar.
   ●   controller: nombre del controlador, dentro de la aplicación “app”, que se desea ejecutar.
   ●   action: nombre de la acción a ejecutar. Esta acción está implementada en “controller”.
   ●   ?param1=value1&param2=value2: parámetros que recibirá la acción.


Por ejemplo, si se tiene una aplicación “blog” y se quiere acceder al listado de entradas, la siguiente
podría ser la URL para hacerlo:

   ●   http://localhost/yupp/blog/entradas/list

Yupp Framework soporta otra forma de pasarle parámetros a la acción, sin necesidad de usar el
formato param=value, este es un ejemplo:

   ●   http://localhost/yupp/app/controller/action/value1/value2

Con este formato, el framework transformará los dos últimos trozos de la URL a parámetros de
nombre “_param_1” y “_param_2” respectivamente, y quedarán accesibles con esos nombres para
la acción correspondient.
6. Creando una aplicación simple
Para crear una aplicación simple, se deben seguir estos pasos:

   1. Ir al escritorio de Yupp Framework
   2. Hacer clic sobre el link “Nueva aplicación”
   3. Ingresar los datos ahí pedidos:
           a. Nombre de la aplicación: ingresar el nombre, por ejemplo “biblioteca”
           b. Descripción: una descripción de la aplicación, por ejemplo “Aplicación para gestión de
               libros”
           c. Lenguages: para qué idiomas estará disponible la aplicación, por ejemplo “es en” para
               español e inglés respectivamente.
           d. Nombre del controlador principal: nombre del controlador que se creará por defecto,
               por ejemplo “libro”.
   4. Hacer clic en “crear”.

Si se cumplieron todos los pasos exitosamente, ser debería volver al escritorio y ver la nueva
aplicación creada. Al hacer clic sobre el icono de la aplicación “biblioteca”, debería mostrarse el texto
“Bienvenido a su nueva aplicación!”. En la siguiente sección se explica en detalle la estructura
interna de la aplicación creada de forma automática por el framework. Ingresando a “/yupp/apps”
desde el sistemas de archivos, deberá haber un nuevo directorio con e nombre “biblioteca”. Dentro
de éste, en el directorio “controllers” debería haber un archivo PHP que implementa el controlador
“libro”, el archivo tendrá el nombre “apps.biblioteca.LibroController.class.php”. Abriendo ese archivo
veremos que la clase tiene una acción implementada, la cual devuelve el mensaje que veíamos
previamente (Bienvenido a su nueva aplicación!).


Creando una clase del modelo
Supongamos que nuestra aplicación debe gestionar libros, entonces necesitamos una clase que
modele un libro. Un libro tiene un título, un género, autor, fecha de edición, idioma y número de
páginas. Para crear esta clase, se deberían seguir los siguientes pasos:

   1. Ir al directorio /yupp/apps/biblioteca/model
   2. Ahí crear el archivo biblioteca.model.Libro.class.php
   3. Programar una clase que herede de PersistentObject
   4. Agregar un constructor al que se le pasan 2 parámetros:
           a. $args = array ()
           b. $isSimpleInstance = false
   5. Agregar llamada al constructor de la clase padre en el constructor de esta clase
   6. Copiar los métodos estáticos de alguna clase de ejemplo
   7. Agregar los atributos mencionados previamente:
           a. $this->addAttribute("titulo", Datatypes :: TEXT);
           b. $this->addAttribute("genero", Datatypes :: TEXT);
           c. $this->addAttribute("autor", Datatypes :: TEXT);
           d. $this->addAttribute("fecha", Datatypes :: DATETIME);
           e. $this->addAttribute("idioma", Datatypes :: TEXT);
           f. $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);
Vamos paso por paso

Luego de los primeros 5 pasos, deberíamos tener programada una clase como esta:

class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       parent :: __construct($args, $isSimpleInstance);
    }
}

Todas las clases del modelo deben heredar de PersistentObject para contar con las funcionalidades
de persistencia. El constructor debe recibir estos dos parámetros para que internamente la clase
PersistentObject realice las tareas necesarias para crear una clase persistente. Esas tareas son
ejecutadas al hacer una llamada explícita al constructor de la clase padre, que en este caso es la
única línea de código dentro del constructor de Libro.
En el paso 6 se indica que deben copiarse los métodos estáticos, estos métodos permiten realizar
distintas operaciones de persistencia y consulta sobre la clase. Luego del paso 6, la clase deberá
quedar así:

class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       parent :: __construct($args, $isSimpleInstance);
    }

    public static function listAll(ArrayObject $params)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: listAll($params);
    }
    public static function count()
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: count();
    }
    public static function get($id)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: get($id);
    }
    public static function findBy(Condition $condition, ArrayObject $params)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: findBy($condition, $params);
    }
    public static function countBy(Condition $condition)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: countBy($condition);
    }
}
Por último, en el paso 7 agregamos los campos de la clase, cada uno con su respectivo tipo. Es
necesario definir el tipo del campo de forma explícita porque PHP no permite definir tipos para los
campos o atributos de una clase, porque PHP es debilmente tipado. Pero para indicarle a la base de
datos de qué tipo serán las columnas de la tabla donde se persistan instancias de la clase Libro, es
necesario la definición de los tipos.

Luego de realizado el paso 7, la clase completa quedaría así:

class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       $this->addAttribute("titulo", Datatypes :: TEXT);
       $this->addAttribute("genero", Datatypes :: TEXT);
       $this->addAttribute("autor", Datatypes :: TEXT);
       $this->addAttribute("fecha", Datatypes :: DATETIME);
       $this->addAttribute("idioma", Datatypes :: TEXT);
       $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);

        parent :: __construct($args, $isSimpleInstance);
    }

    public static function listAll(ArrayObject $params)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: listAll($params);
    }
    public static function count()
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: count();
    }
    public static function get($id)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: get($id);
    }
    public static function findBy(Condition $condition, ArrayObject $params)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: findBy($condition, $params);
    }
    public static function countBy(Condition $condition)
    {
       self :: $thisClass = __CLASS__;
       return PersistentObject :: countBy($condition);
    }
}
Para que nuestro controlador sepa de la existencia de la nueva clase del modelo y la pueda utilizar,
debemos incluirla usando YuppLoader, así LibroController tendrá este aspecto:

YuppLoader::load('biblioteca.model', 'Libro');

class LibroController extends YuppController {

    public function indexAction()
    {
       return $this->renderString("Bienvenido a su nueva aplicacion!");
    }
}



Suponiendo que ya tenemos la base de datos configurada y corriendo, procedamos a crear la
estructura de la base para poder gestionar los libros.

    1. Ingresar al escritorio de Yupp desde un navegador web
    2. Ingresar a las pestaña “Base de Datos”
    3. Debemos ver una zona para la aplicación “biblioteca”, donde se muestra que la clase Libro se
        almacena en cierta tabla, la cual aún no fue creada.
    4. Hacer clic en el link “Crear tablas”
    5. Si todo salió bien, en la zona de la aplicación “biblioteca” debería decir que la tabla para la
        clase Libro fue creada.
    6. Volvemos al listado de aplicaciones (escritorio de Yupp) y hacemos clic sobre el icono de la
        aplicación “biblioteca”.
    7. Si vemos el mensaje “Bienvenido a su nueva aplicacion!”, debemos estar en la siguiente
        URL: http://localhost/yupp/biblioteca/libro/index
    8. Cambiar la url a: http://localhost/yupp/biblioteca/libro/list
    9. El framework nos debería mostrar una vista con el listado de libros, sin ningún libro. Podemos
        apreciar una tabla que muestra todos los atributos de nuestra clase Libro.
    10. Si hacemos clic en el link “Create”, nos debería mostrar una vista donde podemos ingresar
        toda la información de un Libro.
    11. Cuidado con la fecha, ingresarla con el siguiente formato: aaaa-mm-dd
    12. Al hacer clic en el botón “Create”, debemos estar en una vista que muestra los datos
        ingresado.
    13. Volvemos al listado cliqueando en el link “list”, y nos debería mostrar el libro recién ingresado.
    14. Podemos seguir agregando libros, editando sus datos, o eliminándolos.


Algunos comentarios respecto a los pasos previos:

Generación de estructuras en la base de datos:
Toda la generación de tablas y relaciones en la base de datos la realiza el framework de forma
automática, en base a las clases definidas en el modelo de cada aplicación.

Vistas dinámicas:
Todas las vistas que se ven en el flujo de uso de la aplicación (listado, detalles del libro, creación,
edición) son autogenerdas, no fueron programadas como parte de la aplicación.

Acciones dinámicas:
Todas las acciones de listado, altas, bajas y modificaciones están implementadas en el framework, el
programador nunca implementó estas operaciones. Es más, en el controlador LibroController, donde
estas operaciones deben ser implementadas, vemos implementada solo la acción “index”.

Por lo tanto, sin necesidad de programar una aplicación completa, ya se tiene una aplicación
funcional para mostrar y probar. Tampoco es necesario invertir tiempo en diseñar la estructura de la
base de datos, porque también es autogenerada por el framework. Esto es gran parte de la agilidad
que agrega el framework al desarrollo de aplicaciones web.
7. Estructura de las aplicaciones Yupp
Siguiendo con el ejemplo de la aplicación “biblioteca”, en esta sección veremos la estructura interna
de las aplicaciones de Yupp. La estructura generada por el framework para la aplicación “biblioteca”
es la siguiente:

   ●   apps
          ○    biblioteca
                 ■ bootstrap
                 ■ config
                 ■ controllers
                 ■ i18n
                 ■ model
                 ■ services
                 ■ utils
                 ■ views
                 ■ app.xml


/apps
Directorio donde se ubican las aplicaciones instaladas en el framework, tanto para desarrollo como
para su uso por usuarios finales.

/apps/biblioteca
Directorio de la aplicación “biblioteca”.

/apps/biblioteca/bootstrap
Directorio donde se ubican los scripts de arranque de la aplicación. Estos scripts sirven para agregar
datos en la base de datos para la correcta ejecución de la aplicación, por ejemplo se pueden dar de
alta usuarios administradores.

/apps/biblioteca/config
Directorio donde se colocará todo recurso relativo a la configuración de la aplicación.

/apps/biblioteca/controllers
Directorio que contienen los controladores de la aplicación.

/apps/biblioteca/i18n
Directorio donde se colocarán los scripts de traducción (internacionalización) de la aplicación.

/apps/biblioteca/model
Directorio que contiene las clases del modelo de información persistente de la aplicación.

/apps/biblioteca/services
Directorio que contiene las clases que implementan la lógica de negocio de la aplicación.
/apps/biblioteca/utils
Direcorio donde se coloca todo recurso auxiliar para el correcto funcionamiento de la aplicación.

/apps/biblioteca/views
Directorio que contiene las vistas de la aplicación, estas contienen toda la lógica de la interfaz de
usuario de la aplicación.

/apps/biblioteca/app.xml
Descriptor de aplicaciones, que contiene metadatos de la aplicación que son accedidos por el
framework y se utilizarán en el futuro para gestionar aplicaciones.


La estructura mínima para las aplicaciones Yupp podría considerarse similar a la siguiente:

   ●   boostrap
   ●   controllers
   ●   model
   ●   views
   ●   app.xml

Todos los demás directorios que no se utilicen, pueden ser eliminados.



7.1 Configuración de la base de datos por aplicación
En la sección 3.3 se mostró cómo configurar la base de datos en Yupp. Esta configuración es global,
o sea que todas las aplicaciones utilizarán la misma base de datos, con la misma configuración. Esto
no siempre es deseable, por lo que Yupp soporta la configuración de bases de datos por aplicación.



7.1.1 Creando la configuración

Por ejemplo, si quisiéramos que la aplicación “biblioteca” tuviera su propia base de datos,
deberíamos seguir los siguientes pasos:

   1. Si el directorio “config” no existe dentro de “apps/biblioteca”, crearlo.
   2. Dentro de “apps/biblioteca/config”, crear el archivo “db_config.php”
   3. Dentro del archivo, colocar el siguiente código PHP:


$db = array(
         'type'        =>   'mysql',
         'url'         =>   'localhost',
         'user'        =>   'root',
         'pass'        =>   '',
         'database'    =>   'yupp_biblioteca'
      );
El array $db contiene todos los datos de configuración de la base de datos para la aplicación
“biblioteca”. En la clave “type” debe ponerse alguno de estos valores: “mysql”, “sqlite” o “postgres”.
Estos valores están definidos en “core/config/core.config.YuppConfig.class.php”. En el futuro cuando
se soporten otros motores de bases de datos, también podrá elegirse entre ellos. La clave “url” indica
el servidor donde se encuentra instalado el motor de bases de datos. Las claves “user” y “pass” son
usadas para poder acceder a la base de datos. Y por último, la clave “database” define el nombre de
la base de datos que estará utilizando nuestra aplicación.

No es necesaria ninguna otra configuración. Si se cumplen las convenciones de nombrado y
ubicación de los archivos, Yupp framework por sí solo encontrará la configuración y la utilizará.



7.2 Script de bootstrap
Opcionalmente, cada aplicación puede tener un script de boostrap (arranque). Este script se
ejecutará una sola vez luego de instalar la aplicación dentro del framework, y servirá para dar de alta
información necesaria para el correcto funcionamiento de dicha aplicación, como por ejemplo los
usuarios administradores de la aplicación.

El script de bootstrap debe estar situado en el directorio “bootstrap” de la aplicación, y dentro del
directorio un archivo llamado “apps.biblioteca.bootstrap.Bootstrap.script.php” (este sería el nombre
del script de bootstrap para la aplicación “biblioteca”).

Se tienen planes para que en el futuro pueda haber un script de boostrap para cada modo de
ejecución (desarrollo, producción y testing).



7.3 Scripts de testing
Hoy Yupp Framework soporta la definición y ejecución de casos de testing. Este soporte es el
mínimo necesario para estos fines. Se tienen planificadas varias mejoras para el área de testing.

Los casos de testing se definen dentro del directorio “tests” de las aplicaciones Yupp. Un caso de
testing es una clase que hereda de TestCase (clase provista por el framework), donde es necesario
definir el método run(). Por ejemplo, la implementación de un caso de test podría ser el siguiente:

YuppLoader::load('core.testing', 'TestCase');

class TestCase001 extends TestCase {

   private $var = 0;

   public function run()
   {
      $this->test1();
      $this->test2();
      $this->reset();
   }
public function test1()
    {
       $this->var++;

        $this->assert( $this->var == 1, 'Test igual a 1' );
        $this->assert( $this->var != 0, 'Test distinto de 0' );
    }

    public function test2()
    {
       $this->assert( is_numeric($this->var, 'Test is_numeric' );
    }

    public function reset()
    {
       $this->var = 0;
    }
}



El caso de testing debe implementar el método run(), luego dentro de este se invocan todos los
métodos definidos por el programador, que son los que implementan el caso de testing. No hay
restricciones sobre los nombres de los métodos (aparte del método run()).
8. Model: funcionalidades avanzadas
En la sección 1.2 se tuvo una introducción al ORM de Yupp, mostrando cómo se definían las clases
del modelo y los distintos tipos de relaciones entre estas clases. También se mencionó cómo esas
clases y relaciones eran mapeadas a una estructura de base de datos. En esta sección se verán
otros aspectos interesantes que complementan los ya vistos.


8.1 Gestionando relaciones hasOne
Supongamos que la clase Libro que definimos previamente en la sección 6, ahora en lugar de un
atributo “autor” tiene una relación hasOne a una clase Autor que definimos más abajo:

YuppLoader::load("biblioteca.model", "Autor");

class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       $this->addAttribute("titulo", Datatypes :: TEXT);
       $this->addAttribute("genero", Datatypes :: TEXT);
       $this->addAttribute("fecha", Datatypes :: DATETIME);
       $this->addAttribute("idioma", Datatypes :: TEXT);
       $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);

        $this->addHasOne("autor", "Autor");

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->addAttribute("nombre", Datatypes :: TEXT);
      $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}
Una forma sencilla de relacionar una instancia de Libro a una instancia de Autor es en la propia
construcción de las instancias:

$libro = new Libro(
   array(
     "titulo" => "El ingenioso hidalgo don Quixote de la Mancha",
     "genero" => "prosa narrativa",
     "fecha" => "1605-01-01",
     "idioma" => "es",
     "numeroPaginas" => 223,
     "autor" => new Autor(
       array(
          "nombre" => "Miguel de Cervantes Saavedra",
          "fechaNacimiento" => "1547-09-29"
       )
     )
   )
);



Otra forma de asociación es mediante el método dinámico “getX”, donde “X” es el nombre de un
atributo, por ejemplo el atributo hasOne. Entonces podríamos tener el siguiente código:

$libro = new Libro(
   array(
     "titulo" => "El ingenioso hidalgo don Quixote de la Mancha",
     "genero" => "prosa narrativa",
     "fecha" => "1605-01-01",
     "idioma" => "es",
     "numeroPaginas" => 223
   )
);

$autor = new Autor(
   array(
     "nombre" => "Miguel de Cervantes Saavedra",
     "fechaNacimiento" => "1547-09-29"
   )
);

$libro->setAutor( $autor );



Para obtener el autor de una instancia de Libro, se utiliza el método dinámico “getXXX”, donde “XXX”
es el nombre de un atributo, por ejemplo:

$autor = $libro->getAutor();
8.2 Gestionando relaciones hasMany
Para seguir con el ejemplo de los libros, supongamos que ahora Libro tiene una relación hasMany
para los coautores:

YuppLoader::load("biblioteca.model", "Autor");
class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       $this->addAttribute("titulo", Datatypes :: TEXT);
       $this->addAttribute("genero", Datatypes :: TEXT);
       $this->addAttribute("fecha", Datatypes :: DATETIME);
       $this->addAttribute("idioma", Datatypes :: TEXT);
       $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);
       $this->addHasOne("autor", "Autor");
       $this->addHasMany("coautores", "Autor");

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}

Si se tiene una instancia de Libro y dos instancias de Autor, tales que los autores son coautores del
libro, para asociar los coautores al libro se utiliza el método dinámico “addToX”, donde “X” es el
nombre de una relación hasMany, por ejemplo:

$libro = new Libro(...);
$coautor1 = new Autor(...);
$coautor2 = new Autor(...);

$libro->addToCoautores( $coautor1 );
$libro->addToCoautores( $coautor2 );

Para obtener todos los coautores de la instancia de Libro se utiliza el método dinámico “getX” al igual
que en el caso previo para obtener la instancia en la relación hasOne.

$coautores = $libro->getCoautores();

Para quitar un coautor del libro se utiliza el método dinámico “removeFromX”, donde “X” es el
nombre del atributo hasMany. Para invocar a esta operación, la instancia a remover de la relación
debe haber sido persistida en la base de datos, porque es necesario que la instancia tenga
identificador. El identificador solo se establece cuando la instancia es almacenada en la base de
datos.

$libro->removeFromCoautores( $coautor1 );

En este ejemplo es útil recalcar que $coautor1 es removido de la relación hasMany con $libro, pero
que la instancia $coautor1 no es eliminada y sigue persistida en la base de datos.
8.2.1 Tipos de relaciones hasMany

El ORM de Yupp soporta tres tipos distintos de comportamientos para las relaciones hasMany. Estas
relaciones pueden comportarse como colecciones, listas o conjuntos.


Colecciones
Por defecto las relaciones hasMany tienen este comportamiento, que consiste en no tener ningún
tipo de restricción sobre lo que se pone dentro de la relación. Los objetos no tienen orden ni se
verifican duplicados. Ejemplo:

$this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_COLECTION);



Listas
Una relación hasMany definida con comportamiento de lista, almacena el orden con que los objetos
son agregados a la relación. Esto sirve para obtener instancias persistentes, con el mismo orden en
el que fueron persistidas. Ejemplo:

$this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_LIST);



Conjuntos
Las relaciones hasMany definidas como conjuntos, implementan la restricción de verificación por
duplicados. Si en una relación hasMany definida como conjunto se intenta agregar dos veces el
mismo objeto, el segundo no será agregado. Esto funciona si los objetos que se agregan fueron
persistidos previamente. Ejemplo:

$this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_SET);



Nota: como el comportamiento por defecto es de colección, el primer ejemplo se comporta de igual
forma que el siguiente código, sin pasar el tercer parámetro:

$this->addHasMany("coautores", 'Autor');
8.3 Convenciones sobre nombrado de tablas
En la sección 1.2 se vio un ejemplo de clase persistente, donde se declaraba explícitamente el
nombre de la tabla en la base de datos donde las instancias de esa clase iban a ser persistidas. En
esta sección vamos a explicar cuáles son las convenciones en cuanto a los nombres de las tablas en
la base de datos.

8.3.1 Nombrado implícito de tablas

Se toma como nombrado implícito cuando no se define el nombre de la tabla de forma explícita en el
constructor de la clase persistente. En el caso que se vio en la sección 1.2, el nombrado de la tabla
era explícito, haciendo la siguiente invocación:

$this->setWithTable("nombre_de_la_tabla");

En el caso de la aplicación “biblioteca” con la que venimos trabajando, la clase Libro no hace un
nombrado explícito. Por lo tanto se aplica la siguiente convención de Yupp:

Cuando no hay nombrado explícito de la tabla donde se persistirán las instancias de cierta clase del
modelo de información de una aplicación Yupp, el nombre de la tabla será igual al nombre de la
clase en minúsculas.

O sea que para los siguientes nombres de clases, tendremos los siguientes nombres de tablas:

   ●   Libro => libro
   ●   BuenLibro => buenlibro
   ●   BuenLibro2 =>buelibro2



8.3.2 Nombrado explícito de tablas

En la sección anterior se comentó que es el nombrado explícito, que consiste en llamar al método
“setWithTable” con un determinado nombre de tabla. A continuación veremos distintos ejemplos para
los nombres de tablas y como Yupp reacciona ante ellos. Una restricción a considerar es que el
nombre de la tabla no puede contener caracteres que sean usados por los motores de bases de
datos, como por ejemplo el punto (“.”). Yupp no hace ningún tipo de verificación de estos caracteres,
por lo que el programador debe tener especial cuidado.

   ●   Nombre de la tabla: “libro”, nombre aceptado por Yupp: “libro”
   ●   Nombre de la tabla: “Libro”, nombre aceptado por Yupp: “libro”
   ●   Nombre de la tabla: “BuenLibro”, nombre aceptado por Yupp: “buenlibro”
   ●   Nombre de la tabla: “Buen_Libro”, nombre aceptado por Yupp: “buen_libro”
   ●   Nombre de la tabla: “Buen Libro”, nombre aceptado por Yupp: “buen_libro”
Las reglas de Yupp sobre los nombres especificados de forma explícita son:

    ●   El nombre especificado se convierte a minúsculas.
    ●   Si el nombre especificado tiene espacios, se convierten a guiones bajos.



8.3.3 Nombrado de tablas de join

Cuando una relación hasMany es definida, como se hizo previamente en la clase Libro, hacia la
clase Autor, con una relación llamada “coautores”, una tabla intermedia es creada para mantener las
relaciones. En el ejemplo de la aplicación “biblioteca”, esta tabla intermedia es una tabla de join que
sirve para persistir y obtener todos los coautores de un determinado libro.

El nombre de la tabla de join para el caso mencionado será “libro_coautores_autor”, debido a que la
clase donde se define la relación se persiste en la tabla “libro”, a que la clase relacionada se persiste
en la tabla “autor”, y a que la relación se llama “coautores”.



8.4 Creando restricciones sobre campos y relaciones
Las clases persistentes permiten la definición de restricciones sobre los campos declarados en dicha
clase.

8.4.1 Definiendo restricciones

Tomando el ejemplo de la clase Autor, de la aplicación “biblioteca”, podemos definir que el nombre
del autor no puede ser vacío. Existen dos formas de hacerlo, la primera es usando la restricción
“blank”. Aquí el ejemplo completo:

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->addAttribute("nombre", Datatypes :: TEXT);
      $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        $this->addConstraints("nombre", array(
            Constraint::blank(false)
        ));

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}

Entonces, utilizamos blank(false) para indicar que el campo “nombre” no puede ser vacío. Es
necesario diferenciar el caso de un string vacío del caso de un sting null. Si se desea que el nombre
del autor tampoco sea null, debe especificarse una restricción como la siguiente:
// Restricciones
        $this->addConstraints("nombre", array(
            Constraint::nullable(false),
            Constraint::blank(false)
        ));

Mediante la restricción “minLength” que restringe la cantidad de caracteres mínima que debe tener
un campo de tipo TEXT. Por ejemplo podríamos usar la siguiente restricción para indicar que el
nombre debe tener por lo menos 1 carácter y lograr el mismo comportamiento que con
“blank(false)”.:

        // Restricciones
        $this->addConstraints("nombre", array(
            Constraint::minLength(1)
        ));

Si quisiéramos restringir el largo máximo del nombre, por ejemplo a 100 caracteres, utilizaríamos la
restricción “maxLength”:

        // Restricciones
        $this->addConstraints("nombre", array(
            Constraint::blank(false),
            Constraint::maxLength(100)
        ));

Como vemos, es posible definir varias restricciones para el mismo campo. Ahora, si quisiéramos
definir restricciones para campos numéricos, por ejemplo el campo “numeroPaginas” de la clase
Libro, podríamos decir que un libro debe tener como mínimo 20 páginas y como máximo 3000:

        // Restricciones
        $this->addConstraints("numeroPaginas", array(
            Constraint::min(20),
            Constraint::max(3000)
        ));

Este par de restricciones podría expresarse como una sola restricción “between”, la cual indica que
el valor de un campo debe estar entre dos valores datos, de la siguiente forma:

        // Restricciones
        $this->addConstraints("numeroPaginas", array(
            Constraint::between(20, 3000)
        ));

Para ver todas las restricciones disponibles acceder a:
http://code.google.com/p/yupp/source/browse/YuppPHPFramework/core/validation/core.validation.Constraints.class.php
8.4.2 Verificando restricciones

Existen dos formas de verificar restricciones sobre los valores que tienen los campos de una clase
persistente. La primera es utilizando el método “validate” de PersistentObject, la segunda es
utilizando el método “save” de PersistentObject.


8.4.2.1 Validando datos mediante restricciones

El siguiente es un ejemplo de validación utilizando el método validate($validateCascade = false)

$autor = new Autor();
$autor->setNombre("");
if (!$autor->validate()) print_r( $autor->getErrors() );

Como al crear la instancia de Autor, se se establece el valor del campo nombre en un string vacío,
violara la restricción de no vacío que fue definida previamente. Por lo tanto, “validate” devolverá
“false” y mediante el método “getErrors” se obtendrán los errores de validación, y lo que se imprime
será parecido a esto:

Array (
   [nombre] => Array (
      [0] => El valor del atributo 'nombre' no puede ser vacio
   )
)

El método “validate” puede recibir opcionalmente un booleano que indica si la validación debe
hacerse en cascada, o sea, si debería ejecutarse sobre la instancia actual y sobre las instancias de
otras clases que tenga relacionadas. Por defecto la validación no se ejecuta en cascada.


8.4.2.2 Validando datos previa a la persistencia

De forma análoga a “validate”, al ejecutar el método “save” también se validan los datos. Esto quiere
decir que cada vez que se desee persistir una instancia de una clase, internamente se invoca al
método “validate”. En el caso que los valores de los campos de la instancia violen alguna de las
restricciones definidas en la clase, la instancia no es persistida y se generan todos los mensajes de
error para cada campo y cada restricción violada. Esto último es accesible mediante el método
“getErrors”. Por lo tanto, el siguiente código producirá el mismo resultado que el del ejemplo anterior
(notar que se invoca a save y no a validate):

$autor = new Autor();
$autor->setNombre("");
if (!$autor->save()) print_r( $autor->getErrors() );
8.5 Definiendo lógica pre-validación
La clase PersistentObject tiene un método protegido “preValidate” (para ser implementado
opcionalmente por sus subclases), el cual es ejecutado previamente a la validación. Este método fue
ideado para modificar los valores de los campos de la clase, previamente a la ejecución de la
validación. Esto tiene varias utilidades.

Validación forzada de restricciones
Si en el método “preValidate” se detecta que un campo no cumple con cierta restricción, o sea que al
verificar la restricción el valor no cumplirá con dicha restricción, se puede modificar el valor del
campo para que cumpla con la restricción y así no se generen errores de validación. Un ejemplo
podría ser si un valor es null, teniendo una restricción “nullable(false)”, y en “preValidate” se cambia
el valor por un string vacío.

Limpieza de valores
Es común que cuando un usuario ingresa algún texto, este venga con espacios o fines de línea
extras al principio o al final. Si ese tipo de valores son asignados en campos de texto de una clase
persistente, dentro del método “preValidate” podría implementarse una limpieza del texto.
Esto podría servir también para aumentar la seguridad sobre lo que se inserta en la base de datos,
ya que un texto podría tener caracteres inválidos, o incluso código javascript o SQL ingresado por un
usuario malicioso, esto también puede detectarse y limpiarse en el método “preValidate”. A
continuación se muestra un ejemplo que quita espacios extra que pueden venir para el campo
“nombre” del autor.

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      // Campos
      $this->addAttribute("nombre", Datatypes :: TEXT);
      $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

       // Restricciones
       $this->addConstraints("nombre", array(
           Constraint::blank(false)
       ));

       parent :: __construct($args, $isSimpleInstance);
    }
    protected function preValidate()
    {
       $nombre = $this->getNombre();
       if ( !is_null($nombre) ) $this->setNombre( trim($nombre) );
    }

    // Métodos estáticos omitidos
}
8.6 Usando belongsTo
En el ORM de Yupp, hay varias operaciones que pueden realizarse en cascada, o sea que se
aplican sobre una instancia de cierta clase persistente, y sobre las instancias de otras clases
persistentes que tenga asociada. Para esto se necesita la propiedad “belongsTo”, que indica cuál es
el lado fuerte y cuál el débil en una relación entre dos clases. Por ejemplo, si se tienen dos clases A
y B, “A hasOne B” y “B belongsTo A”, el lado fuerte de la relación es A y el débil es B.

Esta propiedad de las relaciones entre clases puede ser definida de forma explícita, o Yupp puede
inferirla mediante convenciones. A continuación se muestras todos los tipos de relaciones entre 2
clases A y B, y cuál lado es considerado fuerte y cuál débil por Yupp en el caso de no definir de
forma explícita la propiedad belongsTo.

Notación:
   ● A(*)->(1)B: indica que la clase A tiene una relación unidireccional a B, con A hasOne B.
   ● A(*)<->(1)B: indica que la clase A tiene una relación bidireccional a B, con A hasOne B y B
       hasMany A.

Casos:
   1. A(*)->(1)B: Yupp no sabe cual lado es el fuerte, se necesita belongsTo explícito.
   2. A(1)<->(1)B: Yupp no sabe cual es el lado fuerte, se necesita belongsTo explícito.
   3. A(1)->(*)B: Yupp considera que B belongsTo A
   4. A(1)<->(*)B: Yupp considera que B belongsTo A
   5. A(*)->(*)B: Yupp considera que B belongsTo A
   6. A(*)<->(*)B: Yupp no sabe cual es el lado fuerte, se necesita belongsTo explícito.


Para ejemplificar estos casos, volvamos a la aplicación biblioteca, donde el modelo es el siguiente:

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      // Campos
      $this->addAttribute("nombre", Datatypes :: TEXT);
      $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        // Restricciones
        $this->addConstraints("nombre", array(
            Constraint::blank(false)
        ));

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}
class Libro extends PersistentObject {

    function __construct($args = array (), $isSimpleInstance = false)
    {
       $this->addAttribute("titulo", Datatypes :: TEXT);
       $this->addAttribute("genero", Datatypes :: TEXT);
       $this->addAttribute("fecha", Datatypes :: DATETIME);
       $this->addAttribute("idioma", Datatypes :: TEXT);
       $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);

        $this->addHasOne("autor", "Autor");
        $this->addHasMany("coautores", "Autor");

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}

O sea que:
   ● Libro hasOne Autor
   ● Libro hasMany Autor (coautores)
   ● No se ha declarado belongsTo explícito en ninguna clase

Con este modelo, podemos ejecutar el siguiente caso de prueba:

$libro = new Libro(
   array(
     "titulo" => "El ingenioso hidalgo don Quixote de la Mancha",
     "genero" => "prosa narrativa",
     "fecha" => "1605-01-01",
     "idioma" => "es",
     "numeroPaginas" => 223,
     "autor" => new Autor( array(
       "nombre" => "Miguel de Cervantes Saavedra",
       "fechaNacimiento" => "1547-09-29"
     )),
     "coautores" => array(
       new Autor( array(
          "nombre" => "Sancho Panza",
          "fechaNacimiento" => "1547-01-01"
       )),
       new Autor( array(
          "nombre" => "Quijote",
          "fechaNacimiento" => "1542-05-21"
       ))
     )
   )
);

if( !$libro->save() ) print_r( $libro->getErrors() );
Al ejecutar este caso de prueba, veremos que en la base de datos se ha guardado el libro y sus
coautores (en cascada), pero no se ha guardado su Autor. Esto se debe a que la relación “autor”
declarada en la clase Libro, entra en el caso 1 de la inferencia de belongsTo por Yupp framework,
por lo que si queremos que se persista también esa relación a Autor, debemos declarar un
belongsTo explícito en la clase Autor:

YuppLoader::load("biblioteca.model", "Libro");

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->belongsTo = array( 'Libro' );

        // Campos
        $this->addAttribute("nombre", Datatypes :: TEXT);
        $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        // Restricciones
        $this->addConstraints("nombre", array(
            Constraint::blank(false)
        ));

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}



Realizando este cambio en la clase Autor, el test anterior almacenará en cascada tanto al autor
como a los coautores del libro. Si luego de ejecutar el caso de prueba de la sección 8.5, ejecutamos
el siguiente caso de prueba, el primer autor tendrá entre sus libros al libro que lo tiene como autor:

$libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos
$autor = Autor::get(1); // Carga el autor con id=1 desde la base de datos
$autor->addToLibros($libro); // Agrega el libro a los libros del autor
if( !$autor->save() ) print_r( $autor->getErrors() ); // Intenta persistir
8.7 Definiendo relaciones de muchos a muchos
De la misma forma que se definen las relaciones de uno a muchos usando hasMany, se pueden
definir relaciones bidireccionales de muchos a muchos. Simplemente es necesario colocar una
referencia hasMany en cada una de las clases. Por ejemplo, si desde la clase Autor se quisieran
todos los libros que escribió, ser podría hacer la siguiente modificación al modelo:

class Autor extends PersistentObject
{
   function __construct($args = array (), $isSimpleInstance = false)
   {
      $this->belongsTo = array( 'Libro' );

        // Campos
        $this->addAttribute("nombre", Datatypes :: TEXT);
        $this->addAttribute("fechaNacimiento", Datatypes :: DATE);

        $this->addHasMany("libros", "Libro");

        // Restricciones
        $this->addConstraints("nombre", array(
            Constraint::blank(false)
        ));

        parent :: __construct($args, $isSimpleInstance);
    }

    // Métodos estáticos omitidos
}



Como vimos en las reglas de belongsTo en la sección previa, para definir relaciones de muchos a
muchos bidireccionales, uno de los lados debe tener declarado un belongsTo. En este caso dejamos
declarado el belongsTo en el Autor.



8.8 Eliminación física vs. eliminación lógica
Siempre que se quiera eliminar una instancia de una clase persistente, se debe ser cuidadoso con la
estrategia de eliminado a utilizar. En el caso de la eliminación física, el o los registros
correspondientes a la persistencia de la instancia a eliminar, serán borrados físicamente de la base
de datos y no se podrán recuperar sus datos. En cambio, con la eliminación lógica, los registros
siguen existiendo, pero tienen una marca de “eliminados”, esa marca es utilizada internamente por el
framework para saber que registros se encuentran activos y cuales fueron eliminados de forma
lógica.
El siguiente código elimina físicamente una instancia de Libro persistida en la base de datos:

$libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos
$libro->delete(); // Eliminación física



El siguiente código elimina lógicamente una instancia de Libro persistida en la base de datos:

$libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos
$libro->delete(true); // Eliminación física
9. Controladores
Cada aplicación Yupp puede tener un conjunto de controladores, los cuales procesan los pedidos del
usuario, e implementan determinada lógica.

Partiendo del ejemplo del controlador generado para la aplicación “biblioteca”, vamos a completarlo
para mostrar los conceptos detrás de la programación de controladores.

YuppLoader::load('biblioteca.model', 'Libro');

class LibroController extends YuppController {

    public function indexAction()
    {
       return $this->renderString("Bienvenido a su nueva aplicacion!");
    }
}




9.1 Convenciones
Ubicación:
Todos los controladores de una aplicación Yupp deben estar dentro el directorio “controllers” de la
aplicación, por ejemplo “biblioteca/controllers”.

Nombres:
En Yupp, los nombres de todas las clases empiezan en mayúsculas. El nombre de las clases que
implementan controladores debe terminar en “Controller”, por ejemplo “LibroController” o
“AutorController”.

Acciones:
Las acciones de un controlador son métodos especiales que pueden ser invocados mediante el
envío de una URL. En la sección 5 vimos cómo están formadas las URLs dentro de Yupp, y que una
parte de estas determina la acción a ejecutar. Un controladores puede además implementar métodos
que no son acciones, por ejemplo métodos auxiliares que son usados por las acciones.
Los nombres de los métodos que implementan acciones son públicos, comienzan en minúsculas y
terminan en “Action”. Además no reciben parámetros de forma explícita. Previamente vimos un
ejemplo con la acción “index” del controlador LibroController.

Retorno de acciones
Las acciones pueden tener varios tipos de retorno. En el ejemplo previo se vio un retorno del tipo
“renderString”, que simplemente muestra en pantalla un determinado texto. En general no vamos a
querer retornar un texto, si no una vista. Más adelante veremos como crear vistas, para esta sección
es suficiente con saber que una vista tiene un determinado nombre y que recibe un conjunto de
parámetros (modelo) que utiliza para generar una página web que se le mostrará al usuario.
Si una acción simplemente retorna sin un valor, Yupp intentará mostrar una vista que tenga al mismo
nombre de la acción que se está ejecutando. Por ejemplo, el siguiente código intentará mostrar una
vista llamada “index” (obviamente, si la vista no existe, ocurrirá un error).

   public function indexAction()
   {
      return;
   }

Una segunda opción, es especificar explícitamente el nombre de la vista. En este caso, el nombre de
la vista podría ser distinto al de la acción, pero igualmente intentaremos mostrar la vista “index”. Este
código logra el mismo efecto que el anterior.

   public function indexAction()
   {
      return $this->render("index");
   }

Digamos ahora que la vista “index” necesita algunos parámetros para mostrarse correctamente. El
controlador puede pasarle un conjunto de parámetros al retornar, por ejemplo el siguiente código
intentará mostrar una vista con el mismo nombre que la acción, o sea “index”, y recibirá un conjunto
de valores.

   public function indexAction()
   {
      return array( 'valor1' => 29, 'valor2' => 'hola' );
   }

Redirigiendo pedidos
Al terminar de ejecutar una acción, esta podría no decidir mostrar una vista, si no realizar una
redirección para ejecutar otra acción. Esto genera un nuevo pedido HTTP reentrante. A continuación
se muestra un ejemplo de acción que redirige el pedido a otra acción:

   public function indexAction()
   {
      return $this->redirect(
         array(
            "controller" => "autor",
            "action" => "show",
            "params" => array( "id" => 101, "mensaje" => "Hola mundo" )
         )
      );
   }

Si esta fuera la acción “index” de LibroController, lo que haría es redirigir el pedido a la acción “show”
de AutorController, enviándole como parámetros “id=101” y “mensaje=Hola mundo”. Los pedidos
HTTP reentrantes son enviados usando el método GET de HTTP, por lo tanto, el pedido sería para
la siguiente URL de Yupp:

               /yupp/biblioteca/autor/show?id=101&mensaje=Hola mundo
9.2 Acciones de infraestructura (scaffolded)
Como vimos en la sección 6, en el controlador LibroController podemos ejecutar acciones que no
están implementadas, como por ejemplo “list”, “show”, “edit” y “create”. Estas acciones se
encuentran implementadas en YuppController, la superclase de todos los controladores. En general
es suficiente la implementación por defecto, pero de ser necesario ejecutar cierta lógica particular,
estas acciones pueden ser implementadas en nuestros controladores. Un caso típico es cuando un
controlador no tiene ninguna clase del modelo de información asociada, por ejemplo LibroController
se encarga de las acciones sobre la clase Libro. Estas acciones se consideran de “infraestructura”
por que son acciones genéricas, capaces de ser aplicadas a cualquier clase del modelo persistente
de cualquier aplicación Yupp.

Existe otro conjunto de acciones que están implementadas en CoreController, el controlador que
implementa las acciones que se realizan desde el escritorio de Yupp. Por ejemplo, si accedemos a la
acción de infraestructura “list” del controlador LibroController mediante la siguiente URL, y luego
vamos al “show” del un libro haciendo clic en su identificador (crear uno si no hay ninguno), vamos a
ver un link hacia su autor relacionado (si tiene uno), haciendo clic ahí veremos los detalles del autor,
aunque no exista el controlador relacionado a la clase Autor.

Comenzamos aquí: http://localhost/yupp/biblioteca/libro/list
Terminamos aquí: http://localhost/yupp/core/core/show?app=biblioteca&class=Autor&id=1


Nota: para tener datos para probar, puedes ejecutar el test que crea un libro y le asocia un autor.



9.3 Recibiendo archivos
Un tipo especial de parámetro que puede ser recibido por el método POST de HTTP son los
archivos. Un usuario puede subir un archivo usando un formulario como este en una vista:

<form method="post" enctype="multipart/form-data">
   <input type="file" name="archivo" value="" />
</form>



Del lado del servidor, supongamos que el controlador que recibe el archivo, tiene una acción con el
siguiente código:

public function recibeArchivoAction()
{
   print_r($this->params);
}
Esta acción mostrará algo similar a esto:

Array (
   [file] => Array (
      [name] => HCE 004.jpg
      [type] => image/jpeg
      [tmp_name] => C:wamptmpphp77.tmp
      [error] => 0
      [size] => 162096
   )
)



Si quisiéramos cargar el contenido del archivo subido al servidor en una variable, por ejemplo para
guardarlo en la base de datos:

public function recibeArchivoAction()
{
   $filename = $this->params["tmp_name"];
   $imagen = FileSystem::read($filename);
}



Y si quisiéramos copiar el archivo a una ubicación determinada:

public function recibeArchivoAction()
{
   $filename = $this->params["tmp_name"];
   $ubicacion = "dir/subdir/nombreArchivo.jpg";

    if (move_uploaded_file($filename, $ubicacion))
    {
       echo "El archivo ha sido cargado correctamente.";
    }
    else
    {
       echo "Ocurrió un error al subir el archivo. No pudo guardarse.";
    }
}
9.4 Devolviendo XML o JSON
Previamente vimos como devolver un string desde una acción. El mismo mecanismo puede ser
usado para devolver un string XML o JSON. Estos serán casos de acciones que no devuelven vistas,
si no que implementan servicios para ser consumidos desde la interfaz de usuario (por ejemplo
mediante pedidos AJAX) o desde otros sistemas.



9.4.1 Programando una acción que devuelve JSON

Digamos que dentro de LibroController necesitamos una acción que devuelva los datos de un
determinado libro, pero lo queremos en notación JSON. Para lograrlo, podríamos implementar la
acción de la siguiente manera:

   public function jsonShowAction()
   {
      YuppLoader::load('core.persistent.serialize', 'JSONPO');

       $id = $this->params['id'];        // Obtiene el parámetro id
       $libro = Libro::get( $id );       // Carga el libro con ese id
       $json = JSONPO::toJSON( $libro ); // Genera la serialización a json

       // Lo que se devolverá en el response HTTP será de tipo json
       header('Content-type: application/json');

       // Escribe el string json en la respuesta al usuario
       return $this->renderString( $json );
   }

La URL Yupp para invocar a esta acción, sería: http://localhost/yupp/biblioteca/libro/jsonShow?id=1

Lo que obtendremos será algo así:

   {
       titulo: "El ingenioso hidalgo don Quixote de la Mancha"
       genero: "prosa narrativa"
       fecha: "1605-01-01 00:00:00"
       idioma: "es"
       numeroPaginas: "223"
       class: "Libro"
       deleted: ""
       autor_id: "1"
       id: "1"
   }
9.4.2 Programando una acción que devuelve XML

Análogamente al ejemplo de JSON, podemos necesitar programar una acción que devuelva XML.

   public function xmlShowAction()
   {
      $id = $this->params['id'];
      $libro = Libro::get( $id );
      $xml = XMLPO::toXML( $libro );

       header('Content-type: text/xml');
       return $this->renderString( $xml );
   }



La URL Yupp para invocar a esta acción, sería: http://localhost/yupp/biblioteca/libro/xmlShow?id=1

Y el resultado es parecido a este XML:

<Libro>
  <titulo>El ingenioso hidalgo don Quixote de la Mancha</titulo>
  <genero>prosa narrativa</genero>
  <fecha>1605-01-01 00:00:00</fecha>
  <idioma>es</idioma>
  <numeroPaginas>223</numeroPaginas>
  <class>Libro</class>
  <deleted/>
  <autor_id>1</autor_id>
  <id>1</id>
</Libro>
10. Vistas
Las vistas implementan la interfaz de usuario de las aplicaciones Yupp. Es común que las
aplicaciones tengan una vista para listar instancias de cierta clase persistente, otra vista para ver los
detalles de una instancia, otra para crear nuevas instancias y otra para editar instancias. En esta
sección veremos los distintos aspectos involucrados en la creación de este tipo de vistas y de otros
tipos de vistas más complejos.



10.1 Fundamentos para la implementación de vistas
Primero que nada, las vistas no son más que scripts PHP que solo contienen lógica de interfaz de
usuario, o sea que:

   ●   Una vista no debería contener lógica de negocio
   ●   Una vista no debería contener consultas complejas a la base de datos
   ●   Una vista no debería modificar el estado de la aplicación


Las vistas son colocadas en el directorio “views” de las aplicaciones Yupp, con la característica de
que las vistas se organizan según los controladores que las muestran. Por ejemplo, si para el
controlador LibroController, se tuviera una vista llamada “list”, esta vista estaría implementada en la
siguiente ubicación:
                                apps/biblioteca/views/libro/list.view.php


La convención de nombrado de vistas es simple: el archivo debe terminar en “.view.php”.
A continuación veremos un ejemplo de una vista para el listado de libros:

<?php
   // Modelo pasado desde el controlador
   $m = Model::getInstance();
?>
<html>
   <head>
     <style>
       table {
          border: 1px solid;
       }
       td {
          border: 1px solid;
          padding: 5px;
       }
     </style>
   </head>
   <body>
     <h1>Libros</h1>
<table>
      <!-- El controlador puso la lista de libros en la clave 'libros' -->
      <?php foreach( $m->get('libros') as $libro) : ?>
        <tr>
          <td><?php echo $libro->getTitulo(); ?></td>
          <td><?php echo $libro->getGenero(); ?></td>
          <td><?php echo $libro->getIdioma(); ?></td>
        </tr>
      <?php endforeach; ?>
    </table>
  </body>
</html>



La acción del controlador que especifica que se debe mostrar la vista anterior, puede ser algo así:

   public function listAction()
   {
      // Carga todos los libros desde la base de datos
      $libros = Libro::listAll($this->params);

       // Muestra la vista list enviándole los libros como modelo
       return array('libros' => $libros);
   }




10.2 Uso de helpers
Los helpers son componentes reusables de código que implementan lógica de interfaz de usuario.
Yupp implementa varios helpers que pueden ser utilizados en la programación de vistas, pero el
programador puede definir sus propios helpers cuando los necesite. En las siguientes secciones
veremos algunos helpers interesantes. Por una lista completa de helpers, puedes visitar la
documentación del proyecto: http://www.simplewebportal.net/yupp_framework_php_doc



10.2.1 Helper layout

Un layout sirve para reutilizar una estructura general entre varias vistas para la interfaz de usuario de
una aplicación. La forma de especificar que una vista utiliza un layout es mediante un etiqueta. Por
ejemplo, si la vista “list” del controlador LibroController (que vimos anteriormente) usara un layout
llamado “default”, el código de la vista sería el siguiente:

<?php
   // Modelo pasado desde el controlador
   $m = Model::getInstance();
?>
<html>
   <layout name="default" />
   <head>
     <style>
       table {
border: 1px solid;
      }
      td {
      border: 1px solid;
        padding: 5px;
      }
    </style>
  </head>
  <body>
    <h1>Libros</h1>
    <table>
      <!-- El controlador puso la lista de libros en la clave 'libros' -->
      <?php foreach( $m->get('libros') as $libro) : ?>
         <tr>
           <td><?php echo $libro->getTitulo(); ?></td>
           <td><?php echo $libro->getGenero(); ?></td>
           <td><?php echo $libro->getIdioma(); ?></td>
         </tr>
      <?php endforeach; ?>
    </table>
  </body>
</html>

Importante: la etiqueta que indica el layout a utilizar debe ir inmediatamente después de la etiqueta
“html”.

El código del layout puede ser similar a el siguiente, donde $head es todo lo que está dentro de la
etiqueta “head” de la vista que referencia al layout, y $body es todo lo que está dentro de la etiqueta
“body” de la vista que referencia al layout.

<html>
  <head>
    <style type="text/css">
    ...
    </style>
    <?php echo $head; ?>
  </head>
  <body>
    ...
    <div style="padding:10px;"><?php echo $body; ?></div>
  </body>
</html>

Los layouts son también scripts PHP, pero a diferencia de las vistas, deben cumplir con las
siguientes convenciones:

   ●   Deben mostrar a las variables $head y $ body.
   ●   El archivo debe terminar en “.layout.php”.
   ●   El archivo debe ubicarse en el directorio “views” de la aplicación.




10.2.2 Helper template
Los templates son otra forma de reutilizar código entre distintas vistas, pero a diferencia del layout
que es para reutilizar la estructura general de la vista, los templates reutilizan lógica de interfaz de
usuario interna a la vista. Por ejemplo si para mostrar el mismo objeto (podría ser una instancia de
Libro) se utilizara la misma lógica en varias vistas, esa lógica podría ponerse dentro de un template,
y reutilizar el template en dichas vistas. A continuación se muestra un ejemplo de cómo puede ser
una llamada a un template que muestra un libro con cierto formato:

Helpers::template( array("controller" => "libro",
                         "name"       => "details",
                         "args"       => array("libro" => $libro) ) );



Los templates también son scripts PHP cuyo nombre termina en “.template.php”, por ejemplo, el
template referenciado desde el código anterior es “libro.template.php”. Este template podrá tener
código PHP, HTML y de otros tipos. Por ejemplo, el template “libro” podría ser así:

<div>
  <b><?php echo $libro->getTitulo(); ?></b>
  (<?php echo $libro->getGenero(); ?>, <?php echo $libro->getIdioma(); ?>)
</div>



Entonces podríamos cambiar el código de la vista “list” (vista en la sección 10.2.1) para que utilice el
template:

<?php
   $m = Model::getInstance(); // Modelo pasado desde el controlador
?>
<html>
   <layout name="default" />
   <head>
     <style>
       table {
          border: 1px solid;
       }
       td {
          border: 1px solid;
          padding: 5px;
       }
     </style>
   </head>
   <body>
     <h1>Libros</h1>
     <!-- El controlador puso la lista de libros en la clave 'libros' -->
     <?php foreach( $m->get('libros') as $libro) : ?>
       <!-- Se le pasa el libro al template -->
       <?php Helpers::template( array(
           "controller" => "libro", "name" => "details",
           "args" => array("libro" => $libro)
       ) ); ?>
     <?php endforeach; ?>
   </body>
</html>



10.2.3 Helper javascript

El helper javascript es útil para controlar la inclusión de scripts javascript. Una posible llamada es la
siguiente:

<?php echo h("js",       array("name" => "jquery/jquery-1.5.1.min") ); ?>

El código PHP previo, generará el siguiente código HTML:

<script type="text/javascript" src="/yupp/js/jquery/jquery-1.5.1.min"></script>



10.2.4 Helper ajax link

El helper ajax link, sirve para crear links que al cliquearlos envían un pedido HTTP a una
determinada acción de un controlador, con la característica de que el pedido va por AJAX. Esto
ayuda a crear aplicaciones web más interactivas. Un ajax link podría ser creado de la siguiente
manera:

<?php echo Helpers::ajax_link( array(
   "app"        => "biblioteca",
   "controller" => "libro",
   "action"     => "jsonShow",
   "id"         => $libro>getId(),
   "body"       => "Obtener comentarios por Ajax",
   "after"      => "after_function",
   "before"     => "before_function" ) ); ?>



El código PHP previo, generará el siguiente código HMTL/Javascript:

<script type="text/javascript">
function ajax_link_0() {
  $.ajax({
      url: '/yupp/biblioteca/libro/jsonShow?id=1',
      beforeSend: before_function,
      success: after_function
  });
}
</script>

<a href="javascript:ajax_link_0()" target="_self" ">Obtener datos por Ajax</a>
El código previo indica que al hacer clic sobre el link, se llama a una función Javascript llamada
“before_function”, y al recibir la respuesta del servidor, se llama a la función “after_function”. Ambas
funciones deben ser implementadas por el programador, como se muestra a continuación:

<script type="text/javascript">
// Handlers para JQuery
  var before_function = function(req, json) {

      $('#estado').html( "Cargando..." );
  }

  var after_function = function(json) {

      var libro = json;
      alert(libro.titulo +' ('+ libro.genero +')');
      $('#estado').html( "" );
  }
</script>



Una característica es que el código Javascript generado, dependerá de la librería Javascript que el
programador referencie, esto quiere decir que la implementación de ajax link varía según si el
programador usa Prototype o jQuery. Esto es transparente al programador.



10.3 Vistas de infraestructura (scaffolded)
De la misma forma que las acciones básicas de los controladores (list, show, create, edit, delete)
están disponibles sin necesidad de programarlas, las vistas relacionadas a las acciones list, show,
create y edit, también son generadas por el framework, sin necesidad de programarlas.

Para indicarle a Yupp que se quiere utilizar una vista particular en lugar de las vistas de
infraestructura, simplemente se debe colocar el archivo de la vista, cumpliendo las convenciones de
nombrado y ubicación. No es necesario realizar ningún tipo de configuración extra.
11. Estado actual del proyecto
11.1 Hoja de ruta del proyecto
El proyecto tiene un camino marcado, con el objetivo de lograr una solución robusta, pequeña,
rápida y completa para el desarrollo de aplicaciones web sobre PHP. Ese camino ya está avanzado,
y este tutorial es prueba de ello. Para seguir el avance, y saber en qué puntos se están trabajando,
en nuestra wiki hay una “hoja de ruta”, donde se actualizan los cambios y mejoras realizadas al
framework, para cada versión del mismo.

                          http://code.google.com/p/yupp/wiki/Hoja_de_ruta



11.2 Información administrativa
Grupo de discusión
Donde realizar consultas, comentarios, compartir experiencias, código, recursos, etc.
http://groups.google.com/group/yuppframeworkphp

Blog
Donde se realizan anuncios y se publican temas interesantes relacionados con el framework y el
desarrollo web en general.
http://yuppframework.blogspot.com/

Twitter
Desde el escritorio del framework pueden ser accedidos los twitts relacionados con este, en general
son para hacer anuncios importantes con respecto al framework.
http://twitter.com/ppazos

Sitio del proyecto
Donde publicamos las liberaciones, las notas de las versiones, preguntas frecuentes. También aquí
están los reportes de bugs y el repositorio de código (SVN).
http://code.google.com/p/yupp/

Documentación del proyecto
Documentación de referencia para el programador.
http://www.simplewebportal.net/yupp_framework_php_doc

Weitere ähnliche Inhalte

Was ist angesagt?

Índice del libro "Hacking Web Technologies"
Índice del libro "Hacking Web Technologies"Índice del libro "Hacking Web Technologies"
Índice del libro "Hacking Web Technologies"Telefónica
 
Índice del libro de Windows Server 2016: Administración, Seguridad y Operaciones
Índice del libro de Windows Server 2016: Administración, Seguridad y OperacionesÍndice del libro de Windows Server 2016: Administración, Seguridad y Operaciones
Índice del libro de Windows Server 2016: Administración, Seguridad y OperacionesTelefónica
 
Índice del libro "Hacking Aplicaciones Web: SQL Injection"
Índice del libro "Hacking Aplicaciones Web: SQL Injection" Índice del libro "Hacking Aplicaciones Web: SQL Injection"
Índice del libro "Hacking Aplicaciones Web: SQL Injection" Telefónica
 
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"Telefónica
 
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWord
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWordÍndice del libro: "Python para pentesters" [2ª Edición] de 0xWord
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWordTelefónica
 
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWord
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWordÍndice del libro "Hacking Web Technologies" Silver Edition de 0xWord
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWordTelefónica
 
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...Telefónica
 
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...Telefónica
 
Postgres programmer josue
Postgres programmer josuePostgres programmer josue
Postgres programmer josueJosué Ruiz
 
J2EE Servlets Tutorial
J2EE Servlets TutorialJ2EE Servlets Tutorial
J2EE Servlets TutorialHicham QAISSI
 
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...Telefónica
 
Índice de libro: "Empire: Hacking Avanzado en el Red Team"
Índice de libro: "Empire: Hacking Avanzado en el Red Team"Índice de libro: "Empire: Hacking Avanzado en el Red Team"
Índice de libro: "Empire: Hacking Avanzado en el Red Team"Telefónica
 
Smarty 2.6.14 Docs
Smarty 2.6.14 DocsSmarty 2.6.14 Docs
Smarty 2.6.14 DocsGina
 

Was ist angesagt? (17)

Introduccion Ajax
Introduccion AjaxIntroduccion Ajax
Introduccion Ajax
 
Índice del libro "Hacking Web Technologies"
Índice del libro "Hacking Web Technologies"Índice del libro "Hacking Web Technologies"
Índice del libro "Hacking Web Technologies"
 
Introduccion a AJAX
Introduccion a AJAXIntroduccion a AJAX
Introduccion a AJAX
 
Índice del libro de Windows Server 2016: Administración, Seguridad y Operaciones
Índice del libro de Windows Server 2016: Administración, Seguridad y OperacionesÍndice del libro de Windows Server 2016: Administración, Seguridad y Operaciones
Índice del libro de Windows Server 2016: Administración, Seguridad y Operaciones
 
Índice del libro "Hacking Aplicaciones Web: SQL Injection"
Índice del libro "Hacking Aplicaciones Web: SQL Injection" Índice del libro "Hacking Aplicaciones Web: SQL Injection"
Índice del libro "Hacking Aplicaciones Web: SQL Injection"
 
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"
Índice del libro "Ataques en redes de datos IPv4&IPv6 (4ª Edición)"
 
Inicio de Programación VB .Net
Inicio de Programación VB .NetInicio de Programación VB .Net
Inicio de Programación VB .Net
 
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWord
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWordÍndice del libro: "Python para pentesters" [2ª Edición] de 0xWord
Índice del libro: "Python para pentesters" [2ª Edición] de 0xWord
 
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWord
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWordÍndice del libro "Hacking Web Technologies" Silver Edition de 0xWord
Índice del libro "Hacking Web Technologies" Silver Edition de 0xWord
 
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...
Índice del libro "Spring Boot & Angular: Desarrollo de Webapps seguras" de 0x...
 
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...
Índice del libro "Malware moderno: Técnicas avanzadas y su influencia en la i...
 
Postgres programmer josue
Postgres programmer josuePostgres programmer josue
Postgres programmer josue
 
J2EE Servlets Tutorial
J2EE Servlets TutorialJ2EE Servlets Tutorial
J2EE Servlets Tutorial
 
Manual de visual basic.net
Manual de visual basic.netManual de visual basic.net
Manual de visual basic.net
 
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...
Índice del libro "Machine Learning aplicado a Ciberseguridad: Técnicas y ejem...
 
Índice de libro: "Empire: Hacking Avanzado en el Red Team"
Índice de libro: "Empire: Hacking Avanzado en el Red Team"Índice de libro: "Empire: Hacking Avanzado en el Red Team"
Índice de libro: "Empire: Hacking Avanzado en el Red Team"
 
Smarty 2.6.14 Docs
Smarty 2.6.14 DocsSmarty 2.6.14 Docs
Smarty 2.6.14 Docs
 

Andere mochten auch

Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIG
Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIGTrabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIG
Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIGPablo Pazos
 
CaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadCaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadPablo Pazos
 
Proyecto traumagen cais jaiio 2010
Proyecto traumagen   cais jaiio 2010Proyecto traumagen   cais jaiio 2010
Proyecto traumagen cais jaiio 2010Pablo Pazos
 
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...Evaluación y propuestas sobre la integración de modalidades imagenológicas co...
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...Pablo Pazos
 
Sistema regional de trauma Uruguay, Argentina, Brasil
Sistema regional de trauma Uruguay, Argentina, BrasilSistema regional de trauma Uruguay, Argentina, Brasil
Sistema regional de trauma Uruguay, Argentina, BrasilPablo Pazos
 
openEHR ¿para qué sirve? HIBA2012
openEHR ¿para qué sirve? HIBA2012openEHR ¿para qué sirve? HIBA2012
openEHR ¿para qué sirve? HIBA2012Pablo Pazos
 
Workshop arquetipos openEHR CAIS 2012
Workshop arquetipos openEHR CAIS 2012Workshop arquetipos openEHR CAIS 2012
Workshop arquetipos openEHR CAIS 2012Pablo Pazos
 
openEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadopenEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadPablo Pazos
 
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...EHRGen: generador de sistemas de historia clínica electrónica basados en el e...
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...Pablo Pazos
 
Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Pablo Pazos
 
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...Marco de trabajo genérico para crear sistemas de historia clínica electrónica...
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...Pablo Pazos
 
Análisis de capacidades de transformacion de mensajes en jboss-esb
Análisis de capacidades de transformacion de mensajes en jboss-esb Análisis de capacidades de transformacion de mensajes en jboss-esb
Análisis de capacidades de transformacion de mensajes en jboss-esb Pablo Pazos
 
openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015Pablo Pazos
 
Towards an e health integration platform to support social security services
Towards an e health integration platform to support social security servicesTowards an e health integration platform to support social security services
Towards an e health integration platform to support social security servicesPablo Pazos
 
Arquitectura orientada a servicios para sistemas que utilizan hl7 tsi3
Arquitectura orientada a servicios para sistemas que utilizan hl7   tsi3Arquitectura orientada a servicios para sistemas que utilizan hl7   tsi3
Arquitectura orientada a servicios para sistemas que utilizan hl7 tsi3Pablo Pazos
 
EHRGen demo presentation
EHRGen demo presentationEHRGen demo presentation
EHRGen demo presentationPablo Pazos
 
Desarrollo profesional en Tecnologias de la Información desde Uruguay
Desarrollo profesional en Tecnologias de la Información desde UruguayDesarrollo profesional en Tecnologias de la Información desde Uruguay
Desarrollo profesional en Tecnologias de la Información desde UruguayPablo Pazos
 
Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Pablo Pazos
 
Introducción a openEHR para clinicos 2013
Introducción a openEHR para clinicos 2013Introducción a openEHR para clinicos 2013
Introducción a openEHR para clinicos 2013Pablo Pazos
 
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Pablo Pazos
 

Andere mochten auch (20)

Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIG
Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIGTrabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIG
Trabajo FEMI Monitoreo y Control de Problemas de Salud mediante SIG
 
CaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadCaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidad
 
Proyecto traumagen cais jaiio 2010
Proyecto traumagen   cais jaiio 2010Proyecto traumagen   cais jaiio 2010
Proyecto traumagen cais jaiio 2010
 
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...Evaluación y propuestas sobre la integración de modalidades imagenológicas co...
Evaluación y propuestas sobre la integración de modalidades imagenológicas co...
 
Sistema regional de trauma Uruguay, Argentina, Brasil
Sistema regional de trauma Uruguay, Argentina, BrasilSistema regional de trauma Uruguay, Argentina, Brasil
Sistema regional de trauma Uruguay, Argentina, Brasil
 
openEHR ¿para qué sirve? HIBA2012
openEHR ¿para qué sirve? HIBA2012openEHR ¿para qué sirve? HIBA2012
openEHR ¿para qué sirve? HIBA2012
 
Workshop arquetipos openEHR CAIS 2012
Workshop arquetipos openEHR CAIS 2012Workshop arquetipos openEHR CAIS 2012
Workshop arquetipos openEHR CAIS 2012
 
openEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadopenEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidad
 
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...EHRGen: generador de sistemas de historia clínica electrónica basados en el e...
EHRGen: generador de sistemas de historia clínica electrónica basados en el e...
 
Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...
 
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...Marco de trabajo genérico para crear sistemas de historia clínica electrónica...
Marco de trabajo genérico para crear sistemas de historia clínica electrónica...
 
Análisis de capacidades de transformacion de mensajes en jboss-esb
Análisis de capacidades de transformacion de mensajes en jboss-esb Análisis de capacidades de transformacion de mensajes en jboss-esb
Análisis de capacidades de transformacion de mensajes en jboss-esb
 
openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015
 
Towards an e health integration platform to support social security services
Towards an e health integration platform to support social security servicesTowards an e health integration platform to support social security services
Towards an e health integration platform to support social security services
 
Arquitectura orientada a servicios para sistemas que utilizan hl7 tsi3
Arquitectura orientada a servicios para sistemas que utilizan hl7   tsi3Arquitectura orientada a servicios para sistemas que utilizan hl7   tsi3
Arquitectura orientada a servicios para sistemas que utilizan hl7 tsi3
 
EHRGen demo presentation
EHRGen demo presentationEHRGen demo presentation
EHRGen demo presentation
 
Desarrollo profesional en Tecnologias de la Información desde Uruguay
Desarrollo profesional en Tecnologias de la Información desde UruguayDesarrollo profesional en Tecnologias de la Información desde Uruguay
Desarrollo profesional en Tecnologias de la Información desde Uruguay
 
Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013
 
Introducción a openEHR para clinicos 2013
Introducción a openEHR para clinicos 2013Introducción a openEHR para clinicos 2013
Introducción a openEHR para clinicos 2013
 
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
 

Ähnlich wie Tutorial manos a la obra con Yupp PHP Framework

Ähnlich wie Tutorial manos a la obra con Yupp PHP Framework (20)

Programacion Concurrente
Programacion ConcurrenteProgramacion Concurrente
Programacion Concurrente
 
Programacion concurrente
Programacion concurrenteProgramacion concurrente
Programacion concurrente
 
Windows 8 Guía Práctica
Windows 8 Guía PrácticaWindows 8 Guía Práctica
Windows 8 Guía Práctica
 
Adobe Actionscript 3.0
Adobe Actionscript 3.0Adobe Actionscript 3.0
Adobe Actionscript 3.0
 
pdf
pdfpdf
pdf
 
pdf
pdfpdf
pdf
 
Programacion.con.adobe.action.script.3.0
Programacion.con.adobe.action.script.3.0Programacion.con.adobe.action.script.3.0
Programacion.con.adobe.action.script.3.0
 
Conceptos informáticos generales
Conceptos informáticos generalesConceptos informáticos generales
Conceptos informáticos generales
 
Fwpa doc-desarrollo
Fwpa doc-desarrolloFwpa doc-desarrollo
Fwpa doc-desarrollo
 
Rapid manual operador Robot Studio ABB
Rapid manual operador Robot Studio ABBRapid manual operador Robot Studio ABB
Rapid manual operador Robot Studio ABB
 
Tutorial Jsf
Tutorial JsfTutorial Jsf
Tutorial Jsf
 
Tutorial JSF
Tutorial JSFTutorial JSF
Tutorial JSF
 
Formato proyecto i web fase 1
Formato proyecto i web fase 1Formato proyecto i web fase 1
Formato proyecto i web fase 1
 
Lujan.pdf
Lujan.pdfLujan.pdf
Lujan.pdf
 
Manual php5 basico
Manual php5 basicoManual php5 basico
Manual php5 basico
 
Manual php5 basico
Manual php5 basicoManual php5 basico
Manual php5 basico
 
Introduccion a xhtml
Introduccion a xhtmlIntroduccion a xhtml
Introduccion a xhtml
 
5. desarrollador web profesional
5. desarrollador web profesional5. desarrollador web profesional
5. desarrollador web profesional
 
Introduccion a xhtml
Introduccion a xhtmlIntroduccion a xhtml
Introduccion a xhtml
 
Introduccion a xhtml
Introduccion a xhtmlIntroduccion a xhtml
Introduccion a xhtml
 

Mehr von Pablo Pazos

Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Pablo Pazos
 
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Pablo Pazos
 
openEHR presentacion informativa 2017
openEHR presentacion informativa 2017openEHR presentacion informativa 2017
openEHR presentacion informativa 2017Pablo Pazos
 
CaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresCaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresPablo Pazos
 
CaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludCaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludPablo Pazos
 
CaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludCaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludPablo Pazos
 
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...Pablo Pazos
 
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Pablo Pazos
 
Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Pablo Pazos
 
Design and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRDesign and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRPablo Pazos
 
openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015Pablo Pazos
 
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Pablo Pazos
 
Developing openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesDeveloping openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesPablo Pazos
 
Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Pablo Pazos
 
Pablo Pazos Curriculum Vitae 2013-05-17
Pablo Pazos Curriculum Vitae 2013-05-17Pablo Pazos Curriculum Vitae 2013-05-17
Pablo Pazos Curriculum Vitae 2013-05-17Pablo Pazos
 
XRE demo presentation
XRE demo presentationXRE demo presentation
XRE demo presentationPablo Pazos
 
openEHR terminology binding
openEHR terminology bindingopenEHR terminology binding
openEHR terminology bindingPablo Pazos
 
Terminology in openEHR
Terminology in openEHRTerminology in openEHR
Terminology in openEHRPablo Pazos
 
Servicios Terminológicos
Servicios TerminológicosServicios Terminológicos
Servicios TerminológicosPablo Pazos
 
Estructura de la Historia Clínica Electrónica openEHR
Estructura de la Historia Clínica Electrónica openEHREstructura de la Historia Clínica Electrónica openEHR
Estructura de la Historia Clínica Electrónica openEHRPablo Pazos
 

Mehr von Pablo Pazos (20)

Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018
 
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
 
openEHR presentacion informativa 2017
openEHR presentacion informativa 2017openEHR presentacion informativa 2017
openEHR presentacion informativa 2017
 
CaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresCaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándares
 
CaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludCaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en salud
 
CaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludCaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en salud
 
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
 
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
 
Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...
 
Design and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRDesign and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHR
 
openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015
 
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
 
Developing openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesDeveloping openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalities
 
Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013
 
Pablo Pazos Curriculum Vitae 2013-05-17
Pablo Pazos Curriculum Vitae 2013-05-17Pablo Pazos Curriculum Vitae 2013-05-17
Pablo Pazos Curriculum Vitae 2013-05-17
 
XRE demo presentation
XRE demo presentationXRE demo presentation
XRE demo presentation
 
openEHR terminology binding
openEHR terminology bindingopenEHR terminology binding
openEHR terminology binding
 
Terminology in openEHR
Terminology in openEHRTerminology in openEHR
Terminology in openEHR
 
Servicios Terminológicos
Servicios TerminológicosServicios Terminológicos
Servicios Terminológicos
 
Estructura de la Historia Clínica Electrónica openEHR
Estructura de la Historia Clínica Electrónica openEHREstructura de la Historia Clínica Electrónica openEHR
Estructura de la Historia Clínica Electrónica openEHR
 

Kürzlich hochgeladen

El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.241514949
 
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúRed Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúCEFERINO DELGADO FLORES
 
FloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptxFloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptx241522327
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxAlexander López
 
Excel (1) tecnologia.pdf trabajo Excel taller
Excel  (1) tecnologia.pdf trabajo Excel tallerExcel  (1) tecnologia.pdf trabajo Excel taller
Excel (1) tecnologia.pdf trabajo Excel tallerValentinaTabares11
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptchaverriemily794
 
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6    CREAR UN RECURSO MULTIMEDIAActividad integradora 6    CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA241531640
 
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPO
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPOAREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPO
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPOnarvaezisabella21
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxaylincamaho
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptJavierHerrera662252
 
tarea de exposicion de senati zzzzzzzzzz
tarea de exposicion de senati zzzzzzzzzztarea de exposicion de senati zzzzzzzzzz
tarea de exposicion de senati zzzzzzzzzzAlexandergo5
 
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxCrear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxNombre Apellidos
 
La Electricidad Y La Electrónica Trabajo Tecnología.pdf
La Electricidad Y La Electrónica Trabajo Tecnología.pdfLa Electricidad Y La Electrónica Trabajo Tecnología.pdf
La Electricidad Y La Electrónica Trabajo Tecnología.pdfjeondanny1997
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxAlexander López
 
El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son241514984
 
Presentación sobre la Inteligencia Artificial
Presentación sobre la Inteligencia ArtificialPresentación sobre la Inteligencia Artificial
Presentación sobre la Inteligencia Artificialcynserafini89
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMidwarHenryLOZAFLORE
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx241523733
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadMiguelAngelVillanuev48
 
tics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxtics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxazmysanros90
 

Kürzlich hochgeladen (20)

El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.El uso de las TIC's en la vida cotidiana.
El uso de las TIC's en la vida cotidiana.
 
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del PerúRed Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
Red Dorsal Nacional de Fibra Óptica y Redes Regionales del Perú
 
FloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptxFloresMorales_Montserrath_M1S3AI6 (1).pptx
FloresMorales_Montserrath_M1S3AI6 (1).pptx
 
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptxEl_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
El_Blog_como_herramienta_de_publicacion_y_consulta_de_investigacion.pptx
 
Excel (1) tecnologia.pdf trabajo Excel taller
Excel  (1) tecnologia.pdf trabajo Excel tallerExcel  (1) tecnologia.pdf trabajo Excel taller
Excel (1) tecnologia.pdf trabajo Excel taller
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
 
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6    CREAR UN RECURSO MULTIMEDIAActividad integradora 6    CREAR UN RECURSO MULTIMEDIA
Actividad integradora 6 CREAR UN RECURSO MULTIMEDIA
 
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPO
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPOAREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPO
AREA TECNOLOGIA E INFORMATICA TRABAJO EN EQUIPO
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
 
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.pptTEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
TEMA 2 PROTOCOLO DE EXTRACCION VEHICULAR.ppt
 
tarea de exposicion de senati zzzzzzzzzz
tarea de exposicion de senati zzzzzzzzzztarea de exposicion de senati zzzzzzzzzz
tarea de exposicion de senati zzzzzzzzzz
 
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptxCrear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
Crear un recurso multimedia. Maricela_Ponce_DomingoM1S3AI6-1.pptx
 
La Electricidad Y La Electrónica Trabajo Tecnología.pdf
La Electricidad Y La Electrónica Trabajo Tecnología.pdfLa Electricidad Y La Electrónica Trabajo Tecnología.pdf
La Electricidad Y La Electrónica Trabajo Tecnología.pdf
 
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptxLAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
LAS_TIC_COMO_HERRAMIENTAS_EN_LA_INVESTIGACIÓN.pptx
 
El uso de las tic en la vida ,lo importante que son
El uso de las tic en la vida ,lo importante  que sonEl uso de las tic en la vida ,lo importante  que son
El uso de las tic en la vida ,lo importante que son
 
Presentación sobre la Inteligencia Artificial
Presentación sobre la Inteligencia ArtificialPresentación sobre la Inteligencia Artificial
Presentación sobre la Inteligencia Artificial
 
Mapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptxMapa-conceptual-del-Origen-del-Universo-3.pptx
Mapa-conceptual-del-Origen-del-Universo-3.pptx
 
GonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptxGonzalezGonzalez_Karina_M1S3AI6... .pptx
GonzalezGonzalez_Karina_M1S3AI6... .pptx
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidad
 
tics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptxtics en la vida cotidiana prepa en linea modulo 1.pptx
tics en la vida cotidiana prepa en linea modulo 1.pptx
 

Tutorial manos a la obra con Yupp PHP Framework

  • 1. Yupp PHP Framework Tutorial “manos a la obra” Autor: Ing. Pablo Pazos Gutiérrez <pablo.swp@gmail.com> Fecha: Mayo 2011 Versión: 1.1
  • 2. Índice 1. Fundamentos de patrones MVC y ORM...........................................................................................4 1.1 Model-View-Controller (MVC).....................................................................................................4 1.1.1 Algunos conceptos a importantes de recordar:....................................................................5 1.2 Object-Relational Mapping (ORM)..............................................................................................6 1.2.1 Mapeo objeto-relacional.......................................................................................................6 1.2.1.1 Mapeo de clase..............................................................................................................6 1.2.1.2 Mapeo de relaciones......................................................................................................7 1.2.1.3 Mapeos de herencia......................................................................................................8 2. Fundamentos de programación ágil y aplicaciones web.................................................................10 3. Instalación y configuración del framework......................................................................................12 3.1 Descargar la liberación.............................................................................................................12 3.2 Descargar del servidor de desarrollo........................................................................................13 3.3 Configuración del framework....................................................................................................14 4. Estructura de Yupp Framework......................................................................................................15 5. URLs en Yupp................................................................................................................................18 6. Creando una aplicación simple.......................................................................................................19 7. Estructura de las aplicaciones Yupp...............................................................................................24 7.1 Configuración de la base de datos por aplicación.....................................................................25 7.1.1 Creando la configuración....................................................................................................25 7.2 Script de bootstrap....................................................................................................................26 7.3 Scripts de testing......................................................................................................................26 8. Model: funcionalidades avanzadas.................................................................................................28 8.1 Gestionando relaciones hasOne...............................................................................................28 8.2 Gestionando relaciones hasMany.............................................................................................30 8.2.1 Tipos de relaciones hasMany.............................................................................................31 8.3 Convenciones sobre nombrado de tablas.................................................................................32 8.3.1 Nombrado implícito de tablas.............................................................................................32 8.3.2 Nombrado explícito de tablas.............................................................................................32 8.3.3 Nombrado de tablas de join................................................................................................33 8.4 Creando restricciones sobre campos y relaciones....................................................................33 8.4.1 Definiendo restricciones.....................................................................................................33 8.4.2 Verificando restricciones....................................................................................................35 8.4.2.1 Validando datos mediante restricciones.......................................................................35 8.4.2.2 Validando datos previa a la persistencia......................................................................35 8.5 Definiendo lógica pre-validación...............................................................................................36 8.6 Usando belongsTo....................................................................................................................37 8.7 Definiendo relaciones de muchos a muchos.............................................................................40 8.8 Eliminación física vs. eliminación lógica....................................................................................40 9. Controladores.................................................................................................................................42 9.1 Convenciones...........................................................................................................................42 9.2 Acciones de infraestructura (scaffolded)...................................................................................44 9.3 Recibiendo archivos..................................................................................................................44 9.4 Devolviendo XML o JSON........................................................................................................46 9.4.1 Programando una acción que devuelve JSON...................................................................46 9.4.2 Programando una acción que devuelve XML.....................................................................47 10. Vistas...........................................................................................................................................48 10.1 Fundamentos para la implementación de vistas.....................................................................48
  • 3. 10.2 Uso de helpers........................................................................................................................49 10.2.1 Helper layout....................................................................................................................49 10.2.2 Helper template................................................................................................................50 10.2.3 Helper javascript...............................................................................................................52 10.2.4 Helper ajax link.................................................................................................................52 10.3 Vistas de infraestructura (scaffolded)......................................................................................53 11. Estado actual del proyecto...........................................................................................................54 11.1 Hoja de ruta del proyecto........................................................................................................54 11.2 Información administrativa......................................................................................................54
  • 4. 1. Fundamentos de patrones MVC y ORM 1.1 Model-View-Controller (MVC) MVC es un patrón arquitectónico, que determina grandes componentes de software, a modo de capas, que se dividen las responsabilidades funcionales de un sistema informático. Es frecuente la asociación de MVC al modelo de 3 capas: interfaz de usuario, lógica de negocio y acceso a datos, donde “view” se asocia a la interfaz de usuario, “controller” a la lógica de negocio, y “model” al acceso a datos. Existen múltiples implementaciones de MVC, en esta sección veremos la alternativa de implementación elegida para Yupp Framework. En el siguiente diagrama se muestra un ciclo de pedido, donde se pasa por los 3 componentes de MVC. En el diagrama se muestra un modelo simplificado del MVC de Yupp Framewrok (YMVC), donde un usuario que realiza un pedido desde su navegador web, y este es atendido por el componente Controller. En Controller se ejecuta la lógica de negocio, se accede a los datos mediante el componente Model, donde se hacen consultas y actualizaciones. Luego el componente View es el que determina que respuesta se le dará al usuario. View también puede acceder a Model pero en general no accede directamente, sino que usa el resultado de la ejecución de la lógica, provisto por Controller. Luego Controller entrega la respuesta al usuario, en general es una página web con datos de las entidades del Model.
  • 5. 1.1.1 Algunos conceptos a importantes de recordar: ● Un controlador implementa cierta lógica que es ejecutada dependiendo del pedido recibido. ● La lógica se implementa en forma de acciones, cada acción es un método dentro del controlador. Un controlador puede tener varias acciones. ● Cada acción determina que vista se va a mostrar al usuario, lo que depende de los parámetros de entrada y la lógica que se ejecute. ● Desde una acción, se pueden mostrar varias vistas distintas, solo una a la vez. ● Cada acción determina que modelo pasarle a cada vista. A continuación se muestra un diagrama más detallado que se aproxima mejor a la implementación de YMVC. 1.1.2 Descripción de los componentes: Routing: se encarga de recibir un pedido del usuario y determinar qué controller lo debe atender. Una instancia de Yupp puede contener múltiples aplicaciones, cada una con múltiples controllers. Filter: es un componente que sirve para realizar acciones previas a la ejecución de la lógica del controller seleccionado. Es útil para realizar verificaciones de seguridad, por ejemplo verificar si el usuario tiene permisos para ejecutar la lógica del controller o no. Data Access Layer (DAL): componente que abstrae el acceso a distintos DBMS, de modo que el framework pueda trabajar, con MySQL o Postgres de forma transparente para el usuario.
  • 6. La clase RequestManager es la que se encarga de recibir los pedidos, procesar los parámetros, utilizar routing para determinar el controller y acción a ejecutar, procesar el resultado, y devolver una vista. También se encarga de procesar errores y mostrarlos de forma amigable al usuario. 1.2 Object-Relational Mapping (ORM) ORM es un mecanismo que permite trabajar con objetos en lugar de registros, en el acceso a bases de datos relacionales. Esto es de especial interés para quienes programamos usando Orientación a Objetos, porque evita la complejidad de tener que trabajar con estructuras de registros relacionales. Para ORM también existen múltiples alternativas de implementación, en esta sección nos concentraremos en la implementación de ORM elegida para Yupp (YORM). Objetivos principales de YORM: ● Definir modelos de datos complejos, completamente orientados a objetos ● Evitar al máximo trabajar con SQL ● Soportar múltiples gestores de bases de datos El primer objetivo implica que se deben soportar el mapeo de clases a tablas, el mapeo de relaciones entre clases, y el mapeo de herencia entre clases. El segundo objetivo implica que se utilizarán estructuras de clases para crear las consultas a las bases de datos, en lugar de utilizar SQL. Y el tercer objetivo implica que el framework se debe abstraer del gestor de bases datos. Como vimos en el MVC, esto se hace con el componente DAL. 1.2.1 Mapeo objeto-relacional 1.2.1.1 Mapeo de clase El primer problema a resolver es el de mapear una clase simple a una tabla en la base de datos relacional. Esto es relativamente sencillo de hacer en general, pero con PHP existe un problema agregado: PHP es dinámico y débilmente tipado, y las bases de datos utilizan registros fuértemente tipados, por lo que para cada campo de una clase programada en PHP, es necesario contar con un mecanismo de especificación del tipo, ya que PHP no lo tiene. El siguiente diagrama muestra la correspondencia entre la definición de una clase y su correspondiente mapeo a una tabla.
  • 7. La implementación de esta clase en Yupp es similar a este código: // Todas clas clases persistentes heredan de PersistentObject class Usuario extends PersistentObject { // Los campos se definen en el constructor function __construct($args = array (), $isSimpleInstance = false) { // Determina el nombre de la tabla $this->setWithTable("usuarios"); // Campos de la clase $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("email", Datatypes :: TEXT); $this->addAttribute("edad", Datatypes :: INT_NUMBER); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); // Llamada al constructor de la superclase // Inyecta atributos útiles para ORM (id, class, deleted) parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } 1.2.1.2 Mapeo de relaciones Habiendo definido 2 clases, estas pueden relacionarse de múltiples formas. Las relaciones entre clases pueden ser unidireccionales o bidireccionales, y pueden tener distintas cardinalidades. Para las cardinalidades, diferenciaremos 2 casos: 1 y N. A continuación se muestra un diagrama con todas las posibilidades de definición de relaciones entre 2 clases: Para las relaciones con un lado N, aparte de las tablas que el YORM creará para las clases A y B, creará una tabla intermedia (tabla de join) para mantener las relaciones. A continuación se muestra un ejemplo. Si a es una instancia de A y b1, b2, b3 son instancias de B, y A tiene varios B (en este caso b1, b2 y b3), las relaciones se mantienen de la siguiente forma:
  • 8. tabla_a tabla_a_b tabla_b id id_a id_a id_b1 id id_b1 id_a id_b2 id id_b2 id_a id_b3 id id_b3 A continuación se muestra el código PHP de la clase A con una relación unidireccional a un B: class A extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->setWithTable("tabla_a"); // Declaración de campos de la clase A omitidos .. $this->addHasOne("b", "B"); // Declaración de relación a un B // Llamada al constructor de la superclase // Inyecta atributos útiles para ORM (id, class, deleted) parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } En el caso de que la clase A tuviera relacionados varios B, la definición de la clase sería: class A extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->setWithTable("tabla_a"); // Declaración de campos de la clase A omitidos .. $this->addHasMany("b", "B"); // Declaración de relación a muchos B // Llamada al constructor de la superclase // Inyecta atributos útiles para ORM (id, class, deleted) parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } 1.2.1.3 Mapeos de herencia
  • 9. Las clases persistentes soportan la definición de herencia (especialización) como en cualquier modelo orientado a objetos. Al conjunto de una clase y todas las clases que heredan de esta, directa o indirectamente, se le llama “estructura de herencia” o “árbol de herencia”. Por ejemplo, si se tienen 2 clases C y D, donde D hereda de C, hay dos opciones de ORM: ● mapear las dos clases a la misma tabla, ó ● que cada clase tenga su propia tabla. Caso 1: D hereda de C y se mapean en la misma tabla. Caso 2: D hereda de C y se mapean en tablas distintas: En el caso 2 se puede apreciar que en la tabla_d se inyecta un nuevo atributo “super_id_c”, que indica cual es el identificador de la parte de la clase D que se hereda de C, y sirve para hacer un join entre las tablas, de modo de obtener una instancia completa de D, que incluye los valores de los atributos declarados tanto en la clase C como en la clase D. También para el caso 2 se debe notar que el identificador de las instancias de D será en que se guarda en la tabla “tabla_d”, ya que es la tabla que corresponde con la clase concreta. Este identificador puede ser distinto al que se guarda en la tabla “tabla_c” (por eso es necesaria la columna “super_id_c”). Para una instancia de D persistita, en la columna “class” de ambas tablas estará el valor “D”. Las instancias de C persistidas, no tendrán ningún registro ingresado en la tabla “tabla_d”.
  • 10. 2. Fundamentos de programación ágil y aplicaciones web En general, el desarrollo ágil refiere a una característica de algunos procesos de desarrollo de software, que permiten que un proyecto tenga: ● Productos tangibles y funcionales en períodos de tiempo cortos ● Mayor visibilidad del avance del proyecto para el cliente ● Capacidad de adaptación rápida a cambios en los requerimientos Que esto sea posible, también depende de las tecnologías que se empleen para los proyectos. En particular los “frameworks ágiles”, como lo es Yupp, han propuesto tecnologías para acompañar y ayudar a los procesos de desarrollo ágil de software. En este sentido, los objetivos de Yupp son: ● Quitar de manos del programador las tareas repetitivas que agregan poco valor al proyecto (consultas a la BD, validación de datos, internacionalización, ajax, etc) ● Seguir el paradigma “convención sobre configuración”, que marca reglas básicas o convenciones, que hacen que no se necesiten grandes y dificultosas configuraciones por cada proyecto. ● Fácil de instalar y usar. ● Minimalista, todo lo necesario, pero no más. ● Permitir generar aplicaciones web funcionales sin necesidad de realizar una programación completa. ● Curva de aprendizaje reducida. Aplicaciones web Principales características de las aplicaciones web: ● Instaladas en la nube ● No necesitan actualizaciones ● Accedidas desde web browsers ● Ejecución mixta, parte en el cliente, parte en el servidor (puede ser más de uno) Las tendencias actuales muestran que en el futuro las aplicaciones basadas en web serán las únicas aplicaciones, y que las aplicaciones de escritorio poco a poco van a desaparecer. Además existe una tendencia de empresas como Google y Mozilla al desarrollo de sistemas operativos y aplicaciones todo basado en web. Por otro lado, con el desarrollo del nuevo estándar HTML5, que incluye de forma nativa soporte para video, sonido, multi-threading, primitivas gráficas 2D y 3D, y otras características, lo que da una infraestructura enorme para el desarrollo de aplicaciones web. En este sentido, Yupp está intentando
  • 11. posicionarse como una opción competitiva entre los frameworks ágiles para el desarrollo de aplicaciones para esta nueva realidad que está comenzando. Algunos vínculos interesantes: ● http://www.youtube.com/watch?v=42Gyy2xr5zA ● http://www.youtube.com/watch?v=ErqCqwkwIDE ● http://www.youtube.com/watch?v=jB5KFJULahs ● http://www.youtube.com/watch?v=KMZLM2AhSE0 ● http://www.youtube.com/watch?v=ANMrzw7JFzA
  • 12. 3. Instalación y configuración del framework Los siguientes pasos suponen que se tiene un servidor web con soporte para PHP instalado. En particular, se referenciará a la aplicación WAMP que es un paquete que trae Apache, MySQL y PHP para Windows. Por más información: http://www.wampserver.com El primer paso es obtener la última versión del framework, para esto hay dos opciones: ● Descargar la liberación ● Descargar del repositorio de desarrollo 3.1 Descargar la liberación Desde la página de Google Code del proyecto [1], en el área de descargas, residen las últimas liberaciones en archivos en formato ZIP. [1] http://code.google.com/p/yupp/
  • 13. 3.2 Descargar del servidor de desarrollo En Google Code también se encuentra el servidor de versiones (SVN) del proyecto. El código fuente de desarrollo se puede descargar desde ahí [2] con cualquier cliente SVN. [2] http://yupp.googlecode.com/svn/YuppPHPFramework Una vez descargado el framework, se copia su contenido al directorio “www” del WAMP. Para verificar que se ha copiado correctamente, se inicia el WAMP, en un navegador web se accede a http://localhost, donde deberá aparecer una página del WAMP. En esa página, hay una zona de proyectos, ahí debería aparecer el directorio descomprimido donde se ha copiado el framewok. Si se ingresa al directorio del framework, se debería ver el escritorio de Yupp como se muestra en la siguiente imagen: En este escritorio aparecerán todas las aplicaciones instaladas en Yupp Framework. Podemos comentar varios aspectos de Yupp: ● Soporta múltiples aplicaciones. ● Sirve para que el desarrollador tenga varios proyectos en los que está trabajando. ● Sirve para que el usuario final pueda usar varias aplicaciones. Yupp es tanto un plataforma de desarrollo, como plataforma de ejecución de aplicaciones web. Otros aspectos del escritorio son: ● Desde aquí se pueden crear nuevas aplicaciones ● Se pueden filtrar las aplicaciones (útil cuando se tiene una cantidad considerable) ● Se pueden ver novedades relacionadas con Yupp y publicadas en Twitter ● Se puede acceder al listado de aplicaciones (vista por defecto) ● Se puede acceder a la vista de Base de Datos (es necesaria la configuración previa) ● Se pueden ejecutar los tests de las aplicaciones ● Se pueden ejecutar los scripts de bootstrap de las aplicaciones ● Se pueden ejecutar las aplicaciones Nota: si se intenta acceder a la vista de Bases de Datos se obtendrá un error que indicará que la base de datos no existe. Esto se debe a que todavía no la hemos creado y configurado.
  • 14. 3.3 Configuración del framework Yupp Framework fue diseñado para que la configuración sea mínima, representando una tarea muy simple a realizar una sola vez. La única configuración necesaria es la de la base de datos a utilizar. Al día de hoy, Yupp Framework soporta MySQL, Postgres y SQLite. Para configurar el gestor de base de datos, es necesario editar el archivo yupp/core/config/core.config.YuppConfig.class.php. En este archivo hay un campo $default_datasource, donde se realiza esta configuración en una estructura como esta: $default_datasource = array( self::MODE_DEV => array( 'type' => self::DB_MYSQL, 'url' => 'localhost', 'user' => 'root', 'pass' => '', 'database' => 'yupp_dev' ), self::MODE_PROD => array( 'type' => self::DB_MYSQL, 'url' => 'localhost', 'user' => 'root', 'pass' => '', 'database' => 'yupp_prod' ), self::MODE_TEST => array( 'type' => self::DB_MYSQL, 'url' => 'localhost', 'user' => 'root', 'pass' => '', 'database' => 'yupp_test' ) ); En esta estructura se indica que configuración de base de datos usar para cada modo de ejecución. Hoy el framework soporta los modos “desarrollo” y “producción”, en un futuro también soportará el modo “testing”. Para cada modo de ejecución se indica: ● tipo de gestor de bases de datos (MySQL, Postgres o SQLite) ● ubicación del gestor de bases de datos ● usuario y clave ● nombre de la base de datos a utilizar
  • 15. 4. Estructura de Yupp Framework La estructura (reducida) del framework es la siguiente: ● apps ○ core ○ tests ■ app.xml ● core ○ app ○ basic ○ config ○ db ○ http ○ layout ○ mvc ○ persistent ○ routing ○ support ○ testing ○ utils ○ validation ○ web ○ App ○ FileSystem ○ Yupp ○ YuppLoader ○ YuppSession ● css ● images ● js ● .htaccess ● index.php Explicación de la estructura /apps: Este directorio contiene las aplicaciones instaladas en el framework /apps/core: Esta aplicación es parte del framework. Todas las vistas y acciones como el escritorio de Yupp, la vista de Bases de Datos, la creación de aplicaciones, etc, son parte de esta aplicación. /apps/tests: Esta aplicación contiene algunos tests sobre el framework. Por un lado, los tests automatizados que pueden ser ejecutados desde el escritorio de Yupp. Por otro lado, al ejecutar la aplicación, se tienen algunas vistas con tests para ejecutar manualmente, que además sirven como referencia para la programación.
  • 16. /apps/tests/app.xml: Descriptor de aplicaciones, usado por Yupp para presentar correctamente la aplicación en el escritorio. En el futuro servirá para gestionar aplicaciones. /core: Es el núcleo del framework. Contiene todas las clases y scripts necesarios para el funcionamiento del framework. /core/app: Contiene recursos relacionados con el manejo de las aplicaciones. /core/basic: Contiene clases útiles para manejar tipos básicos como String y DateTime. /core/config: Contiene elementos de configuración y la implementación de muchas de las convenciones de Yupp, como las de nombrado de los archivos. /core/db: Contiene la implementación de la capa de acceso a datos, los conectores a los distintos motores de bases de datos, y el paquete de creación de consultas. /core/http: Contiene la implementación de HTTPRequest y HTTPResponse. /core/layout: Contiene la clase que da soporte a la definición de layouts en las vistas. /core/mvc: Contiene la implementación de los elementos básicos para soportar controladores, vistas, helpers útiles para la generación de vistas, y para el pasaje del modelo desde el controlador a la vista. /core/persistent: Contiene la implementación del ORM de Yupp. y clases para la serialización a JSON y XML. /core/routing: Este directorio contiene las clases que implementan el ruteo de pedidos al framework, y la ejecución de acciones de los controladores. /core/support: Contiene algunas clases útiles para mantener el contexto de ejecución del framework, para el manejo de medidas de tiempo y para soportar la internacionalización. /core/testing: Contiene las clases necesarias para implementar tests automáticos. /core/utils: Contiene clases utilitarias de uso interno del framework. /core/validation: Contiene las clases que implementan la validación de campos para las clases persistentes. /core/web: Contiene las clases que se encargan de manejar los pedidos al framework, procesar urls, parámetros, y coordinar toda la ejecución de acciones y devolución de vistas. App: Clase que implementa operaciones útiles sobre las aplicaciones. FileSystem: Clase que implementa métodos útiles para acceder al sistema de archivos. Yupp: Clases que implementa operaciones útiles sobre el framework. YuppLoader: Clase que implementa la carga controlada de clases y scripts.
  • 17. YuppSession: Clase que implementa la gestión de la sesión. css: En este directorio se colocan las hojas de estilo de uso global (útiles para varias aplicaciones). images: En este directorio se ponen las imágenes de uso global. js: En este directorio se ponen los archivos javascript para uso global. .htaccess: Indica reglas de redirección de pedidos, todos los pedidos van al index.php. index.php: Punto de entrada de los pedidos del usuario al framework.
  • 18. 5. URLs en Yupp Como se mencionó antes, Yupp es un framework orientado a convenciones. La primer convención que debe quedar clara es la del formato de las URLs que el framework puede recibir. Esto es muy importante, porque toda la ejecución del framework y de sus aplicaciones dependerá de las URLs que se reciban. Antes de entrar en los formatos de las URLs, algunos comentarios: ● Yupp soporta varias aplicaciones ● Cada aplicación puede tener varios controladores ● Cada controlador implementa varias acciones (métodos) ● Dependiendo de los parámetros de entrada, una misma acción puede indicar que se muestren varias vistas, una a la vez. Ejemplo de URL válida en Yupp: ● http://localhost/yupp/app/controller/action?param1=value1&param2=value2 Si el framework fue copiado al directorio “yupp” dentro del directorio “www” del WAMP, esta debería ser una URL válida para Yupp. A continuación se explica cada trozo de la misma: ● http://localhost: acceso al “www” del WAMP, también conocido como “http root”. ● yupp: directorio donde fue copiado el framework dentro del “www” del WAMP. ● app: nombre de la aplicación que se desea ejecutar. ● controller: nombre del controlador, dentro de la aplicación “app”, que se desea ejecutar. ● action: nombre de la acción a ejecutar. Esta acción está implementada en “controller”. ● ?param1=value1&param2=value2: parámetros que recibirá la acción. Por ejemplo, si se tiene una aplicación “blog” y se quiere acceder al listado de entradas, la siguiente podría ser la URL para hacerlo: ● http://localhost/yupp/blog/entradas/list Yupp Framework soporta otra forma de pasarle parámetros a la acción, sin necesidad de usar el formato param=value, este es un ejemplo: ● http://localhost/yupp/app/controller/action/value1/value2 Con este formato, el framework transformará los dos últimos trozos de la URL a parámetros de nombre “_param_1” y “_param_2” respectivamente, y quedarán accesibles con esos nombres para la acción correspondient.
  • 19. 6. Creando una aplicación simple Para crear una aplicación simple, se deben seguir estos pasos: 1. Ir al escritorio de Yupp Framework 2. Hacer clic sobre el link “Nueva aplicación” 3. Ingresar los datos ahí pedidos: a. Nombre de la aplicación: ingresar el nombre, por ejemplo “biblioteca” b. Descripción: una descripción de la aplicación, por ejemplo “Aplicación para gestión de libros” c. Lenguages: para qué idiomas estará disponible la aplicación, por ejemplo “es en” para español e inglés respectivamente. d. Nombre del controlador principal: nombre del controlador que se creará por defecto, por ejemplo “libro”. 4. Hacer clic en “crear”. Si se cumplieron todos los pasos exitosamente, ser debería volver al escritorio y ver la nueva aplicación creada. Al hacer clic sobre el icono de la aplicación “biblioteca”, debería mostrarse el texto “Bienvenido a su nueva aplicación!”. En la siguiente sección se explica en detalle la estructura interna de la aplicación creada de forma automática por el framework. Ingresando a “/yupp/apps” desde el sistemas de archivos, deberá haber un nuevo directorio con e nombre “biblioteca”. Dentro de éste, en el directorio “controllers” debería haber un archivo PHP que implementa el controlador “libro”, el archivo tendrá el nombre “apps.biblioteca.LibroController.class.php”. Abriendo ese archivo veremos que la clase tiene una acción implementada, la cual devuelve el mensaje que veíamos previamente (Bienvenido a su nueva aplicación!). Creando una clase del modelo Supongamos que nuestra aplicación debe gestionar libros, entonces necesitamos una clase que modele un libro. Un libro tiene un título, un género, autor, fecha de edición, idioma y número de páginas. Para crear esta clase, se deberían seguir los siguientes pasos: 1. Ir al directorio /yupp/apps/biblioteca/model 2. Ahí crear el archivo biblioteca.model.Libro.class.php 3. Programar una clase que herede de PersistentObject 4. Agregar un constructor al que se le pasan 2 parámetros: a. $args = array () b. $isSimpleInstance = false 5. Agregar llamada al constructor de la clase padre en el constructor de esta clase 6. Copiar los métodos estáticos de alguna clase de ejemplo 7. Agregar los atributos mencionados previamente: a. $this->addAttribute("titulo", Datatypes :: TEXT); b. $this->addAttribute("genero", Datatypes :: TEXT); c. $this->addAttribute("autor", Datatypes :: TEXT); d. $this->addAttribute("fecha", Datatypes :: DATETIME); e. $this->addAttribute("idioma", Datatypes :: TEXT); f. $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER);
  • 20. Vamos paso por paso Luego de los primeros 5 pasos, deberíamos tener programada una clase como esta: class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { parent :: __construct($args, $isSimpleInstance); } } Todas las clases del modelo deben heredar de PersistentObject para contar con las funcionalidades de persistencia. El constructor debe recibir estos dos parámetros para que internamente la clase PersistentObject realice las tareas necesarias para crear una clase persistente. Esas tareas son ejecutadas al hacer una llamada explícita al constructor de la clase padre, que en este caso es la única línea de código dentro del constructor de Libro. En el paso 6 se indica que deben copiarse los métodos estáticos, estos métodos permiten realizar distintas operaciones de persistencia y consulta sobre la clase. Luego del paso 6, la clase deberá quedar así: class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { parent :: __construct($args, $isSimpleInstance); } public static function listAll(ArrayObject $params) { self :: $thisClass = __CLASS__; return PersistentObject :: listAll($params); } public static function count() { self :: $thisClass = __CLASS__; return PersistentObject :: count(); } public static function get($id) { self :: $thisClass = __CLASS__; return PersistentObject :: get($id); } public static function findBy(Condition $condition, ArrayObject $params) { self :: $thisClass = __CLASS__; return PersistentObject :: findBy($condition, $params); } public static function countBy(Condition $condition) { self :: $thisClass = __CLASS__; return PersistentObject :: countBy($condition); } }
  • 21. Por último, en el paso 7 agregamos los campos de la clase, cada uno con su respectivo tipo. Es necesario definir el tipo del campo de forma explícita porque PHP no permite definir tipos para los campos o atributos de una clase, porque PHP es debilmente tipado. Pero para indicarle a la base de datos de qué tipo serán las columnas de la tabla donde se persistan instancias de la clase Libro, es necesario la definición de los tipos. Luego de realizado el paso 7, la clase completa quedaría así: class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("titulo", Datatypes :: TEXT); $this->addAttribute("genero", Datatypes :: TEXT); $this->addAttribute("autor", Datatypes :: TEXT); $this->addAttribute("fecha", Datatypes :: DATETIME); $this->addAttribute("idioma", Datatypes :: TEXT); $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER); parent :: __construct($args, $isSimpleInstance); } public static function listAll(ArrayObject $params) { self :: $thisClass = __CLASS__; return PersistentObject :: listAll($params); } public static function count() { self :: $thisClass = __CLASS__; return PersistentObject :: count(); } public static function get($id) { self :: $thisClass = __CLASS__; return PersistentObject :: get($id); } public static function findBy(Condition $condition, ArrayObject $params) { self :: $thisClass = __CLASS__; return PersistentObject :: findBy($condition, $params); } public static function countBy(Condition $condition) { self :: $thisClass = __CLASS__; return PersistentObject :: countBy($condition); } }
  • 22. Para que nuestro controlador sepa de la existencia de la nueva clase del modelo y la pueda utilizar, debemos incluirla usando YuppLoader, así LibroController tendrá este aspecto: YuppLoader::load('biblioteca.model', 'Libro'); class LibroController extends YuppController { public function indexAction() { return $this->renderString("Bienvenido a su nueva aplicacion!"); } } Suponiendo que ya tenemos la base de datos configurada y corriendo, procedamos a crear la estructura de la base para poder gestionar los libros. 1. Ingresar al escritorio de Yupp desde un navegador web 2. Ingresar a las pestaña “Base de Datos” 3. Debemos ver una zona para la aplicación “biblioteca”, donde se muestra que la clase Libro se almacena en cierta tabla, la cual aún no fue creada. 4. Hacer clic en el link “Crear tablas” 5. Si todo salió bien, en la zona de la aplicación “biblioteca” debería decir que la tabla para la clase Libro fue creada. 6. Volvemos al listado de aplicaciones (escritorio de Yupp) y hacemos clic sobre el icono de la aplicación “biblioteca”. 7. Si vemos el mensaje “Bienvenido a su nueva aplicacion!”, debemos estar en la siguiente URL: http://localhost/yupp/biblioteca/libro/index 8. Cambiar la url a: http://localhost/yupp/biblioteca/libro/list 9. El framework nos debería mostrar una vista con el listado de libros, sin ningún libro. Podemos apreciar una tabla que muestra todos los atributos de nuestra clase Libro. 10. Si hacemos clic en el link “Create”, nos debería mostrar una vista donde podemos ingresar toda la información de un Libro. 11. Cuidado con la fecha, ingresarla con el siguiente formato: aaaa-mm-dd 12. Al hacer clic en el botón “Create”, debemos estar en una vista que muestra los datos ingresado. 13. Volvemos al listado cliqueando en el link “list”, y nos debería mostrar el libro recién ingresado. 14. Podemos seguir agregando libros, editando sus datos, o eliminándolos. Algunos comentarios respecto a los pasos previos: Generación de estructuras en la base de datos: Toda la generación de tablas y relaciones en la base de datos la realiza el framework de forma automática, en base a las clases definidas en el modelo de cada aplicación. Vistas dinámicas: Todas las vistas que se ven en el flujo de uso de la aplicación (listado, detalles del libro, creación, edición) son autogenerdas, no fueron programadas como parte de la aplicación. Acciones dinámicas:
  • 23. Todas las acciones de listado, altas, bajas y modificaciones están implementadas en el framework, el programador nunca implementó estas operaciones. Es más, en el controlador LibroController, donde estas operaciones deben ser implementadas, vemos implementada solo la acción “index”. Por lo tanto, sin necesidad de programar una aplicación completa, ya se tiene una aplicación funcional para mostrar y probar. Tampoco es necesario invertir tiempo en diseñar la estructura de la base de datos, porque también es autogenerada por el framework. Esto es gran parte de la agilidad que agrega el framework al desarrollo de aplicaciones web.
  • 24. 7. Estructura de las aplicaciones Yupp Siguiendo con el ejemplo de la aplicación “biblioteca”, en esta sección veremos la estructura interna de las aplicaciones de Yupp. La estructura generada por el framework para la aplicación “biblioteca” es la siguiente: ● apps ○ biblioteca ■ bootstrap ■ config ■ controllers ■ i18n ■ model ■ services ■ utils ■ views ■ app.xml /apps Directorio donde se ubican las aplicaciones instaladas en el framework, tanto para desarrollo como para su uso por usuarios finales. /apps/biblioteca Directorio de la aplicación “biblioteca”. /apps/biblioteca/bootstrap Directorio donde se ubican los scripts de arranque de la aplicación. Estos scripts sirven para agregar datos en la base de datos para la correcta ejecución de la aplicación, por ejemplo se pueden dar de alta usuarios administradores. /apps/biblioteca/config Directorio donde se colocará todo recurso relativo a la configuración de la aplicación. /apps/biblioteca/controllers Directorio que contienen los controladores de la aplicación. /apps/biblioteca/i18n Directorio donde se colocarán los scripts de traducción (internacionalización) de la aplicación. /apps/biblioteca/model Directorio que contiene las clases del modelo de información persistente de la aplicación. /apps/biblioteca/services Directorio que contiene las clases que implementan la lógica de negocio de la aplicación.
  • 25. /apps/biblioteca/utils Direcorio donde se coloca todo recurso auxiliar para el correcto funcionamiento de la aplicación. /apps/biblioteca/views Directorio que contiene las vistas de la aplicación, estas contienen toda la lógica de la interfaz de usuario de la aplicación. /apps/biblioteca/app.xml Descriptor de aplicaciones, que contiene metadatos de la aplicación que son accedidos por el framework y se utilizarán en el futuro para gestionar aplicaciones. La estructura mínima para las aplicaciones Yupp podría considerarse similar a la siguiente: ● boostrap ● controllers ● model ● views ● app.xml Todos los demás directorios que no se utilicen, pueden ser eliminados. 7.1 Configuración de la base de datos por aplicación En la sección 3.3 se mostró cómo configurar la base de datos en Yupp. Esta configuración es global, o sea que todas las aplicaciones utilizarán la misma base de datos, con la misma configuración. Esto no siempre es deseable, por lo que Yupp soporta la configuración de bases de datos por aplicación. 7.1.1 Creando la configuración Por ejemplo, si quisiéramos que la aplicación “biblioteca” tuviera su propia base de datos, deberíamos seguir los siguientes pasos: 1. Si el directorio “config” no existe dentro de “apps/biblioteca”, crearlo. 2. Dentro de “apps/biblioteca/config”, crear el archivo “db_config.php” 3. Dentro del archivo, colocar el siguiente código PHP: $db = array( 'type' => 'mysql', 'url' => 'localhost', 'user' => 'root', 'pass' => '', 'database' => 'yupp_biblioteca' );
  • 26. El array $db contiene todos los datos de configuración de la base de datos para la aplicación “biblioteca”. En la clave “type” debe ponerse alguno de estos valores: “mysql”, “sqlite” o “postgres”. Estos valores están definidos en “core/config/core.config.YuppConfig.class.php”. En el futuro cuando se soporten otros motores de bases de datos, también podrá elegirse entre ellos. La clave “url” indica el servidor donde se encuentra instalado el motor de bases de datos. Las claves “user” y “pass” son usadas para poder acceder a la base de datos. Y por último, la clave “database” define el nombre de la base de datos que estará utilizando nuestra aplicación. No es necesaria ninguna otra configuración. Si se cumplen las convenciones de nombrado y ubicación de los archivos, Yupp framework por sí solo encontrará la configuración y la utilizará. 7.2 Script de bootstrap Opcionalmente, cada aplicación puede tener un script de boostrap (arranque). Este script se ejecutará una sola vez luego de instalar la aplicación dentro del framework, y servirá para dar de alta información necesaria para el correcto funcionamiento de dicha aplicación, como por ejemplo los usuarios administradores de la aplicación. El script de bootstrap debe estar situado en el directorio “bootstrap” de la aplicación, y dentro del directorio un archivo llamado “apps.biblioteca.bootstrap.Bootstrap.script.php” (este sería el nombre del script de bootstrap para la aplicación “biblioteca”). Se tienen planes para que en el futuro pueda haber un script de boostrap para cada modo de ejecución (desarrollo, producción y testing). 7.3 Scripts de testing Hoy Yupp Framework soporta la definición y ejecución de casos de testing. Este soporte es el mínimo necesario para estos fines. Se tienen planificadas varias mejoras para el área de testing. Los casos de testing se definen dentro del directorio “tests” de las aplicaciones Yupp. Un caso de testing es una clase que hereda de TestCase (clase provista por el framework), donde es necesario definir el método run(). Por ejemplo, la implementación de un caso de test podría ser el siguiente: YuppLoader::load('core.testing', 'TestCase'); class TestCase001 extends TestCase { private $var = 0; public function run() { $this->test1(); $this->test2(); $this->reset(); }
  • 27. public function test1() { $this->var++; $this->assert( $this->var == 1, 'Test igual a 1' ); $this->assert( $this->var != 0, 'Test distinto de 0' ); } public function test2() { $this->assert( is_numeric($this->var, 'Test is_numeric' ); } public function reset() { $this->var = 0; } } El caso de testing debe implementar el método run(), luego dentro de este se invocan todos los métodos definidos por el programador, que son los que implementan el caso de testing. No hay restricciones sobre los nombres de los métodos (aparte del método run()).
  • 28. 8. Model: funcionalidades avanzadas En la sección 1.2 se tuvo una introducción al ORM de Yupp, mostrando cómo se definían las clases del modelo y los distintos tipos de relaciones entre estas clases. También se mencionó cómo esas clases y relaciones eran mapeadas a una estructura de base de datos. En esta sección se verán otros aspectos interesantes que complementan los ya vistos. 8.1 Gestionando relaciones hasOne Supongamos que la clase Libro que definimos previamente en la sección 6, ahora en lugar de un atributo “autor” tiene una relación hasOne a una clase Autor que definimos más abajo: YuppLoader::load("biblioteca.model", "Autor"); class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("titulo", Datatypes :: TEXT); $this->addAttribute("genero", Datatypes :: TEXT); $this->addAttribute("fecha", Datatypes :: DATETIME); $this->addAttribute("idioma", Datatypes :: TEXT); $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER); $this->addHasOne("autor", "Autor"); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos }
  • 29. Una forma sencilla de relacionar una instancia de Libro a una instancia de Autor es en la propia construcción de las instancias: $libro = new Libro( array( "titulo" => "El ingenioso hidalgo don Quixote de la Mancha", "genero" => "prosa narrativa", "fecha" => "1605-01-01", "idioma" => "es", "numeroPaginas" => 223, "autor" => new Autor( array( "nombre" => "Miguel de Cervantes Saavedra", "fechaNacimiento" => "1547-09-29" ) ) ) ); Otra forma de asociación es mediante el método dinámico “getX”, donde “X” es el nombre de un atributo, por ejemplo el atributo hasOne. Entonces podríamos tener el siguiente código: $libro = new Libro( array( "titulo" => "El ingenioso hidalgo don Quixote de la Mancha", "genero" => "prosa narrativa", "fecha" => "1605-01-01", "idioma" => "es", "numeroPaginas" => 223 ) ); $autor = new Autor( array( "nombre" => "Miguel de Cervantes Saavedra", "fechaNacimiento" => "1547-09-29" ) ); $libro->setAutor( $autor ); Para obtener el autor de una instancia de Libro, se utiliza el método dinámico “getXXX”, donde “XXX” es el nombre de un atributo, por ejemplo: $autor = $libro->getAutor();
  • 30. 8.2 Gestionando relaciones hasMany Para seguir con el ejemplo de los libros, supongamos que ahora Libro tiene una relación hasMany para los coautores: YuppLoader::load("biblioteca.model", "Autor"); class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("titulo", Datatypes :: TEXT); $this->addAttribute("genero", Datatypes :: TEXT); $this->addAttribute("fecha", Datatypes :: DATETIME); $this->addAttribute("idioma", Datatypes :: TEXT); $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER); $this->addHasOne("autor", "Autor"); $this->addHasMany("coautores", "Autor"); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } Si se tiene una instancia de Libro y dos instancias de Autor, tales que los autores son coautores del libro, para asociar los coautores al libro se utiliza el método dinámico “addToX”, donde “X” es el nombre de una relación hasMany, por ejemplo: $libro = new Libro(...); $coautor1 = new Autor(...); $coautor2 = new Autor(...); $libro->addToCoautores( $coautor1 ); $libro->addToCoautores( $coautor2 ); Para obtener todos los coautores de la instancia de Libro se utiliza el método dinámico “getX” al igual que en el caso previo para obtener la instancia en la relación hasOne. $coautores = $libro->getCoautores(); Para quitar un coautor del libro se utiliza el método dinámico “removeFromX”, donde “X” es el nombre del atributo hasMany. Para invocar a esta operación, la instancia a remover de la relación debe haber sido persistida en la base de datos, porque es necesario que la instancia tenga identificador. El identificador solo se establece cuando la instancia es almacenada en la base de datos. $libro->removeFromCoautores( $coautor1 ); En este ejemplo es útil recalcar que $coautor1 es removido de la relación hasMany con $libro, pero que la instancia $coautor1 no es eliminada y sigue persistida en la base de datos.
  • 31. 8.2.1 Tipos de relaciones hasMany El ORM de Yupp soporta tres tipos distintos de comportamientos para las relaciones hasMany. Estas relaciones pueden comportarse como colecciones, listas o conjuntos. Colecciones Por defecto las relaciones hasMany tienen este comportamiento, que consiste en no tener ningún tipo de restricción sobre lo que se pone dentro de la relación. Los objetos no tienen orden ni se verifican duplicados. Ejemplo: $this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_COLECTION); Listas Una relación hasMany definida con comportamiento de lista, almacena el orden con que los objetos son agregados a la relación. Esto sirve para obtener instancias persistentes, con el mismo orden en el que fueron persistidas. Ejemplo: $this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_LIST); Conjuntos Las relaciones hasMany definidas como conjuntos, implementan la restricción de verificación por duplicados. Si en una relación hasMany definida como conjunto se intenta agregar dos veces el mismo objeto, el segundo no será agregado. Esto funciona si los objetos que se agregan fueron persistidos previamente. Ejemplo: $this->addHasMany("coautores", 'Autor', PersistentObject::HASMANY_SET); Nota: como el comportamiento por defecto es de colección, el primer ejemplo se comporta de igual forma que el siguiente código, sin pasar el tercer parámetro: $this->addHasMany("coautores", 'Autor');
  • 32. 8.3 Convenciones sobre nombrado de tablas En la sección 1.2 se vio un ejemplo de clase persistente, donde se declaraba explícitamente el nombre de la tabla en la base de datos donde las instancias de esa clase iban a ser persistidas. En esta sección vamos a explicar cuáles son las convenciones en cuanto a los nombres de las tablas en la base de datos. 8.3.1 Nombrado implícito de tablas Se toma como nombrado implícito cuando no se define el nombre de la tabla de forma explícita en el constructor de la clase persistente. En el caso que se vio en la sección 1.2, el nombrado de la tabla era explícito, haciendo la siguiente invocación: $this->setWithTable("nombre_de_la_tabla"); En el caso de la aplicación “biblioteca” con la que venimos trabajando, la clase Libro no hace un nombrado explícito. Por lo tanto se aplica la siguiente convención de Yupp: Cuando no hay nombrado explícito de la tabla donde se persistirán las instancias de cierta clase del modelo de información de una aplicación Yupp, el nombre de la tabla será igual al nombre de la clase en minúsculas. O sea que para los siguientes nombres de clases, tendremos los siguientes nombres de tablas: ● Libro => libro ● BuenLibro => buenlibro ● BuenLibro2 =>buelibro2 8.3.2 Nombrado explícito de tablas En la sección anterior se comentó que es el nombrado explícito, que consiste en llamar al método “setWithTable” con un determinado nombre de tabla. A continuación veremos distintos ejemplos para los nombres de tablas y como Yupp reacciona ante ellos. Una restricción a considerar es que el nombre de la tabla no puede contener caracteres que sean usados por los motores de bases de datos, como por ejemplo el punto (“.”). Yupp no hace ningún tipo de verificación de estos caracteres, por lo que el programador debe tener especial cuidado. ● Nombre de la tabla: “libro”, nombre aceptado por Yupp: “libro” ● Nombre de la tabla: “Libro”, nombre aceptado por Yupp: “libro” ● Nombre de la tabla: “BuenLibro”, nombre aceptado por Yupp: “buenlibro” ● Nombre de la tabla: “Buen_Libro”, nombre aceptado por Yupp: “buen_libro” ● Nombre de la tabla: “Buen Libro”, nombre aceptado por Yupp: “buen_libro”
  • 33. Las reglas de Yupp sobre los nombres especificados de forma explícita son: ● El nombre especificado se convierte a minúsculas. ● Si el nombre especificado tiene espacios, se convierten a guiones bajos. 8.3.3 Nombrado de tablas de join Cuando una relación hasMany es definida, como se hizo previamente en la clase Libro, hacia la clase Autor, con una relación llamada “coautores”, una tabla intermedia es creada para mantener las relaciones. En el ejemplo de la aplicación “biblioteca”, esta tabla intermedia es una tabla de join que sirve para persistir y obtener todos los coautores de un determinado libro. El nombre de la tabla de join para el caso mencionado será “libro_coautores_autor”, debido a que la clase donde se define la relación se persiste en la tabla “libro”, a que la clase relacionada se persiste en la tabla “autor”, y a que la relación se llama “coautores”. 8.4 Creando restricciones sobre campos y relaciones Las clases persistentes permiten la definición de restricciones sobre los campos declarados en dicha clase. 8.4.1 Definiendo restricciones Tomando el ejemplo de la clase Autor, de la aplicación “biblioteca”, podemos definir que el nombre del autor no puede ser vacío. Existen dos formas de hacerlo, la primera es usando la restricción “blank”. Aquí el ejemplo completo: class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); $this->addConstraints("nombre", array( Constraint::blank(false) )); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } Entonces, utilizamos blank(false) para indicar que el campo “nombre” no puede ser vacío. Es necesario diferenciar el caso de un string vacío del caso de un sting null. Si se desea que el nombre del autor tampoco sea null, debe especificarse una restricción como la siguiente:
  • 34. // Restricciones $this->addConstraints("nombre", array( Constraint::nullable(false), Constraint::blank(false) )); Mediante la restricción “minLength” que restringe la cantidad de caracteres mínima que debe tener un campo de tipo TEXT. Por ejemplo podríamos usar la siguiente restricción para indicar que el nombre debe tener por lo menos 1 carácter y lograr el mismo comportamiento que con “blank(false)”.: // Restricciones $this->addConstraints("nombre", array( Constraint::minLength(1) )); Si quisiéramos restringir el largo máximo del nombre, por ejemplo a 100 caracteres, utilizaríamos la restricción “maxLength”: // Restricciones $this->addConstraints("nombre", array( Constraint::blank(false), Constraint::maxLength(100) )); Como vemos, es posible definir varias restricciones para el mismo campo. Ahora, si quisiéramos definir restricciones para campos numéricos, por ejemplo el campo “numeroPaginas” de la clase Libro, podríamos decir que un libro debe tener como mínimo 20 páginas y como máximo 3000: // Restricciones $this->addConstraints("numeroPaginas", array( Constraint::min(20), Constraint::max(3000) )); Este par de restricciones podría expresarse como una sola restricción “between”, la cual indica que el valor de un campo debe estar entre dos valores datos, de la siguiente forma: // Restricciones $this->addConstraints("numeroPaginas", array( Constraint::between(20, 3000) )); Para ver todas las restricciones disponibles acceder a: http://code.google.com/p/yupp/source/browse/YuppPHPFramework/core/validation/core.validation.Constraints.class.php
  • 35. 8.4.2 Verificando restricciones Existen dos formas de verificar restricciones sobre los valores que tienen los campos de una clase persistente. La primera es utilizando el método “validate” de PersistentObject, la segunda es utilizando el método “save” de PersistentObject. 8.4.2.1 Validando datos mediante restricciones El siguiente es un ejemplo de validación utilizando el método validate($validateCascade = false) $autor = new Autor(); $autor->setNombre(""); if (!$autor->validate()) print_r( $autor->getErrors() ); Como al crear la instancia de Autor, se se establece el valor del campo nombre en un string vacío, violara la restricción de no vacío que fue definida previamente. Por lo tanto, “validate” devolverá “false” y mediante el método “getErrors” se obtendrán los errores de validación, y lo que se imprime será parecido a esto: Array ( [nombre] => Array ( [0] => El valor del atributo 'nombre' no puede ser vacio ) ) El método “validate” puede recibir opcionalmente un booleano que indica si la validación debe hacerse en cascada, o sea, si debería ejecutarse sobre la instancia actual y sobre las instancias de otras clases que tenga relacionadas. Por defecto la validación no se ejecuta en cascada. 8.4.2.2 Validando datos previa a la persistencia De forma análoga a “validate”, al ejecutar el método “save” también se validan los datos. Esto quiere decir que cada vez que se desee persistir una instancia de una clase, internamente se invoca al método “validate”. En el caso que los valores de los campos de la instancia violen alguna de las restricciones definidas en la clase, la instancia no es persistida y se generan todos los mensajes de error para cada campo y cada restricción violada. Esto último es accesible mediante el método “getErrors”. Por lo tanto, el siguiente código producirá el mismo resultado que el del ejemplo anterior (notar que se invoca a save y no a validate): $autor = new Autor(); $autor->setNombre(""); if (!$autor->save()) print_r( $autor->getErrors() );
  • 36. 8.5 Definiendo lógica pre-validación La clase PersistentObject tiene un método protegido “preValidate” (para ser implementado opcionalmente por sus subclases), el cual es ejecutado previamente a la validación. Este método fue ideado para modificar los valores de los campos de la clase, previamente a la ejecución de la validación. Esto tiene varias utilidades. Validación forzada de restricciones Si en el método “preValidate” se detecta que un campo no cumple con cierta restricción, o sea que al verificar la restricción el valor no cumplirá con dicha restricción, se puede modificar el valor del campo para que cumpla con la restricción y así no se generen errores de validación. Un ejemplo podría ser si un valor es null, teniendo una restricción “nullable(false)”, y en “preValidate” se cambia el valor por un string vacío. Limpieza de valores Es común que cuando un usuario ingresa algún texto, este venga con espacios o fines de línea extras al principio o al final. Si ese tipo de valores son asignados en campos de texto de una clase persistente, dentro del método “preValidate” podría implementarse una limpieza del texto. Esto podría servir también para aumentar la seguridad sobre lo que se inserta en la base de datos, ya que un texto podría tener caracteres inválidos, o incluso código javascript o SQL ingresado por un usuario malicioso, esto también puede detectarse y limpiarse en el método “preValidate”. A continuación se muestra un ejemplo que quita espacios extra que pueden venir para el campo “nombre” del autor. class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { // Campos $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); // Restricciones $this->addConstraints("nombre", array( Constraint::blank(false) )); parent :: __construct($args, $isSimpleInstance); } protected function preValidate() { $nombre = $this->getNombre(); if ( !is_null($nombre) ) $this->setNombre( trim($nombre) ); } // Métodos estáticos omitidos }
  • 37. 8.6 Usando belongsTo En el ORM de Yupp, hay varias operaciones que pueden realizarse en cascada, o sea que se aplican sobre una instancia de cierta clase persistente, y sobre las instancias de otras clases persistentes que tenga asociada. Para esto se necesita la propiedad “belongsTo”, que indica cuál es el lado fuerte y cuál el débil en una relación entre dos clases. Por ejemplo, si se tienen dos clases A y B, “A hasOne B” y “B belongsTo A”, el lado fuerte de la relación es A y el débil es B. Esta propiedad de las relaciones entre clases puede ser definida de forma explícita, o Yupp puede inferirla mediante convenciones. A continuación se muestras todos los tipos de relaciones entre 2 clases A y B, y cuál lado es considerado fuerte y cuál débil por Yupp en el caso de no definir de forma explícita la propiedad belongsTo. Notación: ● A(*)->(1)B: indica que la clase A tiene una relación unidireccional a B, con A hasOne B. ● A(*)<->(1)B: indica que la clase A tiene una relación bidireccional a B, con A hasOne B y B hasMany A. Casos: 1. A(*)->(1)B: Yupp no sabe cual lado es el fuerte, se necesita belongsTo explícito. 2. A(1)<->(1)B: Yupp no sabe cual es el lado fuerte, se necesita belongsTo explícito. 3. A(1)->(*)B: Yupp considera que B belongsTo A 4. A(1)<->(*)B: Yupp considera que B belongsTo A 5. A(*)->(*)B: Yupp considera que B belongsTo A 6. A(*)<->(*)B: Yupp no sabe cual es el lado fuerte, se necesita belongsTo explícito. Para ejemplificar estos casos, volvamos a la aplicación biblioteca, donde el modelo es el siguiente: class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { // Campos $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); // Restricciones $this->addConstraints("nombre", array( Constraint::blank(false) )); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos }
  • 38. class Libro extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->addAttribute("titulo", Datatypes :: TEXT); $this->addAttribute("genero", Datatypes :: TEXT); $this->addAttribute("fecha", Datatypes :: DATETIME); $this->addAttribute("idioma", Datatypes :: TEXT); $this->addAttribute("numeroPaginas", Datatypes :: INT_NUMBER); $this->addHasOne("autor", "Autor"); $this->addHasMany("coautores", "Autor"); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } O sea que: ● Libro hasOne Autor ● Libro hasMany Autor (coautores) ● No se ha declarado belongsTo explícito en ninguna clase Con este modelo, podemos ejecutar el siguiente caso de prueba: $libro = new Libro( array( "titulo" => "El ingenioso hidalgo don Quixote de la Mancha", "genero" => "prosa narrativa", "fecha" => "1605-01-01", "idioma" => "es", "numeroPaginas" => 223, "autor" => new Autor( array( "nombre" => "Miguel de Cervantes Saavedra", "fechaNacimiento" => "1547-09-29" )), "coautores" => array( new Autor( array( "nombre" => "Sancho Panza", "fechaNacimiento" => "1547-01-01" )), new Autor( array( "nombre" => "Quijote", "fechaNacimiento" => "1542-05-21" )) ) ) ); if( !$libro->save() ) print_r( $libro->getErrors() );
  • 39. Al ejecutar este caso de prueba, veremos que en la base de datos se ha guardado el libro y sus coautores (en cascada), pero no se ha guardado su Autor. Esto se debe a que la relación “autor” declarada en la clase Libro, entra en el caso 1 de la inferencia de belongsTo por Yupp framework, por lo que si queremos que se persista también esa relación a Autor, debemos declarar un belongsTo explícito en la clase Autor: YuppLoader::load("biblioteca.model", "Libro"); class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->belongsTo = array( 'Libro' ); // Campos $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); // Restricciones $this->addConstraints("nombre", array( Constraint::blank(false) )); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } Realizando este cambio en la clase Autor, el test anterior almacenará en cascada tanto al autor como a los coautores del libro. Si luego de ejecutar el caso de prueba de la sección 8.5, ejecutamos el siguiente caso de prueba, el primer autor tendrá entre sus libros al libro que lo tiene como autor: $libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos $autor = Autor::get(1); // Carga el autor con id=1 desde la base de datos $autor->addToLibros($libro); // Agrega el libro a los libros del autor if( !$autor->save() ) print_r( $autor->getErrors() ); // Intenta persistir
  • 40. 8.7 Definiendo relaciones de muchos a muchos De la misma forma que se definen las relaciones de uno a muchos usando hasMany, se pueden definir relaciones bidireccionales de muchos a muchos. Simplemente es necesario colocar una referencia hasMany en cada una de las clases. Por ejemplo, si desde la clase Autor se quisieran todos los libros que escribió, ser podría hacer la siguiente modificación al modelo: class Autor extends PersistentObject { function __construct($args = array (), $isSimpleInstance = false) { $this->belongsTo = array( 'Libro' ); // Campos $this->addAttribute("nombre", Datatypes :: TEXT); $this->addAttribute("fechaNacimiento", Datatypes :: DATE); $this->addHasMany("libros", "Libro"); // Restricciones $this->addConstraints("nombre", array( Constraint::blank(false) )); parent :: __construct($args, $isSimpleInstance); } // Métodos estáticos omitidos } Como vimos en las reglas de belongsTo en la sección previa, para definir relaciones de muchos a muchos bidireccionales, uno de los lados debe tener declarado un belongsTo. En este caso dejamos declarado el belongsTo en el Autor. 8.8 Eliminación física vs. eliminación lógica Siempre que se quiera eliminar una instancia de una clase persistente, se debe ser cuidadoso con la estrategia de eliminado a utilizar. En el caso de la eliminación física, el o los registros correspondientes a la persistencia de la instancia a eliminar, serán borrados físicamente de la base de datos y no se podrán recuperar sus datos. En cambio, con la eliminación lógica, los registros siguen existiendo, pero tienen una marca de “eliminados”, esa marca es utilizada internamente por el framework para saber que registros se encuentran activos y cuales fueron eliminados de forma lógica.
  • 41. El siguiente código elimina físicamente una instancia de Libro persistida en la base de datos: $libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos $libro->delete(); // Eliminación física El siguiente código elimina lógicamente una instancia de Libro persistida en la base de datos: $libro = Libro::get(1); // Carga el libro con id=1 desde la base de datos $libro->delete(true); // Eliminación física
  • 42. 9. Controladores Cada aplicación Yupp puede tener un conjunto de controladores, los cuales procesan los pedidos del usuario, e implementan determinada lógica. Partiendo del ejemplo del controlador generado para la aplicación “biblioteca”, vamos a completarlo para mostrar los conceptos detrás de la programación de controladores. YuppLoader::load('biblioteca.model', 'Libro'); class LibroController extends YuppController { public function indexAction() { return $this->renderString("Bienvenido a su nueva aplicacion!"); } } 9.1 Convenciones Ubicación: Todos los controladores de una aplicación Yupp deben estar dentro el directorio “controllers” de la aplicación, por ejemplo “biblioteca/controllers”. Nombres: En Yupp, los nombres de todas las clases empiezan en mayúsculas. El nombre de las clases que implementan controladores debe terminar en “Controller”, por ejemplo “LibroController” o “AutorController”. Acciones: Las acciones de un controlador son métodos especiales que pueden ser invocados mediante el envío de una URL. En la sección 5 vimos cómo están formadas las URLs dentro de Yupp, y que una parte de estas determina la acción a ejecutar. Un controladores puede además implementar métodos que no son acciones, por ejemplo métodos auxiliares que son usados por las acciones. Los nombres de los métodos que implementan acciones son públicos, comienzan en minúsculas y terminan en “Action”. Además no reciben parámetros de forma explícita. Previamente vimos un ejemplo con la acción “index” del controlador LibroController. Retorno de acciones Las acciones pueden tener varios tipos de retorno. En el ejemplo previo se vio un retorno del tipo “renderString”, que simplemente muestra en pantalla un determinado texto. En general no vamos a querer retornar un texto, si no una vista. Más adelante veremos como crear vistas, para esta sección es suficiente con saber que una vista tiene un determinado nombre y que recibe un conjunto de parámetros (modelo) que utiliza para generar una página web que se le mostrará al usuario.
  • 43. Si una acción simplemente retorna sin un valor, Yupp intentará mostrar una vista que tenga al mismo nombre de la acción que se está ejecutando. Por ejemplo, el siguiente código intentará mostrar una vista llamada “index” (obviamente, si la vista no existe, ocurrirá un error). public function indexAction() { return; } Una segunda opción, es especificar explícitamente el nombre de la vista. En este caso, el nombre de la vista podría ser distinto al de la acción, pero igualmente intentaremos mostrar la vista “index”. Este código logra el mismo efecto que el anterior. public function indexAction() { return $this->render("index"); } Digamos ahora que la vista “index” necesita algunos parámetros para mostrarse correctamente. El controlador puede pasarle un conjunto de parámetros al retornar, por ejemplo el siguiente código intentará mostrar una vista con el mismo nombre que la acción, o sea “index”, y recibirá un conjunto de valores. public function indexAction() { return array( 'valor1' => 29, 'valor2' => 'hola' ); } Redirigiendo pedidos Al terminar de ejecutar una acción, esta podría no decidir mostrar una vista, si no realizar una redirección para ejecutar otra acción. Esto genera un nuevo pedido HTTP reentrante. A continuación se muestra un ejemplo de acción que redirige el pedido a otra acción: public function indexAction() { return $this->redirect( array( "controller" => "autor", "action" => "show", "params" => array( "id" => 101, "mensaje" => "Hola mundo" ) ) ); } Si esta fuera la acción “index” de LibroController, lo que haría es redirigir el pedido a la acción “show” de AutorController, enviándole como parámetros “id=101” y “mensaje=Hola mundo”. Los pedidos HTTP reentrantes son enviados usando el método GET de HTTP, por lo tanto, el pedido sería para la siguiente URL de Yupp: /yupp/biblioteca/autor/show?id=101&mensaje=Hola mundo
  • 44. 9.2 Acciones de infraestructura (scaffolded) Como vimos en la sección 6, en el controlador LibroController podemos ejecutar acciones que no están implementadas, como por ejemplo “list”, “show”, “edit” y “create”. Estas acciones se encuentran implementadas en YuppController, la superclase de todos los controladores. En general es suficiente la implementación por defecto, pero de ser necesario ejecutar cierta lógica particular, estas acciones pueden ser implementadas en nuestros controladores. Un caso típico es cuando un controlador no tiene ninguna clase del modelo de información asociada, por ejemplo LibroController se encarga de las acciones sobre la clase Libro. Estas acciones se consideran de “infraestructura” por que son acciones genéricas, capaces de ser aplicadas a cualquier clase del modelo persistente de cualquier aplicación Yupp. Existe otro conjunto de acciones que están implementadas en CoreController, el controlador que implementa las acciones que se realizan desde el escritorio de Yupp. Por ejemplo, si accedemos a la acción de infraestructura “list” del controlador LibroController mediante la siguiente URL, y luego vamos al “show” del un libro haciendo clic en su identificador (crear uno si no hay ninguno), vamos a ver un link hacia su autor relacionado (si tiene uno), haciendo clic ahí veremos los detalles del autor, aunque no exista el controlador relacionado a la clase Autor. Comenzamos aquí: http://localhost/yupp/biblioteca/libro/list Terminamos aquí: http://localhost/yupp/core/core/show?app=biblioteca&class=Autor&id=1 Nota: para tener datos para probar, puedes ejecutar el test que crea un libro y le asocia un autor. 9.3 Recibiendo archivos Un tipo especial de parámetro que puede ser recibido por el método POST de HTTP son los archivos. Un usuario puede subir un archivo usando un formulario como este en una vista: <form method="post" enctype="multipart/form-data"> <input type="file" name="archivo" value="" /> </form> Del lado del servidor, supongamos que el controlador que recibe el archivo, tiene una acción con el siguiente código: public function recibeArchivoAction() { print_r($this->params); }
  • 45. Esta acción mostrará algo similar a esto: Array ( [file] => Array ( [name] => HCE 004.jpg [type] => image/jpeg [tmp_name] => C:wamptmpphp77.tmp [error] => 0 [size] => 162096 ) ) Si quisiéramos cargar el contenido del archivo subido al servidor en una variable, por ejemplo para guardarlo en la base de datos: public function recibeArchivoAction() { $filename = $this->params["tmp_name"]; $imagen = FileSystem::read($filename); } Y si quisiéramos copiar el archivo a una ubicación determinada: public function recibeArchivoAction() { $filename = $this->params["tmp_name"]; $ubicacion = "dir/subdir/nombreArchivo.jpg"; if (move_uploaded_file($filename, $ubicacion)) { echo "El archivo ha sido cargado correctamente."; } else { echo "Ocurrió un error al subir el archivo. No pudo guardarse."; } }
  • 46. 9.4 Devolviendo XML o JSON Previamente vimos como devolver un string desde una acción. El mismo mecanismo puede ser usado para devolver un string XML o JSON. Estos serán casos de acciones que no devuelven vistas, si no que implementan servicios para ser consumidos desde la interfaz de usuario (por ejemplo mediante pedidos AJAX) o desde otros sistemas. 9.4.1 Programando una acción que devuelve JSON Digamos que dentro de LibroController necesitamos una acción que devuelva los datos de un determinado libro, pero lo queremos en notación JSON. Para lograrlo, podríamos implementar la acción de la siguiente manera: public function jsonShowAction() { YuppLoader::load('core.persistent.serialize', 'JSONPO'); $id = $this->params['id']; // Obtiene el parámetro id $libro = Libro::get( $id ); // Carga el libro con ese id $json = JSONPO::toJSON( $libro ); // Genera la serialización a json // Lo que se devolverá en el response HTTP será de tipo json header('Content-type: application/json'); // Escribe el string json en la respuesta al usuario return $this->renderString( $json ); } La URL Yupp para invocar a esta acción, sería: http://localhost/yupp/biblioteca/libro/jsonShow?id=1 Lo que obtendremos será algo así: { titulo: "El ingenioso hidalgo don Quixote de la Mancha" genero: "prosa narrativa" fecha: "1605-01-01 00:00:00" idioma: "es" numeroPaginas: "223" class: "Libro" deleted: "" autor_id: "1" id: "1" }
  • 47. 9.4.2 Programando una acción que devuelve XML Análogamente al ejemplo de JSON, podemos necesitar programar una acción que devuelva XML. public function xmlShowAction() { $id = $this->params['id']; $libro = Libro::get( $id ); $xml = XMLPO::toXML( $libro ); header('Content-type: text/xml'); return $this->renderString( $xml ); } La URL Yupp para invocar a esta acción, sería: http://localhost/yupp/biblioteca/libro/xmlShow?id=1 Y el resultado es parecido a este XML: <Libro> <titulo>El ingenioso hidalgo don Quixote de la Mancha</titulo> <genero>prosa narrativa</genero> <fecha>1605-01-01 00:00:00</fecha> <idioma>es</idioma> <numeroPaginas>223</numeroPaginas> <class>Libro</class> <deleted/> <autor_id>1</autor_id> <id>1</id> </Libro>
  • 48. 10. Vistas Las vistas implementan la interfaz de usuario de las aplicaciones Yupp. Es común que las aplicaciones tengan una vista para listar instancias de cierta clase persistente, otra vista para ver los detalles de una instancia, otra para crear nuevas instancias y otra para editar instancias. En esta sección veremos los distintos aspectos involucrados en la creación de este tipo de vistas y de otros tipos de vistas más complejos. 10.1 Fundamentos para la implementación de vistas Primero que nada, las vistas no son más que scripts PHP que solo contienen lógica de interfaz de usuario, o sea que: ● Una vista no debería contener lógica de negocio ● Una vista no debería contener consultas complejas a la base de datos ● Una vista no debería modificar el estado de la aplicación Las vistas son colocadas en el directorio “views” de las aplicaciones Yupp, con la característica de que las vistas se organizan según los controladores que las muestran. Por ejemplo, si para el controlador LibroController, se tuviera una vista llamada “list”, esta vista estaría implementada en la siguiente ubicación: apps/biblioteca/views/libro/list.view.php La convención de nombrado de vistas es simple: el archivo debe terminar en “.view.php”. A continuación veremos un ejemplo de una vista para el listado de libros: <?php // Modelo pasado desde el controlador $m = Model::getInstance(); ?> <html> <head> <style> table { border: 1px solid; } td { border: 1px solid; padding: 5px; } </style> </head> <body> <h1>Libros</h1>
  • 49. <table> <!-- El controlador puso la lista de libros en la clave 'libros' --> <?php foreach( $m->get('libros') as $libro) : ?> <tr> <td><?php echo $libro->getTitulo(); ?></td> <td><?php echo $libro->getGenero(); ?></td> <td><?php echo $libro->getIdioma(); ?></td> </tr> <?php endforeach; ?> </table> </body> </html> La acción del controlador que especifica que se debe mostrar la vista anterior, puede ser algo así: public function listAction() { // Carga todos los libros desde la base de datos $libros = Libro::listAll($this->params); // Muestra la vista list enviándole los libros como modelo return array('libros' => $libros); } 10.2 Uso de helpers Los helpers son componentes reusables de código que implementan lógica de interfaz de usuario. Yupp implementa varios helpers que pueden ser utilizados en la programación de vistas, pero el programador puede definir sus propios helpers cuando los necesite. En las siguientes secciones veremos algunos helpers interesantes. Por una lista completa de helpers, puedes visitar la documentación del proyecto: http://www.simplewebportal.net/yupp_framework_php_doc 10.2.1 Helper layout Un layout sirve para reutilizar una estructura general entre varias vistas para la interfaz de usuario de una aplicación. La forma de especificar que una vista utiliza un layout es mediante un etiqueta. Por ejemplo, si la vista “list” del controlador LibroController (que vimos anteriormente) usara un layout llamado “default”, el código de la vista sería el siguiente: <?php // Modelo pasado desde el controlador $m = Model::getInstance(); ?> <html> <layout name="default" /> <head> <style> table {
  • 50. border: 1px solid; } td { border: 1px solid; padding: 5px; } </style> </head> <body> <h1>Libros</h1> <table> <!-- El controlador puso la lista de libros en la clave 'libros' --> <?php foreach( $m->get('libros') as $libro) : ?> <tr> <td><?php echo $libro->getTitulo(); ?></td> <td><?php echo $libro->getGenero(); ?></td> <td><?php echo $libro->getIdioma(); ?></td> </tr> <?php endforeach; ?> </table> </body> </html> Importante: la etiqueta que indica el layout a utilizar debe ir inmediatamente después de la etiqueta “html”. El código del layout puede ser similar a el siguiente, donde $head es todo lo que está dentro de la etiqueta “head” de la vista que referencia al layout, y $body es todo lo que está dentro de la etiqueta “body” de la vista que referencia al layout. <html> <head> <style type="text/css"> ... </style> <?php echo $head; ?> </head> <body> ... <div style="padding:10px;"><?php echo $body; ?></div> </body> </html> Los layouts son también scripts PHP, pero a diferencia de las vistas, deben cumplir con las siguientes convenciones: ● Deben mostrar a las variables $head y $ body. ● El archivo debe terminar en “.layout.php”. ● El archivo debe ubicarse en el directorio “views” de la aplicación. 10.2.2 Helper template
  • 51. Los templates son otra forma de reutilizar código entre distintas vistas, pero a diferencia del layout que es para reutilizar la estructura general de la vista, los templates reutilizan lógica de interfaz de usuario interna a la vista. Por ejemplo si para mostrar el mismo objeto (podría ser una instancia de Libro) se utilizara la misma lógica en varias vistas, esa lógica podría ponerse dentro de un template, y reutilizar el template en dichas vistas. A continuación se muestra un ejemplo de cómo puede ser una llamada a un template que muestra un libro con cierto formato: Helpers::template( array("controller" => "libro", "name" => "details", "args" => array("libro" => $libro) ) ); Los templates también son scripts PHP cuyo nombre termina en “.template.php”, por ejemplo, el template referenciado desde el código anterior es “libro.template.php”. Este template podrá tener código PHP, HTML y de otros tipos. Por ejemplo, el template “libro” podría ser así: <div> <b><?php echo $libro->getTitulo(); ?></b> (<?php echo $libro->getGenero(); ?>, <?php echo $libro->getIdioma(); ?>) </div> Entonces podríamos cambiar el código de la vista “list” (vista en la sección 10.2.1) para que utilice el template: <?php $m = Model::getInstance(); // Modelo pasado desde el controlador ?> <html> <layout name="default" /> <head> <style> table { border: 1px solid; } td { border: 1px solid; padding: 5px; } </style> </head> <body> <h1>Libros</h1> <!-- El controlador puso la lista de libros en la clave 'libros' --> <?php foreach( $m->get('libros') as $libro) : ?> <!-- Se le pasa el libro al template --> <?php Helpers::template( array( "controller" => "libro", "name" => "details", "args" => array("libro" => $libro) ) ); ?> <?php endforeach; ?> </body>
  • 52. </html> 10.2.3 Helper javascript El helper javascript es útil para controlar la inclusión de scripts javascript. Una posible llamada es la siguiente: <?php echo h("js", array("name" => "jquery/jquery-1.5.1.min") ); ?> El código PHP previo, generará el siguiente código HTML: <script type="text/javascript" src="/yupp/js/jquery/jquery-1.5.1.min"></script> 10.2.4 Helper ajax link El helper ajax link, sirve para crear links que al cliquearlos envían un pedido HTTP a una determinada acción de un controlador, con la característica de que el pedido va por AJAX. Esto ayuda a crear aplicaciones web más interactivas. Un ajax link podría ser creado de la siguiente manera: <?php echo Helpers::ajax_link( array( "app" => "biblioteca", "controller" => "libro", "action" => "jsonShow", "id" => $libro>getId(), "body" => "Obtener comentarios por Ajax", "after" => "after_function", "before" => "before_function" ) ); ?> El código PHP previo, generará el siguiente código HMTL/Javascript: <script type="text/javascript"> function ajax_link_0() { $.ajax({ url: '/yupp/biblioteca/libro/jsonShow?id=1', beforeSend: before_function, success: after_function }); } </script> <a href="javascript:ajax_link_0()" target="_self" ">Obtener datos por Ajax</a> El código previo indica que al hacer clic sobre el link, se llama a una función Javascript llamada “before_function”, y al recibir la respuesta del servidor, se llama a la función “after_function”. Ambas funciones deben ser implementadas por el programador, como se muestra a continuación: <script type="text/javascript">
  • 53. // Handlers para JQuery var before_function = function(req, json) { $('#estado').html( "Cargando..." ); } var after_function = function(json) { var libro = json; alert(libro.titulo +' ('+ libro.genero +')'); $('#estado').html( "" ); } </script> Una característica es que el código Javascript generado, dependerá de la librería Javascript que el programador referencie, esto quiere decir que la implementación de ajax link varía según si el programador usa Prototype o jQuery. Esto es transparente al programador. 10.3 Vistas de infraestructura (scaffolded) De la misma forma que las acciones básicas de los controladores (list, show, create, edit, delete) están disponibles sin necesidad de programarlas, las vistas relacionadas a las acciones list, show, create y edit, también son generadas por el framework, sin necesidad de programarlas. Para indicarle a Yupp que se quiere utilizar una vista particular en lugar de las vistas de infraestructura, simplemente se debe colocar el archivo de la vista, cumpliendo las convenciones de nombrado y ubicación. No es necesario realizar ningún tipo de configuración extra.
  • 54. 11. Estado actual del proyecto 11.1 Hoja de ruta del proyecto El proyecto tiene un camino marcado, con el objetivo de lograr una solución robusta, pequeña, rápida y completa para el desarrollo de aplicaciones web sobre PHP. Ese camino ya está avanzado, y este tutorial es prueba de ello. Para seguir el avance, y saber en qué puntos se están trabajando, en nuestra wiki hay una “hoja de ruta”, donde se actualizan los cambios y mejoras realizadas al framework, para cada versión del mismo. http://code.google.com/p/yupp/wiki/Hoja_de_ruta 11.2 Información administrativa Grupo de discusión Donde realizar consultas, comentarios, compartir experiencias, código, recursos, etc. http://groups.google.com/group/yuppframeworkphp Blog Donde se realizan anuncios y se publican temas interesantes relacionados con el framework y el desarrollo web en general. http://yuppframework.blogspot.com/ Twitter Desde el escritorio del framework pueden ser accedidos los twitts relacionados con este, en general son para hacer anuncios importantes con respecto al framework. http://twitter.com/ppazos Sitio del proyecto Donde publicamos las liberaciones, las notas de las versiones, preguntas frecuentes. También aquí están los reportes de bugs y el repositorio de código (SVN). http://code.google.com/p/yupp/ Documentación del proyecto Documentación de referencia para el programador. http://www.simplewebportal.net/yupp_framework_php_doc