Más con Symfony

2.5. Creando una colección de rutas propia

En estos momentos, cada cliente (Client) puede modificar sus objetos página (Page) mediante un CRUD accedido a través de la URL /pages. Desafortunadamente, cada cliente puede ver y modificar todos los objetos Page, incluso los que no le pertenecen. La URL http://pete.sympalbuilder.com/backend.php/pages por ejemplo mostrará una lista de todas las páginas creadas mediante el archivo de datos - la página location de la tienda de animales de Pete y la página menu del City Pub.

Para solucionar este problema, se va a reutilizar la ruta propia acClientObjectRoute que se creo para el frontend. La clase sfDoctrineRouteCollection genera un grupo de objetos sfDoctrineRoute. No obstante, en esta aplicación es necesario generar un grupo de objetos acClientObjectRoute.

Para ello, se va a utilizar una colección de rutas propia. Crea un nuevo archivo llamado acClientObjectRouteCollection.class.php dentro del directorio lib/routing. El contenido del archivo es realmente sencillo:

// lib/routing/acClientObjectRouteCollection.class.php
class acClientObjectRouteCollection extends sfObjectRouteCollection
{
  protected
    $routeClass = 'acClientObjectRoute';
}

La propiedad $routeClass define la clase que se utiliza al crear cada una de las rutas de la colección. Por tanto, ahora cada ruta individual será de tipo acClientObjectRoute. Si se accede ahora a la URL http://pete.sympalbuilder.com/backend.php/pages solamente se muestra una página: la página location de la tienda de animales de Pete. Gracias a la clase de ruta propia, la acción index sólo devuelve los objetos Page relacionados con el Client correcto en función del subdominio de la petición. Como se acaba de demostrar, es posible crear con unas pocas líneas de código, un módulo completo del backend que pueden utilizar varios clientes diferentes.

2.5.1. Creando nuevas páginas

Actualmente las páginas de creación y modificación de objetos Page muestran una lista desplegable con todos los Client. En lugar de permitir que los usuarios puedan elegir el Client, que además podría comprometer la seguridad, se va a fijar el Client automáticamente en función del subdominio de la petición.

En primer lugar, actualiza el objeto PageForm en lib/form/PageForm.class.php.

public function configure()
{
  $this->useFields(array(
    'title',
    'content',
  ));
}

La lista desplegable ya no se muestra en los formularios de tipo Page. El problema es que al quitar la lista de clientes, cuando se crean objetos Page ya no se incluye el valor client_id. La solución consiste en añadir a mano el objeto Client relacionado en las acciones new y create.

public function executeNew(sfWebRequest $request)
{
  $page = new Page();
  $page->Client = $this->getRoute()->getClient();
  $this->form = new PageForm($page);
}

El código anterior utiliza un método llamado getClient() que todavía no existe en la clase acClientObjectRoute. A continuación se muestran las modificaciones necesarias para añadirlo:

// lib/routing/acClientObjectRoute.class.php
class acClientObjectRoute extends sfDoctrineRoute
{
  // ...

  protected $client = null;

  public function matchesUrl($url, $context = array())
  {
    // ...

    $this->client = $client;

    return array_merge(array('client_id' => $client->id), $parameters);
  }

  public function getClient()
  {
    return $this->client;
  }
}

Para hacer que el objeto Client está disponible a través de la ruta, se añade una propiedad $client en la clase y se establece su valor en el método matchesUrl(). Ahora los nuevos objetos Page ya incluirán correctamente el valor de la columna client_id en función del subdominio de la petición.