Doctrine2 mengabstraksi segala sesuatu yang berhubungan dengan repositori dengan sangat baik sehingga Anda mungkin ingin melakukan segala sesuatu yang lain di pengontrol. Misalkan kita memiliki entitas Bug:
/** @Entity */
class Bug
{
/** @Column(type="integer") */
private $id;
/** @Column(length=50) */
private $status;
//...
}
Untuk mendapatkan daftar bug yang diperbaiki, kami mendapatkan repositori bug dari EntityManager dan meminta daftar bug dengan status sama dengan “Diperbaiki”.
php
// $em instanceof Doctrine\ORM\EntityManager
$fixedbugs = $em->getRepository('Bug')
->findBy(array('status' => 'fixed'));
Itu mudah. Tentunya tidak ada salahnya untuk memasukkan kode ini ke dalam controller? Meskipun kode ini tidak terlihat seperti itu, sebenarnya ini adalah kueri basis data. Inilah jalan pintasnya:
$fixedbugs = $em
->createQuery("SELECT b FROM Bug b WHERE b.status="fixed"")
->getResult();
Menanyakan hal ini di pengontrol kami akan memicu beberapa peringatan serius. Ini berarti bahwa meskipun semua abstraksi disediakan oleh Doctrine2, kami masih menyambungkan pengontrol ke perpustakaan pada saat ini. Jika suatu hari kita memutuskan untuk mengubah cara status kesalahan direpresentasikan dalam database, kita perlu memodifikasi semua pengontrol.
Mari kita lihat lebih dekat repositorinya. Evans mendefinisikannya sebagai “objek yang memberikan ilusi kumpulan memori semua objek bertipe itu,” dengan klien berbicara dengannya menggunakan bahasa domain. Dengan kata lain, findBy(array(‘status’ => ‘fixed’)) terlalu umum: dalam bahasa domain, kami ingin meminta repositori untuk findAllFixedBugs(). Jika skema database berubah, kita cukup mengubah metode ini. Untungnya repositori Doctrine2 dapat diperluas:
/**
* @Entity(repositoryClass="BugRepository")
*/
class Bug
{ /* ... */ }
class BugRepository extends EntityRepository
{
public function findAllFixedBugs()
{
return $this->_em
->createQuery("SELECT b FROM Bug b WHERE b.status="fixed"")
->getResult();
}
}
Akhirnya kita bisa mengganti kode di controller dengan ini
$fixedbugs = $em->getRepository('Bug')->findAllFixedBugs();
Pengontrol kami sekarang dipisahkan dari database. Sebagai bonus tambahan, kode ini melakukan pekerjaan yang jauh lebih baik dalam mengkomunikasikan maksudnya dibandingkan versi pertama kami.
Tokil Johnson – 23/03/2012
Terlihat sangat bagus tetapi meninggalkan saya dengan pertanyaan. Saya tidak paham dengan Doktrin dan Anda mungkin hanya menulis ini sebagai contoh kasar, jadi mohon maafkan pertanyaan bodoh ini! 🙂
Saya bertanya-tanya mengapa Anda ingin menulis sesuatu yang spesifik seperti findAllFixedBugs()? Menurut saya, Anda perlu menggunakan findAllFixedBugsFilteredByUser() dan findAllFixedBugsWithStatusCritical() di tikungan berikutnya?
Mengapa Anda tidak menggunakan findBy() dalam versi final metode ini daripada menulis pernyataan SQL biasa?
Lebih dari itu: percepat postingan blog, kami membutuhkan lebih banyak 🙂
Matias Villaes – 23/03/2012
Ini sungguh sebuah contoh kasar.
Anda memerlukan lebih banyak metode, yang akan Anda temukan saat menulis tes (lihat artikel saya sebelumnya). Maksud dari penggunaan metode ini adalah kode Anda berbicara dalam bahasa yang sama dengan yang Anda gunakan untuk berbicara dengan pelanggan Anda (disebut “bahasa universal” di DDD). Jika Anda memutuskan untuk memindahkan kesalahan dari database relasional ke layanan jarak jauh, pendekatan Anda akan tetap ada, namun implementasinya akan sangat berbeda. Tentu saja, Anda dapat dengan mudah mengganti BugRepository dengan objek tiruan selama pengujian, sehingga Anda tidak memerlukan repositori untuk menguji pengontrol.
Tidak ada alasan khusus mengapa saya tidak menggunakan findBy() dalam cuplikan kode terakhir, kecuali saya ingin mengilustrasikan bahwa metode ini dapat berisi kueri kompleks yang tidak dapat diselesaikan dengan find by.
Di luar topik: Kueri dalam contoh ini adalah DQL, bukan SQL. http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/dql-doctrine-query-lingual.html
Alessandro Nadarin – 23/03/2012
Hai Tokil,
Ya, pola Repositori dirancang khusus untuk merangkum semua metode yang diperlukan untuk mengambil objek dari database. Jadi pada dasarnya Anda menambahkan setiap kemungkinan kueri yang Anda perlukan dalam aplikasi Anda…
Jelasnya, Anda dapat menggunakan kelas khusus untuk mengabstraksi beberapa metode antara repositori dan EntityRepository, yang merupakan warisan EntityRepository.
Untuk menggunakan api OO alih-alih pernyataan DQL mentah, Anda memerlukan instance QueryBuilder:
$qb = $em->getRepository('Odino\BlogBundle\Entity\Content')->createQueryBuilder('u')
->where('u.isActive = 1')
->andWhere("u.keywords LIKE ?1")
->setParameter(1, "%$tag%");
$qb->getQuery()->execute();
selamat tinggal!
Tokil Johnson – 23/03/2012
Terima kasih atas inspirasinya!