Tutorial manos a la obra con Yupp PHP Framework

75
Yupp PHP Framework Tutorial “manos a la obra” Autor: Ing. Pablo Pazos Gutiérrez <[email protected]> Fecha: Mayo 2011 Versión: 1.1

description

 

Transcript of Tutorial manos a la obra con Yupp PHP Framework

Page 1: Tutorial manos a la obra con Yupp PHP Framework

Yupp PHP FrameworkTutorial “manos a la obra”

Autor: Ing. Pablo Pazos Gutiérrez<[email protected]>

Fecha: Mayo 2011Versión: 1.1

Page 2: Tutorial manos a la obra con Yupp PHP Framework

Índice1. Fundamentos de patrones MVC y ORM............................................................................................4

1.1 Model-View-Controller (MVC).......................................................................................................41.1.1 Algunos conceptos a importantes de recordar:.....................................................................5

1.2 Object-Relational Mapping (ORM)................................................................................................61.2.1 Mapeo objeto-relacional.........................................................................................................6

1.2.1.1 Mapeo de clase...............................................................................................................61.2.1.2 Mapeo de relaciones.......................................................................................................71.2.1.3 Mapeos de herencia........................................................................................................9

2. Fundamentos de programación ágil y aplicaciones web.................................................................103. Instalación y configuración del framework.......................................................................................12

3.1 Descargar la liberación...............................................................................................................123.2 Descargar del servidor de desarrollo..........................................................................................133.3 Configuración del framework......................................................................................................14

4. Estructura de Yupp Framework........................................................................................................155. URLs en Yupp..................................................................................................................................186. Creando una aplicación simple........................................................................................................197. Estructura de las aplicaciones Yupp................................................................................................24

7.1 Configuración de la base de datos por aplicación......................................................................257.1.1 Creando la configuración.....................................................................................................25

7.2 Script de bootstrap......................................................................................................................267.3 Scripts de testing........................................................................................................................26

8. Model: funcionalidades avanzadas..................................................................................................288.1 Gestionando relaciones hasOne................................................................................................288.2 Gestionando relaciones hasMany..............................................................................................30

8.2.1 Tipos de relaciones hasMany..............................................................................................318.3 Convenciones sobre nombrado de tablas..................................................................................32

8.3.1 Nombrado implícito de tablas..............................................................................................328.3.2 Nombrado explícito de tablas..............................................................................................328.3.3 Nombrado de tablas de join.................................................................................................33

8.4 Creando restricciones sobre campos y relaciones.....................................................................338.4.1 Definiendo restricciones.......................................................................................................338.4.2 Verificando restricciones......................................................................................................35

8.4.2.1 Validando datos mediante restricciones........................................................................358.4.2.2 Validando datos previa a la persistencia.......................................................................35

8.5 Definiendo lógica pre-validación.................................................................................................368.6 Usando belongsTo......................................................................................................................378.7 Definiendo relaciones de muchos a muchos..............................................................................408.8 Eliminación física vs. eliminación lógica.....................................................................................40

9. Controladores...................................................................................................................................429.1 Convenciones.............................................................................................................................429.2 Acciones de infraestructura (scaffolded)....................................................................................449.3 Recibiendo archivos...................................................................................................................449.4 Devolviendo XML o JSON..........................................................................................................46

9.4.1 Programando una acción que devuelve JSON....................................................................469.4.2 Programando una acción que devuelve XML......................................................................47

10. Vistas..............................................................................................................................................4810.1 Fundamentos para la implementación de vistas......................................................................48

Page 3: Tutorial manos a la obra con Yupp PHP Framework

10.2 Uso de helpers..........................................................................................................................4910.2.1 Helper layout......................................................................................................................4910.2.2 Helper template..................................................................................................................5010.2.3 Helper javascript................................................................................................................5210.2.4 Helper ajax link...................................................................................................................52

10.3 Vistas de infraestructura (scaffolded).......................................................................................5311. Estado actual del proyecto.............................................................................................................54

11.1 Hoja de ruta del proyecto..........................................................................................................5411.2 Información administrativa........................................................................................................54

Page 4: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 5: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 6: Tutorial manos a la obra con Yupp PHP Framework

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:

Page 7: Tutorial manos a la obra con Yupp PHP Framework

// Todas clas clases persistentes heredan de PersistentObjectclass 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

Page 8: Tutorial manos a la obra con Yupp PHP Framework

id id_a id_a id_b1

id_a id_b2

id_a id_b3

id id_b1

id id_b2

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

Page 9: Tutorial manos a la obra con Yupp PHP Framework

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

Page 10: Tutorial manos a la obra con Yupp PHP Framework

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

Page 11: Tutorial manos a la obra con Yupp PHP Framework

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 =42 Gyy 2 xr 5 zA ● http :// www . youtube . com / watch ? v = ErqCqwkwIDE ● http :// www . youtube . com / watch ? v = jB 5 KFJULahs ● http :// www . youtube . com / watch ? v = KMZLM 2 AhSE 0 ● http :// www . youtube . com / watch ? v = ANMrzw 7 JFzA

Page 12: Tutorial manos a la obra con Yupp PHP Framework

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 /

Page 13: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 14: Tutorial manos a la obra con Yupp PHP Framework

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

Page 15: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 16: Tutorial manos a la obra con Yupp PHP Framework

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

Page 17: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 18: Tutorial manos a la obra con Yupp PHP 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 ? param 1= value 1& param 2= value 2

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 / value 1/ value 2

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.

Page 19: Tutorial manos a la obra con Yupp PHP Framework

6. Creando una aplicación simple

Para crear una aplicación simple, se deben seguir estos pasos:

1. Ir al escritorio de Yupp Framework2. 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 modeloSupongamos 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/model2. Ahí crear el archivo biblioteca.model.Libro.class.php3. Programar una clase que herede de PersistentObject4. 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 clase6. Copiar los métodos estáticos de alguna clase de ejemplo7. 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);

Page 20: Tutorial manos a la obra con Yupp PHP Framework

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); }}

Page 21: Tutorial manos a la obra con Yupp PHP Framework

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); }}

Page 22: Tutorial manos a la obra con Yupp PHP Framework

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 web2. 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-dd12. 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:

Page 23: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 24: Tutorial manos a la obra con Yupp PHP Framework

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

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

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

/apps/biblioteca/bootstrapDirectorio 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/configDirectorio donde se colocará todo recurso relativo a la configuración de la aplicación.

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

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

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

/apps/biblioteca/servicesDirectorio que contiene las clases que implementan la lógica de negocio de la aplicación.

Page 25: Tutorial manos a la obra con Yupp PHP Framework

/apps/biblioteca/utilsDirecorio donde se coloca todo recurso auxiliar para el correcto funcionamiento de la aplicación.

/apps/biblioteca/viewsDirectorio 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.xmlDescriptor 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' );

Page 26: Tutorial manos a la obra con Yupp PHP Framework

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(); }

Page 27: Tutorial manos a la obra con Yupp PHP Framework

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()).

Page 28: Tutorial manos a la obra con Yupp PHP Framework

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:

Page 29: Tutorial manos a la obra con Yupp PHP Framework

$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();

Page 30: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 31: Tutorial manos a la obra con Yupp PHP Framework

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.

ColeccionesPor 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);

ListasUna 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);

ConjuntosLas 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');

Page 32: Tutorial manos a la obra con Yupp PHP Framework

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”

Page 33: Tutorial manos a la obra con Yupp PHP Framework

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:

Page 34: Tutorial manos a la obra con Yupp PHP Framework

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

Page 35: Tutorial manos a la obra con Yupp PHP Framework

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() );

Page 36: Tutorial manos a la obra con Yupp PHP Framework

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 restriccionesSi 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 valoresEs 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}

Page 37: Tutorial manos a la obra con Yupp PHP Framework

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 A4. A(1)<->(*)B: Yupp considera que B belongsTo A5. A(*)->(*)B: Yupp considera que B belongsTo A6. 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}

Page 38: Tutorial manos a la obra con Yupp PHP Framework

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() );

Page 39: Tutorial manos a la obra con Yupp PHP Framework

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 autorif( !$autor->save() ) print_r( $autor->getErrors() ); // Intenta persistir

Page 40: Tutorial manos a la obra con Yupp PHP Framework

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.

Page 41: Tutorial manos a la obra con Yupp PHP Framework

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

Page 42: Tutorial manos a la obra con Yupp PHP Framework

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

Page 43: Tutorial manos a la obra con Yupp PHP Framework

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

Page 44: Tutorial manos a la obra con Yupp PHP Framework

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);}

Page 45: Tutorial manos a la obra con Yupp PHP Framework

Esta acción mostrará algo similar a esto:

Array ( [file] => Array ( [name] => HCE 004.jpg [type] => image/jpeg [tmp_name] => C:\wamp\tmp\php77.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."; }}

Page 46: Tutorial manos a la obra con Yupp PHP Framework

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"

}

Page 47: Tutorial manos a la obra con Yupp PHP Framework

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>

Page 48: Tutorial manos a la obra con Yupp PHP Framework

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>

Page 49: Tutorial manos a la obra con Yupp PHP Framework

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

Page 50: Tutorial manos a la obra con Yupp PHP Framework

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

Page 51: Tutorial manos a la obra con Yupp PHP Framework

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>

Page 52: Tutorial manos a la obra con Yupp PHP Framework

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

Page 53: Tutorial manos a la obra con Yupp PHP Framework

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

Page 54: Tutorial manos a la obra con Yupp PHP Framework

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ónDonde realizar consultas, comentarios, compartir experiencias, código, recursos, etc.http :// groups . google . com / group / yuppframeworkphp

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

TwitterDesde 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 proyectoDonde 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 proyectoDocumentación de referencia para el programador.http :// www . simplewebportal . net / yupp _ framework _ php _ doc