Secara singkat tentang spesifikasi:
Spesifikasi adalah pola desain yang dengannya Anda dapat mencerminkan aturan logika bisnis dalam bentuk rantai objek yang dihubungkan oleh operasi logika Boolean. Spesifikasi memungkinkan Anda untuk menghapus duplikat, metode serupa dalam repositori dan duplikasi logika bisnis.
Hari ini ada dua (jika Anda tahu proyek lain, silakan tulis di komentar) proyek PHP yang sukses dan populer yang memungkinkan Anda untuk menggambarkan aturan bisnis dalam spesifikasi dan memfilter kumpulan data. Ini adalah Spesifikasi RulerZ dan Happyr Doctrine . Kedua proyek adalah alat yang kuat dengan kelebihan dan kekurangan mereka. Membandingkan proyek-proyek ini akan menarik seluruh artikel. Di sini saya ingin memberi tahu Anda apa yang dibawa oleh rilis baru dalam Spesifikasi Ajaran kepada kami.
Secara singkat tentang Spesifikasi Ajaran
Mereka yang kurang lebih akrab dengan proyek, dapat dengan aman melewati bagian ini.
Dengan bantuan proyek ini, Anda dapat mendeskripsikan spesifikasi dalam bentuk objek, menyusunnya dari komposisi dan, dengan demikian, membuat aturan bisnis yang kompleks. Komposisi yang dihasilkan dapat digunakan kembali secara bebas, dan digabungkan menjadi komposisi yang lebih kompleks yang mudah diuji. Spesifikasi Ajaran digunakan untuk membangun kueri Ajaran. Pada dasarnya, Spesifikasi Doktrin adalah tingkat abstraksi atas QueryBuilder dan Ajaran ORM Doctrine.
Spesifikasi berlaku melalui Gudang Doktrin:
$result = $em->getRepository(MyEntity::class)->match($spec);
Spesifikasi dapat diterapkan secara manual, tetapi tidak terlalu nyaman dan, dalam jangka panjang, tidak ada gunanya. $spec = ... $alias = 'e'; $qb = $em->getRepository(MyEntity::class)->createQueryBuilder($alias); $spec->modify($qb, $alias); $filter = (string) $spec->getFilter($qb, $alias); $qb->andWhere($filter); $result = $qb->getQuery()->execute();
Ada beberapa metode dalam repositori:
match
- mendapatkan semua hasil yang sesuai dengan spesifikasi;matchSingleResult
- setara dengan Query::getSingleResult()
;matchOneOrNullResult
- setara dengan matchSingleResult
, tetapi memungkinkan null
;getQuery
- membuat QueryBuilder dengan menerapkan spesifikasi padanya dan mengembalikan objek Query darinya.
Baru-baru ini, metode getQueryBuilder
telah ditambahkan ke mereka, yang menciptakan QueryBuilder dan, menerapkan spesifikasi padanya, mengembalikannya.
Proyek mengidentifikasi beberapa jenis spesifikasi:
Spesifikasi Logis
Spesifikasi andX
dan orX
juga berfungsi sebagai kumpulan spesifikasi.
Spec::andX()
Spec::orX()
Spec::not()
Merupakan kebiasaan untuk menginstal objek spesifikasi perpustakaan melalui fasad Spec
, tetapi ini tidak perlu. Anda dapat secara eksplisit instantiate objek spesifikasi:
new AndX(); new OrX(): new Not();
Spesifikasi Filter
Spesifikasi penyaringan, pada kenyataannya, membuat aturan logika bisnis dan digunakan dalam permintaan WHERE
. Ini termasuk operasi perbandingan:
isNull
- SQL IS NULL
setaraisNotNull
- SQL IS NOT NULL
setarain
- setara dengan IN ()
notIn
NOT IN ()
- NOT IN ()
eq
- uji kesetaraan =
neq
- periksa ketimpangan !=
lt
- kurang dari <
lte
- kurang dari atau sama dengan <=
gt
- lebih dari >
gte
- lebih besar dari atau sama dengan >=
like
- SQL LIKE
setarainstanceOfX
- setara dengan DQL INSTANCE OF
Contoh menggunakan spesifikasi pemfilteran:
$spec = Spec::andX( Spec::eq('ended', 0), Spec::orX( Spec::lt('endDate', new \DateTime()), Spec::andX( Spec::isNull('endDate'), Spec::lt('startDate', new \DateTime('-4 weeks')) ) ) );
Pengubah kueri
Pengubah kueri tidak ada hubungannya dengan logika bisnis dan aturan bisnis. Sesuai namanya, mereka hanya memodifikasi QueryBuilder. Nama dan tujuan pengubah standar sesuai dengan metode serupa di QueryBuilder.
join
leftJoin
innerJoin
limit
offset
orderBy
groupBy
having
Saya ingin mencatat pengubah slice
secara terpisah. Ini menggabungkan limit
fungsi dan offset
dan menghitung offset berdasarkan ukuran slice dan nomor seri. Dalam implementasi pengubah ini, kami tidak setuju dengan penulis proyek. Membuat pengubah, saya mengejar tujuan menyederhanakan konfigurasi spesifikasi selama pagination. Dalam konteks ini, halaman pertama dengan nomor seri 1 seharusnya setara dengan irisan pertama dengan nomor seri 1. Tetapi penulis proyek menganggapnya tepat untuk memulai hitung mundur dalam gaya pemrograman, yaitu, dari 0. Oleh karena itu, perlu diingat bahwa jika Anda memerlukan irisan pertama, Anda perlu menentukan 0 sebagai nomor seri.
Pengubah Hasil
Pengubah hasil ada sedikit terpisah dari spesifikasi. Itu berlaku untuk Pertanyaan Ajaran. Pengubah berikut mengontrol hidrasi data ( Query::setHydrationMode()
):
asArray
asSingleScalar
asScalar
Pengubah cache
mengontrol caching hasil kueri.
Kita juga harus menyebutkan roundDateTimeParams
modifier. Ini membantu menyelesaikan masalah caching ketika Anda perlu bekerja dengan aturan bisnis yang mengharuskan membandingkan beberapa nilai dengan waktu saat ini. Ini adalah aturan bisnis normal, tetapi karena kenyataan bahwa waktu tidak konstan, caching selama lebih dari satu detik tidak akan bekerja untuk Anda. Pengubah roundDateTimeParams
dirancang untuk mengatasi masalah ini. Itu melewati semua parameter permintaan, mencari tanggal di dalamnya dan membulatkannya ke nilai yang ditentukan, yang memberi kita nilai tanggal yang selalu kelipatan satu nilai dan kami tidak akan mendapatkan tanggal di masa mendatang. Artinya, jika kami ingin men-cache permintaan selama 10 menit, kami menggunakan Spec::cache(600)
dan Spec::roundDateTimeParams(600)
. Awalnya, diusulkan untuk menggabungkan kedua pengubah ini untuk kenyamanan, tetapi diputuskan untuk memisahkan mereka untuk SRP.
Spesifikasi Tertanam
Spesifikasi Happyr Doctrine memiliki antarmuka terpisah untuk spesifikasi yang menggabungkan filter dan pengubah permintaan. Satu-satunya spesifikasi yang ditentukan adalah countOf
yang memungkinkan Anda untuk mendapatkan jumlah entitas yang sesuai dengan spesifikasi tersebut. Untuk membuat spesifikasi Anda sendiri, biasanya untuk memperluas kelas BaseSpecification
abstrak.
Inovasi
Metode baru telah ditambahkan ke repositori:
matchSingleScalarResult
- setara dengan Query::getSingleScalarResult()
;matchScalarResult
- setara dengan Query::getScalarResult()
;iterate
adalah setara dengan Query::iterate()
.
Spesifikasi MemberOfX
- DQL yang setara dengan MEMBER OF
dan pengubah query indexBy
- setara dengan QueryBuilder::indexBy()
.
Operan
Rilis baru ini memperkenalkan konsep Operand . Semua kondisi dalam filter terdiri dari operan kiri dan kanan dan operator di antaranya.
<left_operand> <operator> <right_operand>
Dalam versi sebelumnya, operan kiri hanya bisa menjadi bidang entitas, dan operan kanan hanya bisa menjadi nilai. Ini adalah mekanisme sederhana dan efektif yang cukup untuk sebagian besar tugas. Pada saat yang sama, ia memberlakukan batasan tertentu:
- Tidak dapat menggunakan fungsi;
- Tidak dapat menggunakan alias untuk bidang;
- Tidak mungkin membandingkan dua bidang;
- Tidak mungkin membandingkan dua nilai;
- Tidak dapat menggunakan operasi aritmatika;
- Tidak dapat menentukan tipe data untuk nilai.
Dalam versi baru, objek operan diteruskan ke filter dalam argumen dan transformasi mereka dalam DQL didelegasikan ke operan itu sendiri. Ini membuka banyak kemungkinan dan membuat filter lebih mudah.
Bidang dan nilai
Untuk mempertahankan kompatibilitas ke belakang, argumen pertama dalam filter dikonversi ke operan bidang jika bukan operan, dan argumen terakhir juga dikonversi ke operan nilai. Karena itu, Anda seharusnya tidak memiliki masalah dalam memperbarui.
Anda dapat membandingkan 2 bidang:
Anda dapat membandingkan 2 bidang entitas yang berbeda:
Operasi aritmatika
Dukungan tambahan untuk operasi aritmatika standar -
, +
, *
, /
, %
. Sebagai contoh, perhatikan perhitungan poin pengguna:
Operasi aritmatika dapat disarangkan satu dengan yang lain:
Fungsi
Rilis baru menambahkan operan dengan fungsi. Mereka dapat digunakan sebagai metode statis dari kelas Spec
, atau melalui metode Spec::fun()
.
Fungsi dapat bersarang satu sama lain:
Argumen untuk fungsi dapat dikirimkan sebagai argumen terpisah, atau dengan meneruskannya dalam array:
Manajemen pengambilan sampel
Terkadang Anda perlu mengelola daftar nilai pengembalian. Sebagai contoh:
- Tambahkan entitas lain ke hasilnya agar tidak membuat subqueries untuk mendapatkan tautan;
- Untuk mengembalikan bukan seluruh entitas, tetapi hanya satu set bidang yang terpisah;
- Gunakan alias;
- Gunakan alias tersembunyi dengan syarat untuk menyortir (itu membutuhkan Doktrin, tetapi mereka berjanji untuk memperbaikinya ).
Sebelum versi 0.8.0, tugas ini membutuhkan pembuatan spesifikasi untuk kebutuhan ini. Dimulai dengan versi 0.8.0, Anda dapat menggunakan metode getQueryBuilder()
dan mengelola seleksi melalui antarmuka QueryBuilder.
Rilis baru 1.0.0 menambahkan select
dan addSelect
permintaan. select
sepenuhnya menggantikan daftar nilai yang dapat dipilih, dan addSelect
menambahkan nilai baru ke daftar. Sebagai nilai, Anda bisa menggunakan objek yang mengimplementasikan antarmuka Selection
atau filter. Dengan demikian, Anda dapat memperluas kemampuan perpustakaan agar sesuai dengan kebutuhan Anda. Pertimbangkan peluang yang sudah ada.
Anda dapat memilih satu bidang:
Anda dapat menambahkan satu bidang ke pilihan:
Anda dapat memilih beberapa bidang:
Anda dapat menambahkan entitas ke nilai yang dikembalikan:
Anda dapat menggunakan alias untuk bidang yang dapat dipilih:
Anda dapat menambahkan bidang tersembunyi ke pilihan:
Anda dapat menggunakan ekspresi, misalnya, untuk mendapatkan diskon pada suatu produk:
Anda dapat menggunakan alias dalam spesifikasi:
Pada dasarnya itu saja. Di sinilah inovasi berakhir. Rilis baru telah membawa banyak fitur menarik dan bermanfaat. Saya harap mereka membuat Anda tertarik.
PS: Saya bisa menggunakan contoh untuk menganalisis penggunaan spesifikasi dan menunjukkan kelebihan dan kekurangan dari penggunaannya. Jika ini menarik bagi Anda, tulis di komentar atau di PM.