Manual de Symfony Objetivos: 1. Modelar correctamente nuestra base de datos en formato YML con sus respectivas relaciones 2. Exportar la base de datos con información por defecto. En la presente ficha aprenderemos a modelar nuestra base de datos en formato YML, luego a partir de la estructura que creemos construir su respectivo modelo, formularios y filtros y finalmente exportar la base de datos con datos iniciales. 1.
Como observamos en el manual 1 de symfony para la creación de un mantenimiento de la clase persona, primero generamos la definición de la entidad “Persona” en el archivo “config » doctrine » schema.yml”, este archivo no sólo sirve para definir una entidad sino que en realidad se deben definir todas las entidades de nuestro proyecto en formato YML. En esta parte del manual aprenderemos como definir varias entidades con sus respectivas relaciones. Para empezar, debemos definir la conexión que vamos a usar para conectarnos a nuestra base de datos, esto la hacíamos en el fichero “config » databases.yml”: all: doctrine: class: sfDoctrineDatabase param: dsn: mysql:host=localhost;dbname=bd_proyecto username: root password: attributes: default_table_charset: utf8 default_table_collate: utf8_spanish_ci Donde “doctrine” es el nombre de la conexión la cual vamos a usar para definir todas nuestras entidades.
2.
Antes de construir nuestra entidades tenemos que centrarnos un poco en como hace symfony para reconocer una entidad, tomamos como ejemplo la siguiente la siguiente entidad “Persona”: Persona: connection: doctrine tableName: t_persona actAs: Sluggable: alias: slug_persona fields: [nombres, ape_paterno, ape_materno] canUpdate: true Timestampable: created: name: fec_crea updated: name: fec_modifica columns: nro_doc: { type: string(15), notnull: true } ape_paterno: { type: string(40), notnull: true } ape_materno: { type: string(40), notnull: true } nombres: { type: string(40), notnull: true } sexo: { type: enum, values: [M, F] } fec_nacimiento: { type: date(25), notnull: true } direccion: { type: string(80) } telefono: { type: string(20) } celular: { type: string(20) } correo: { type: string(60) }
Donde:
Persona: Es el nombre de la entidad y la clase que se va a generar después. connection: doctrine Es la conexión que definimos anteriormente y la forma como symfony se conecta con nuestra base de datos física. tableName: t_persona Es el nombre de la tabla que se va a generar en nuestra base de datos física. actAs: Sluggable: alias: slug_persona fields: [nombres, ape_paterno, ape_materno] canUpdate: true Timestampable: created: name: fec_crea updated: name: fec_modifica Es el comportamiento particular que puede adoptar nuestra entidad: Sluggable » Genera un campo “slug” que será único para cada registro de la entidad y que puede funcionar como una clave pero que toma valores más comprensible para el usuario, por ejemplo el slug para: Jose Carlos Fernández Gomez sería » jose-carlos-fernandez-gomez. Timestampable » Genera en este caso dos campos adicionales “fec_crea” y “fec_modifica” que tienen la función de registrar de forma automática la fecha de creación de un registro y la última fecha de modificación del mismo. columns: nro_doc: { type: string(8), fixed: true, notnull: true } ape_paterno: { type: string(40), notnull: true } ape_materno: { type: string(40), notnull: true } nombres: { type: string(40), notnull: true } sexo: { type: enum, values: [M, F] } fec_nacimiento: { type: date(25), notnull: true } direccion: { type: string(80) } telefono: { type: string(20) } celular: { type: string(20) } correo: { type: string(60) } Aquí se describen todas las columnas de nuestra entidad, fíjese que no se ha descrito la columna que corresponde a la clave primaria, esta se genera por defecto con el nombre de “id”. Primero se coloca el nombre de la columna y a continuación los atributos de esta: type: Es el tipo de dato de nuestra columna, puede ser de varios tipos: boolean: que puede tomar solo dos valores 1 | 0. Test: columns: booltest: boolean integer: Test: columns: integertest: type: integer(4) unsigned: true
Campo de tipo entero, se define entre paréntesis la longitud del entero y luego si será un entero con o sin signo. float: Test: columns: floattest: float Campo de tipo real. decimal: Test: columns: decimaltest: type: decimal(18) scale: 2 Numero decimal con 18 números enteros y 2 decimales
string: Test: columns: stringtest: type: string(200) Cadena de longitud 200 variable -> varchar(200) Test: columns: stringtest: type: string(20) fixed: true Cadena de longitud fija de 20 -> char(20) time: Test: columns: timetest: time date: Test: columns: datetest: date enum: Test: columns: enumtest: type: enum values: [php, java, python]
3.
Tipo de datos especial que solo acepta los valores enumerados en “values”. Relaciones:
Algo importante al momento de diseñar nuestra base de datos es definir correctamente las relaciones de integridad referencial, lo cual podemos hacer perfectamente con YML, para ello veremos los tipos de relaciones que veremos con más frecuencia, para ello tomaremos como ejemplo:
El anterior gráfico representa una base de datos para foros. La representación de sus entidades sería la siguiente: Foro: connection: doctrine tableName: t_foro columns: nombre: { type: string(100), notnull: true } descripcion: { type: string(5000) } # ---------------------------------HiloForo: Connection: doctrine tableName: t_hilo_foro columns: usuario_id: { type: integer, notnull: true } foro_id: { type: integer, notnull: true } titulo: { type: string(100), notnull: true } actualizado: { type: integer(4) } cerrado: { type: boolean } # -----------------------------------Usuario: Connection: doctrine tableName: t_usuario columns: nombre: { type: string(100) , notnull: true } login: { type: string(20) , notnull: true } password: { type: string(50) , notnull: true } activo: { type: boolean }
# -----------------------------------Correo:
Connection: doctrine tableName: t_correo columns: usuario_id: { type: integer, notnull: true } direccion: { type: string(60), notnull: true } # -----------------------------------Grupo: Connection: doctrine tableName: t_grupo columns: nombre: { type: string(50), notnull: true } # -----------------------------------UsuarioGrupo: Connection: doctrine tableName: t_usuario_grupo columns: usuario_id: { type: integer, notnull: true } grupo_id: { type: integer, notnull: true }
Ahora debemos definir la relación entre ellos: Sabemos por definición que tenemos 3 tipos de relaciones (más frecuentes): Relación de 1 a 1. Relación de 1 a varios o varios a 1. Relación de varios a varios. Observamos en nuestro diagrama que existen definidos los 3 tipos de relaciones: 1 foro tiene varios hilos (1 a varios). 1 usuarios está presente en varios hilos (1 a varios). 1 usuario sólo tiene 1 correo (1 a 1). 1 usuario puede pertenecer a varios grupos y un grupo puede tener varios usuarios (varios a varios). La forma como debemos construir las relaciones es la siguiente:
1 a 1: # -----------------------------------Usuario: se crea automaticamente el id Connection: doctrine tableName: t_usuario columns: nombre: { type: string(100) , notnull: true } login: { type: string(20) , notnull: true } password: { type: string(50) , notnull: true } activo: { type: boolean }
atributos de la tabla
# -----------------------------------Correo: Connection: doctrine tableName: t_correo columns: atributos de la tabla usuario_id: { type: integer, notnull: true } direccion: { type: string(60), notnull: true } relations: Usuario: local: usuario_id foreign: id ## hace referencia a la clave primaria de usuario que es “id” foreignType: one ## el tipo de relación es de 1 a 1
relacion que tiene con la tabla USUARIO
1 a varios | varios a 1: Foro: connection: doctrine tableName: t_foro columns: nombre: { type: string(100), notnull: true } descripcion: { type: string(5000) } relations: Hilos: ## un foro tiene “varios hilos” class: HiloForo local: id ## es la clave primaria de esta entidad “id” foreign: foro_id type: many ## la relación de es de varios # ---------------------------------HiloForo: Connection: doctrine tableName: t_hilo_foro columns: usuario_id: { type: integer, notnull: true } foro_id: { type: integer, notnull: true } titulo: { type: string(100), notnull: true } actualizado: { type: integer(4) } cerrado: { type: boolean } relations: Foro: ## un hilo de un foro pertenece a “un solo foro” local: foro_id ## es la clave foranea de esta entidad “foro_id” foreign: id ## es la clave primaria de la entidad foro type: one ## la relación en esta entidad es de 1 Usuario: ## un hilo de un foro pertenece a “un solo usuario” local: usuario_id ## es la clave foranea de esta entidad “usuario_id” foreign: id ## es la clave primaria de la entidad usuario type: one ## la relación en esta entidad es de 1 # -----------------------------------Usuario: Connection: doctrine tableName: t_usuario columns: nombre: { type: string(100) , notnull: true } login: { type: string(20) , notnull: true } password: { type: string(50) , notnull: true } activo: { type: boolean } relations: Hilos: ## un usuario participa en “varios hilos” class: HiloForo local: id ## es la clave primaria de esta entidad “id” foreign: usuario_id type: many ## la relación de es de varios
varios a varios: # -----------------------------------Usuario: Connection: doctrine tableName: t_usuario columns: nombre: { type: string(100) , notnull: true } login: { type: string(20) , notnull: true } password: { type: string(50) , notnull: true } activo: { type: boolean } relations: Grupos: ## un usuario esta en “varios grupos” class: Grupo ## la clase a la que se debe hacer referencia refClass: UsuarioGrupo ## es la clase que permite la definición de varios a varios local: usuario_id ## la clave local de usuario en UsuarioGrupo foreign: grupo_id ## la clave foránea de grupo en UsuarioGrupo
# -----------------------------------Grupo: Connection: doctrine tableName: t_grupo columns: nombre: { type: string(50), notnull: true } relations: Usuarios: ## un grupo tiene “varios usuarios” class: Usuario ## la clase a la que se debe hacer referencia refClass: UsuarioGrupo ## es la clase que permite la definición de varios a varios local: grupo_id ## la clave local de grupo en UsuarioGrupo foreign: usuario_id ## la clave foránea de usuario en UsuarioGrupo
# -----------------------------------UsuarioGrupo: Connection: doctrine tableName: t_usuario_grupo columns: usuario_id: { type: integer, notnull: true } grupo_id: { type: integer, notnull: true }
Entonces nuestro esquema de datos quedaría de la siguiente forma: # -----------------------------------Usuario: Connection: doctrine tableName: t_usuario columns: nombre: { type: string(100) , notnull: true } login: { type: string(20) , notnull: true } password: { type: string(50) , notnull: true } activo: { type: boolean } Hilos: class: HiloForo local: id foreign: usuario_id type: many Grupos: class: Grupo refClass: UsuarioGrupo local: usuario_id foreign: grupo_id # -----------------------------------Correo: Connection: doctrine tableName: t_correo columns: usuario_id: { type: integer, notnull: true } direccion: { type: string(60), notnull: true } relations: Usuario: local: usuario_id foreign: id foreignType: one # -----------------------------------Foro: connection: doctrine tableName: t_foro columns: nombre: { type: string(100), notnull: true } descripcion: { type: string(5000) } relations: Hilos: class: HiloForo local: id foreign: foro_id type: many # ---------------------------------HiloForo: Connection: doctrine tableName: t_hilo_foro columns: usuario_id: { type: integer, notnull: true } foro_id: { type: integer, notnull: true } titulo: { type: string(100), notnull: true } actualizado: { type: integer(4) } cerrado: { type: boolean } relations: Foro: local: foro_id foreign: id type: one Usuario: local: usuario_id foreign: id type: one
# -----------------------------------Grupo: Connection: doctrine tableName: t_grupo columns: nombre: { type: string(50), notnull: true } relations: Usuarios: class: Usuario refClass: UsuarioGrupo local: grupo_id foreign: usuario_id # -----------------------------------UsuarioGrupo: Connection: doctrine tableName: t_usuario_grupo columns: usuario_id: { type: integer, notnull: true } grupo_id: { type: integer, notnull: true }
4.
Una vez aprendido esto modele el esquema para sus respectivas bases de datos.