Espacio Daycry - Espacio de programación

  • Inicio
  • Categorias
    • - Codeigniter
    • - Symfony
    • - HTML5
    • - Linux / Ubuntu
    • - PHP
    • - Jquery
  • PortFolio - Proyectos Codeiniter
    • - Encuestas Online
    • - Estadísticas - GLPI
    • - Gestión de colas
    • - Web Service - REST

jueves, 21 de agosto de 2014

Symfony - Día 3: El modelo de datos

Posted by daycry at 12:27 Labels: symfony
Aquellos de ustedes locos por abrir el editor de texto y hacer algo de PHP estarán encantados de saber que el tutorial de hoy nos introduce algo en el desarrollo. Vamos a definir el modelo de datos Jobeet, utilizaremos un ORM para interactuar con la base de datos, y construiremos el primer módulo de la aplicación. Pero como Symfony hace una gran parte del trabajo por nosotros, vamos a tener un módulo web totalmente funcional sin tener que escribir mucho código PHP.

El Modelo Relacional

Los casos de uso que escribimos ayer describen los principales objetos de nuestro proyecto: puestos de trabajo, afiliados, y las categorías. Aquí está el correspondiente diagrama de entidad relación:
Diagrama de Entidad Relación
Además de las columnas descritas en los casos de uso, también hemos añadido un campocreated_at a algunas tablas. Symfony reconoce estos campos y establece el valor de la hora actual de sistema cuando un registro es creado. Esto es lo mismo para el campo updated_at: su valor se establece siempre a la hora del sistema en que el registro se actualiza.

El Esquema

Para almacenar los puestos de trabajo, los afiliados, y las categorías, es evidente que necesitamos una base de datos relacional.
Pero como Symfony es un Framework Orientado a Objetos, nos gustaría manipular los objetos cada vez que podamos. Por ejemplo, en lugar de escribir sentencias SQL para recuperar los registros de la base de datos, preferimos más usar los objetos.
La información de la base de datos relacional debe ser mapeada a un modelo de objetos. Esto se puede hacer con una herramienta ORM, o Mapeador, y afortunadamente, Symfony tiene incluido dos de ellas: Propel y Doctrine. En este tutorial, usaremos Doctrine.
El ORM necesita una descripción de las tablas y sus relaciones para crear las clases relacionadas. Hay dos maneras de crear este esquema de descripción: ingeniería reversa de una base de datos existente o creándolo a mano.
Como la base de datos no existe todavía, y como queremos mantener la base de datos Jobeet agnóstica, vamos a crear el archivo de esquema a mano editando el archivo vacíoconfig/doctrine/schema.yml:
# config/doctrine/schema.yml
---
JobeetCategory:
  actAs: { Timestampable: ~ }
  columns:
    name: { type: string(255), notnull: true, unique: true }
 
JobeetJob:
  actAs: { Timestampable: ~ }
  columns:
    category_id:  { type: integer, notnull: true }
    type:         { type: string(255) }
    company:      { type: string(255), notnull: true }
    logo:         { type: string(255) }
    url:          { type: string(255) }
    position:     { type: string(255), notnull: true }
    location:     { type: string(255), notnull: true }
    description:  { type: string(4000), notnull: true }
    how_to_apply: { type: string(4000), notnull: true }
    token:        { type: string(255), notnull: true, unique: true }
    is_public:    { type: boolean, notnull: true, default: 1 }
    is_activated: { type: boolean, notnull: true, default: 0 }
    email:        { type: string(255), notnull: true }
    expires_at:   { type: timestamp, notnull: true }
  relations:
    JobeetCategory: { onDelete: CASCADE, local: category_id, foreign: id, foreignAlias: JobeetJobs } 
 
JobeetAffiliate:
  actAs: { Timestampable: ~ }
  columns:
    url:       { type: string(255), notnull: true }
    email:     { type: string(255), notnull: true, unique: true }
    token:     { type: string(255), notnull: true }
    is_active: { type: boolean, notnull: true, default: 0 }
  relations:
    JobeetCategories:
      class: JobeetCategory
      refClass: JobeetCategoryAffiliate
      local: affiliate_id
      foreign: category_id
      foreignAlias: JobeetAffiliates
 
JobeetCategoryAffiliate:
  columns:
    category_id:  { type: integer, primary: true }
    affiliate_id: { type: integer, primary: true }
  relations:
    JobeetCategory:  { onDelete: CASCADE, local: category_id, foreign: id }
    JobeetAffiliate: { onDelete: CASCADE, local: affiliate_id, foreign: id }
Si decidiste crear las tablas escribiendo las sentencias SQL, puedes generar el archivo de configuración del esquema correspondiente schema.yml,
ejecutando la tarea doctrine:build-schema:
$ php symfony doctrine:build-schema
La anterior tarea requiere que tengas la base de datos configurada en eldatabases.yml. Te mostraremos como configurar la base de datos en un paso posterior. Si tratas de ejecutar esta tarea ahora no funcionará ya que no sabe que base de datos contruir para el esquema.
El esquema es la traducción directa de un diagrama de entidad relación en formato YAML.
El Formato YAML
De acuerdo con el sitio web oficial YAML, YAML es "es una serialización de datos estándar muy amigable para todos los lenguajes de programación"
Dicho de otra manera, YAML es un lenguaje sencillo para describir los datos (strings, integers, dates, arrays, y hashes).
En YAML, la estructura se muestra a través de la sangría, la secuencia de elementos se denotan por un guión, y los pares clave/valor están separados por dos puntos. YAML también tiene una sintaxis abreviada para describir la misma estructura con menos líneas, donde los arrays explícitamente se muestran con [] y los hashes o array asociativos con {}.
Si todavía no están familiarizados con YAML, es hora de empezar con él pues el framework Symfony lo utiliza ampliamente para sus archivos de configuración. Un buen punto de partida es la documentación del componente YAML de Symfony.
Hay una cosa importante que necesitas recordar cuando estás editando un archivo YAML: la indentación debe hacerse con uno o mas espacios en blanco, pero nunca con tabulaciones.
El archivo schema.yml contiene la descripción de todas las tablas y sus columnas. Cada columna se describe con la siguiente información:
  • type: El tipo de columna (boolean, integer, float, decimal, string, array, object,blob, clob, timestamp, time, date, enum, gzip)
  • notnull: Es true si deseas que la columna sea obligadoria
  • unique: Es true si deseas crear un índice único para la columna.
El atributo onDelete define el comportamiento ON DELETE para claves foráneas, y Doctrine da soporte para CASCADE, SETNULL, y RESTRICT. Por ejemplo, cuando un registro de job es borrado, todos los registros jobeet_category_affiliate
relacionados serán automáticamente eliminados de la base de datos
Nota del Traductor Si bien no es probable, es posible que se quiera eliminar una categoría completa del sistema.
El campo category_id de la entidad JobeetJob, tiene al final añadida la opción onDelete. La misma está establecida como CASCADE, para determinar que cuando una categoría sea eliminada, tambien se eliminen los registros job (los puestos de trabajo).
Esto se debe a que los registros job tienen establecido como campo obligatorio a la categoría asociada (a la que pertenece), por lo que no sería correcto dejarhuerfano a un registro, ni establecer éste valor a null.

La Base De Datos

El framework Symfony soporta todas las Base De Datos soportadas por PDO (MySQL, PostgreSQL, SQLite, Oracle, MSSQL, ...). PDO es la capa de abstracción de base de datos que viene con PHP.
Vamos a usar MySQL para este tutorial:
$ mysqladmin -uroot -p create jobeet
Enter password: mYsEcret ## La clave se mostrará como ********
Eres libre de elegir otro motor de base de datos si lo deseas. No será difícil adaptar el código que vamos a escribir ya que vamos a utilizar el ORM quien será quien escriba el SQL por nosotros.
Tenemos que decirle a Symfony que base de datos usar para el proyecto Jobeet:
$ php symfony configure:database "mysql:host=localhost;dbname=jobeet" root mYsEcret
La tarea configure:database emplea tres argumentos: el PDO DSN, el nombre de usuario, y la clave de acceso a la base de datos. Si no tienes ninguna contraseña de la base en el servidor de desarrollo, basta con omitir el tercer argumento.
La tarea configure:database almacena la configuración de la base de datos en el archivo de configuración config/databases.yml. En lugar de utilizar la tarea, puedes editar este archivo manualmente.
Pasar la clave de la base de datos por linea de comandos es conveniente peroinseguro. Dependiendo de quienes tiene acceso a tu entorno, podría ser mejor editar el config/databases.yml para cambiar la clave. Desde luego, para mantener la clave a salvo, el acceso al archivo de configuración debería también ser restringido.

El ORM

Gracias al archivo de descripción de la base de datos schema.yml, podemos utilizar algunas de las tareas de Doctrine para generar los comandos SQL necesarios para crear tablas de la base de datos:
Primero para generar el SQL debes contruir el modelo apartir de tus archivos esquema.
$ php symfony doctrine:build --model
Ahora que tus modelos existen puedes generar e insertar el SQL.
$ php symfony doctrine:build --sql
La tarea doctrine:build --sql genera comandos SQL en el directorio data/sql/, optimizado para el motor de base de datos que hemos configurado:
# snippet from data/sql/schema.sql
CREATE TABLE jobeet_category (id BIGINT AUTO_INCREMENT, name VARCHAR(255)
NOT NULL COMMENT 'test', created_at DATETIME, updated_at DATETIME, slug
VARCHAR(255), UNIQUE INDEX sluggable_idx (slug), PRIMARY KEY(id))
ENGINE = INNODB;
Para realmente crear las tablas en la base de datos, necesitas ejecutar la tarea doctrine:insert-sql:
$ php symfony doctrine:insert-sql 
Como con cualquier herramienta de línea de comandos, las tareas symfony pueden tener argumentos y opciones. Cada tarea viene con un mensaje de ayuda que se puede mostrar ejecutando la tarea help:
$ php symfony help doctrine:insert-sql
El mensaje de ayuda lista de todos los posibles argumentos y opciones, da los valores por defecto para cada uno de ellos, y proporciona algunos ejemplos útiles.
El ORM también genera las clases PHP que mapea los registros de la tabla con los objetos:
$ php symfony doctrine:build --model
La tarea doctrine:build --model genera archivos PHP en el directorio lib/model/ que se pueden utilizar para interactuar con la base de datos. Navegando por los archivos generados, probablemente habrás notado que Doctrine genera cuatro clases por tabla. Para la tablajobeet_job:
  • JobeetJob: Un objeto de esta clase representa un único registro de la tablajobeet_job. La clase está vacía por defecto.
  • BaseJobeetJob: La clase padre de JobeetJob. Cada vez que ejecutas doctrine:build --model, esta clase es sobreescrita, por lo que todas las personalizaciones se deben hacer en la clase JobeetJob.
  • JobeetJobTable: La clase define los métodos que mayormente devuelve coleccionesde objetos JobeetJob. La clase está vacía por defecto.
Los valores de las columnas de un registro se pueden manipular con el modelo de objetos mediante el uso de algunos métodos get*() y métodos set*():
$job = new JobeetJob();
$job->setPosition('Web developer');
$job->save();
 
echo $job->getPosition();
 
$job->delete();
También puedes definir claves foráneas directamente por la vinculación de objetos:
$category = new JobeetCategory();
$category->setName('Programming');
 
$job = new JobeetJob();
$job->setCategory($category);
La tarea doctrine:build --all es un acceso directo para las tareas que han ejecutado en esta sección y algunas más. Por lo tanto, ejecuta esta tarea ahora para generar formularios y validadores para el modelo de clases de Jobeet:
$ php symfony doctrine:build --all --no-confirmation
Verás los validadores en acción al final del día y los formularios se explicarán en gran detalle en el día 10.

Los Datos Iniciales

Los tablas se han creado en la base de datos, pero no hay datos en ellas. Para cualquier aplicación web, hay tres tipos de datos:
  • Datos Iniciales: Los datos iniciales son necesarios para que la aplicación funcione. Por ejemplo, Jobeet necesita algunas categorías iniciales. Si no, nadie será capaz de envíar un puesto de trabajo. También necesitamos un administrador de usuarios para poder acceder al backend.
  • Datos de Prueba: Los datos de prueba son necesarios para que la aplicación sea probada. Como desarrollador, escribes pruebas para asegurarte que Jobeet se comporta como se describe en los casos de uso, y la mejor manera es escribir pruebas automáticas. Por lo tanto, cada vez que ejecutes tus pruebas, necesitas una base de datos limpia con algunos datos nuevos de prueba en ella.
  • Los Datos del Usuario: Los datos del usuario son creados por los usuarios durante la vida normal de la aplicación.
Cada vez que Symfony crea las tablas en la base de datos, todos los datos se pierden. Para rellenar la base de datos con algunos los datos iniciales, podriamos crear un script PHP, o ejecutar sentencias SQL con algun programa mysql. Pero como la necesidad es bastante común, hay una mejor manera con Symfony: crear archivos YAML en el directorio data/fixtures/ y usar la tarea doctrine:data-load para cargarlos en la base de datos.
Primero, crea los siguientes archivos de datos:
# data/fixtures/categories.yml
JobeetCategory:
  design:
    name: Design
  programming:
    name: Programming
  manager:
    name: Manager
  administrator:
    name: Administrator
 
# data/fixtures/jobs.yml
JobeetJob:
  job_sensio_labs:
    JobeetCategory: programming
    type:         full-time
    company:      Sensio Labs
    logo:         sensio-labs.gif
    url:          http://www.sensiolabs.com/
    position:     Web Developer
    location:     Paris, France
    description:  |
      You've already developed websites with symfony and you want to work
      with Open-Source technologies. You have a minimum of 3 years
      experience in web development with PHP or Java and you wish to
      participate to development of Web 2.0 sites using the best
      frameworks available.
    how_to_apply: |
      Send your resume to fabien.potencier [at] sensio.com
    is_public:    true
    is_activated: true
    token:        job_sensio_labs
    email:        job@example.com
    expires_at:   '2008-10-10'
 
  job_extreme_sensio:
    JobeetCategory:  design
    type:         part-time
    company:      Extreme Sensio
    logo:         extreme-sensio.gif
    url:          http://www.extreme-sensio.com/
    position:     Web Designer
    location:     Paris, France
    description:  |
      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
      eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
      enim ad minim veniam, quis nostrud exercitation ullamco laboris
      nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
      in reprehenderit in.
 
      Voluptate velit esse cillum dolore eu fugiat nulla pariatur.
      Excepteur sint occaecat cupidatat non proident, sunt in culpa
      qui officia deserunt mollit anim id est laborum.
    how_to_apply: |
      Send your resume to fabien.potencier [at] sensio.com
    is_public:    true
    is_activated: true
    token:        job_extreme_sensio
    email:        job@example.com
    expires_at:   '2008-10-10'
El archivo de datos de puestos de trabajo hace referencia a dos imágenes. Puedes descargarlas de
(/get/jobeet/sensio-labs.gif, /get/jobeet/extreme-sensio.gif) y colocarlas en el directorio uploads/jobs/.
Esta escrito en YAML, y define el modelo de objetos, etiquetados con un nombre único (por ejemplo, hemos definido dos puestos de trabajo etiquetados con job_sensio_labs yjob_extreme_sensio). Estas etiquetas son de gran utilidad para vincular objetos relacionados sin tener que definir claves primarias (que a menudo son auto-incrementales y no se pueden establecer). Por ejemplo, la categoría de job_sensio_labs es programming, que es la etiqueta dada a la categoría 'Programming'.
En un archivo YAML, cuado una cadena tiene saltos de linea (como la columnadescription en el archivo de datos de puestos de trabajo), puedes usar la barra vertical (|) para indicar que la cadena aparecerá en varias lineas.
A través de un archivo de datos se puede tener objetos de uno o varios modelos, hemos decidido crear un archivo por cada modelo para los datos de Jobeet.
Propel require que los archivos de datos tengan un prefijo númerico que determine el orden en el cual los archivos serán cargados. Con Doctrine esto no es necesario ya que todos los archivos serán cargados y guardados en el correcto orden para asegurar
que las claves foraneas sean adecuadas.
En un archivo de datos, no es necesario definir todos los valores de las columnas. Si no que, Symfony utilizará el valor predeterminado definido en el esquema de base de datos. Y como Symfony usa Doctrine para cargar los datos en la base de datos, todos los comportamientos incorporados (como el seteo automático a created_at o updated_at), o los comportamientos personalizados que puedes haber agregado al modelo de las clases son activados.
La carga de los datos iniciales en la base de datos es tan simple como ejecutar la tareadoctrine:data-load:
$ php symfony doctrine:data-load
La tarea doctrine:build --all --and-load es un atajo para la tareadoctrine:build --all seguida de la tarea doctrine:data-load.
Ejecuta la tarea doctrine:build --all --and-load para asegurarte que todo es generado desde tu esquema. Esto generará tus formularios, filtros, modelos, vaciará tu base de datos y la re-creará de nuevo con todas las tablas.
$ php symfony doctrine:build --all --and-load

Miralo en acción en el Navegador

Hemos utilizado la interfaz de línea de comandos mucho, pero eso no es realmente emocionante, especialmente para un proyecto web. Ahora tenemos todo lo que necesitamos para crear páginas Web que interactúan con la base de datos.
Vamos a ver cómo mostrar la lista de puestos de trabajo, cómo editar un trabajo, y cómo eliminar un puesto de trabajo. Como se explicó durante el día 1, un proyecto symfony se hace de las aplicaciones. Cada aplicación está dividida en módulos. Un módulo es un conjunto de código PHP auto-contenido que representa una característica de la aplicación (el módulo API, por ejemplo), o un conjunto de manipulaciones que el usuario puede hacer sobre un objeto del modelo (un módulo job, por ejemplo).
Symfony es capaz de generar automáticamente un módulo para un determinado modelo que proporciona las características básicas de manipulación:
$ php symfony doctrine:generate-module --with-show --non-verbose-templates frontend job JobeetJob
La tarea doctrine:generate-module genera módulo job en la aplicación frontend para el modeloJobeetJob. Como con la mayoría de las tareas symfony, algunos archivos y directorios se han creado para ti bajo el directorio apps/frontend/modules/job/:
DirectorioDescripción
actions/Acciones del módulo
templates/Plantillas del módulo
El archivo actions/actions.class.php define todas las acciones disponibles para el módulojob:
Nombre de la acciónDescripción
indexMuestra los registros de la tabla
showMuestra los campos de un registro
newMuestra un formulario para crear un nuevo registro
createCrea un nuevo registro
editMuestra un formulario para crear editar un registro existente
updateActualiza un registro con los valores que envió el usuario
deleteBorra un registro de la tabla
Ahora puedes probar el módulo job en un navegador:
 http://www.jobeet.com.localhost/frontend_dev.php/job
El módulo Job
Si intentas editar un puesto de trabajo, te darás cuenta que el combo Category id tiene una lista
de todos los nombres de las categorías. El valor de cada opción esta dado por el método__toString().
Doctrine tratará de dar un método base __toString() adivinandolo de una columna descriptiva de nombre como ser, title, name, subject, etc. Si quieres algo distinto entonces necesitas agregar tus propios métodos __toString() como se ve más abajo. El modelo JobeetCategoryesta listo para adivinar el método __toString() usando la columna name de la tablajobeet_category.
// lib/model/doctrine/JobeetJob.class.php
class JobeetJob extends BaseJobeetJob
{
  public function __toString()
  {
    return sprintf('%s at %s (%s)', $this->getPosition(), $this->getCompany(), $this->getLocation());
  }
}
 
// lib/model/doctrine/JobeetAffiliate.class.php
class JobeetAffiliate extends BaseJobeetAffiliate
{
  public function __toString()
  {
    return $this->getUrl();
  }
}
Ahora puedes editar y crear puestos de trabajo. Trata de dejar un campo obligatorio en blanco, o tratar de dar una fecha no válida. Así es, Symfony ha creado básicas reglas de validación analizando el esquema de base de datos.
Validación

Referencia: http://symfony.com/legacy/doc/jobeet/1_4/es/03?orm=Doctrine
Tweet

Related Posts

  • Symfony - Día 21: La Memoria Cache
    Symfony - Día 21: La Memoria Cache
  • Symfony - Día 20: Los Plugins
    Symfony - Día 20: Los Plugins
  • Symfony - Día 19: Internacionalización y Localización
    Symfony - Día 19: Internacionalización y Localización
  • Symfony - Día 18: AJAX
    Symfony - Día 18: AJAX

No hay comentarios :

Publicar un comentario

Entrada más reciente Entrada antigua Inicio
Suscribirse a: Enviar comentarios ( Atom )

Sígueme en las Redes Sociales



Follow @daycry9



Donaciones

Suscribirse a

Entradas
Atom
Entradas
Comentarios
Atom
Comentarios

Datos personales

daycry
Ver todo mi perfil

Entradas populares

  • Crear archivos PHP ejecutables por terminal UBUNTU
    En este apartado vamos a explicar como ejercutar archivos PHP a través del terminal de Ubuntu. Lo primero que tendríamos que hacer es inst...
  • Pâginación PHP con Librería Zebra Pagination
    En este blog voy a comentar un tema que se utilizan en casi todas las páginas web que existen, y es el tema de la paginación. La paginaci...
  • PHPExcel - Codeigniter
    Este post trata de la integración de la librería PHPExcel en Codeigniter, aunque se podría aplicar a cualquier librería, como por ejemplo mP...
  • PHP- Operaciones con fechas - Sumar Horas, minutos y segundos
    Ejemplo para añadir o sumar un número determinado de hora/s, minuto/s, segundo/s a una fecha en php. Con la función strtotime se puede ...
  • Codeigniter - Múltiples conexiones a base de datos
    Este tema es uno de los temas primordiales sobre el framework Codeigniter, ya que en alguna ocación nos hemos visto obligados a recoger dato...

© Espacio Daycry - Espacio de programación 2013 . Powered by Bootstrap , Blogger templates and RWD Testing Tool