Archivo de abril, 2011

Symfony: Enrutamiento (II)

0

Por defecto Symfony no muestra el archivo que hace de controlador (index.php, frontend_dev.php, etc) para cambiarlo vamos al archivo settings.yml aquí podemos indicar que no se muestre el nombre del controlador de la siguiente manera:

[codesyntax lang=»text»]

prod:
  .settings:
    no_script_name:  off

[/codesyntax]

 

Hiperenlaces, botones y formularios

[codesyntax lang=»php» title=»Los helpers de enlaces aceptan opciones adicionales»]

/ Opciones adicionales como array asociativo
<?php echo link_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia', array(
  'class'  => 'miclasecss',
  'target' => '_blank'
)) ?>

// Opciones adicionales como cadena de texto (producen el mismo resultado)
<?php echo link_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia','class=miclasecss target=_blank') ?>
 => <a href="/url/con/enrutamiento/a/Economia_en_Francia" class="miclasecss" target="_blank">Mi artículo</a>

[/codesyntax]

[codesyntax lang=»php» title=»URL que admiten los helpers de enlaces»]

// URI interna
<?php echo link_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia') ?>
 => <a href="/url/con/enrutamiento/a/Economia_en_Francia">Mi artículo</a>

// URI interna con parámetros dinámicos
<?php echo link_to('Mi artículo', 'articulo/ver?titulo='.$articulo->getTitulo()) ?>

// URI interna con anclas (enlaces a secciones internas de la página)
<?php echo link_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia#seccion1') ?>
 => <a href="/url/con/enrutamiento/a/Economia_en_Francia#seccion1">Mi artículo</a>

// URL absolutas
<?php echo link_to('Mi artículo', 'http://www.ejemplo.com/cualquierpagina.html') ?>
 => <a href="http://www.ejemplo.com/cualquierpagina.html">Mi artículo</a>

[/codesyntax]

[codesyntax lang=»php» title=»Helpers de enlaces para las etiquetas a, input y form»]

// Enlace simple de texto
<?php echo link_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia') ?>
 => <a href="/url/con/enrutamiento/a/Economia_en_Francia">Mi artículo</a>

// Enlace en una imagen
<?php echo link_to(image_tag('ver.gif'), 'articulo/ver?titulo=Economia_en_Francia') ?>
 => <a href="/url/con/enrutamiento/a/Economia_en_Francia"><img src="/images/ver.gif?x81947" /></a>

// Boton
<?php echo button_to('Mi artículo', 'articulo/ver?titulo=Economia_en_Francia') ?>
 => <input value="Mi artículo" type="button" onclick="document.location.href='/url/con/enrutamiento/a/Economia_en_Francia';" />

// Formulario
<?php echo form_tag('articulo/ver?titulo=Economia_en_Francia') ?>
 => <form method="post" action="/url/con/enrutamiento/a/Economia_en_Francia" />

[/codesyntax]

[codesyntax lang=»php» title=»Opciones confirm y popup en los helpers de enlaces»]

<?php echo link_to('Borrar elemento', 'item/borrar?id=123', 'confirm=¿Estás seguro?') ?>
 => <a onclick="return confirm('¿Estás seguro?');"
       href="/url/con/enrutamiento/a/borrar/123.html">Borrar elemento</a>

<?php echo link_to('Añadir al carrito', 'carritoCompra/anadir?id=100', 'popup=true') ?>
 => <a onclick="window.open(this.href);return false;"
       href="/url/con/enrutamiento/a/carritoCompra/anadir/id/100.html">Añadir al carrito</a>

<?php echo link_to('Añadir al carrito', 'carritoCompra/anadir?id=100', array(
  'popup' => array('popupWindow', 'width=310,height=400,left=320,top=0')
)) ?>
 => <a onclick="window.open(this.href,'popupWindow','width=310,height=400,left=320,top=0');return false;"
       href="/url/con/enrutamiento/a/carritoCompra/anadir/id/100.html">Añadir al carrito</a>

[/codesyntax]

 

Symfony: El enrutamiento (I)

0

Continuo con el libro de Symfony 1.4 en esta ocasión toca el enrutamiento.

Normalmente las urls que escribimos son así:

http://www.ejemplo.com/web/galeria/album.php?nombre=mis%20vacaciones
http://www.ejemplo.com/web/weblog/publico/post/listado.php
http://www.ejemplo.com/web/general/contenido/pagina.php?nombre=sobre%20nosotros

Y deberían ser así:

http://www.ejemplo.com/articulos/economia/2006/sectores-actividad.html

Principalmente porque son mucho más legibles para los usuarios y buscadores, y además evitamos mostrar información a un posible atacante.

El sistema de enrutamiento utiliza un archivo de configuración especial, llamado routing.yml, en el que se pueden definir las reglas de enrutamiento.

[codesyntax lang=»text»]

articulo_segun_titulo:
  url:    articulos/:tema/:ano/:titulo.html
  param:  { module: articulo, action: permalink }

[/codesyntax]

Todas las peticiones realizadas a una aplicación Symfony son analizadas en primer lugar por el sistema de enrutamiento (que es muy sencillo porque todas las peticiones se gestionan mediante un único controlador frontal). El sistema de enrutamiento busca coincidencias entre la URL de la petición y los patrones definidos en las reglas de enrutamiento. Si se produce una coincidencia, las partes del patrón que tienen nombre se transforman en parámetros de la petición y se juntan a los parámetros definidos en la clave param:.

Después, la petición se pasa a la acción permalink del módulo articulo, que dispone de toda la información necesaria en los parámetros de la petición para obtener el artículo solicitado.

El mecanismo de enrutamiento también funciona en la otra dirección. Para mostrar las URL en los enlaces de una aplicación, se debe proporcionar al sistema de enrutamiento la información necesaria para determinar la regla que se debe aplicar a cada enlace. Además, no se deben escribir los enlaces directamente con etiquetas <a> (ya que de esta forma no se estaría utilizando el sistema de enrutamiento) sino con un helper especial:

[codesyntax lang=»text»]

// El helper url_for() transforma una URI interna en una URL externa
<a href="<?php echo url_for('articulo/permalink?tema=economia&ano=2006&titulo=sectores-actividad') ?>">pincha aquí</a>

// El helper reconoce que la URI cumple con la regla articulo_segun_titulo
// El sistema de enrutamiento crea una URL externa a partir de el
 => <a href="http://www.ejemplo.com/articulos/economia/2006/sectores-actividad.html">pincha aquí</a>

// El helper link_to() muestra directamente un enlace
// y evita tener que mezclar PHP y HTML
<?php echo link_to(
  'pincha aqui',
  'articulo/permalink?tema=economia&ano=2006&titulo=sectores-actividad'
) ?>

// Internamente link_to() llama a url_for(), por lo que el resultado es el mismo
 => <a href="http://www.ejemplo.com/articulos/economia/2006/sectores-actividad.html">pincha aquí</a>

[/codesyntax]

Sintel | Corto de animación 3D hecho en Blender

0

Symfony: El modelo (III)

0

CONEXIONES A LA BASE DE DATOS

[codesyntax lang=»text» title=»Conexión básica»]

> php symfony configure:database "mysql://login:password@localhost/blog"

[/codesyntax]

[codesyntax lang=»text» title=»Definiendo una conexión para un entorno concreto de la aplicación»]

> php symfony --env=prod configure:database "mysql://login:password@localhost/blog"

[/codesyntax]

[codesyntax lang=»text» title=»Definiendo una conexión para una aplicación concreta»]

> php symfony --app=frontend configure:database "mysql://login:password@localhost/blog"

[/codesyntax]

 

[codesyntax lang=»text» title=»Definiendo una conexión diferente de la principal para el proyecto»]

> php symfony --name=otraconexion configure:database "mysql://login:password@localhost/blog"

[/codesyntax]

 

Las opciones de conexión con la base de datos también se pueden establecer manualmente en el archivo databases.yml que se encuentra en el directorio config/.

 

[codesyntax lang=»text» title=»Opciones abreviadas de la conexión a la base de datos»]

all:
  propel:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://login:password@localhost/blog

[/codesyntax]

[codesyntax lang=»text» title=»Ejemplo de conexiónes con la base de datos»]

prod:
  propel:
    param:
      hostspec:           mi_servidor_datos
      usuarioname:           mi_nombre_usuario
      password:           xxxxxxxxxx

all:
  propel:
    class:                sfPropelDatabase
    param:
      phptype:            mysql     # fabricante de la base de datos
      hostspec:           localhost
      database:           blog
      usuarioname:           login
      password:           passwd
      port:               80
      encoding:           utf8      # Codificación utilizada para crear la tabla
      persistent:         true      # Utilizar conexiones persistentes

[/codesyntax]

Los valores permitidos para el parámetro phptype corresponden a los tipos de bases de datos soportados por PDO:

  • mysql
  • mssql
  • pgsql
  • sqlite
  • oracle

Si se utiliza una base de datos de tipo SQLite, el parámetro hostspec debe indicar la ruta al archivo de base de datos.

[codesyntax lang=»text» title=»Opciones de conexión a una base de datos SQLite»]

all:
  propel:
    class:          sfPropelDatabase
    param:
      phptype:      sqlite
      database:     %SF_DATA_DIR%/blog.db

[/codesyntax]

 

EXTENDER EL MODELO

Los métodos del modelo que se generan automáticamente están muy bien, pero no siempre son suficientes. Si se incluye lógica de negocio propia, es necesario extender el modelo añadiendo nuevos métodos o redefiniendo algunos de los existentes.

 

AÑADIR NUEVOS MÉTODOS

Los nuevos métodos se pueden añadir en las clases vacías del modelo que se generan en el directorio lib/model/. Se emplea $this para invocar a los métodos del objeto actual y self:: para invocar a los métodos estáticos de la clase actual. No se debe olvidar que las clases personalizadas heredan los métodos de las clases Base del directorio lib/model/om/.

[codesyntax lang=»php» title=»Personalizar el modelo, en lib/model/Articulo.php»]

<?

class Articulo extends BaseArticulo
{
  public function __toString()
  {
    return $this->getTitulo();  // getTitulo() se hereda de BaseArticulo
  }
}

[/codesyntax]

También se pueden extender las clases peer, como por ejemplo para obtener todos los artículos ordenados por fecha de creación:

[codesyntax lang=»php» title=»Personalizando el modelo, en lib/model/ArticuloPeer.php»]

<?

class ArticuloPeer extends BaseArticuloPeer
{
  public static function getTodosOrdenadosPorFecha()
  {
    $c = new Criteria();
    $c->addAscendingOrderByColumn(self::CREATED_AT);
    return self::doSelect($c);
  }
}

[/codesyntax]

 

[codesyntax lang=»php» title=»El uso de métodos personalizados del modelo es idéntico al de los métodos generados automáticamente»]

<?

foreach (ArticuloPeer::getTodosOrdenadosPorFecha() as $articulo)
{
  echo $articulo;   // Se llama al método mágico __toString()
}

[/codesyntax]

 

REDEFINIR MÉTODOS EXISTENTES

Si alguno de los métodos generados automáticamente en las clases Base no satisfacen las necesidades de la aplicación, se pueden redefinir en las clases personalizadas. Solamente es necesario mantener el mismo número de argumentos para cada método.

Por ejemplo, el método $articulo->getComentarios() devuelve un array de objetos Comentario, sin ningún tipo de ordenamiento. Si se necesitan los resultados ordenados por fecha de creación siendo el primero el comentario más reciente, se puede redefinir el método getComentarios(). Como el método getComentarios() original (guardado en lib/model/om/BaseArticulo.php) requiere como argumentos un objeto de tipo Criteria y una conexión, la nueva función debe contener esos mismos parámetros.

[codesyntax lang=»php» title=»Redefiniendo los métodos existentes en el modelo, en lib/model/Articulo.php»]

<?

public function getComentarios($criteria = null, $con = null)
{
  if (is_null($criteria))
  {
    $criteria = new Criteria();
  }
  else
  {
    // Los objetos se pasan por referencia en PHP5, por lo que se debe clonar
    // el objeto original para no modificarlo
    $criteria = clone $criteria;
  }
  $criteria->addDescendingOrderByColumn(ComentarioPeer::CREATED_AT);

  return parent::getComentarios($criteria, $con);
}

[/codesyntax]

El método personalizado acaba llamando a su método padre en la clase Base, lo que se considera una buena práctica. No obstante, es posible saltarse completamente la clase Base y devolver el resultado directamente.

 

USO DE COMPORTAMIENTOS EN EL MODELO

Algunas de las modificaciones que se realizan en el modelo son genéricas y por tanto se pueden reutilizar. Por ejemplo, los métodos que hacen que un objeto del modelo sea reordenable o un bloqueo de tipo optimistic en la base de datos para evitar conflictos cuando se guardan de forma concurrente los objetos se pueden considerar extensiones genéricas que se pueden añadir a muchas clases.

Symfony encapsula estas extensiones en «comportamientos» (del inglés behaviors). Los comportamientos son clases externas que proporcionan métodos extras a las clases del modelo. Las clases del modelo están definidas de forma que se puedan enganchar estas clases externas y Symfony extiende las clases del modelo mediante sfMixer.

Para habilitar los comportamientos en las clases del modelo, se debe modificar una opción del archivo config/propel.ini:

propel.builder.AddBehaviors = true // El valor por defecto es false

Symfony no incluye por defecto ningún comportamiento, pero se pueden instalar mediante plugins. Una vez que el plugin se ha instalado, se puede asignar un comportamiento a una clase mediante una sola línea de código. Si por ejemplo se ha instalado el plugin sfPropelParanoidBehaviorPlugin en la aplicación, se puede extender la clase Articulo con este comportamiento añadiendo la siguiente línea de código al final del archivo Articulo.class.php:

[codesyntax lang=»php»]

<?

sfPropelBehavior::add('Articulo', array(
  'paranoid' => array('column' => 'deleted_at')
));

[/codesyntax]

 

Después de volver a generar el modelo, los objetos de tipo Articulo que se borren permanecerán en la base de datos, aunque será invisibles a las consultas que hacen uso de los métodos del ORM, a no ser que se deshabilite temporalmente el comportamiento mediante sfPropelParanoidBehavior::disable().

Desde la versión 1.1 de Symfony también es posible declarar los comportamientos directamente en el archivo schema.yml, incluyéndolos bajo la clave _behaviors.

La lista de plugins de Symfony disponible en el wiki incluye numerosos comportamientos http://trac.symfony-project.org/wiki/SymfonyPlugins#Behaviors. Cada comportamiento tiene su propia documentación y su propia guía de instalación.

 

SINTAXIS EXTENDIDA DEL ESQUEMA

Atributos

Se pueden definir atributos específicos para las conexiones y las tablas. Estas opciones se establecen bajo la clave _attributes.

[codesyntax lang=»text»]

propel:
  _attributes:   { noXsd: false, defaultIdMethod: none, package: lib.model }
  blog_articulo:
    _attributes: { phpName: Articulo }

[/codesyntax]

Si se quiere validar el esquema antes de que se genere el código asociado, se debe desactivar en la conexión el atributo noXSD. La conexión también permite que se le indique el atributo defaultIdMethod. Si no se indica, se utilizará el método nativo de generación de IDs –por ejemplo, autoincrement en MySQL o sequences en PostgreSQL. El otro valor permitido es none.

El atributo package es como un namespace; indica la ruta donde se guardan las clases generadas automáticamente. Su valor por defecto es lib/model/, pero se puede modificar para organizar el modelo en una estructura de subpaquetes. Si por ejemplo no se quieren mezclar en el mismo directorio las clases del núcleo de la aplicación con las clases de un sistema de estadísticas, se pueden definir dos esquemas diferentes con los paquetes lib.model.business y lib.model.stats.

Ya se ha visto el atributo de tabla phpName, que se utiliza para establecer el nombre de la clase generada automáticamente para manejar cada tabla de la base de datos.

Las tablas que guardan contenidos adaptados para diferentes idiomas (es decir, varias versiones del mismo contenido en una tabla relacionada, para conseguir la internacionalización) también pueden definir dos atributos adicionales.

[codesyntax lang=»text»]

propel:
  blog_articulo:
    _attributes: { isI18N: true, i18nTable: db_group_i18n }

[/codesyntax]

 

DETALLE DE LAS COLUMNAS

La sintaxis básica ofrece dos posibilidades: dejar que Symfony deduzca las características de una columna a partir de su nombre (indicando un valor vacío para esa columna) o definir el tipo de columna con uno de los tipos predefinidos.
[codesyntax lang=»text»]

propel:
  blog_articulo:
    id:                 # Symfony se encarga de esta columna
    titulo: varchar(50)  # Definir el tipo explícitamente

[/codesyntax]

Se pueden definir muchos más aspectos de cada columna. Si se definen, se utiliza un array asociativo para indicar las opciones de la columna.

[codesyntax lang=»text»]

propel:
  blog_articulo:
    id:       { type: integer, required: true, primaryKey: true, autoIncrement: true }
    name:     { type: varchar(50), default: foobar, index: true }
    group_id: { type: integer, foreignTable: db_group, foreignReference: id, onDelete: cascade }

[/codesyntax]

Los parámetros de las columnas son los siguientes:

  • type: Tipo de columna. Se puede elegir entre boolean, tinyint, smallint, integer, bigint, double, float, real, decimal, char, varchar(tamano), longvarchar, date, time, timestamp, bu_date, bu_timestamp, blob y clob
  • required: valor booleano. Si vale true la columna debe tener obligatoriamente un valor.
  • default: el valor por defecto.
  • primaryKey: valor booleano. Si vale true indica que es una clave primaria.
  • autoIncrement: valor booleano. Si se indica true para las columnas de tipo integer, su valor se auto-incrementará.
  • sequence: el nombre de la secuencia para las bases de datos que utilizan secuencias para las columnas autoIncrement (por ejemplo PostgreSQL y Oracle).
  • index: valor booleano. Si vale true, se construye un índice simple; si vale unique se construye un índice único para la columna.
  • foreignTable: el nombre de una tabla, se utiliza para crear una clave externa a otra tabla.
  • foreignReference: el nombre de la columna relacionada si las claves externas se definen mediante foreignTable.
  • onDelete: determina la acción que se ejecuta cuando se borra un registro en una tabla relacionada. Si su valor es setnull, la columna de la clave externa se establece a null. Si su valor es cascade, se borra el registro relacionado. Si el sistema gestor de bases de datos no soporta este comportamiento, el ORM lo emula. Esta opción solo tiene sentido para las columnas que definen una foreignTable y una foreignReference.
  • isCulture: valor booleano. Su valor es true para las columnas de tipo culture en las tablas de contenidos adaptados a otros idiomas.

 

CLAVES EXTERNAS

Además de los atributos de columna foreignTable y foreignReference, es posible añadir claves externas bajo la clave _foreignKeys: de cada tabla.

[codesyntax lang=»text»]

propel:
  blog_articulo:
    id:
    titulo:     varchar(50)
    usuario_id: { type: integer }
    _foreignKeys:
      -
        foreignTable: blog_usuario
        onDelete:     cascade
        references:
          - { local: usuario_id, foreign: id }

[/codesyntax]

La sintaxis alternativa es muy útil para las claves externas múltiples y para indicar un nombre a cada clave externa.

[codesyntax lang=»text»]

_foreignKeys:
  mi_clave_externa:
    foreignTable:  db_usuario
    onDelete:      cascade
    references:
      - { local: usuario_id, foreign: id }
      - { local: post_id, foreign: id }

[/codesyntax]

 

INDICES

Además del atributo de columna index, es posible añadir claves índices bajo la clave _indexes: de cada tabla. Si se quieren crean índices únicos, se debe utilizar la clave _uniques:. En las columnas que requieren un tamaño, por ejemplo por ser columnas de texto, el tamaño del índice se indica entre paréntesis, de la misma forma que se indica el tamaño de cualquier columna.

[codesyntax lang=»text»]

propel:
  blog_articulo:
    id:
    titulo:            varchar(50)
    created_at:
    _indexes:
      mi_indice:      [titulo(10), usuario_id]
    _uniques:
      mi_otro_indice: [created_at]

[/codesyntax]

 

COLUMNAS VACÍAS

Cuando Symfony se encuentra con una columna sin ningún valor, utiliza algo de magia para determinar su valor.

[codesyntax lang=»text»]

// Las columnas vacías llamadas "id" se consideran claves primarias
id:         { type: integer, required: true, primaryKey: true, autoIncrement: true }

// Las columnas vacías llamadas "XXX_id" se consideran claves externas
loquesea_id:  { type: integer, foreignTable: db_loquesea, foreignReference: id }

// Las columnas vacías llamadas created_at, updated at, created_on y updated_on
// se consideran fechas y automáticamente se les asigna el tipo "timestamp"
created_at: { type: timestamp }
updated_at: { type: timestamp }

[/codesyntax]

Para las claves externas, Symfony busca una tabla cuyo phpName sea igual al principio del nombre de la columna; si se encuentra, se utiliza ese nombre de tabla como foreignTable.

 

TABLAS I18N

Symfony permite internacionalizar los contenidos mediante tablas relacionadas. De esta forma, cuando se dispone de contenido que debe ser internacionalizado, se guarda en 2 tablas distintas: una contiene las columnas invariantes y otra las columnas que permiten la internacionalización.

Todo lo anterior se considera de forma implícita cuando en el archivo schema.yml se dispone de una tabla con el nombre cualquiernombre_i18n.

[codesyntax lang=»text»]

propel:
  db_group:
    id:
    created_at:

  db_group_i18n:
    name:        varchar(50)

[/codesyntax]

[codesyntax lang=»text»]

propel:
  db_group:
    _attributes: { isI18N: true, i18nTable: db_group_i18n }
    id:
    created_at:

  db_group_i18n:
    id:       { type: integer, required: true, primaryKey: true, foreignTable: db_group, foreignReference: id, onDelete: cascade }
    culture:  { isCulture: true, type: varchar(7), required: true, primaryKey: true }
    name:     varchar(50)

[/codesyntax]

 

COMPORTAMIENTOS

Los comportamientos son plugins que modifican el modelo de datos para añadir nuevas funcionalidades a las clases de Propel.

[codesyntax lang=»text»]

propel:
  blog_articulo:
    titulo:         varchar(50)
    _behaviors:
      paranoid:     { column: deleted_at }

[/codesyntax]

 

Optimizar el servidor web Apache

1

Tenía intención de crear un post explicando la optimización de Apache, pero la verdad es que en la red ya existe bastante información al respecto por tanto os dejo dos links, uno explicando cada uno de los parámetros que se pueden modificar en el archivo httpd.conf de Apache y el otro con algunos ejemplos de optimización:   – Definición de parámetros: http://www.codenb.com/optimizar-apache-16/ – Ejemplos: http://www.forosdelweb.com/f58/recetas-para-configuracion-apache-404961/

Symfony: El modelo (II)

0

Cuando Symfony construye el modelo, crea una clase de objeto base para cada una de las tablas definidas en schema.yml. Cada una de estas clases contiene una serie de constructores y accesores por defecto en función de la definición de cada columna: los métodos new, getXXX() y setXXX() (donde XXX es el nombre del campo) permiten crear y obtener las propiedades de los objetos:

[codesyntax lang=»php» title=»Métodos generados en una clase objeto»]

<?php

$articulo = new Articulo();
$articulo->setTitulo('Mi primer artículo');
$articulo->setContenido('Este es mi primer artículo. \n Espero que te guste.');

$titulo    = $articulo->getTitulo();
$contenido = $articulo->getContenido();

[/codesyntax]

 

Para establecer el valor de varios campos a la vez, se puede utilizar el método fromArray(), que también se genera para cada clase objeto:

[codesyntax lang=»php» title=»El método fromArray() es un setter múltiple»]

<?php

$articulo->fromArray(array(
  'titulo'   => 'Mi primer artículo',
  'contenido' => 'Este es mi primer artículo. \n Espero que te guste.'
));

[/codesyntax]

[codesyntax lang=»php» title=»Las claves externas se traducen en getters especiales»]

<?php

// Relación de "muchos a uno"
echo $comentario->getArticulo()->getTitulo();
 => Mi primer artículo
echo $comentario->getArticulo()->getContenido();
 => Este es mi primer artículo.
    Espero que te guste.

// Relación "uno a muchos"
$comentarios = $articulo->getComentarios();

[/codesyntax]

La columna articulo_id de la tabla blog_comentario define implícitamente una clave externa a la tabla blog_articulo. Cada comentario está relacionado con un artículo y un artículo puede tener muchos comentarios. Las clases generadas contienen 5 métodos que traducen esta relación a la forma orientada a objetos, de la siguiente manera:

  • $comentario->getArticulo(): para obtener el objeto Articulo relacionado
  • $comentario->getArticuloId(): para obtener el ID del objeto Articulo relacionado
  • $comentario->setArticulo($articulo): para definir el objeto Articulo relacionado
  • $comentario->setArticuloId($id): para definir el objeto Articulo relacionado a partir de un ID
  • $articulo->getComentarios(): para obtener los objetos Comentario relacionados

[codesyntax lang=»php» title=»Las claves externas se traducen en un setter especial»]

<?php

$comentario = new Comentario();
$comentario->setAutor('Steve');
$comentario->setContenido('¡Es el mejor artículo que he leído nunca!');

// Añadir este comentario al anterior objeto $articulo
$comentario->setArticulo($articulo);

// Sintaxis alternativa
// Solo es correcta cuando el objeto artículo ya
// ha sido guardado anteriormente en la base de datos
$comentario->setArticuloId($articulo->getId());

[/codesyntax]

El método getArticulo() devuelve un objeto de tipo Articulo, que permite utilizar el método accesor getTitulo(). Se trata de una alternativa mucho mejor que realizar la unión de las tablas manualmente, ya que esto último necesitaría varias líneas de código (empezando con la llamada al método $comment->getArticuloId()).

La variable $comentarios contiene un array de objetos de tipo Comentario. Se puede mostrar el primer comentario mediante $comentarios[0] o se puede recorrer la colección entera mediante foreach ($comentarios as $comentario).

Al utilizar el constructor new se crea un nuevo objeto, pero no un registro en la tabla blog_articulo. Si se modifica el objeto, tampoco se reflejan esos cambios en la base de datos. Para guardar los datos en la base de datos, se debe invocar el método save() del objeto.

[codesyntax lang=»php»]

<?php

$articulo->save();

[/codesyntax]

[codesyntax lang=»php» title=»Borrar registros de la base de datos mediante el método delete() del objeto relacionado»]

<?php

foreach ($articulo->getComentarios() as $comentario)
{
  $comentario->delete();
}

[/codesyntax]

Si se conoce la clave primaria de un registro concreto, se puede utilizar el método retrieveByPk() de la clase peer para obtener el objeto relacionado.

[codesyntax lang=»php»]

<?php

$articulo = ArticuloPeer::retrieveByPk(7);

[/codesyntax]

En algunos casos, la clave primaria está formada por más de una columna. Es esos casos, el método retrieveByPK() permite indicar varios parámetros, uno para cada columna de la clave primaria.

También se pueden obtener varios objetos a la vez mediante sus claves primarias, invocando el método retrieveByPKs(), que espera como argumento un array de claves primarias.

 

Cuando se quiere obtener más de un registro, se debe utilizar el método doSelect() de la clase peer correspondiente a los objetos que se quieren obtener. Por ejemplo, para obtener objetos de la clase Articulo, se llama al método ArticuloPeer::doSelect().

El primer parámetro del método doSelect() es un objeto de la clase Criteria, que es una clase para definir consultas simples sin utilizar SQL, para conseguir la abstracción de base de datos.

Un objeto Criteria vacío devuelve todos los objetos de la clase.

[codesyntax lang=»php» title=»Obtener registros mediante Criteria con el método doSelect() (Criteria vacío)»]

<?php

$c = new Criteria();
$articulos = ArticuloPeer::doSelect($c);

// Genera la siguiente consulta SQL
SELECT blog_articulo.ID, blog_articulo.TITLE, blog_articulo.CONTENIDO,
       blog_articulo.CREATED_AT
FROM   blog_articulo;

[/codesyntax]

Para las selecciones más complejas de objetos, se necesitan equivalentes a las sentencias WHERE, ORDER BY, GROUP BY y demás de SQL. El objeto Criteria dispone de métodos y parámetros para indicar todas estas condiciones. Por ejemplo, para obtener todos los comentarios escritos por el usuario Steve y ordenados por fecha:

[codesyntax lang=»php» title=»Obtener registros mediante Criteria con el método doSelect() (Criteria con condiciones)»]

<?php

$c = new Criteria();
$c->add(ComentarioPeer::AUTOR, 'Steve');
$c->addAscendingOrderByColumn(ComentarioPeer::CREATED_AT);
$comentarios = ComentarioPeer::doSelect($c);

// Genera la siguiente consulta SQL
SELECT blog_comentario.ARTICULO_ID, blog_comentario.AUTOR, blog_comentario.CONTENIDO,
       blog_comentario.CREATED_AT
FROM   blog_comentario
WHERE  blog_comentario.autor = 'Steve'
ORDER BY blog_comentario.CREATED_AT ASC;

[/codesyntax]

as constantes de clase que se pasan como parámetros a los métodos add() hacen referencia a los nombres de las propiedades. Su nombre se genera a partir del nombre de las columnas en mayúsculas. Por ejemplo, para indicar la columna contenido de la tabla blog_articulo, se utiliza la constante de clase llamada ArticuloPeer::CONTENIDO.

Otro ejemplo del uso de Criteria con condiciones múltiples. En el ejemplo se obtienen todos los comentarios del usuario Steve en los artículos que contienen la palabra enjoy y además, ordenados por fecha.

 

[codesyntax lang=»php»]

<?php

$c = new Criteria();
$c->add(ComentarioPeer::AUTOR, 'Steve');
$c->addJoin(ComentarioPeer::ARTICULO_ID, ArticuloPeer::ID);
$c->add(ArticuloPeer::CONTENIDO, '%enjoy%', Criteria::LIKE);
$c->addAscendingOrderByColumn(ComentarioPeer::CREATED_AT);
$comentarios = ComentarioPeer::doSelect($c);

// Genera la siguiente consulta SQL
SELECT blog_comentario.ID, blog_comentario.ARTICULO_ID, blog_comentario.AUTOR,
       blog_comentario.CONTENIDO, blog_comentario.CREATED_AT
FROM   blog_comentario, blog_articulo
WHERE  blog_comentario.AUTOR = 'Steve'
       AND blog_articulo.CONTENIDO LIKE '%enjoy%'
       AND blog_comentario.ARTICULO_ID = blog_articulo.ID
ORDER BY blog_comentario.CREATED_AT ASC

[/codesyntax]

Además del método doSelect(), todas las clases peer tienen un método llamado doCount(), que simplemente cuenta el número de registros que satisfacen las condiciones pasadas como parámetro y devuelve ese número como un entero.

Las clases peer también incluyen métodos doDelete(), doInsert() y doUpdate() (todos ellos requieren como parámetro un objeto de tipo Criteria).

Por último, si solo se quiere obtener el primer objeto, se puede reemplazar el método doSelect() por doSelectOne(). Es muy útil cuando se sabe que las condiciones de Criteria solo van a devolver un resultado, y su ventaja es que el método devuelve directamente un objeto en vez de un array de objetos.

A veces, no es necesario obtener los objetos, sino que solo son necesarios algunos datos calculados por la base de datos. Por ejemplo, para obtener la fecha de creación de todos los artículos, no tiene sentido obtener todos los artículos y después recorrer el array de los resultados.

Para realizar consultas a la base de datos con PDO, es necesario realizar los siguientes pasos:

  • Obtener la conexión con la base de datos.
  • Construir la consulta.
  • Crear una sentencia con esa consulta.
  • Iterar el result set que devuelve la ejecución de la sentencia.

[codesyntax lang=»php» title=»Consultas SQL personalizadas con PDO»]

<?php

conexion = Propel::getConnection();
$consulta = 'SELECT MAX(%s) AS max FROM %s';
$consulta = sprintf($consulta, ArticuloPeer::CREATED_AT, ArticuloPeer::TABLE_NAME);
$sentencia = $conexion->prepare($consulta);
$sentencia->execute();
$resultset = $sentencia->fetch(PDO::FETCH_OBJ);
$max = $resultset->max;

[/codesyntax]

Normalmente, cuando una tabla tiene una columna llamada created_at, se utiliza para almacenar un timestamp de la fecha de creación del registro. La misma idea se aplica a las columnas updated_at, cuyo valor se debe actualizar cada vez que se actualiza el propio registro.

La buena noticia es que Symfony reconoce estos nombres de columna y se ocupa de actualizar su valor de forma automática. No es necesario establecer manualmente el valor de las columnas created_at y updated_at; se actualizan automáticamente. Lo mismo se aplica a las columnas llamadas created_on y updated_on.
[codesyntax lang=»php» title=»Las columnas created_at y updated_at se gestionan automáticamente»]

<?php

$comentario = new Comentario();
$comentario->setAutor('Steve');
$comentario->save();

// Muestra la fecha de creación
echo $comentario->getCreatedAt();
 => [fecha de la operación INSERT de la base de datos]

[/codesyntax]

Además, los getters de las columnas de fechas permiten indicar el formato de la fecha como argumento:

[codesyntax lang=»php»]

<?php

echo $comentario->getCreatedAt('Y-m-d');

[/codesyntax]

 

«Chuletas» para Symfony

0

Más de uno conocerá esas imágenes o PDFs que, de forma resumida, muestran todos los métodos y funciones de los lenguajes de programación o de frameworks. Con Symfony eso no es diferente, además de ser muy útil en las primeras etapas de aprendizaje. Os dejo el link:

http://trac.symfony-project.org/wiki/CheatSheets

 

¡Qué lo disfrutéis!

Ir arriba