El tutorial Jobeet

3.2. El esquema

Los datos de las ofertas de trabajo, afiliados y categorías se guardan en una base de datos relacional. Por otra parte, como Symfony es un framework orientado a objetos, nuestro objetivo es trabajar con objetos siempre que sea posible. Así por ejemplo, preferimos utilizar objetos a tener que escribir sentencias SQL para obtener los registros de la base de datos.

Para trabajar con objetos en una base de datos relacional, es necesario realizar un mapeo o conversión entre la información de la base de datos y los objetos PHP. Este mapeo se realiza con unas herramientas llamadas ORM y Symfony incluye por defecto dos de las más utilizadas: Propel y Doctrine. En este tutorial vamos a utilizar Propel.

A partir de la descripción de cada tabla y de las relaciones entre tablas, el ORM crea las clases PHP necesarias para trabajar con objetos. Existen dos formas de crear la descripción del esquema de datos: mediante la introspección de una base de datos existente o creando el esquema manualmente.

Nota Existen aplicaciones para crear bases de datos gráficamente (por ejemplo Dbdesigner de Fabforce) y para generar archivos de tipo schema.xml (por ejemplo DB Designer 4 TO Propel Schema Converter).

Como todavía no tenemos ninguna base de datos y como queremos que Jobeet funcione con todos los tipos de gestores de bases de datos, vamos a crear el archivo del esquema a mano. Para ello, abre el archivo config/schema.yml y añade lo siguiente tal y como está escrito:

# config/schema.yml
propel:
  jobeet_category:
    id:           ~
    name:         { type: varchar(255), required: true, index: unique }

  jobeet_job:
    id:           ~
    category_id:  { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true }
    type:         { type: varchar(255) }
    company:      { type: varchar(255), required: true }
    logo:         { type: varchar(255) }
    url:          { type: varchar(255) }
    position:     { type: varchar(255), required: true }
    location:     { type: varchar(255), required: true }
    description:  { type: longvarchar, required: true }
    how_to_apply: { type: longvarchar, required: true }
    token:        { type: varchar(255), required: true, index: unique }
    is_public:    { type: boolean, required: true, default: 1 }
    is_activated: { type: boolean, required: true, default: 0 }
    email:        { type: varchar(255), required: true }
    expires_at:   { type: timestamp, required: true }
    created_at:   ~
    updated_at:   ~

  jobeet_affiliate:
    id:           ~
    url:          { type: varchar(255), required: true }
    email:        { type: varchar(255), required: true, index: unique }
    token:        { type: varchar(255), required: true }
    is_active:    { type: boolean, required: true, default: 0 }
    created_at:   ~

  jobeet_category_affiliate:
    category_id:  { type: integer, foreignTable: jobeet_category, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }
    affiliate_id: { type: integer, foreignTable: jobeet_affiliate, foreignReference: id, required: true, primaryKey: true, onDelete: cascade }

Nota Si eres de los que prefieres crear la base de datos directamente con sentencias SQL, puedes generar el archivo de configuración schema.yml a partir de una base de datos existente mediante la tarea propel:build-schema

$ php symfony propel:build-schema

La tarea anterior requiere que se haya configurado una base de datos en el archivo databases.yml, tal y como se explica más adelante. Por tanto, si ejecutas ahora esa tarea, no va a funcionar correctamente porque no sabe la base de datos para la que debe crear el esquema.

El esquema de datos no es más que la traducción del diagrama de entidad-relación al formato YAML.

El archivo schema.yml describe todas las tablas y columnas de la base de datos. Cada columna se describe con la siguiente información:

  • type: el tipo de columna, que puede ser boolean, tinyint, smallint, integer, bigint, double, float, real, decimal, char, varchar(size), longvarchar, date, time, timestamp, blob y clob.
  • required: si vale true, la columna es obligatoria.
  • index: si vale true, se crea un índice para la columna; si vale unique, se crea un índice único.
  • primaryKey: indica que esta columna es clave primaria de la tabla.
  • foreignTable, foreignReference: indica que esta columna es clave externa de otra tabla.

En las columnas cuyo valor es simplemente ~, que en realidad es como se indica el valor null en YAML (id, created_at y updated_at), Symfony adivina cuál es la mejor configuración para esa columna (los campos llamados id se consideran claves primarias y los campos llamados created_at y updated_at se consideran de tipo timestamp).

Nota El atributo onDelete define el comportamiento de las claves primarias ante las sentencias ON DELETE. Propel admite los valores CASCADE, SETNULL y RESTRICT. Cuando se borra por ejemplo el registro de una oferta de trabajo job) todos los registros relacionados de la tabla jobeet_category_affiliate se borran automáticamente mediante la base de datos o mediante Propel si el sistema gestor de base de datos no es capaz de hacerlo.