Saya secara teratur melihat artikel dengan gaya "Cara menggunakan templat Repositori dengan Eloquent" (salah satunya masuk ke intisari PHP baru-baru ini). Konten mereka yang biasa: mari kita buat antarmuka PostRepositoryInterface , kelas EloquentPostRepository , ikat dengan baik di wadah ketergantungan dan gunakan save dan temukan alih-alih metode Ekovent standar.
Mengapa templat ini diperlukan terkadang mereka tidak menulis sama sekali ("Ini templat ! Tidak cukup?"), Terkadang mereka menulis sesuatu tentang kemungkinan perubahan basis data (kejadian yang sangat umum di setiap proyek), serta tentang pengujian dan mocha-stub. Manfaat dari memperkenalkan template seperti itu ke dalam proyek Laravel biasa dalam artikel seperti itu sulit untuk ditangkap.
Mari kita coba mencari tahu apa apa? Templat Repositori memungkinkan Anda untuk abstrak dari sistem penyimpanan tertentu (yang biasanya kita miliki sebagai basis data), memberikan konsep abstrak kumpulan entitas.
Contoh-contoh dengan Eloquent Repository dibagi menjadi dua jenis:
- Variasi array Eloquent ganda
- Repositori Eloquent Murni
Variasi array Eloquent ganda
Contoh yang pertama (diambil dari artikel acak):
<?php interface FaqRepository { public function all($columns = array('*')); public function newInstance(array $attributes = array()); public function paginate($perPage = 15, $columns = array('*')); public function create(array $attributes); public function find($id, $columns = array('*')); public function updateWithIdAndInput($id, array $input); public function destroy($id); } class FaqRepositoryEloquent implements FaqRepository { protected $faqModel; public function __construct(Faq $faqModel) { $this->faqModel = $faqModel; } public function newInstance(array $attributes = array()) { if (!isset($attributes['rank'])) { $attributes['rank'] = 0; } return $this->faqModel->newInstance($attributes); } public function paginate($perPage = 0, $columns = array('*')) { $perPage = $perPage ?: Config::get('pagination.length'); return $this->faqModel ->rankedWhere('answered', 1) ->paginate($perPage, $columns); } public function all($columns = array('*')) { return $this->faqModel->rankedAll($columns); } public function create(array $attributes) { return $this->faqModel->create($attributes); } public function find($id, $columns = array('*')) { return $this->faqModel->findOrFail($id, $columns); } public function updateWithIdAndInput($id, array $input) { $faq = $this->faqModel->find($id); return $faq->update($input); } public function destroy($id) { return $this->faqModel->destroy($id); } }
Metode all , find , paginate mengembalikan objek Eloquent , namun buat , updateWithIdAndInput sedang menunggu array.
Pembaruan namaWithIdAndInput itu sendiri berarti bahwa "repositori" ini hanya akan digunakan untuk operasi CRUD.
Tidak ada logika bisnis normal yang diharapkan, tetapi kami akan mencoba menerapkan yang paling sederhana:
<?php class FaqController extends Controller { public function publish($id, FaqRepository $repository) { $faq = $repository->find($id);
Dan jika tanpa repositori:
<?php class FaqController extends Controller { public function publish($id) { $faq = Faq::findOrFail($id);
Dua kali lebih mudah.
Mengapa memperkenalkan abstraksi ke dalam proyek yang hanya akan mempersulitnya?
- Pengujian unit?
Semua orang tahu bahwa proyek CRUD reguler di Laravel dicakup oleh tes unit sedikit lebih dari 100%.
Tetapi kita akan membahas pengujian unit sedikit lebih lambat. - Demi bisa mengubah database?
Namun Eloquent sudah menyediakan beberapa opsi basis data.
Menggunakan entitas Eloquent untuk basis yang tidak didukung untuk aplikasi yang hanya berisi logika CRUD akan menyusahkan dan membuang-buang waktu.
Dalam hal ini, repositori, yang mengembalikan array PHP murni dan hanya menerima array juga, terlihat jauh lebih alami.
Dengan menghapus Eloquent, kami mendapatkan abstraksi nyata dari data warehouse.
Repositori Eloquent Murni
Contoh repositori yang hanya berfungsi dengan Eloquent (juga ditemukan dalam satu artikel):
<?php interface PostRepositoryInterface { public function get($id); public function all(); public function delete($id); public function save(Post $post); } class PostRepository implements PostRepositoryInterface { public function get($id) { return Post::find($id); } public function all() { return Post::all(); } public function delete($id) { Post::destroy($id); } public function save(Post $post) { $post->save(); } }
Saya tidak akan memarahi Antarmuka akhiran yang tidak perlu dalam artikel ini.
Implementasi ini sedikit lebih seperti apa yang dikatakan deskripsi template.
Implementasi dari logika paling sederhana terlihat sedikit lebih alami:
<?php class FaqController extends Controller { public function publish($id, PostRepositoryInterface $repository) { $post = $repository->find($id);
Namun, menerapkan repositori untuk posting blog yang paling sederhana adalah mainan yang dapat dinikmati anak-anak.
Mari kita coba sesuatu yang lebih rumit.
Entitas sederhana dengan sub-entitas. Misalnya, survei dengan kemungkinan jawaban (pemungutan suara reguler di situs atau dalam obrolan).
Kasus menciptakan objek survei semacam itu. Dua opsi:
- Buat PollRepository dan PollOptionRepository dan gunakan keduanya.
Masalah dengan opsi ini adalah bahwa abstraksi tidak berhasil.
Sebuah survei dengan jawaban yang mungkin adalah satu entitas dan penyimpanannya dalam database seharusnya dilaksanakan oleh satu kelas PollRepository .
PollOptionRepository :: delete tidak akan mudah, karena ia akan memerlukan objek Poll untuk memahami apakah opsi jawaban ini dapat dihapus (karena jika polling hanya memiliki satu opsi, itu tidak akan menjadi polling).
Dan Templat Repositori tidak menyiratkan penerapan logika bisnis di dalam repositori. - Di dalam PollRepository, tambahkan metode saveOption dan deleteOption .
Masalahnya hampir sama. Abstraksi dari penyimpanan ternyata menjadi semacam sampah ... pilihan jawaban harus diambil secara terpisah.
Tetapi bagaimana jika esensinya bahkan lebih kompleks? Dengan sekelompok subtansi lain?
Pertanyaan yang sama muncul: mengapa ini semua?
Dapatkan lebih banyak abstraksi dari sistem penyimpanan daripada yang diberikan Eloquent - tidak akan berfungsi.
Pengujian unit?
Berikut adalah contoh kemungkinan unit test dari buku saya - https://gist.github.com/adelf/a53ce49b22b32914879801113cf79043
Melakukan tes unit sebesar itu untuk operasi yang paling sederhana tidak cukup untuk dinikmati semua orang.
Saya hampir yakin bahwa tes seperti itu dalam proyek ini akan ditinggalkan.
Tidak ada yang mau mendukung mereka. Saya sedang mengerjakan proyek dengan tes seperti itu, saya tahu.
Jauh lebih mudah dan lebih tepat untuk fokus pada pengujian fungsional.
Terutama jika itu adalah proyek API.
Jika logika bisnis begitu rumit sehingga Anda benar-benar ingin menutupinya dengan tes, maka lebih baik untuk mengambil perpustakaan data mapper seperti Doctrine dan benar-benar memisahkan logika bisnis dari sisa aplikasi. Pengujian unit akan 10 kali lebih mudah.
Jika Anda benar-benar ingin menikmati pola desain dalam proyek Eloquent Anda, maka pada artikel berikutnya saya akan menunjukkan bagaimana Anda dapat menerapkan sebagian template Repositori dan mendapatkan manfaat darinya.