La URI interna de la página de una oferta de trabajo es muy larga y bastante aburrida de escribir (url_for('job/show?id='.$job->getId().'&company='.$job->getCompany().'&location='.$job->getLocation().'&position='.$job->getPosition())
). Como se ha comentado en la sección anterior, es posible modificar la clase que utiliza cada ruta. En el caso de la ruta llamada job_show_user
, se va a emplear la clase sfPropelRoute, ya que es una clase optimizada para las rutas que representan objetos Propel o colecciones de objetos Propel:
job_show_user:
url: /job/:company/:location/:id/:position
class: sfPropelRoute
options: { model: JobeetJob, type: object }
param: { module: job, action: show }
requirements:
id: \d+
sf_method: [get]
La opción options
establece el comportamiento de la ruta. La opción model
define la clase del modelo de Propel relacionada con la ruta (en este caso, JobeetJob
) y la opción type
indica que esta ruta está relacionada con un solo objeto. Si la ruta representara una colección de objetos, se debería utilizar el valor list
en esta opción type
.
Como la ruta job_show_user
ahora está relacionada con JobeetJob
, se puede simplificar la llamanda al helper url_for()
de la siguiente manera:
url_for(array('sf_route' => 'job_show_user', 'sf_subject' => $job))
Incluso se puede simplificar todavía más:
url_for('job_show_user', $job)
Nota La primera forma es útil cuando tienes que pasar más argumentos aparte del objeto.
Todo esto es posible porque todas las variables de la ruta tienen un método para acceder a su valor dentro de la clase JobeetJob
. La variable company
por ejemplo se sustituye por el valor devuelto por el método getCompany()
.
Si observas el aspecto de las URL generadas, verás que todavía no son exactamente como queríamos:
http://jobeet.localhost/frontend_dev.php/job/Sensio+Labs/Paris%2C+France/1/Web+Developer
El siguiente paso consiste en preparar los valores de cada columna para que se muestren correctamente en la URL, proceso que se conoce con el nombre de slugify, por lo que debemos sustituir todos los caracteres que no sean ASCII por un guión medio -
. Para ello, abre el archivo JobeetJob
y añade los siguientes métodos en la clase:
// lib/model/JobeetJob.php
public function getCompanySlug()
{
return Jobeet::slugify($this->getCompany());
}
public function getPositionSlug()
{
return Jobeet::slugify($this->getPosition());
}
public function getLocationSlug()
{
return Jobeet::slugify($this->getLocation());
}
A continuación, crea un archivo llamado lib/Jobeet.class.php
y añade el método slugify
a la nueva clase:
// lib/Jobeet.class.php
class Jobeet
{
static public function slugify($text)
{
// replace all non letters or digits by -
$text = preg_replace('/\W+/', '-', $text);
// trim and lowercase
$text = strtolower(trim($text, '-'));
return $text;
}
}
Nota Para optimizar un poco el sitio disponible, este tutorial no muestra la instrucción <?php
en los trozos de código que sólo incluyen PHP. Obviamente no te olvides de incluir esa instrucción cada vez que crees un archivo PHP.
Los cambios anteriores han creado tres métodos accesores virtuales: getCompanySlug()
,
getPositionSlug()
y getLocationSlug()
. Los tres métodos devuelven el valor original de la columna de datos después de aplicarle el método slugify()
. Por tanto, ahora la ruta job_show_user
también puede hacer uso de estos métodos accesores para reemplazar los valores originales de cada columna por sus valores virtuales:
job_show_user:
url: /job/:company_slug/:location_slug/:id/:position_slug
class: sfPropelRoute
options: { model: JobeetJob, type: object }
param: { module: job, action: show }
requirements:
id: \d+
sf_method: [get]
Como acabamos de añadir una nueva clase, antes de refrescar la portada de Jobeet es necesario que borres la cache de Symfony:
$ php symfony cc
Si vuelves a acceder a la portada de Jobeet, verás que las URL ahora sí que son tal y como las queríamos:
http://jobeet.localhost/frontend_dev.php/job/sensio-labs/paris-france/1/web-developer
Todo lo anterior es sólo parte de lo que son capaces las rutas de Symfony. Las rutas pueden generar una URL en función de un objeto, pero también pueden obtener el objeto relacionado con una URL. El objeto relacionado se puede obtener mediante el método getObject()
del objeto de la ruta. Cuando procesa una petición, el sistema de enrutamiento guarda el objeto relacionado con la ruta para que lo utilices en las acciones. Por tanto, modifica el método executeShow()
para obtener el objeto Jobeet
mediante el objeto de la ruta:
class jobActions extends sfActions
{
public function executeShow(sfWebRequest $request)
{
$this->job = $this->getRoute()->getObject();
$this->forward404Unless($this->job);
}
// ...
}
Si tratas de obtener la oferta de trabajo relacionada con un id
desconocido, verás una página de error 404, pero esta vez el mensaje ha cambiado:
El motivo es que la excepción del error 404 se ha lanzado automáticamente desde el método getRoute()
. Por tanto, puedes simplificar todavía más el método executeShow
:
class jobActions extends sfActions
{
public function executeShow(sfWebRequest $request)
{
$this->job = $this->getRoute()->getObject();
}
// ...
}
Nota Si no quieres que la ruta muestre un error de tipo 404, establece la opción allow_empty
a true
en la definición de esa ruta.
Nota El objeto relacionado con la ruta no se carga de forma automática. Este objeto sólo se obtiene de la base de datos cuando se invoca el método getRoute()
.