Thursday, February 12, 2015

Symfony 2 Hari 4: Perancangan database

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

Seperti apa struktur databasenya?

Sebelum membuka editor dan menulis kode, ada baiknya kita pikirkan dulu struktur databasenya. Skenario user dari hari kemarin memberikan kita gambaran akan adanya tiga object utama yaitu, Jobs, Affiliates, Categories. Berikut adalah relasi antar tabelnya:

Sebagai kolom tambahan sebagaimana dijelaskan pada skenario user kemarin yaitu created_at dan updated_at, juga sudah kita buat. Kita akan membuat fungsi yang akan dipanggil saat data disimpan atau diupdate untuk mengisi field tersebut.

Kita bangun databasenya

Untuk menyimpan data Jobs, Affiliates, dan Categories Symfony 2 menggunakan Doctrine ORM. Untuk medefinisikan database buka file parameters.yml yang terletak di direktori app/config/parameters.yml. Untuk tutorial ini kita menggunakan PDO MySql.

app/config/parameters.yml  

parameters: 
    database_driver: pdo_mysql 
    database_host: localhost 
    database_port: null 
    database_name: jobeet 
    database_user: root 
    database_password: password

Sekarang Doctrine tahu mengenai database, untuk membuat databasenya tinggal jalankan command berikut melalui terminal:

php app/console doctrine:database:create

Schema databasenya

Untuk memberitahu Doctrine mengenai objectnya kita akan membuat file 'metadata' untuk mendefinisikan bagaimana objectnya akan disimpan kedalam database. Sekarang buat folder yang bernama doctrine di dalam direktori src/Ibw/JobeetBundle/Resources/config. Kemudian buat file-file baru, dengan nama Category.orm.yml, Affiliate.orm.yml, Job.orm.yml. Ingat nama filenya case sensitive, jadi perhatikan kapitalnya. Lalu ketikan kode berikut pada masing-masing file:

src/Ibw/JobeetBundle/Resources/config/doctrine/Category.orm.yml

Ibw\JobeetBundle\Entity\Category:
    type: entity
    table: category
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        name:
            type: string
            length: 255
            unique: true
    oneToMany:
        jobs:
            targetEntity: Job
            mappedBy: category
    manyToMany:
        affiliates:
            targetEntity: Affiliate
            mappedBy: categories
 



 src/Ibw/JobeetBundle/Resources/config/doctrine/Job.orm.yml

Ibw\JobeetBundle\Entity\Job:
    type: entity
    table: job
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        type:
            type: string
            length: 255
            nullable: true
        company:
            type: string
            length: 255
        logo:
            type: string
            length: 255
            nullable: true
        url:
            type: string
            length: 255
            nullable: true
        position:
            type: string
            length: 255
        location:
            type: string
            length: 255
        description:
            type: text
        how_to_apply:
            type: text
        token:
            type: string
            length: 255
            unique: true
        is_public:
            type: boolean
            nullable: true
        is_activated:
            type: boolean
            nullable: true
        email:
            type: string
            length: 255
        expires_at:
            type: datetime
        created_at:
            type: datetime
        updated_at:
            type: datetime
            nullable: true
    manyToOne:
        category:
            targetEntity: Category
            inversedBy: jobs
            joinColumn:
                name: category_id
                referencedColumnName: id
    lifecycleCallbacks:
        prePersist: [ setCreatedAtValue ]
        preUpdate: [ setUpdatedAtValue ]
 



  src/Ibw/JobeetBundle/Resources/config/doctrine/Affiliate.orm.yml

Ibw\JobeetBundle\Entity\Affiliate:
    type: entity
    table: affiliate
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        url:
            type: string
            length: 255
        email:
            type: string
            length: 255
            unique: true
        token:
            type: string
            length: 255
        is_active:
            type: boolean
            nullable: true
        created_at:
            type: datetime
    manyToMany:
        categories:
            targetEntity: Category
            joinTable:
                name: category_affiliate
                joinColumns:
                    affiliate_id:
                        referencedColumnName: id
                inverseJoinColumns:
                    category_id:
                        referencedColumnName: id
    lifecycleCallbacks:
        prePersist: [ setCreatedAtValue ]
 

  

ORM-nya

Sekarang Doctrine dapat menggenarate objectnya dengan menjalankan command berikut:

php app/console doctrine:generate:entities IbwJobeetBundle

Jika kamu melihat folder Entity yang berada di folder src/Ibw/JobeetBundle/ maka kamu akan melihat file baru saja dibuat oleh Doctrine yaitu: Category.php, Job.php, dan Affiliate.php. Buka file Job.php dan set value untuk kolom created_at dan updated_at.

src/Ibw/JobeetBundle/Entity/Job.php

// ...

    /**
     * @ORM\PrePersist
     */
    public function setCreatedAtValue()
    {
        if(!$this->getCreatedAt()) {
            $this->created_at = new \DateTime();
        }
    }

    /**
     * @ORM\PreUpdate
     */
    public function setUpdatedAtValue()
    {
        $this->updated_at = new \DateTime();
    }
 


Begitu juga untuk file Affiliate.php 


src/Ibw/JobeetBundle/Entity/Affiliate.php


// ...

    /**
     * @ORM\PrePersist
     */
    public function setCreatedAtValue()
    {
        $this->created_at = new \DateTime();
    }

// ...
 


Kode ini akan memberitahu Doctrine untuk mengeset value dari created_at dan updated_at saat data disimpan atau diupdate.

Kita akan meminta Doctrine untuk menggerate table sebagaiman yang telah kita definisikan diatas. Ketikan command berikut di terminal.

php app/console doctrine:schema:update --force

Dan secara ajaib saat kamu lihat databasemu kamu akan melihat ada empat table di sana yaitu: job, category, affiliate, dan category_affiliate.



Sample data

Kita dapat menggenerate sample data dengan menggunakan bantuan doctrine fixturebundle. Untuk mengaktifkan fitur ini, ikuti langkah berikut ini:

1. Buka file composer.json, kemudian tambahkan baris berikut di block require:

sanbox/composer.json

// ...
    "require": {
        // ...
        "doctrine/doctrine-fixtures-bundle": "dev-master",
        "doctrine/data-fixtures": "dev-master"
    },

// ...


2. Update library vendor-nya dengan menjalankan command berikut:

php composer.phar update

3. Daftarkan doctrine fixture bundle ke app kernel, buka file app/AppKernel.php

app/AppKernel.php

// ...

public function registerBundles()
{
    $bundles = array(
        // ...
        new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle()
    );

    // ...
}
 

Jika semua sudah selesai sekarang kita bisa membuat file baru untuk menggenerate datanya. Buatlah folder baru dengan nama ORM di direktori src/Ibw/JobeetBundle/DataFixtures/ORM. Kemudian buat file baru dengan nama LoadCategoryData.php, dan LoadJobData.php, di dalamnya, lalu tambahkan kode berikut.


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


<?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\Category;

class LoadCategoryData extends AbstractFixture implements OrderedFixtureInterface
{
    public function load(ObjectManager $em)
    {
        $design = new Category();
        $design->setName('Design');

        $programming = new Category();
        $programming->setName('Programming');

        $manager = new Category();
        $manager->setName('Manager');

        $administrator = new Category();
        $administrator->setName('Administrator');

        $em->persist($design);
        $em->persist($programming);
        $em->persist($manager);
        $em->persist($administrator);
        $em->flush();

        $this->addReference('category-design', $design);
        $this->addReference('category-programming', $programming);
        $this->addReference('category-manager', $manager);
        $this->addReference('category-administrator', $administrator);
    }

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


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


<?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\Job;

class LoadJobData extends AbstractFixture implements OrderedFixtureInterface
{
    public function load(ObjectManager $em)
    {
         $job_sensio_labs = new Job();
         $job_sensio_labs->setCategory($em->merge($this->getReference('category-programming')));
         $job_sensio_labs->setType('full-time');
         $job_sensio_labs->setCompany('Sensio Labs');
         $job_sensio_labs->setLogo('sensio-labs.gif');
         $job_sensio_labs->setUrl('http://www.sensiolabs.com/');
         $job_sensio_labs->setPosition('Web Developer');
         $job_sensio_labs->setLocation('Paris, France');
         $job_sensio_labs->setDescription('You\'ve already developed websites with symfony and you want to work with Open-Source technologies. You have a minimum of 3 years experience in web development with PHP or Java and you wish to participate to development of Web 2.0 sites using the best frameworks available.');
         $job_sensio_labs->setHowToApply('Send your resume to fabien.potencier [at] sensio.com');
         $job_sensio_labs->setIsPublic(true);
         $job_sensio_labs->setIsActivated(true);
         $job_sensio_labs->setToken('job_sensio_labs');
         $job_sensio_labs->setEmail('job@example.com');
         $job_sensio_labs->setExpiresAt(new \DateTime('+30 days'));
         $job_extreme_sensio = new Job();
         $job_extreme_sensio->setCategory($em->merge($this->getReference('category-design')));
         $job_extreme_sensio->setType('part-time');
         $job_extreme_sensio->setCompany('Extreme Sensio');
         $job_extreme_sensio->setLogo('extreme-sensio.gif');
         $job_extreme_sensio->setUrl('http://www.extreme-sensio.com/');
         $job_extreme_sensio->setPosition('Web Designer');
         $job_extreme_sensio->setLocation('Paris, France');
         $job_extreme_sensio->setDescription('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in.');
         $job_extreme_sensio->setHowToApply('Send your resume to fabien.potencier [at] sensio.com');
         $job_extreme_sensio->setIsPublic(true);
         $job_extreme_sensio->setIsActivated(true);
         $job_extreme_sensio->setToken('job_extreme_sensio');
         $job_extreme_sensio->setEmail('job@example.com');
         $job_extreme_sensio->setExpiresAt(new \DateTime('+30 days'));

         $em->persist($job_sensio_labs);
         $em->persist($job_extreme_sensio);
         $em->flush();
    }

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

Setelah file fixture selesai dibuat kamu bisa memanggilnya untuk meload data dengan menggunakan command berikut:

php app/console doctrine:fixtures:load
 

Sekarang kalau kamu melihat ke database maka di sana sudah ada data sample yang kita buat barusan. Take it easy!


Tampilkan datanya di browser

Untuk menampilkan datanya di browser maka kita harus membuat model, controller, dan viewnya terlebih dahulu. Dan kabar baiknya adalah kamu dapat melakukannya dengan mudah di Symfony2 hanya dengan satu langkah. Jalankan perintah ini di terminal:

php app/console doctrine:generate:crud --entity=IbwJobeetBundle:Job --route-prefix=ibw_job --with-write --format=yml


Setelah menjalankan perintah tersebut maka file basic untuk model, controller, dan view akan tergenerate secara otomatis. Langkah berikutnya adalah edit file routingnya:

src/Ibw/JobeetBundle/Resources/config/routing/job.yml


IbwJobeetBundle_job:
        resource: "@IbwJobeetBundle/Resources/config/routing/job.yml"
        prefix:   /job

# ...


Kita juga harus menabahkan _toString() method di model Category, method ini akan digunakan untuk menampilkan selected list pada saat menambah data Job.

src/Ibw/JobeetBundle/Entity/Category.php


// ...

public function __toString()
{
    return $this->getName() ? $this->getName() : "";
}

// ...
 

Bersihkan cachenya dengan syntaks berikut:

php app/console cache:clear --env=dev
php app/console cache:clear --env=prod

Kemudian akses melalui web browser localhost/sanbox/web/app_dev.php/job/ jika kamu beruntung kamu akan melihat tampilan data Job di browser. Good Luck!

No comments:

Post a Comment