Practical symfony

Día 16: Servicios Web

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


About

You are currently reading "Practical symfony" which is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.

Jobeet Links

Master symfony

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Books on symfony

Learn more about symfony with the official guides.
books.sensiolabs.com

L'audit Qualité par SensioLabs

200 points de contrôle de votre applicatif web.
audit.sensiolabs.com

Chapter Content

Los Afiliados

Los Datos

El Servicio Web de los Puestos de Trabajo

La Acción

El Formato xml

El Formato json

El Formato yaml

Probando los Servicios Web

El Formulario de Afiliación

Enrutamiento

Inicialización

Las Plantillas

Las Acciones

Las Pruebas

El Backend para Afiliados

Envíando Emails

Instalación y Configuración del Zend Framework

Envíando Emails

Nos vemos mañana

Feedback

symfony training
Be trained by symfony experts
Feb 21: Köln (Getting Started with Symfony2 - English)
Feb 27: Köln (Mastering Symfony2 - English)
Mar 05: Köln (Web Development with Symfony2 - Deutsch)
Mar 05: Montreal (Web Development with Symfony2 - English)
Mar 05: Montreal (Getting Started with Symfony2 - English)
and more...

Search


powered by google
You are currently browsing "Practical symfony" in Spanish for the 1.2 version - Doctrine edition - Switch to version: - Switch to ORM: - Switch to language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
This version of symfony is not maintained anymore.
If some of your projects still use this version, consider upgrading as soon as possible.
Practical symfony (Doctrine edition)
Support symfony!
Buy this book
or donate.
Buy Practical symfony (Doctrine edition) from amazon.com

Con agregar feeds a Jobeet, los solicitantes de puestos de trabajo pueden ahora ser informados de los nuevos puestos de trabajo en tiempo real.

En el otro lado de la valla, esta cuando se envía un puesto de empleo, y deseas tener la mayor exposición/publicidad posible. Si tu trabajo es sindicado en una gran cantidad de pequeños sitios web, tendrás una mejor oportunidad de encontrar a la persona adecuada. Ese es el poder de la Larga Cola o long tail. Los afiliados podrán publicar los puestos de trabajos más recientes en sus sitios web gracias a los servicios web que se desarrollarán hoy.

Los Afiliados

Según los requisitos del día 2:

"Caso de Uso F7: Un afiliado recupera la lista de puestos de trabajos activos"

Los Datos

Vamos a crear un nuevo archivo de datos para los afiliados:

# data/fixtures/affiliates.yml
JobeetAffiliate:
  sensio_labs:
    url:       http://www.sensio-labs.com/
    email:     fabien.potencier@example.com
    is_active: true
    token:     sensio_labs
    JobeetCategories: [programming]
 
  symfony:
    url:       http://www.symfony-project.org/
    email:     fabien.potencier@example.org
    is_active: false
    token:     symfony
    JobeetCategories: [design, programming]

La creación de registros para la tabla intermedia de una relación muchos-a-muchos es tan simple como definir un array cuya clave sea el nombre de la relación. El contenido del array es el nombre de los objetos definidos en los archivos de datos. Puede enlazar objetos desde diferentes archivos, pero los nombres deben haber sido definidos antes.

En el archivo de datos, los tokens están hardcodeados para simplificar las pruebas, pero cuando un usuario real solicita una cuenta, el token tendrán que ser generado:

// lib/model/doctrine/JobeetAffiliate.php
class JobeetAffiliate extends BaseJobeetAffiliate
{
  public function preValidate($event)
  {
    $object = $event->getInvoker();
 
    if (!$object->getToken())
    {
      $object->setToken(sha1($object->getEmail().rand(11111, 99999)));
    }
  }
 
  // ...
}

Ahora puedes recargar los datos:

$ php symfony doctrine:data-load

El Servicio Web de los Puestos de Trabajo

Como siempre, cuando se crea un nuevo recurso, es un buen hábito primero definir la dirección URL:

# apps/frontend/config/routing.yml
api_jobs:
  url:     /api/:token/jobs.:sf_format
  class:   sfDoctrineRoute
  param:   { module: api, action: list }
  options: { model: JobeetJob, type: list, method: getForToken }
  requirements:
    sf_format: (?:xml|json|yaml)

Por esta ruta, la variable especial sf_format termina la dirección URL y los valores válidos son xml, json, o yaml.

El método getForToken() es llamado cuando la acción recupera la colección de objetos relacionados con la ruta. Como tenemos que comprobar que el afiliado esta activado, tenemos que sobreescribir el comportamiento predeterminado de la ruta:

// lib/model/doctrine/JobeetJobTable.class.php
class JobeetJobTable extends Doctrine_Table
{
  public function getForToken(array $parameters)
  {
    $affiliate = Doctrine::getTable('JobeetAffiliate')->findOneByToken($parameters['token']);
    if (!$affiliate || !$affiliate->getIsActive())
    {
      throw new sfError404Exception(sprintf('Affiliate with token "%s" does not exist or is not activated.', $parameters['token']));
    }
 
    return $affiliate->getActiveJobs();
  }
 
  // ...
}

Si el token no existe en la base de datos, arrojamos una excepción sfError404Exception. Esta clase excepción se convierten automáticamente en una respuesta 404. Esta es la forma más sencilla de generar una página 404 de una clase del modelo.

El método getForToken() utiliza un nuevo método llamado getActiveJobs() y devuelve la lista de puestos de trabajo activos actualmente:

// lib/model/doctrine/JobeetAffiliate.class.php
class JobeetAffiliate extends BaseJobeetAffiliate
{
  public function getActiveJobs()
  {
    $q = Doctrine_Query::create()
      ->select('j.*')
      ->from('JobeetJob j')
      ->leftJoin('j.JobeetCategory c')
      ->leftJoin('c.JobeetAffiliates a')
      ->where('a.id = ?', $this->getId());
 
    $q = Doctrine::getTable('JobeetJob')->addActiveJobsQuery($q);
 
    return $q->execute();
  }
 
  // ...
}

El último paso es crear la acción y plantillas para la api. Inicializa el módulo con la tarea generate:module:

$ php symfony generate:module frontend api

Como no vamos a utilizar la acción predeterminada index, puedes eliminarla de la clase action, y eliminar la plantilla asociada indexSucess.php.

La Acción

Todos los formatos comparten la misma acción list:

// apps/frontend/modules/api/actions/actions.class.php
public function executeList(sfWebRequest $request)
{
  $this->jobs = array();
  foreach ($this->getRoute()->getObjects() as $job)
  {
    $this->jobs[$this->generateUrl('job_show_user', $job, true)] = $job->asArray($request->getHost());
  }
}

En lugar de pasar un array de objetos JobeetJob a las plantillas, se pasa un array de cadenas. Como tenemos tres modelos diferentes para la misma acción, la lógica de proceso de los valores ha sido refactorizada en el método JobeetJob::asArray():

// lib/model/doctrine/JobeetJob.class.php
class JobeetJob extends BaseJobeetJob
{
  public function asArray($host)
  {
    return array(
      'category'     => $this->getJobeetCategory()->getName(),
      'type'         => $this->getType(),
      'company'      => $this->getCompany(),
      'logo'         => $this->getLogo() ? 'http://'.$host.'/uploads/jobs/'.$this->getLogo() : null,
      'url'          => $this->getUrl(),
      'position'     => $this->getPosition(),
      'location'     => $this->getLocation(),
      'description'  => $this->getDescription(),
      'how_to_apply' => $this->getHowToApply(),
      'expires_at'   => $this->getCreatedAt(),
    );
  }
 
  // ...
}

El Formato xml

Soportar el formato xml es tan simple como crear una plantilla:

<!-- apps/frontend/modules/api/templates/listSuccess.xml.php -->
<?xml version="1.0" encoding="utf-8"?>
<jobs>
<?php foreach ($jobs as $url => $job): ?>
  <job url="<?php echo $url ?>">
<?php foreach ($job as $key => $value): ?>
    <<?php echo $key ?>><?php echo $value ?></<?php echo $key ?>>
<?php endforeach; ?>
  </job>
<?php endforeach; ?>
</jobs>

El Formato json

Soportar el formato JSON es similar:

<!-- apps/frontend/modules/api/templates/listSuccess.json.php -->
[
<?php $nb = count($jobs); $i = 0; foreach ($jobs as $url => $job): ++$i ?>
{
  "url": "<?php echo $url ?>",
<?php $nb1 = count($job); $j = 0; foreach ($job as $key => $value): ++$j ?>
  "<?php echo $key ?>": <?php echo json_encode($value).($nb1 == $j ? '' : ',') ?>
 
<?php endforeach; ?>
}<?php echo $nb == $i ? '' : ',' ?>
 
<?php endforeach; ?>
]

El Formato yaml

Para Formatos nativos, Symfony hace algunas configuraciones en el fondo, como cambiar el content type, y desactivar el layout.

Como el Formato YAML no esta en la lista de los formatos nativos, la respuesta y su content type se puede cambiar y el layout desactivado en la acción:

class apiActions extends sfActions
{
  public function executeList(sfWebRequest $request)
  {
    $this->jobs = array();
    foreach ($this->getRoute()->getObjects() as $job)
    {
      $this->jobs[$this->generateUrl('job_show_user', $job, true)] = $job->asArray($request->getHost());
    }
 
    switch ($request->getRequestFormat())
    {
      case 'yaml':
        $this->setLayout(false);
        $this->getResponse()->setContentType('text/yaml');
        break;
    }
  }
}

En una acción, el método setLayout() cambia el layout por defecto o se desactiva cuando se establece en false.

La plantilla de YAML dice lo siguiente:

<!-- apps/frontend/modules/api/templates/listSuccess.yaml.php -->
<?php foreach ($jobs as $url => $job): ?>
-
  url: <?php echo $url ?>
 
<?php foreach ($job as $key => $value): ?>
  <?php echo $key ?>: <?php echo sfYaml::dump($value) ?>
 
<?php endforeach; ?>
<?php endforeach; ?>

Si intentas llamar a los servicios web con un token no-válido, tendrás una página XML 404 para el formato XML, y una página JSON 404 para el formato JSON. Pero para el formato YAML, Symfony no sabe qué mostrar.

Cuando creas un formato, una plantilla personalizada de error debe ser creada. La plantilla se utilizará para páginas 404, y todas las demás excepciones.

Dado que la excepción debe ser diferente según sea un entorno de desarrollo o producción, dos archivos son necesarios (config/error/exception.yaml.php para depuración, y config/error/error.yaml.php para producción):

// config/error/exception.yaml.php
<?php echo sfYaml::dump(array(
  'error'       => array(
    'code'      => $code,
    'message'   => $message,
    'debug'     => array(
      'name'    => $name,
      'message' => $message,
      'traces'  => $traces,
    ),
)), 4) ?>
 
// config/error/error.yaml.php
<?php echo sfYaml::dump(array(
  'error'       => array(
    'code'      => $code,
    'message'   => $message,
))) ?>

Antes de probarlo, debes crear un layout para el formato YAML:

// apps/frontend/templates/layout.yaml.php
<?php echo $sf_content ?>

404

Sobreescribiendo las plantillas por defecto de error 404 y de excepción es tan simple como crear los archivos en cuestión en el directorio config/error/.

Probando los Servicios Web

Para probar el servicio web, copia los datos de los afiliados de data/fixtures/ a test/fixtures/ y sustituye el contenido del archivo autogenerado apiActionsTest.php con el siguiente contenido:

// test/functional/frontend/apiActionsTest.php
include(dirname(__FILE__).'/../../bootstrap/functional.php');
 
$browser = new JobeetTestFunctional(new sfBrowser());
$browser->loadData();
 
$browser->
  info('1 - Web service security')->
 
  info('  1.1 - A token is needed to access the service')->
  get('/api/foo/jobs.xml')->
  with('response')->isStatusCode(404)->
 
  info('  1.2 - An inactive account cannot access the web service')->
  get('/api/symfony/jobs.xml')->
  with('response')->isStatusCode(404)->
 
  info('2 - The jobs returned are limited to the categories configured for the affiliate')->
  get('/api/sensio_labs/jobs.xml')->
  with('request')->isFormat('xml')->
  with('response')->checkElement('job', 32)->
 
  info('3 - The web service supports the JSON format')->
  get('/api/sensio_labs/jobs.json')->
  with('request')->isFormat('json')->
  with('response')->contains('"category": "Programming"')->
 
  info('4 - The web service supports the YAML format')->
  get('/api/sensio_labs/jobs.yaml')->
  with('response')->begin()->
    isHeader('content-type', 'text/yaml; charset=utf-8')->
    contains('category: Programming')->
  end()
;

En esta prueba, te darás cuenta de dos nuevos métodos:

El Formulario de Afiliación

Ahora que el servicio web está listo para ser utilizado, vamos a crear el Formulario de Afiliación. Vamos a describir una vez más el clásico proceso de agregar una nueva funcionalidad a una aplicación.

Enrutamiento

Lo sabes. La ruta es la primera cosa a crear:

// apps/frontend/config/routing.yml
affiliate:
  class:   sfDoctrineRouteCollection
  options:
    model: JobeetAffiliate
    actions: [new, create]
    object_actions: { wait: get }

Se trata de una clásica colección de rutas Doctrine con una nueva opción de configuración: actions. Como no necesitamos todas las siete acciones definidas por defecto para la ruta, la opción actions instruye a la ruta para sólo coincidir con las acciones new y create . La ruta adicional wait se utilizarán para dar al inminente afiliado algunos comentarios acerca de su cuenta.

Inicialización

El segundo paso clásico es generar un módulo:

$ php symfony doctrine:generate-module frontend affiliate JobeetAffiliate --non-verbose-templates

Las Plantillas

La tarea doctrine:generate-module genera las clásicas siete acciones y sus correspondientes plantillas. En el directorio templates/, elimina todos los archivos, pero no _form.php ni newSuccess.php. Y para los archivos que mantenemos, sustituye sus contenidos con los siguientes:

<!-- apps/frontend/modules/affiliate/templates/newSuccess.php -->
<?php use_stylesheet('job.css') ?>
 
<h1>Become an Affiliate</h1>
 
<?php include_partial('form', array('form' => $form)) ?>
 
<!-- apps/frontend/modules/affiliate/templates/_form.php -->
<?php include_stylesheets_for_form($form) ?>
<?php include_javascripts_for_form($form) ?>
 
<?php echo form_tag_for($form, 'affiliate') ?>
  <table id="job_form">
    <tfoot>
      <tr>
        <td colspan="2">
          <input type="submit" value="Submit" />
        </td>
      </tr>
    </tfoot>
    <tbody>
      <?php echo $form ?>
    </tbody>
  </table>
</form>

Crea la plantilla waitSuccess.php:

<!-- apps/frontend/modules/affiliate/templates/waitSuccess.php -->
<h1>Your affiliate account has been created</h1>
 
<div style="padding: 20px">
  Thank you!
  You will receive an email with your affiliate token
  as soon as your account will be activated.
</div>

Por último, cambiar el enlace en el pie de página para que apunte al módulo affiliate:

// apps/frontend/templates/layout.php
<li class="last">
  <a href="<?php echo url_for('@affiliate_new') ?>">Become an affiliate</a>
</li>

Las Acciones

Una vez más, ya que sólo se utiliza el formulario de creación, abre el archivo actions.class.php y elimina todos los métodos pero deja executeNew(), executeCreate(), y processForm().

Para la acción processForm(), cambiar la URL de redireccionamiento a la acción wait:

// apps/frontend/modules/affiliate/actions/actions.class.php
$this->redirect($this->generateUrl('affiliate_wait', $jobeet_affiliate));

La acción wait es simple que no hace falta pasarle nada a la plantilla:

// apps/frontend/modules/affiliate/actions/actions.class.php
public function executeWait()
{
}

El afiliado no puede elegir su token, ni puede activar su cuenta inmediatamente. Abre el archivo JobeetAffiliateForm para personalizar el formulario:

// lib/form/doctrine/JobeetAffiliateForm.class.php
class JobeetAffiliateForm extends BaseJobeetAffiliateForm
{
  public function configure()
  {
    unset($this['is_active'], $this['token'], $this['created_at'], $this['updated_at']);
 
    $this->widgetSchema['jobeet_categories_list']->setOption('expanded', true);
    $this->widgetSchema['jobeet_categories_list']->setLabel('Categories');
 
    $this->validatorSchema['jobeet_categories_list']->setOption('required', true);
 
    $this->widgetSchema['url']->setLabel('Your website URL');
    $this->widgetSchema['url']->setAttribute('size', 50);
 
    $this->widgetSchema['email']->setAttribute('size', 50);
 
    $this->validatorSchema['email'] = new sfValidatorEmail(array('required' => true));
  }
}

El framework de formularios soporta relaciones muchos-a-muchos como cualquier otra columna. Por defecto, esta relación es mostrada como un cuadro desplegable gracias al widget sfWidgetFormChoice. Como se ha visto durante el día 10, hemos cambiado lo mostrado mediante el uso de la opción expanded.

Como emails y URLs tienden a ser bastante más largo que el tamaño predeterminado de una etiqueta input, los atributos de HTML por defecto se puede configurar utilizando el método setAttribute().

fFormulario de Afiliado

Las Pruebas

El último paso es escribir algunas pruebas funcionales para la nueva función.

Sustituye las pruebas generadas para el módulo affiliate con el código siguiente:

// test/functional/frontend/affiliateActionsTest.php
include(dirname(__FILE__).'/../../bootstrap/functional.php');
 
$browser = new JobeetTestFunctional(new sfBrowser());
$browser->loadData();
 
$browser->
  info('1 - An affiliate can create an account')->
 
  get('/affiliate/new')->
  click('Submit', array('jobeet_affiliate' => array(
    'url'                            => 'http://www.example.com/',
    'email'                          => 'foo@example.com',
    'jobeet_categories_list'         => array(Doctrine::getTable('JobeetCategory')->findOneBySlug('programming')->getId()),
  )))->
  isRedirected()->
  followRedirect()->
  with('response')->checkElement('#content h1', 'Your affiliate account has been created')->
 
  info('2 - An affiliate must at least select one category')->
 
  get('/affiliate/new')->
  click('Submit', array('jobeet_affiliate' => array(
    'url'   => 'http://www.example.com/',
    'email' => 'foo@example.com',
  )))->
  with('form')->isError('jobeet_categories_list')
;

El Backend para Afiliados

Por el backend, un module affiliate debe ser creado para activar los afiliados por el administrador:

$ php symfony doctrine:generate-admin backend JobeetAffiliate --module=affiliate

Para acceder al nuevo módulo creado, añade un enlace en el menú principal con el número de afiliados que deben ser activados:

<!-- apps/backend/templates/layout.php -->
<li>
  <a href="<?php echo url_for('@jobeet_affiliate') ?>">
    Affiliates - <strong><?php echo Doctrine::getTable('JobeetAffiliate')->countToBeActivated() ?></strong>
  </a>
</li>
 
// lib/model/doctrine/JobeetAffiliateTable.class.php
class JobeetAffiliateTable extends Doctrine_Table
{
  public function countToBeActivated()
  {
    $q = $this->createQuery('a')
      ->where('a.is_active = ?', 0);
 
    return $q->count();
  }
 
  // ...
 
}

Como la única acción necesaria en el backend es para activar o desactivar las cuentas, cambia la sección config del generador por defecto para simplificar la interfaz un poco y añade un enlace para activar directamente las cuentas en la vista list:

# apps/backend/modules/affiliate/config/generator.yml
config:
  fields:
    is_active: { label: Active? }
  list:
    title:   Affiliate Management
    display: [is_active, url, email, token]
    sort:    [is_active]
    object_actions:
      activate:   ~
      deactivate: ~
    batch_actions:
      activate:   ~
      deactivate: ~
    actions: {}
  filter:
    display: [url, email, is_active]

Para que los administradores sean más productivos, cambiar el filtro para mostrar únicamente los afiliados a ser activados:

// apps/backend/modules/affiliate/lib/affiliateGeneratorConfiguration.class.php
class affiliateGeneratorConfiguration extends BaseAffiliateGeneratorConfiguration
{
  public function getFilterDefaults()
  {
    return array('is_active' => '0');
  }
}

El único otro código a escribir es para las acciones activate, deactivate :

// apps/backend/modules/affiliate/actions/actions.class.php
class affiliateActions extends autoAffiliateActions
{
  public function executeListActivate()
  {
    $this->getRoute()->getObject()->activate();
 
    $this->redirect('@jobeet_affiliate');
  }
 
  public function executeListDeactivate()
  {
    $this->getRoute()->getObject()->deactivate();
 
    $this->redirect('@jobeet_affiliate');
  }
 
  public function executeBatchActivate(sfWebRequest $request)
  {
    $q = Doctrine_Query::create()
      ->from('JobeetAffiliate a')
      ->whereIn('a.id', $request->getParameter('ids'));
 
    $affiliates = $q->execute();
 
    foreach ($affiliates as $affiliate)
    {
      $affiliate->activate();
    }
 
    $this->redirect('@jobeet_affiliate');
  }
 
  public function executeBatchDeactivate(sfWebRequest $request)
  {
    $q = Doctrine_Query::create()
      ->from('JobeetAffiliate a')
      ->whereIn('a.id', $request->getParameter('ids'));
 
    $affiliates = $q->execute();
 
    foreach ($affiliates as $affiliate)
    {
      $affiliate->deactivate();
    }
 
    $this->redirect('@jobeet_affiliate');
  }
}
 
// lib/model/doctrine/JobeetAffiliate.class.php
class JobeetAffiliate extends BaseJobeetAffiliate
{
  public function activate()
  {
    $this->setIsActive(true);
 
    return $this->save();
  }
 
  public function deactivate()
  {
    $this->setIsActive(false);
 
    return $this->save();
  }
 
  // ...
}

Backend para Afiliados

Envíando Emails

Cuando una cuenta de afiliado es activada por el administrador, un mensaje de correo electrónico debe enviarse al afiliado para confirmar su suscripción y darle su token.

PHP tiene un buen número de bibliotecas para enviar mensajes de correo electrónico como SwiftMailer, Zend_Mail, y ezcMail. Como vamos a usar algunas otras bibliotecas del Zend Framework en próximos días, vamos a usar Zend_Mail para enviar nuestros mensajes de correo electrónico.

Instalación y Configuración del Zend Framework

La biblioteca Zend Mail es parte del Zend Framework. Como no necesitamos de todo del Zend Framework, sólo se necesita instalar algunas partes en el directorio lib/vendor/, junto con el symfony framework.

En primer lugar, la descarga Zend Framework y descomprime los archivos de modo que tengas un directorio lib/vendor/Zend/. Puedes limpiar el directorio eliminando todo menos los siguientes archivos y directorios:

El directorio Search/ no se necesita para enviar mensajes de correo electrónico, sino que será necesario para el tutorial de mañana.

Luego, agrega el código siguiente a la claseProjectConfiguration para proporcionar una manera simple de registrar el Zend autoloader:

// config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration
{
  static protected $zendLoaded = false;
 
  static public function registerZend()
  {
    if (self::$zendLoaded)
    {
      return;
    }
 
    set_include_path(sfConfig::get('sf_lib_dir').'/vendor'.PATH_SEPARATOR.get_include_path());
    require_once sfConfig::get('sf_lib_dir').'/vendor/Zend/Loader.php';
    Zend_Loader::registerAutoload();
    self::$zendLoaded = true;
  }
 
  // ...
}

Envíando Emails

Edita la acción activate para enviar un correo electrónico cuando el administrador valida un afiliado:

// apps/backend/modules/affiliate/actions/actions.class.php
class affiliateActions extends autoAffiliateActions
{
  public function executeListActivate()
  {
    $affiliate = $this->getRoute()->getObject();
    $affiliate->activate();
 
    // send an email to the affiliate
    ProjectConfiguration::registerZend();
    $mail = new Zend_Mail();
    $mail->setBodyText(<<<EOF
Your Jobeet affiliate account has been activated.
 
Your token is {$affiliate->getToken()}.
 
The Jobeet Bot.
EOF
);
    $mail->setFrom('jobeet@example.com', 'Jobeet Bot');
    $mail->addTo($affiliate->getEmail());
    $mail->setSubject('Jobeet affiliate token');
    $mail->send();
 
    $this->redirect('@jobeet_affiliate');
  }
 
  // ...
}

Para que el código funcione, es necesario cambiar jobeet@example.com a una verdadera dirección de correo electrónico.

Un completo tutorial sobre la biblioteca Zend_Mail está disponible en Zend Framework website.

Nos vemos mañana

Gracias a la arquitectura REST de symfony, es muy fácil de implementar los servicios web para tus proyectos. Si bien, escribimos el código de servicios web de sólo lectura, tienes suficiente conocimientos sobre symfony para implementar un servicio web de lectura y escritura.

La implementación de un formulario de alta de cuentas de afiliado en el frontend y su contraparte backend fue tan fácil ya que ahora estás familiarizado con el proceso de agregar nuevas características a tu proyecto.

Si te acuerdas de los requisitos del día 2:

"El afiliado también puede limitar el número de puestos de trabajo a ser devuelto, y refinar su consulta, especificando la categoría."

La implementación de esta función es tan fácil que te permitiremos hacerlo esta noche.

Mañana, vamos a implementar la última característica faltante del sitio web Jobeet, el motor de búsqueda.

Feedback

Este capítulo ha sido traducido por Roberto Germán Puentes Díaz. Si encuentras algún error que deseas corregir o realizar algún comentario, no dudes en enviarlo por correo a puentesdiaz [arroba] gmail.com

Día 17: El Motor de Busqueda  »
« Día 15: Feeds o Canales

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.