Tutorial Jobeet con Symfony2 Día 6: Más trabajo con el modelo

De WikiSalud
Saltar a: navegación, buscar

Contenido

El objeto de consulta Doctrine

De los requerimientos del segundo día: "En la página principal, los usuarios ven las últimas ofertas de trabajo activas." Pero hasta ahora, todos las ofertas son mostradas, si están activas o no.

src/Ens/JobeetBundle/Controller/JobController.php
// src/Ens/JobeetBundle/Controller/JobController.php
// ...
 
class JobController extends Controller
{
  public function indexAction()
  {
    $em = $this->getDoctrine()->getEntityManager();
 
    $entities = $em->getRepository('EnsJobeetBundle:Job')->findAll();
 
    return $this->render('EnsJobeetBundle:Job:index.html.twig', array(
      'entities' => $entities
    ));
 
  // ...
}

Una oferta de trabajo activa es aquella que fue publicada hace menos de 30 días. El método $entities = $em->getRepository('EnsJobeetBundle:Job')->findAll() obtendrá todos los trabajos. No estamos especificando ninguna condición, lo cual significa que todos los registros son recuperados de la base de datos Cambiemoslo para seleccionar solo ofertas de trabajo activas


src/Ens/JobeetBundle/Controller/JobController.php
public function indexAction()
{
  $em = $this->getDoctrine()->getEntityManager();
 
  $query = $em->createQuery(
    'SELECT j FROM EnsJobeetBundle:Job j WHERE j.created_at > :date'
  )->setParameter('date', date('Y-m-d H:i:s', time() - 86400 * 30));
  $entities = $query->getResult();
 
  return $this->render('EnsJobeetBundle:Job:index.html.twig', array(
    'entities' => $entities
  ));
}

Depurando el SQL generado por Doctrine

Algunas veces, es bastante útil ver el SQL generado por Doctrine, por ejemplo, para depurar a consulta que no trabaja como se espera. En el ambiente de desarrollo, gracias a la barra de herramientas web para depuración, toda la información que necesitas esta disponible desde la comodidad de tu navegador (http://jobeet.local/app_dev.php): Acá va una imagen sobre esa puta barra Acá va otra imagen sobre el sql generado

Serialización de objetos

Incluso si el codigo arriba trabaja, esta lejos de ser perfecto y no toma en cuenta algunos requerimientos del día 2: "Un usuario puede regresar y reactiva o extender la validez de una oferta de trabajo por un extra de 30 días..." But as the above code only relies on the created_at value, and because this column stores the creation date, we cannot satisfy the above requirement.

Si recuerdas el esquema de la base de datos descrita durante el día 3, también tenemos definida una columna expires_at. Actualmente, si este valor no esta configurado en el archivo de fixture, permanece siemper vacío. <revisar la realidad de esto. En realidad debe llenarse por el esquema>, puede cuando una oferta de trabajo es creada, puede ser automaticamente configurada a 30 días después de la actual fecha. Cuando necesitas hacer algo automicamente antes de que un objeto Doctrine sea serializado a la base de datos, puedes añadir estas acciones a las callback del ciclo de vida en el archivo que mapea objetos a la base de datos, como hicimos antes con la columna created_at column.

src/Ens/JobeetBundle/Resources/config/doctrine/Job.orm.yml
# src/Ens/JobeetBundle/Resources/config/doctrine/Job.orm.yml
# ...
 
  lifecycleCallbacks:
    prePersist: [ setCreatedAtValue, setExpiresAtValue ]
    preUpdate: [ setUpdatedAtValue ]

Ahora tenemos que reconstruir las clases de las entidades, así Doctrine añadirá la nueva función:

php app/console doctrine:generate:entities EnsJobeetBundle

Abre el archivo src/Ens/JobeetBundle/Entity/Job.php y edita la nueva función añadida:

src/Ens/JobeetBundle/Entity/Job.php
# src/Ens/JobeetBundle/Entity/Job.php
# ...
 
public function setExpiresAtValue()
{
  if(!$this->getExpiresAt())
  {
    $now = $this->getCreatedAt() ? $this->getCreatedAt()->format('U') : time();
    $this->expires_at = new \DateTime(date('Y-m-d H:i:s', $now + 86400 * 30));
  }
}

Ahora, cambiemos la acción para usar la columna expires_at en lugar de created_at para seleccionar las ofertas de trabajo activas:

src/Ens/JobeetBundle/Controller/JobController.php
// src/Ens/JobeetBundle/Controller/JobController.php
// ...
 
public function indexAction()
{
  $em = $this->getDoctrine()->getEntityManager();
 
  $query = $em->createQuery(
    'SELECT j FROM EnsJobeetBundle:Job j WHERE j.expires_at > :date'
  )->setParameter('date', date('Y-m-d H:i:s', time()));
  $entities = $query->getResult();
 
  return $this->render('EnsJobeetBundle:Job:index.html.twig', array(
    'entities' => $entities
  ));
}

Trabajando sobre Fixtures

Refresca la página Jobeet en tu navegador, no va a cambiar nada ya que las ofertas de trabajo en la base de datos han sido publicadas hace pocos días. Vamos a cambiar las fixtures para añadir un trabajo que ya haya expirado

src/Ens/JobeetBundle/DataFixtures/ORM/LoadJobData.php
// src/Ens/JobeetBundle/DataFixtures/ORM/LoadJobData.php
// ...
 
$job_expired = new Job();
$job_expired->setCategory($em->merge($this->getReference('category-programming')));
$job_expired->setType('full-time');
$job_expired->setCompany('Sensio Labs');
$job_expired->setLogo('sensio-labs.gif');
$job_expired->setUrl('http://www.sensiolabs.com/');
$job_expired->setPosition('Web Developer Expired');
$job_expired->setLocation('Paris, France');
$job_expired->setDescription('Lorem ipsum dolor sit amet, consectetur adipisicing elit.');
$job_expired->setHowToApply('Send your resume to lorem.ipsum [at] dolor.sit');
$job_expired->setIsPublic(true);
$job_expired->setIsActivated(true);
$job_expired->setToken('job_expired');
$job_expired->setEmail('job@example.com');
$job_expired->setCreatedAt(new \DateTime('2005-12-01'));
 
// ...
 
$em->persist($job_expired);

Recarga las fixtures y refresca tu navegador para asegurarse que la oferta de trabajo vieja no se muestra:

php app/console doctrine:fixtures:load

Refactorizando

Aunque el código que hemos escrito trabaja bien, no es del todo correcto aún. ¿Puedes ver el problema?

El código de la consulta Doctrine no pertenece a la acción (Capa controlador), pertenece a la Capa Modelo. En el modelo MVC, el Modelo define todas la lógica de negocios, y el controlador solo llama al Modelo para recuperar datos de el. Como el código retorna una colección de trabajos moveremos el código al Modelo. Para eso necesitaremos crear un respositorio personalizado para la entidad Job y añadiremos la consulta a esa clase

Abre /src/Ens/JobeetBundle/Resources/config/doctrine/Job.orm.yml, y añade lo siguiente:

/src/Ens/JobeetBundle/Resources/config/doctrine/Job.orm.yml
# /src/Ens/JobeetBundle/Resources/config/doctrine/Job.orm.yml
 
Ens\JobeetBundle\Entity\Job:
  type: entity
  repositoryClass: Ens\JobeetBundle\Repository\JobRepository
  # ...

Doctrine puede generar la clase repositorio para ti corriendo el comando generate:entities usado antes:

php app/console doctrine:generate:entities EnsJobeetBundle

A continuación, añade un método nuevo - getActiveJobs() -a la recientemente creada clase repositorio. Este metodo consultará por todos los entidades trabajos activos ordenados por la columna expires_at (Y filtrada por categoría si recibe el parametro $category_id)

src/Ens/JobeetBundle/Repository/JobRepository.php
// src/Ens/JobeetBundle/Repository/JobRepository.php
 
namespace Ens\JobeetBundle\Repository;
use Doctrine\ORM\EntityRepository;
 
class JobRepository extends EntityRepository
{
  public function getActiveJobs($category_id = null)
  {
    $qb = $this->createQueryBuilder('j')
      ->where('j.expires_at > :date')
      ->setParameter('date', date('Y-m-d H:i:s', time()))
      ->orderBy('j.expires_at', 'DESC');
 
    if($category_id)
    {
      $qb->andWhere('j.category = :category_id')
         ->setParameter('category_id', $category_id);
    }
 
    $query = $qb->getQuery();
 
    return $query->getResult();
  }
}

Ahora el código de la acción puede usar este nuevo metodo para conseguir todas las ofertas de trabajo activas

src/Ens/JobeetBundle/Controller/JobController.php
// src/Ens/JobeetBundle/Controller/JobController.php
// ...
 
public function indexAction()
{
  $em = $this->getDoctrine()->getEntityManager();
 
  $entities = $em->getRepository('EnsJobeetBundle:Job')->getActiveJobs();
 
  return $this->render('EnsJobeetBundle:Job:index.html.twig', array(
    'entities' => $entities
  ));
}
 
// ...

Esta refactorización tiene muchos beneficios sobre el código previo:

  • La lógica que obtiene todas las ofertas de trabajo activas está ahora en el Modelo, donde pertenece
  • El código en el controlador es más delgado y mucho más leíble
  • El método getActiveJobs() es reusable (Por ejemplo en otro controlador)
  • Ahora pueden crearse pruebas unitarias para el código del Modelo

Categorías en la página principal

Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas