Saya ingin menarik perhatian Anda konsep mengatur pemfilteran dengan permintaan URL. Sebagai contoh, saya akan menggunakan bahasa PHP dan kerangka Laravel.
Konsep
Idenya adalah untuk membuat kelas 
QueryFilter universal untuk bekerja dengan filter.
GET /posts?title=source&status=active 
Dengan menggunakan contoh ini, kami akan memfilter 
posting (model Posting) dengan kriteria berikut:
- Kehadiran kata "sumber" di bidang judul ;
- Nilai "terbitkan" di bidang status ;
Contoh aplikasi
Model 
Pos <?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model {  protected $fillable = [ 'name', 'id', 'title', 'slug', 'status', 'type', 'published_at', 'updated_at', ]; } 
Tambahkan rute:
 Route::get('/posts', 'PostController@index'); 
Buat file 
Resource \ Post untuk output dalam 
format JSON :
 namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class Post extends JsonResource {  public function toArray($request) { return [ 'id' => $this->ID, 'title' => $this->post_title, 'slug' => $this->post_name, 'status' => $this->post_status, 'type' => $this->post_type, 'published_at' => $this->post_date, 'updated_at' => $this->post_modified, ]; } } 
Dan controller itu sendiri dengan satu aksi tunggal:
 namespace App\Http\Controllers; use App\Http\Resources\Post as PostResource; use App\Post; class PostController extends Controller {  public function index() { $posts = Post::limit(10)->get(); return PostResource::collection($posts); } } 
Pemfilteran standar diatur oleh kode berikut:
  public function index(Request $request) { $query = Post::limit(10); if ($request->filled('status')) { $query->where('post_status', $request->get('status')); } if ($request->filled('title')) { $title = $request->get('title'); $query->where('post_title', 'like', "%$title%"); } $posts = $query->get(); return PostResource::collection($posts); } 
Dengan pendekatan ini, kita dihadapkan dengan pertumbuhan controller, yang tidak diinginkan.
Menerapkan QueryFilter
Arti dari konsep tersebut adalah menggunakan kelas terpisah untuk setiap entitas yang memetakan metode ke setiap bidang untuk penyaringan.
Saring berdasarkan permintaan:
 GET /posts?title=source&status=publish 
Untuk memfilter, kita akan memiliki kelas 
PostFilter dan metode 
title () dan 
status () . 
PostFilter akan memperluas kelas abstrak 
QueryFiler yang bertanggung jawab untuk mencocokkan metode kelas dengan parameter yang dikirimkan.
Metode berlaku ()Kelas 
QueryFIlter memiliki metode 
apply () , yang bertanggung jawab untuk 
menggunakan filter yang ada di kelas anak 
PostFilter .
 namespace App\Http\Filters; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; abstract class QueryFilter {  protected $request;  protected $builder;  public function __construct(Request $request) { $this->request = $request; }  public function apply(Builder $builder) { $this->builder = $builder; foreach ($this->fields() as $field => $value) { $method = camel_case($field); if (method_exists($this, $method)) { call_user_func_array([$this, $method], (array)$value); } } }  protected function fields(): array { return array_filter( array_map('trim', $this->request->all()) ); } } 
Intinya adalah bahwa untuk setiap bidang yang melewati 
Permintaan kami memiliki metode terpisah di kelas filter anak (kelas PostFilter). Ini memungkinkan kami untuk menyesuaikan logika untuk setiap bidang filter.
Kelas PostFilterSekarang mari kita beralih ke membuat kelas 
PostFilter yang memperluas 
QueryFilter . Seperti disebutkan sebelumnya, kelas ini harus berisi metode untuk setiap bidang yang harus kita filter. Dalam kasus kami, metode 
judul ($ nilai) dan 
status ($ nilai) namespace App\Http\Filters; use Illuminate\Database\Eloquent\Builder; class PostFilter extends QueryFilter {  public function status(string $status) { $this->builder->where('post_status', strtolower($status)); }  public function title(string $title) { $words = array_filter(explode(' ', $title)); $this->builder->where(function (Builder $query) use ($words) { foreach ($words as $word) { $query->where('post_title', 'like', "%$word%"); } }); } } 
Di sini saya tidak melihat alasan untuk analisis terperinci dari masing-masing metode, pertanyaan yang cukup standar. Intinya adalah bahwa sekarang kita memiliki metode terpisah untuk setiap bidang dan kita dapat menggunakan logika apa pun yang kita butuhkan untuk membentuk permintaan.
Buat scopeFilter ()Sekarang kita perlu mengikat desainer model dan permintaan
  public function scopeFilter(Builder $builder, QueryFilter $filter) { $filter->apply($builder); } 
Untuk mencari, kita perlu memanggil metode 
filter () dan mengirimkan instance dari 
QueryFilter , dalam kasus 
PostFilter kami .
 $filteredPosts = Post::filter($postFilter)->get(); 
Dengan demikian, semua logika penyaringan diproses dengan memanggil metode 
filter ($ postFilter) , menyimpan pengontrol dari logika yang tidak perlu.
Untuk memfasilitasi penggunaan kembali, Anda dapat menempatkan metode 
scopeFilter di dalam sifat dan menggunakannya untuk setiap model yang perlu disaring.
 namespace App\Http\Filters; use Illuminate\Database\Eloquent\Builder; trait Filterable {  public function scopeFilter(Builder $builder, QueryFilter $filter) { $filter->apply($builder); } } 
Dalam 
Post menambahkan:
 class Post extends CorcelPost { use Filterable; 
Tetap menambahkan 
index () ke metode controller sebagai parameter 
PostFilter dan memanggil metode model 
filter () .
 class PostController extends Controller {  public function index(PostFilter $filter) { $posts = Post::filter($filter)->limit(10)->get(); return PostResource::collection($posts); } } 
Itu saja. Kami memindahkan semua logika penyaringan ke kelas yang sesuai, mengamati prinsip tanggung jawab tunggal (S dalam sistem prinsip SOLID)
Kesimpulan
Pendekatan penerapan filter ini memungkinkan Anda untuk tetap menggunakan pengontrol tipis trailer, dan juga memfasilitasi penulisan tes.
Berikut ini contoh menggunakan PHP dan Laravel. Tapi seperti yang saya katakan, ini adalah konsep dan dapat bekerja dengan bahasa atau kerangka kerja apa pun.
Referensi