12.8.1. La opción display
La página del listado muestra por defecto todas las columnas del modelo, en el mismo orden en el que se indicaron en el archivo del esquema. La opción display
establece las columnas que se muestran y el orden en el que lo hacen:
# apps/backend/modules/category/config/generator.yml
config:
list:
title: Category Management
display: [=name, slug]
El símbolo =
delante de la columna name
es una convención que indica que se debe convertir la cadena de texto en un enlace.
A continuación se realiza la misma configuración en el módulo job
para hacerlo más fácil de leer:
# apps/backend/modules/job/config/generator.yml
config:
list:
title: Job Management
display: [company, position, location, url, is_activated, email]
12.8.2. La opción layout
Los listados se pueden mostrar con diferentes layouts. El layout por defecto es tabular
, que muestra el valor de cada columna en su propia columna de la tabla. No obstante, en el módulo job
sería mejor utilizar el layout stacked
, que es el otro layout que incluye Symfony:
# apps/backend/modules/job/config/generator.yml
config:
list:
title: Job Management
layout: stacked
display: [company, position, location, url, is_activated, email]
params: |
%%is_activated%% <small>%%category_id%%</small> - %%company%%
(<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)
En el layout stacked
, cada objeto se representa en una sola cadena de texto, cuyo formato se define en la opción params
.
Nota En el ejemplo anterior, la opción display
sigue siendo necesaria porque define las columnas por las que el usuario puede reordenar los resultados.
12.8.3. Columnas virtuales
Si se utiliza la configuración anterior, el fragmento %%category_id%%
se reemplaza por el valor de la clave primaria de la categoría. Sin embargo, en este caso sería más útil mostrar el nombre de la categoría.
Cuando se hace uso de la notación %%
, la variable indicada no tiene que ser obligatoriamente una columna real de la base de datos. Para mostrar el valor de una variable, lo único que necesita el generador de la parte de administración es un método getter en la clase del modelo.
Si queremos mostrar el nombre de una categoría, podemos crear un método llamado getCategoryName()
en la clase JobeetJob
y reemplazar el fragmento %%category_id%%
por %%category_name%%
.
Por otra parte, la clase JobeetJob
ya dispone de un método llamado getJobeetCategory()
y que devuelve el objeto de la categoría relacionada. Por tanto, si utilizas %%jobeet_category%%
, ya se va a mostrar el nombre de la categoría, ya que la clase JobeetCategory
incluye un método mágico __toString()
que convierte un objeto en una cadena de texto.
# apps/backend/modules/job/config/generator.yml
%%is_activated%% <small>%%jobeet_category%%</small> - %%company%%
(<em>%%email%%</em>) is looking for a %%=position%% (%%location%%)
12.8.4. La opción sort
Si eres un administrador, seguramente querrás ver las últimas ofertas de trabajo publicadas. Para configurar la columna por la que se ordenan los datos por defecto, incluye la opción sort
indicando el nombre de la columna y el tipo de ordenación:
# apps/backend/modules/job/config/generator.yml
config:
list:
sort: [expires_at, desc]
12.8.5. La opción max_per_page
El listado incluye por defecto una paginación que muestra 20 elementos en cada página. Este valor se puede modificar con la opción max_per_page
:
# apps/backend/modules/job/config/generator.yml
config:
list:
max_per_page: 10
12.8.6. La opción batch_actions
En un listado se puede ejecutar una misma acción sobre varios objetos a la vez. Estas acciones por lotes no se necesitan en el módulo category
, por lo que podemos eliminarlas:
# apps/backend/modules/category/config/generator.yml
config:
list:
batch_actions: {}
La opción batch_actions
define la lista de acciones que se pueden realizar por lotes. Para eliminar esta opción, simplemente se indica un array vacío.
Por defecto cada módulo dispone de una acción de borrado por lotes llamada delete
y que define el propio framework. Vamos a suponer que para el módulo job
necesitamos además una acción por lotes que permita extender la validez de varias ofertas de trabajo por otros 30 días:
# apps/backend/modules/job/config/generator.yml
config:
list:
batch_actions:
_delete: ~
extend: ~
Las acciones cuyo nombre comienza por _
son acciones que incluye el propio framework. Si refrescas la página en el navegador y seleccionas la acción Extend, Symfony lanza una excepción que indica que debes crear un método llamado executeBatchExtend()
:
// apps/backend/modules/job/actions/actions.class.php
class jobActions extends autoJobActions
{
public function executeBatchExtend(sfWebRequest $request)
{
$ids = $request->getParameter('ids');
$jobs = JobeetJobPeer::retrieveByPks($ids);
foreach ($jobs as $job)
{
$job->extend(true);
}
$this->getUser()->setFlash('notice', 'The selected jobs have been extended successfully.');
$this->redirect('@jobeet_job');
}
}
Las claves primarias de los elementos seleccionados se almacenan en el parámetro ids
de la petición. Una vez obtenidas las claves primarias, se ejecuta para cada oferta de trabajo seleccionada el método JobeetJob::extend()
con un argumento adicional que permite saltarse la comprobación de la fecha de expiración que realiza ese método.
Actualiza el método extend()
pra que tenga en cuenta este nuevo parámetro:
// lib/model/JobeetJob.php
class JobeetJob extends BaseJobeetJob
{
public function extend($force = false)
{
if (!$force && !$this->expiresSoon())
{
return false;
}
$this->setExpiresAt(time() + 86400 * sfConfig::get('app_active_days'));
$this->save();
return true;
}
// ...
}
Una vez aumentada la validez de todas las ofertas de trabajo, se redirige al usuario a la portada del módulo job
:
12.8.7. La opción object_actions
En el listado de elementos siempre se muestra una columna adicional que contiene las acciones que se pueden realizar sobre un objeto individual. En el módulo category
no necesitamos estas acciones porque ya disponemos del nombre de la categoría que es un enlace a la página de modificación de datos y porque tampoco necesitamos borrar una categoría directamente desde el listado:
# apps/backend/modules/category/config/generator.yml
config:
list:
object_actions: {}
En el módulo job
vamos a dejar todas las acciones existentes y vamos a añadir una nueva acción llamada extend
que es similar a la que acabamos de crear como acción por lotes:
# apps/backend/modules/job/config/generator.yml
config:
list:
object_actions:
extend: ~
_edit: ~
_delete: ~
Como sucede para las acciones por lotes, las acciones _delete
y _edit
son acciones que define el propio framework, ya que su nombre empieza por _
. Para que la acción extend
se pueda utilizar, debemos definir la acción listExtend()
:
// apps/backend/modules/job/actions/actions.class.php
class jobActions extends autoJobActions
{
public function executeListExtend(sfWebRequest $request)
{
$job = $this->getRoute()->getObject();
$job->extend(true);
$this->getUser()->setFlash('notice', 'The selected jobs have been extended successfully.');
$this->redirect('@jobeet_job');
}
// ...
}
12.8.8. La opción actions
En las secciones anteriores se ha mostrado cómo añadir acciones por lotes y acciones que afectan a un solo objeto. Por su parte, la opción actions
define las acciones que no utilizan ningún objeto, como la acción para crear un nuevo objeto. A continuación vamos a eliminar la opción new
incluida por defecto y vamos a añadir una acción que borre todas las ofertas de trabajo que llevan más de 60 días sin ser activadas por parte del usuario que las insertó:
# apps/backend/modules/job/config/generator.yml
config:
list:
actions:
deleteNeverActivated: { label: Delete never activated jobs }
Hasta ahora, todas las acciones las hemos definido mediante ~
, lo que significa que Symfony configura automáticamente esas acciones. Cada acción se puede personalizar pasándole un array de parámetros. La opción label
redefine la etiqueta generada por defecto por Symfony.
Por defecto, la acción que se ejecuta cuando pinchas el enlace es el nombre de la acción prefijado con list
.
Crea la acción listDeleteNeverActivated
en el módulo job
:
// apps/backend/modules/job/actions/actions.class.php
class jobActions extends autoJobActions
{
public function executeListDeleteNeverActivated(sfWebRequest $request)
{
$nb = JobeetJobPeer::cleanup(60);
if ($nb)
{
$this->getUser()->setFlash('notice', sprintf('%d never activated jobs have been deleted successfully.', $nb));
}
else
{
$this->getUser()->setFlash('notice', 'No job to delete.');
}
$this->redirect('@jobeet_job');
}
// ...
}
Como ya te habrás dado cuenta, hemos reutilizado el método JobeetJobPeer::cleanup()
que definimos ayer. Este es otro ejemplo de las posibilidades de reutilización de código que nos brinda el patrón de diseño MVC.
Nota También puedes modificar la acción que se ejecuta mediante el parámetro action
:
deleteNeverActivated: { label: Delete never activated jobs, action: foo }
12.8.9. La opción peer_method
Como muestra la barra de depuración web, se necesitan 14 consultas a la base de datos para mostrar el listado de ofertas de trabajo:
Si pinchas sobre ese número, verás que la mayoría de consultas se utilizan para obtener el nombre de la categoría de cada oferta de trabajo:
Si quieres reducir el número de consultas, en la opción peer_method
puedes modificar el método por defecto que se emplea para obtener las ofertas de trabajo:
# apps/backend/modules/job/config/generator.yml
config:
list:
peer_method: doSelectJoinJobeetCategory
El método doSelectJoinJobeetCategory()
añade un JOIN
entre las tablas job
y category
para crear de forma automática el objeto de tipo categoría relacionado con cada oferta de trabajo.
Ahora el número de consultas se ha reducido a sólo cuatro: