Saturday, March 7, 2015

Symfony 2 hari 24: Membuat API web service dengan Symfony 2

Artikel ini dirunut berdasarkan Jobeet Tutorial, yang dibuat oleh Fabien Potencier, untuk Symfony 1.4.

Web service API dengan Symfony 2




Untuk membantu penyebaran data job yang diposting dari web kita ke web yang ingin menjadi afiliasi maka kita akan membuat fitur API yang mengirimkan data job terupdate agar dapat ditampilkan di website mereka.

Ok sekarang saatnya membuat membuat data fixture untuk memasukan data affiliate. Buat file LoadAffiliateData.php

src/Ibw/JobeetBundle/DataFixtures/ORM/LoadAffiliateData.php

namespace Ibw\JobeetBundle\DataFixtures\ORM;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Ibw\JobeetBundle\Entity\Affiliate;

class LoadAffiliateData extends AbstractFixture implements OrderedFixtureInterface
{
    public function load(ObjectManager $em)
    {
        $affiliate = new Affiliate();

        $affiliate->setUrl('http://sensio-labs.com/');
        $affiliate->setEmail('address1@example.com');
        $affiliate->setToken('sensio-labs');
        $affiliate->setIsActive(true);
        $affiliate->addCategorie($em->merge($this->getReference('category-programming')));

        $em->persist($affiliate);

        $affiliate = new Affiliate();

        $affiliate->setUrl('/');
        $affiliate->setEmail('address2@example.org');
        $affiliate->setToken('symfony');
        $affiliate->setIsActive(false);
        $affiliate->addCategorie($em->merge($this->getReference('category-programming')), $em->merge($this->getReference('category-design')));

        $em->persist($affiliate);
        $em->flush();

        $this->addReference('affiliate', $affiliate);
    }

    public function getOrder()
    {
        return 3; // This represents the order in which fixtures will be loaded
    }
}


======================================

Kemudian jalankan perintah berikut untuk memasukan data ke dalam tabel:

php app/console doctrine:fixtures:load
Selanjutnya tambahkan method token di model affiliate, tambahkan sintak berikut di file Affiliate.orm.yml
src//Ibw/JobeetBundle/Resources/config/doctrine/Affiliate.orm.yml 
# ...
    lifecycleCallbacks:
        prePersist: [ setCreatedAtValue, setTokenValue ]
============================================
Selanjutnya jalankan perintah ini melalui terminal. 
php app/console doctrine:generate:entities IbwJobeetBundle
Ok, mari kita tambahkan methodnya:
src/Ibw/JobeetBundle/Entity/Affiliate.php
  public function setTokenValue()
    {
        if(!$this->getToken()) {
            $token = sha1($this->getEmail().rand(11111, 99999));
            $this->token = $token;
        }
        return $this;
    }
================================================
Reload datanya dengan menjalankan perintah berikut:
php app/console doctrine:fixtures:load

Webservice untuk Job-nya

Ok langkah pertamanya adalah kita tambahkan routingnya terlebih dahulu edit file routingnya:


src/Ibw/JobeetBundle/Resources/config/routing.yml 
   
IbwJobeetBundle_api:
    pattern: /api/{token}/jobs.{_format}
    defaults: {_controller: "IbwJobeetBundle:Api:list"}
    requirements:
        _format: xml|json|yaml
 ===============================================
Seperti biasanya setelah kita menambahkan routing baru kita perlu untuk membersihkan cachenya, jalankan perintah berikut untuk melakukannya:

php app/console cache:clear --env=dev
php app/console cache:clear --env=prod
Buat file ApiController.php dan tambahkan kode berikut:
src/Ibw/JobeetBundle/Controller/ApiController.php
namespace Ibw\JobeetBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Ibw\JobeetBundle\Entity\Affiliate;
use Ibw\JobeetBundle\Entity\Job;
use Ibw\JobeetBundle\Repository\AffiliateRepository;

class ApiController extends Controller
{
    public function listAction(Request $request, $token)
    {
        $em = $this->getDoctrine()->getManager();

        $jobs = array();

        $rep = $em->getRepository('IbwJobeetBundle:Affiliate');
        $affiliate = $rep->getForToken($token);

        if(!$affiliate) {
            throw $this->createNotFoundException('This affiliate account does not exist!');
        }

        $rep = $em->getRepository('IbwJobeetBundle:Job');
        $active_jobs = $rep->getActiveJobs(null, null, null, $affiliate->getId());

        foreach ($active_jobs as $job) {
            $jobs[$this->get('router')->generate('ibw_job_show', array('company' => $job->getCompanySlug(), 'location' => $job->getLocationSlug(), 'id' => $job->getId(), 'position' => $job->getPositionSlug()), true)] = $job->asArray($request->getHost());
        }

        $format = $request->getRequestFormat();
        $jsonData = json_encode($jobs);

        if ($format == "json") {
            $headers = array('Content-Type' => 'application/json');
            $response = new Response($jsonData, 200, $headers);

            return $response;
        }

        return $this->render('IbwJobeetBundle:Api:jobs.' . $format . '.twig', array('jobs' => $jobs)); 
    }
}
==============================================
Untuk mendapatkan data affiliate berdasarkan tokennya, kita perlu menambahkan method getForToken
src/Ibw/JobeetBundle/Resources/config/doctrine/Affiliate.orm.yml
Ibw\JobeetBundle\Entity\Affiliate:
    type: entity
    repositoryClass: Ibw\JobeetBundle\Repository\AffiliateRepository
    # ...

Kemudian jalankan perintah berikut ini untuk mengupdate modelnya:

php app/console doctrine:generate:entities IbwJobeetBundle
Selanjutnya tambahkan kode berikut di AffililateRepository.php
src/Ibw/JobeetBundle/Repository/AffiliateRepository.php

namespace Ibw\JobeetBundle\Repository;

use Doctrine\ORM\EntityRepository;

/**
* AffiliateRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class AffiliateRepository extends EntityRepository
{
    public function getForToken($token)
    {
        $qb = $this->createQueryBuilder('a')
            ->where('a.is_active = :active')
            ->setParameter('active', 1)
            ->andWhere('a.token = :token')
            ->setParameter('token', $token)
            ->setMaxResults(1)
        ;

        try{
            $affiliate = $qb->getQuery()->getSingleResult();
        } catch(\Doctrine\Orm\NoResultException $e){
            $affiliate = null;
        }

        return $affiliate;
    }
}

============================================

Setelah kita berhasil mengidentifikasi affiliate berdasarkan tokennya selanjutnya kita akan membuat method untuk mengambilkan data untuk affiliate tersebut:


src/Ibw/JobeetBundle/Repository/JobRepository.php
// ...

    public function getActiveJobs($category_id = null, $max = null, $offset = null, $affiliate_id = null)
    {
        $qb = $this->createQueryBuilder('j')
            ->where('j.expires_at > :date')
            ->setParameter('date', date('Y-m-d H:i:s', time()))
            ->andWhere('j.is_activated = :activated')
            ->setParameter('activated', 1)
            ->orderBy('j.expires_at', 'DESC');

        if($max) {
            $qb->setMaxResults($max);
        }

        if($offset) {
            $qb->setFirstResult($offset);
        }

        if($category_id) {
            $qb->andWhere('j.category = :category_id')
                ->setParameter('category_id', $category_id);
        }
        // j.category c, c.affiliate a
        if($affiliate_id) {
            $qb->leftJoin('j.category', 'c')
               ->leftJoin('c.affiliates', 'a')
               ->andWhere('a.id = :affiliate_id')
               ->setParameter('affiliate_id', $affiliate_id)
            ;
        }

        $query = $qb->getQuery();

        return $query->getResult();
    }

// ...
Karena data yang dikembalikan dalam bentuk array maka kita akan membuat method asArray() untuk menampung data tersebut:
src/Ibw/JobeetBundle/Entity/Job.php
public function asArray($host)
{
    return array(
        'category'     => $this->getCategory()->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()->format('Y-m-d H:i:s'),
    );
}
==================================================  

Format XML  

Buatlah format XML support, dengan membuat format XML seperti berikut ini:


src/Ibw/JobeetBundle/Resources/views/Api/jobs.xml.twig

<?xml version="1.0" encoding="utf-8"?>
<jobs>
{% for url, job in jobs %}
    <job url="{{ url }}">
{% for key,value in job %}
        <{{ key }}>{{ value }}</{{ key }}>
{% endfor %}
    </job>
{% endfor %}
</jobs>


==============================================

Format JSON

Buta juga format JSON untuk affiliate API:

src/Ibw/JobeetBundle/Resources/views/Api/jobs.json.twig

 {% for url, job in jobs %}
{% i = 0, count(jobs), ++i %}
[
    "url":"{{ url }}",
{% for key, value in job %} {% j = 0, count(key), ++j %}
    "{{ key }}":"{% if j == count(key)%} {{ json_encode(value) }}, {% else %} {{ json_encode(value) }}
                 {% endif %}"
{% endfor %}]
{% endfor %}

================================================

Format YML

Begitu juga format YML/YAML

src/Ibw/JobeetBundle/Resources/views/Api/jobs.yaml.twig

{% for url,job in jobs %}
    Url: {{ url }}
{% for key, value in job %}
        {{ key }}: {{ value }}
{% endfor %}
{% endfor %} 
 
 


================================================ 

No comments:

Post a Comment