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 Show
Chọn Bộ lọcLoạ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 Mỗi bộ lọc chọn được tạo bởi Nova chứa hai phương thức. Phương thức Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng Bộ lọc BooleanNova 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 Bạn có thể tạo bộ lọc boolean bằng lệnh Mỗi bộ lọc boolean do Nova tạo ra chứa hai phương thức. Khi xây dựng các bộ lọc boolean, đối số Hãy xem một ví dụ về bộ lọc Phương thức Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng 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 Bạn có thể tạo bộ lọc ngày bằng lệnh Mỗi bộ lọc ngày được tạo bởi Nova chứa một phương thức. Khi xây dựng bộ lọc ngày, đối số Hãy xem một ví dụ về bộ lọc Như bạn có thể thấy trong ví dụ trên, bạn có thể tận dụng 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 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 raCô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 caoTìm kiếm người dùngMột số cách mà tôi biết chúng tôi muốn lọc người dùng bao gồm;
Đâ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ạoMô 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
yêu cầu tìm kiếmTô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", Chúng ta đang nói gì ở đây?
Làm cho nó hoạt động — giải pháp đơn giản nhấtTô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 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) 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. 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ôiVậ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) 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(); 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ôiKhi 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)
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
Đ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 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'); 0Mộ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'); 1Trì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 raHiệ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
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'); 3Như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'); 4Và 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'); 5Chú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'); 6Bạ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'); 7Mộ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'); 8Và Route::post('/search', 'SearchController@filter'); 9Tuyệ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 nayTô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ôiQuay 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 0Chú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
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 1Hãy đi qua từng dòng này php artisan make:controller SearchController 2Lặ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 3Mỗ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 4Nế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 6Và đâ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ùngMã 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 7Tô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ậnChú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 8Khi 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? |