Làm cách nào để áp dụng nhiều bộ lọc trong laravel?

Bộ lọc Nova cho phép bạn xác định phạm vi truy vấn chỉ mục Nova của mình với các điều kiện tùy chỉnh. Ví dụ: bạn có thể muốn xác định bộ lọc để xem nhanh người dùng "Quản trị viên" trong ứng dụng của mình

Làm cách nào để áp dụng nhiều bộ lọc trong laravel?

Chọn Bộ lọc

Loại bộ lọc Nova phổ biến nhất là bộ lọc "chọn", cho phép người dùng chọn tùy chọn bộ lọc từ menu lựa chọn thả xuống. Bạn có thể tạo bộ lọc chọn lọc bằng lệnh Artisan nova:filter. Theo mặc định, Nova sẽ đặt các bộ lọc mới được tạo trong thư mục app/Nova/Filters

Mỗi bộ lọc chọn được tạo bởi Nova chứa hai phương thức. applyoptions. Phương thức apply chịu trách nhiệm sửa đổi truy vấn để đạt được trạng thái bộ lọc mong muốn, trong khi phương thức options xác định "giá trị" mà bộ lọc có thể có. Hãy xem một ví dụ về bộ lọc UserType

Phương thức options sẽ trả về một mảng khóa và giá trị. Các phím của mảng sẽ được sử dụng làm văn bản "thân thiện với con người" sẽ được hiển thị trong giao diện người dùng Nova. Các giá trị của mảng sẽ được chuyển vào phương thức apply dưới dạng đối số $value. Bộ lọc này xác định hai giá trị có thể. app/Nova/Filters0 và app/Nova/Filters1

Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng $value sắp tới để sửa đổi truy vấn của mình. Phương thức apply sẽ trả về phiên bản truy vấn đã sửa đổi

Bộ lọc Boolean

Nova cũng hỗ trợ các bộ lọc "boolean", cho phép người dùng chọn nhiều tùy chọn bộ lọc bằng danh sách các hộp kiểm

Làm cách nào để áp dụng nhiều bộ lọc trong laravel?

Bạn có thể tạo bộ lọc boolean bằng lệnh app/Nova/Filters4 Artisan. Theo mặc định, Nova sẽ đặt các bộ lọc mới được tạo trong thư mục app/Nova/Filters

Mỗi bộ lọc boolean do Nova tạo ra chứa hai phương thức. applyoptions. Phương thức apply chịu trách nhiệm sửa đổi truy vấn để đạt được trạng thái bộ lọc mong muốn, trong khi phương thức tùy chọn xác định "giá trị" mà bộ lọc có thể có

Khi xây dựng các bộ lọc boolean, đối số $value được truyền cho phương thức apply là một mảng kết hợp chứa giá trị boolean của mỗi tùy chọn trong bộ lọc của bạn

Hãy xem một ví dụ về bộ lọc UserType

Phương thức options sẽ trả về một mảng khóa và giá trị. Các phím của mảng sẽ được sử dụng làm văn bản "thân thiện với con người" sẽ được hiển thị trong giao diện người dùng Nova. Các giá trị của mảng sẽ được chuyển vào phương thức apply dưới dạng đối số $value. Bộ lọc này xác định hai giá trị có thể. app/Nova/Filters0 và app/Nova/Filters1

Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng $value sắp tới để sửa đổi truy vấn của mình. Phương thức apply sẽ trả về phiên bản truy vấn đã sửa đổi

Nova cũng hỗ trợ bộ lọc "ngày", cho phép người dùng chọn giá trị của bộ lọc thông qua lịch chọn ngày

Làm cách nào để áp dụng nhiều bộ lọc trong laravel?

Bạn có thể tạo bộ lọc ngày bằng lệnh apply9 Artisan. Theo mặc định, Nova sẽ đặt các bộ lọc mới được tạo trong thư mục app/Nova/Filters

Mỗi bộ lọc ngày được tạo bởi Nova chứa một phương thức. apply. Phương thức apply chịu trách nhiệm sửa đổi truy vấn để đạt được trạng thái bộ lọc mong muốn

Khi xây dựng bộ lọc ngày, đối số $value được truyền cho phương thức apply là biểu diễn chuỗi của ngày đã chọn

Hãy xem một ví dụ về bộ lọc options5

Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng $value sắp tới để sửa đổi truy vấn của mình. Phương thức apply sẽ trả về phiên bản truy vấn đã sửa đổi

Lọc tiêu đề

Nếu bạn muốn thay đổi tiêu đề bộ lọc được hiển thị trong menu lựa chọn bộ lọc của Nova, bạn có thể xác định thuộc tính options8 trên lớp bộ lọc

Gần đây tôi cần triển khai tính năng tìm kiếm trong dự án quản lý sự kiện mà tôi đang xây dựng. Những gì bắt đầu như một vài tùy chọn đơn giản (tìm kiếm theo tên, e-mail, v.v.), đã trở thành một bộ tham số khá lớn

Hôm nay, tôi sẽ giới thiệu quá trình tôi đã trải qua và cách tôi xây dựng một hệ thống tìm kiếm linh hoạt và có thể mở rộng. Đối với những bạn muốn xem mã cuối cùng, hãy đến kho lưu trữ Git để xem mã

Những gì chúng tôi sẽ tạo ra

Công ty của chúng tôi cần một cách để theo dõi các sự kiện và cuộc họp khác nhau mà chúng tôi tổ chức với khách hàng trên khắp thế giới. Hiện tại, cách duy nhất chúng tôi thực hiện việc này là để mỗi nhân viên lưu trữ thông tin chi tiết về các cuộc họp trong lịch Outlook của họ. Không có khả năng mở rộng

Chúng tôi cần thứ gì đó mà mọi người trong công ty có thể truy cập, để xem thông tin chi tiết về khách hàng nào của chúng tôi được mời và trạng thái rsvp của họ

Điều này cũng sẽ giúp chúng tôi biết người dùng nào sẽ mời tham gia các sự kiện trong tương lai, bằng cách sử dụng dữ liệu về lần tương tác cuối cùng của chúng tôi với họ

Ảnh chụp màn hình gói sự kiện sử dụng bộ lọc tìm kiếm nâng cao

Tìm kiếm người dùng

Một số cách mà tôi biết chúng tôi muốn lọc người dùng bao gồm;

  • Theo tên, e-mail hoặc địa điểm
  • Bởi công ty họ làm việc cho
  • Người dùng đã được mời tham gia một sự kiện nhất định
  • Người dùng đã tham dự một sự kiện nhất định
  • Những người dùng mà chúng tôi đã mời và đã trả lời cho một sự kiện
  • Người dùng mà chúng tôi đã mời nhưng chưa phản hồi
  • Người dùng cho biết họ sẽ tham dự nhưng không đến
  • Người dùng được chỉ định cho một trong những người quản lý bán hàng nhất định của chúng tôi

Đây hoàn toàn không phải là một danh sách đầy đủ, nhưng dùng để hiển thị số lượng bộ lọc mà chúng tôi cần. Đây sẽ là một thử thách

Đây là giao diện người dùng của tìm kiếm nâng cao có sẵn trong ứng dụng cuối cùng mà chúng tôi đã tạo

Mô hình và mối quan hệ

Chúng tôi sẽ làm việc với một số mô hình cho ví dụ này

  • Người dùng — những Người dùng cá nhân có thể được mời tham gia Sự kiện. Một Người dùng có thể được mời tham gia nhiều Sự kiện
  • Sự kiện — các Sự kiện mà chúng tôi tổ chức. Có thể tạo nhiều sự kiện
  • Rsvp — phản hồi của Người dùng đối với một Sự kiện nhất định. Người dùng có một Rsvp cho một Sự kiện
  • Người quản lý — mỗi Người dùng có thể có nhiều Người quản lý bán hàng nội bộ

yêu cầu tìm kiếm

Tôi muốn bắt đầu bằng cách hình dung yêu cầu tìm kiếm của mình trông như thế nào trước khi viết một dòng mã. Điều này giúp tôi hiểu rõ hơn về những dữ liệu mà chức năng tìm kiếm của tôi sẽ làm việc và các thông số khác nhau có thể phối hợp với nhau như thế nào

Đây là ví dụ tải trọng JSON POST mà chúng tôi sẽ sử dụng để tạo tìm kiếm

{    "name": "Billy",
"company": "Google",
"city": "London",
"event": "key-note-presentation-new-york-05-2016",
"responded": true,
"response": "I will be attending",
"managers": [
"Tom Jones",
"Joe Bloggs"
],
}

Chúng ta đang nói gì ở đây?

Cho tôi biết tất cả người dùng có tên 'Billy' thuộc công ty 'Google', có trụ sở tại 'London', những người 'đã phản hồi' lời mời tham gia sự kiện 'key-note-presentation-new-york-05–

Làm cho nó hoạt động — giải pháp đơn giản nhất

Tôi là một tín đồ vững chắc của KISS - hãy giữ nó đơn giản, ngu ngốc. Khá thường xuyên, giải pháp đơn giản nhất thường là tốt nhất. Vì vậy, hãy bắt đầu với cách chúng tôi có thể triển khai tìm kiếm này bằng cách sử dụng mã đơn giản nhất có thể

Đầu tiên, hãy mở các tuyến đường của chúng tôi. php để thêm điểm cuối cho tìm kiếm của chúng tôi

Route::post('/search', 'SearchController@filter');

Tiếp theo, hãy tạo SearchController

php artisan make:controller SearchController

Và hãy thêm phương thức filter() mà chúng ta đã chỉ định trong tệp route

<?php

namespace App\Http\Controllers;
use App\User;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class SearchController extends Controller
{
public function filter(Request $request, User $user)
{
//
}
}

Chúng tôi biết rằng phương thức bộ lọc sẽ cần truy cập dữ liệu yêu cầu, vì vậy tôi đã đưa dữ liệu đó vào phương thức. sẽ tự động giải quyết vấn đề này và cung cấp nó cho phương thức. Tương tự như vậy đối với mô hình Người dùng, chúng tôi sẽ sử dụng mô hình này để thực hiện tìm kiếm và trả về dữ liệu

Điều khó khăn với thuật toán tìm kiếm của chúng tôi là mỗi tham số là tùy chọn. Sau lần lặp đầu tiên của chúng tôi bằng cách sử dụng K. I. S. S. một điểm bắt đầu rõ ràng là viết một số điều kiện để kiểm tra xem từng tham số trong tải trọng của chúng tôi có tồn tại hay không (vì chúng có thể không có trong yêu cầu tiếp theo)

Đây là lần thử đầu tiên của chúng tôi

public function filter(Request $request, User $user)
{
// Search for a user based on their name.
if ($request->has('name')) {
return $user->where('name', $request->input('name'))->get();
}

// Search for a user based on their company.
if ($request->has('company')) {
return $user->where('company', $request->input('company'))
->get();
}

// Search for a user based on their city.
if ($request->has('city')) {
return $user->where('city', $request->input('city'))->get();
}

// Continue for all of the filters.

// No filters have been provided, so
// let's return all users. This is
// bad - we should paginate in
// reality.
return User::all();
}

Có quá nhiều lỗi với mã này, thật khó để biết bắt đầu từ đâu

Đầu tiên, nó sẽ chỉ áp dụng một điều kiện duy nhất cho mô hình Người dùng, trước khi trả lại. Vì vậy, không thể tìm thấy người dùng có tên 'Billy' và người này cũng sống ở 'London'

Một cách để thực hiện điều đó sẽ là các điều kiện lồng nhau

// Search for a user based on their name.
if ($request->has('name')) {
// Has a 'city' search parameter also been provided?
if ($request->has('city')) {
// Search for a user based on their name and their city. return $user->where('name', $request->input('name'))
->where('city', $request->input('city'))
->get();
}
return $user->where('name', $request->input('name'))->get();}

Tôi chắc rằng bạn có thể thấy rằng điều này có thể hoạt động với hai hoặc ba tham số, nhưng khi chúng tôi thêm nhiều tùy chọn hơn thì điều này trở nên không thể quản lý được

Cải thiện api tìm kiếm của chúng tôi

Vậy làm thế nào chúng ta có thể làm cho nó hoạt động mà không phát điên với các điều kiện lồng nhau?

Chúng tôi có thể thực hiện cấu trúc lại với mô hình Người dùng, để làm việc với trình tạo thay vì trả lại mô hình trực tiếp

public function filter(Request $request, User $user)
{
$user = $user->newQuery();

// Search for a user based on their name.
if ($request->has('name')) {
$user->where('name', $request->input('name'));
}

// Search for a user based on their company.
if ($request->has('company')) {
$user->where('company', $request->input('company'));
}

// Search for a user based on their city.
if ($request->has('city')) {
$user->where('city', $request->input('city'));
}

// Continue for all of the filters.

// Get the results and return them.
return $user->get();
}

Tốt hơn nhiều. Chúng tôi hiện đang thêm từng tham số tìm kiếm làm công cụ sửa đổi cho phiên bản truy vấn được trả về từ $user->newQuery()

Điều này cho phép chúng tôi thực hiện các tìm kiếm sử dụng tất cả các tham số

Vì vậy, hãy để điều này hoạt động với tất cả các tham số từ tải trọng mẫu

$user = $user->newQuery();

// Search for a user based on their name.
if ($request->has('name')) {
$user->where('name', $request->input('name'));
}

// Search for a user based on their company.
if ($request->has('company')) {
$user->where('company', $request->input('company'));
}

// Search for a user based on their city.
if ($request->has('city')) {
$user->where('city', $request->input('city'));
}

// Only return users who are assigned
// to the given sales manager(s).
if ($request->has('managers')) {
$user->whereHas('managers', function ($query) use ($request) {
$query->whereIn('managers.name', $request->input('managers'));
});
}

// Has an 'event' parameter been provided?
if ($request->has('event')) {

// Only return users who have
// been invited to the event.
$user->whereHas('rsvp.event', function ($query) use ($request) {
$query->where('event.slug', $request->input('event'));
});

// Only return users who have responded
// to the invitation (with any type of
// response).
if ($request->has('responded')) {
$user->whereHas('rsvp', function ($query) use ($request) {
$query->whereNotNull('responded_at');
});
}

// Only return users who have responded
// to the invitation with a specific
// response.
if ($request->has('response')) {
$user->whereHas('rsvp', function ($query) use ($request) {
$query->where('response', 'I will be attending');
});
}
}

// Get the results and return them.
return $user->get();

Tuyệt vời, nó hoạt động

Tái cấu trúc, hay không tái cấu trúc?

Chúng tôi đang ở điểm mà mã của chúng tôi hoạt động. Chúng tôi có thể trả lại người dùng dựa trên các tham số tìm kiếm tùy chọn. Nhưng, mã của chúng tôi có hoàn hảo không?

Về cơ bản, chúng tôi dựa trên tất cả logic dựa trên một chuỗi các điều kiện có trong Bộ điều khiển. Đó có phải là nơi thích hợp để lưu trữ logic này?

Đây đều là những câu hỏi hợp lệ và các nhà phát triển khác nhau sẽ có câu trả lời khác nhau. Nhưng trước khi chúng tôi tiếp tục, điều thực sự quan trọng là phải xem xét dự án cụ thể của bạn. Nếu bạn đang tạo một thứ gì đó nhỏ, thứ gì đó có thời hạn sử dụng ngắn hoặc một ứng dụng tương đối đơn giản, tôi khuyên bạn đừng bận tâm đến việc tái cấu trúc và hãy giữ mẫu mà tôi mô tả trong bài viết này trong kho vũ khí của bạn như một thứ cần xem xét cho một

Độ phức tạp bổ sung được đưa vào cơ sở mã của bạn có làm cho api dễ sử dụng hơn hoặc dễ quản lý hơn không?

Tuy nhiên, nếu bạn đang xây dựng thứ gì đó phức tạp hơn một chút, chúng tôi sẽ cần một giải pháp tinh tế và dễ quản lý hơn

Viết api tìm kiếm mới của chúng tôi

Khi tôi bắt đầu một phần chức năng mới, tôi muốn bắt đầu bằng cách xem cách tôi muốn sử dụng api của mình, trước khi viết mã lõi thực tế. Cách tiếp cận này thường được gọi là lập trình mơ ước (cách khác, suy nghĩ mơ ước)

“Trước khi triển khai một thành phần, bạn viết một số mã thực sự sử dụng nó. Bằng cách này, bạn khám phá những chức năng nào với những tham số nào bạn thực sự cần, dẫn đến một giao diện rất tốt. Bạn cũng sẽ có một số mã kiểm tra tốt cho thành phần của mình

Ý tưởng dựa trên thực tế là mục đích của giao diện là đơn giản hóa mã sử dụng thành phần đó, chứ không phải đơn giản hóa mã triển khai nó. " (Nguồn. c2. com)

Theo kinh nghiệm của tôi, điều này dẫn đến mã dễ đọc hơn nhiều và api sạch hơn để làm việc với. Một tác dụng phụ quan trọng không kém là nó cũng cho phép tôi nắm bắt tốt hơn các yêu cầu của doanh nghiệp thông qua các bài kiểm tra chấp nhận, thay vì lao thẳng vào các bài kiểm tra đơn vị. Do đó, tôi có thể tự tin hơn rằng mã tôi đang viết đáp ứng các yêu cầu mà tôi đã gợi ra từ các bên liên quan thông qua ngôn ngữ dành riêng cho miền được sử dụng trong api của tôi

Áp dụng điều này vào tính năng tìm kiếm của chúng tôi;

________số 8_______

Tôi nghĩ rằng đọc khá độc đáo. Theo nguyên tắc thông thường, nếu tôi có thể đọc mã tôi đã viết dưới dạng một câu, thì tôi rất vui. Trong trường hợp này

Trả về kết quả tìm kiếm của người dùng với các bộ lọc được áp dụng

Điều đó có ý nghĩa để làm phiền các bên liên quan kỹ thuật và phi kỹ thuật

Tôi biết rằng tôi cần tạo một lớp Tìm kiếm người dùng và lớp đó cần một phương thức áp dụng tĩnh, phương thức này chấp nhận một loạt các bộ lọc. Bắt đầu nào

<?phpnamespace App\Search;use Illuminate\Http\Request;class UserSearch
{
public static function apply(Request $filters)
{
// Return the search results
}
}

Cách dễ nhất để làm việc này là chỉ cần sao chép và dán mã từ bộ điều khiển của chúng tôi, ngay vào phương thức áp dụng

Route::post('/search', 'SearchController@filter');
0

Một vài thay đổi đã được thực hiện. Đầu tiên, biến $request sử dụng trong mã Controller trước đó đã được đổi tên thành $filters, để cải thiện khả năng đọc

Thứ hai, phương thức newQuery() trên lớp Người dùng không thể được gọi tĩnh, do đó, một thể hiện của lớp Người dùng phải được tạo trước khi phương thức có thể được gọi. Điều này có thể được thực hiện trong một bước

Route::post('/search', 'SearchController@filter');
1

Trình điều khiển của chúng tôi hiện có thể được cấu trúc lại để sử dụng api Tìm kiếm người dùng mới mà chúng tôi mong muốn được lập trình

Route::post('/search', 'SearchController@filter');
2

Điều đó tốt hơn nhiều, phải không? . Chúng tôi chưa thực sự tái cấu trúc bất kỳ mã nào, nhưng chúng tôi có bộ điều khiển sạch hơn. Chuỗi điều kiện dài vừa được giao cho một lớp chuyên dụng

Đây là nơi phép màu xảy ra

Hiện tại có bảy tham số trong yêu cầu tìm kiếm mẫu của chúng tôi, nhưng thực tế chúng tôi sẽ có nhiều tham số hơn nên trong trường hợp này, một tệp không thể quản lý được. Nếu coi S. O. L. I. D. nguyên tắc, ý tưởng về trách nhiệm duy nhất bị phá vỡ với giải pháp hiện tại của chúng tôi. Phương thức apply() của chúng tôi hiện đang chịu trách nhiệm cho

  • Kiểm tra nếu một tham số tồn tại
  • Chuyển đổi tham số thành điều kiện truy vấn
  • Thực hiện truy vấn tìm kiếm

Có tất cả các bộ lọc thực hiện hành động trong một tệp có nghĩa là tôi sẽ cần phải tiếp tục sửa đổi lớp Tìm kiếm người dùng mỗi khi tôi muốn thêm bộ lọc mới hoặc điều chỉnh hành vi của một bộ lọc hiện có. Vì vậy, điều hợp lý là tôi nên có một lớp Bộ lọc dành riêng cho từng tùy chọn có sẵn

Hãy thiết lập bộ lọc đầu tiên của chúng tôi, 'Tên'. Nhưng trước tiên, hãy xem cách chúng tôi muốn có thể sử dụng bộ lọc api của mình bằng cách sử dụng chương trình wishful

Tôi muốn có thể làm một cái gì đó như

Route::post('/search', 'SearchController@filter');
3

Nhưng bây giờ, biến $user không còn ý nghĩa. Hãy đổi tên nó thành $query

Route::post('/search', 'SearchController@filter');
4

Và di chuyển logic có điều kiện của chúng ta sang applyFiltersToQuery() mới

Tiếp theo, hãy tạo lớp bộ lọc tìm kiếm đầu tiên của chúng ta, bắt đầu bằng thứ gì đó đơn giản;

Route::post('/search', 'SearchController@filter');
5

Chúng tôi có một phương thức đơn giản chấp nhận đối tượng Trình tạo và giá trị tìm kiếm (trong trường hợp ví dụ của chúng tôi là 'Billy'), sau đó áp dụng công cụ sửa đổi truy vấn cần thiết và trả về phiên bản trình tạo

Hãy tạo một cái khác;

Route::post('/search', 'SearchController@filter');
6

Bạn sẽ thấy rằng điều này thực hiện cùng một loại nhiệm vụ như bộ lọc 'Tên', nhưng lần này áp dụng một điều kiện cho thuộc tính 'thành phố'. Lưu ý rằng tôi đã giới thiệu một quy ước ở đây, mỗi bộ lọc có một phương thức duy nhất 'apply()' chấp nhận một phiên bản trình tạo và giá trị đã được cung cấp từ yêu cầu tìm kiếm. Đây là một điểm rất quan trọng, tôi sẽ trình bày chi tiết hơn sau

Để đảm bảo rằng tất cả các bộ lọc của chúng tôi tuân thủ quy ước này, hãy giới thiệu một Giao diện

Route::post('/search', 'SearchController@filter');
7

Một điểm khác cần lưu ý là tôi đã thêm tài liệu đầy đủ vào phương thức Giao diện. Lợi ích của việc thực hiện điều này trong Giao diện của tôi là tôi có thể sử dụng IDE (PHPStorm) của mình để tự động tạo cùng một tài liệu cho mỗi lớp triển khai Giao diện

Tiếp theo, hãy triển khai giao diện Bộ lọc mới của chúng ta trong các lớp bộ lọc Tên và Thành phố

Route::post('/search', 'SearchController@filter');
8

Route::post('/search', 'SearchController@filter');
9

Tuyệt vời. Bây giờ chúng tôi có hai bộ lọc tuân thủ cùng một quy ước. Ghi chú. cấu trúc thư mục của tôi như sau

Cấu trúc tệp cho tìm kiếm cho đến nay

Tôi đã đặt tất cả các bộ lọc của mình vào một thư mục riêng để tôi có thể dễ dàng xem những bộ lọc nào khả dụng. Tôi đang sử dụng không gian tên PSR-4 để chúng tuân theo cấu trúc thư mục ở trên

Sử dụng các bộ lọc tìm kiếm mới của chúng tôi

Quay trở lại phương thức applyFiltersToQuery() trong lớp UserSearch, chúng ta có thể thấy rằng bây giờ có thể bắt đầu loại bỏ một số điều kiện

Tôi sẽ thực hiện điều này dần dần, tái cấu trúc từng bước một. Đầu tiên, hãy ủy quyền cho các lớp Lọc của người dùng nếu chúng ta có đầu vào tương ứng

php artisan make:controller SearchController
0

Chúng tôi vẫn đang sử dụng các điều kiện để kiểm tra sự tồn tại của từng bộ lọc trong yêu cầu nhưng trách nhiệm về cách sửa đổi truy vấn hiện hoàn toàn do các bộ lọc riêng lẻ nắm giữ. Bởi vì chúng tôi đã mã hóa cứng các tham số và lớp bộ lọc tương ứng của chúng, nếu chúng tôi muốn thêm bộ lọc mới trong tương lai, chúng tôi vẫn cần mở lớp Tìm kiếm người dùng và sửa đổi mã. Điều đó không lý tưởng, vì vậy hãy giải quyết vấn đề đó tiếp theo

Thực sự rất dễ dàng để chuyển đổi điều này thành hoàn toàn năng động, vì chúng tôi đã giới thiệu một quy ước đặt tên

Ứng dụng\UserSearch\Filters\Name

Ứng dụng\Tìm kiếm người dùng\Bộ lọc\Thành phố

Chúng tôi chỉ đơn giản là tạo một lớp, bằng với tên của tham số (được chuyển đổi thành trường hợp thích hợp), trong không gian tên Bộ lọc

Đó là một quy tắc đơn giản, có thể được thực hiện như sau

php artisan make:controller SearchController
1

Hãy đi qua từng dòng này

php artisan make:controller SearchController
2

Lặp lại từng bộ lọc, gán tên tham số đầu vào (ví dụ: 'city') cho $filterName và giá trị của nó cho $value (ví dụ: 'London')

php artisan make:controller SearchController
3

Mỗi tên tham số sẽ được chia thành các từ, viết hoa chữ cái đầu tiên và sau đó bỏ dấu cách. Để lấy trọng tải ví dụ của chúng tôi

php artisan make:controller SearchController
4

Nếu chúng tôi sử dụng tham số tìm kiếm có tên là 'has_Responseed', thay vì 'đã phản hồi', thì chúng tôi cần tạo một bộ lọc có tên là 'HasResponded' để tuân theo quy ước này

php artisan make:controller SearchController
5

Để đảm bảo rằng chúng tôi không cố gắng gọi một phương thức trên một lớp không tồn tại, chúng tôi có thể kiểm tra xem $decorator có tồn tại hay không trước khi thực hiện cuộc gọi. Điều này bảo vệ api của chúng tôi khỏi người dùng cuối cố gắng đoán các tham số mà chúng tôi không tiết lộ

php artisan make:controller SearchController
6

Và đây là nơi phép màu xảy ra. PHP cho phép chúng ta sử dụng biến $decorator như một lớp và gọi các phương thức trên đó (trong trường hợp này là phương thức apply() của nó). Quay trở lại Giao diện của chúng tôi, bây giờ chúng tôi có thể thấy lợi ích của việc dành thêm vài phút để thiết lập giao diện đó. Chúng tôi có thể đảm bảo rằng bất kỳ Bộ lọc nào của chúng tôi sẽ hoạt động và phản hồi theo cùng một cách — mỗi Bộ lọc có hành vi nội bộ độc đáo của riêng chúng

tái cấu trúc cuối cùng

Mã này tốt hơn nhiều trong lớp Tìm kiếm người dùng của chúng tôi, nhưng tôi nghĩ nó vẫn có thể được cải thiện, đây là lớp cuối cùng

php artisan make:controller SearchController
7

Tôi đã quyết định xóa phương thức applyFiltersToQuery() vì nó có vẻ dư thừa khi xem xét phương thức chính được gọi là 'áp dụng'

Tôi cũng đã trích xuất một số điểm phức tạp khi xây dựng chuỗi trang trí và kiểm tra xem trình trang trí có tồn tại cho các chức năng chuyên dụng hay không — giúp việc kiểm tra dễ dàng hơn và tách biệt trách nhiệm hơn

Điều này có nghĩa là Tìm kiếm người dùng không cần phải sửa đổi để mở rộng api tìm kiếm của chúng tôi. Cần một loại bộ lọc mới? . Chỉ cần tạo lớp bộ lọc trong không gian tên App\UserSearch\Filters (tuân theo quy ước đặt tên lớp như đã giải thích trước đó) và triển khai giao diện Bộ lọc

Phần kết luận

Chúng tôi đã chuyển từ một phương thức Bộ điều khiển khổng lồ duy nhất chứa tất cả logic tìm kiếm của chúng tôi sang một hệ thống lọc mô-đun cho phép bật, tắt và thêm các bộ lọc mà không cần sửa đổi bất kỳ mã lõi nào. Theo đề xuất của @rockroxx trong các nhận xét, một công cụ tái cấu trúc tuyệt vời khác sẽ là trích xuất các phương thức thành một đặc điểm và đặt Người dùng làm const có thể được thực thi bởi Giao diện

php artisan make:controller SearchController
8

Khi bạn hiểu đầy đủ về mẫu thiết kế này, bạn sẽ có thể thay thế nhiều điều kiện của mình bằng tính đa hình

Tôi đã thêm mã vào GitHub để bạn có thể rẽ nhánh, kiểm tra và thử nghiệm

Bạn sẽ giải quyết các bộ lọc tìm kiếm nâng cao như thế nào?