Otro de los requerimientos que establecimos durante el segundo día era: "las ofertas se agrupan por categoría y se ordenan por fecha de publicación (primero se muestran los trabajos más recientes)".
Hasta ahora no hemos tenido en cuenta la categoría de cada oferta de trabajo, aunque los requerimientos de la aplicación indican que la portada muestra las ofertas de trabajo agrupadas por categoría. En primer lugar debemos obtener todas las categorías que tienen al menos una oferta de trabajo activa.
Abre la clase JobeetCategoryPeer
y añade el siguiente método llamado getWithJobs()
:
// lib/model/JobeetCategoryPeer.php
class JobeetCategoryPeer extends BaseJobeetCategoryPeer
{
static public function getWithJobs()
{
$criteria = new Criteria();
$criteria->addJoin(self::ID, JobeetJobPeer::CATEGORY_ID);
$criteria->add(JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN);
$criteria->setDistinct();
return self::doSelect($criteria);
}
}
El método Criteria::addJoin()
añade una condición de tipo JOIN
en la sentencia SQL generada. Por defecto la condición JOIN
se añade a la condición WHERE
. Si quieres modificar el tipo de JOIN
, utiliza uno de los siguientes valores como tercer argumento:Criteria::LEFT_JOIN
, Criteria::RIGHT_JOIN
y Criteria::INNER_JOIN
.
Ahora actualiza la acción index
para que utilice el nuevo método:
// apps/frontend/modules/job/actions/actions.class.php
public function executeIndex(sfWebRequest $request)
{
$this->categories = JobeetCategoryPeer::getWithJobs();
}
En la plantilla asociada a la acción ahora tenemos que iterar por todas las categorías para mostrar sus ofertas de trabajo activas:
// apps/frontend/modules/job/templates/indexSuccess.php
<?php use_stylesheet('jobs.css') ?>
<div id="jobs">
<?php foreach ($categories as $category): ?>
<div class="category_<?php echo Jobeet::slugify($category->getName()) ?>">
<div class="category">
<div class="feed">
<a href="">Feed</a>
</div>
<h1><?php echo $category ?></h1>
</div>
<table class="jobs">
<?php foreach ($category->getActiveJobs() as $i => $job): ?>
<tr class="<?php echo fmod($i, 2) ? 'even' : 'odd' ?>">
<td class="location">
<?php echo $job->getLocation() ?>
</td>
<td class="position">
<?php echo link_to($job->getPosition(), 'job_show_user', $job) ?>
</td>
<td class="company">
<?php echo $job->getCompany() ?>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
<?php endforeach; ?>
</div>
Nota La plantilla anterior utiliza echo $category
para mostrar el nombre de la categoría. ¿Te parece extraño? Teniendo en cuenta que $category
es un objeto, ¿cómo es posible que echo
muestre mágicamente el nombre de la categoría? La respuesta se encuentra en el tutorial del día 3, donde definimos métodos mágicos __toString()
en todas las clases del modelo.
Para que la plantilla anterior funcione correctamente, debemos añadir el método getActiveJobs()
en la clase JobeetCategory
:
// lib/model/JobeetCategory.php
public function getActiveJobs()
{
$criteria = new Criteria();
$criteria->add(JobeetJobPeer::CATEGORY_ID, $this->getId());
return JobeetJobPeer::getActiveJobs($criteria);
}
En la llamada al método add()
, hemos omitido el tecer argumento porque Criteria::EQUAL
es el valor por defecto.
El método JobeetCategory::getActiveJobs()
utiliza a su vez el método JobeetJobPeer::getActiveJobs()
para obtener las ofertas de trabajo activas para la categoría indicada.
Cuando se invoca el método JobeetJobPeer::getActiveJobs()
, queremos hacer la condición más restrictiva pasándole una categoría. En lugar de pasar el objeto de la categoría actual, hemos decidido pasarle un objeto de tipo Criteria
, ya que es la mejor forma de encapsular una condición genérica.
Por tanto, el método getActiveJobs()
tiene que que tenerlo en cuenta y debe fusionar el objeto Criteria
que se le pasa y su propio Criteria
. Como Criteria
es un objeto, el código resultante es muy sencillo:
// lib/model/JobeetJobPeer.php
static public function getActiveJobs(Criteria $criteria = null)
{
if (is_null($criteria))
{
$criteria = new Criteria();
}
$criteria->add(JobeetJobPeer::EXPIRES_AT, time(), Criteria::GREATER_THAN);
$criteria->addDescendingOrderByColumn(self::EXPIRES_AT);
return self::doSelect($criteria);
}