Đẩy xa hơn nữa - những lời khuyên tốt nhất và những cách thực hành tốt cho Laravel 5.7

Bài đăng này có phiên bản âm thanh nhờ ứng dụng Blogcast của Miguel Piedrafita.

Laravel đã được nhiều nhà phát triển PHP biết đến vì đã viết mã sạch, hoạt động và có khả năng sửa lỗi. Nó cũng hỗ trợ cho nhiều tính năng, đôi khi aren được liệt kê trong các tài liệu, hoặc chúng đã bị xóa, nhưng chúng đã bị xóa vì nhiều lý do.

Tôi đã làm việc với Laravel trong 2 năm sử dụng sản xuất và tôi đã học được từ việc viết mã xấu thành mã tốt hơn và tôi đã tận dụng lợi thế của Laravel kể từ lần đầu tiên tôi bắt đầu viết mã với nó. Tôi sẽ chỉ cho bạn các thủ thuật bí ẩn có thể giúp bạn khi viết mã với Laravel.

Sử dụng phạm vi địa phương khi bạn cần truy vấn mọi thứ

Laravel có một cách hay để viết truy vấn cho trình điều khiển cơ sở dữ liệu của bạn bằng Trình tạo truy vấn. Một cái gì đó như thế này:

$ order = Order :: where ('status', 'deliver') -> where ('đã trả', true) -> get ();

Điều này là khá tốt đẹp. Điều này khiến tôi từ bỏ SQL và tập trung vào mã hóa dễ tiếp cận hơn đối với tôi. Nhưng bit mã này có thể được viết tốt hơn nếu chúng ta sử dụng phạm vi cục bộ.

Phạm vi cục bộ cho phép chúng tôi tạo các phương thức Trình tạo truy vấn của riêng mình, chúng tôi có thể xâu chuỗi khi chúng tôi cố gắng truy xuất dữ liệu. Ví dụ: thay vì các câu lệnh -> where (), chúng ta có thể sử dụng -> deliver () và -> pay () theo cách sạch hơn.

Đầu tiên, trong mô hình Đặt hàng của chúng tôi, chúng tôi nên thêm một số phương thức:

Lớp học mở rộng Mô hình
{
   ...
   phạm vi chức năng công cộng Được phân phối ($ truy vấn) {
      trả về $ query-> where ('status', 'deliver');
   }
   hàm công khai scopePaid ($ query) {
      trả về $ query-> where ('đã trả', true);
   }
}

Khi khai báo phạm vi cục bộ, bạn nên sử dụng cách đặt tên chính xác cho phạm vi [Something]. Theo cách này, Laravel sẽ biết rằng đây là một phạm vi và sẽ sử dụng nó trong Trình tạo truy vấn của bạn. Đảm bảo bạn bao gồm đối số đầu tiên được tự động chèn bởi Laravel và là đối tượng trình tạo truy vấn.

$ đơn hàng = Đơn hàng :: giao () -> trả tiền () -> get ();

Để truy xuất động hơn, bạn có thể sử dụng phạm vi cục bộ động. Mỗi phạm vi cho phép bạn đưa ra các tham số.

Lớp học mở rộng Mô hình
{
   ...
   Hàm công khai scopeStatus ($ truy vấn, chuỗi $ status) {
      trả về $ query-> where ('status', $ status);
   }
}
$ đơn hàng = Đơn hàng :: trạng thái ('đã giao') -> đã thanh toán () -> get ();

Ở phần sau của bài viết này, bạn sẽ tìm hiểu lý do tại sao bạn nên sử dụng Snake_case cho các trường cơ sở dữ liệu, nhưng đây là lý do đầu tiên: Laravel sử dụng theo mặc định trong đó [Something] để thay thế phạm vi trước đó. Vì vậy, thay vì trước đây, bạn có thể làm:

Đặt hàng :: whereStatus ('giao') -> trả tiền () -> get ();

Laravel sẽ tìm kiếm phiên bản sn_case của Something từ đâu đó [Something]. Nếu bạn có trạng thái trong DB của mình, bạn sẽ sử dụng ví dụ trước. Nếu bạn có Shipping_status, bạn có thể sử dụng:

Đặt hàng :: whereShippingStatus ('đã giao') -> trả tiền () -> get ();

Đó là lựa chọn của bạn!

Sử dụng tệp Yêu cầu khi cần

Laravel cung cấp cho bạn một cách hùng hồn để xác nhận các biểu mẫu của bạn. Hoặc là nó có một yêu cầu POST hoặc một yêu cầu GET, nó sẽ không thể xác nhận nó nếu bạn cần nó.

Bạn có thể xác nhận theo cách này trong bộ điều khiển của bạn:

cửa hàng chức năng công cộng (Yêu cầu $ request)
{
    $ validatedData = $ request-> xác thực ([
        'title' => 'bắt buộc | duy nhất: bài viết | tối đa: 255',
        'cơ thể' => 'bắt buộc',
    ]);

    // Bài đăng trên blog hợp lệ ...
}

Nhưng khi bạn có quá nhiều mã trong các phương thức điều khiển của mình, nó có thể khá khó chịu. Bạn muốn giảm càng nhiều mã càng tốt trong bộ điều khiển của bạn. Ít nhất, đây là điều đầu tiên tôi nghĩ nếu tôi phải viết thật nhiều logic.

Laravel cung cấp cho bạn một cách * dễ thương * để xác thực các yêu cầu bằng cách tạo các lớp yêu cầu và sử dụng chúng thay vì lớp Yêu cầu lỗi thời. Bạn chỉ cần tạo yêu cầu của bạn:

Nghệ nhân php thực hiện: yêu cầu StoreBlogPost

Trong thư mục ứng dụng / http / Yêu cầu / thư mục bạn sẽ tìm thấy tệp yêu cầu của mình:

lớp StoreBlogPostRequest mở rộng FormRequest
{
   chức năng công cộng ủy quyền ()
   {
      trả về $ this-> user () -> can ('create.posts');
   }
   quy tắc chức năng công cộng ()
   {
       trở về [
         'title' => 'bắt buộc | duy nhất: bài viết | tối đa: 255',
         'cơ thể' => 'bắt buộc',
       ];
   }
}

Bây giờ, thay vì Illuminate \ http \ Request trong phương thức của bạn, bạn nên thay thế bằng lớp vừa tạo:

sử dụng Ứng dụng \ http \ Yêu cầu \ StoreBlogPostRequest;
cửa hàng chức năng công cộng (StoreBlogPostRequest $ request)
{
    // Bài đăng trên blog hợp lệ ...
}

Phương thức Authorize () phải là boolean. Nếu nó sai, nó sẽ ném 403, vì vậy hãy chắc chắn rằng bạn bắt được nó trong phương thức render /) của ứng dụng / Exceptions / Handler.php:

kết xuất chức năng công cộng ($ request, ngoại lệ $ ngoại lệ)
{
   if ($ ngoại lệof \ Illuminate \ Auth \ Access \ AuthorizationException) {
      //
   }
   return cha mẹ :: render ($ request, $ ngoại lệ);
}

Phương thức bị thiếu ở đây, trong lớp yêu cầu là hàm message (), đó là một mảng chứa các thông báo sẽ được trả về trong trường hợp xác thực thất bại:

lớp StoreBlogPostRequest mở rộng FormRequest
{
   chức năng công cộng ủy quyền ()
   {
      trả về $ this-> user () -> can ('create.posts');
   }
   quy tắc chức năng công cộng ()
   {
       trở về [
         'title' => 'bắt buộc | duy nhất: bài viết | tối đa: 255',
         'cơ thể' => 'bắt buộc',
       ];
   }
   tin nhắn chức năng công cộng ()
   {
      trở về [
        'title.required' => 'Tiêu đề là bắt buộc.',
        'title.unique' => 'Tiêu đề bài viết đã tồn tại.',
        ...
      ];
   }
}

Để bắt chúng trong bộ điều khiển của bạn, bạn có thể sử dụng biến lỗi trong tệp lưỡi của mình:

@if ($ lỗi-> bất kỳ ())
   @foreach ($ error-> all () là $ error)
      {{$ lỗi}}
   @endforeach
@endif

Trong trường hợp bạn muốn nhận thông báo xác thực trường xác định, bạn có thể thực hiện như sau (nó sẽ trả về một thực thể boolean sai nếu xác thực được thông qua cho trường đó):


@if ($ lỗi-> có ('tiêu đề'))
    {{$ lỗi-> đầu tiên ('tiêu đề')}} 
@endif

Phạm vi ma thuật

Khi xây dựng mọi thứ, bạn có thể sử dụng phạm vi ma thuật đã được nhúng

  • Lấy kết quả bằng created_at, giảm dần:
Người dùng :: mới nhất () -> get ();
  • Lấy kết quả theo bất kỳ trường nào, giảm dần:
Người dùng :: mới nhất ('last_login_at') -> get ();
  • Lấy kết quả theo thứ tự ngẫu nhiên:
Người dùng :: inRandomOrder () -> get ();
  • Chỉ chạy một phương thức truy vấn nếu có gì đó đúng
// Giả sử người dùng ở trên trang tin tức và muốn sắp xếp nó theo cách mới nhất trước
// mydomain.com/news?sort=new
Người dùng :: khi ($ request-> truy vấn ('sort'), hàm ($ query, $ sort) {
   if ($ sort == 'mới') {
      trả về $ query-> mới nhất ();
   }
   
   trả về $ truy vấn;
}) -> nhận ();

Thay vì khi () bạn có thể sử dụng trừ khi, điều đó ngược lại với khi ().

Sử dụng Mối quan hệ để tránh các truy vấn lớn (hoặc các câu hỏi xấu)

Bạn đã bao giờ sử dụng một tấn tham gia trong một truy vấn chỉ để có thêm thông tin? Thật khó để viết các lệnh SQL đó, ngay cả với Trình tạo truy vấn, nhưng các mô hình đã làm điều đó với Mối quan hệ. Ban đầu, có thể bạn đã quen thuộc, do lượng thông tin cao mà tài liệu cung cấp, nhưng điều này sẽ giúp bạn hiểu rõ hơn về cách mọi thứ hoạt động và làm thế nào để ứng dụng của bạn chạy mượt hơn.

Kiểm tra tài liệu quan hệ tại đây.

Sử dụng Công việc cho các nhiệm vụ tốn thời gian

Công việc của Laravel là một công cụ bắt buộc mạnh mẽ để chạy các tác vụ trong nền.

  • Bạn có muốn gửi email không? Việc làm.
  • Bạn có muốn phát một tin nhắn? Việc làm.
  • Bạn có muốn xử lý hình ảnh? Việc làm.

Công việc giúp bạn từ bỏ thời gian tải cho người dùng của mình vào các tác vụ tiêu tốn thời gian như thế này. Chúng có thể được đặt vào hàng đợi được đặt tên, chúng có thể được ưu tiên và đoán xem - Laravel đã thực hiện hàng đợi ở hầu hết mọi nơi có thể: xử lý một số PHP trong nền hoặc gửi thông báo hoặc phát sự kiện, hàng đợi ở đó!

Bạn có thể kiểm tra tài liệu Queues tại đây.

Tôi thích sử dụng Laravel Horizon cho hàng đợi vì nó dễ cài đặt, nó có thể được sử dụng bằng Trình giám sát và thông qua tệp cấu hình, tôi có thể cho Horizon biết bao nhiêu quy trình tôi muốn cho mỗi hàng đợi.

Bám sát tiêu chuẩn cơ sở dữ liệu & Accessor

Laravel dạy bạn ngay từ đầu rằng các biến và phương thức của bạn phải là $ camelCase camelCase () trong khi các trường cơ sở dữ liệu của bạn phải là sn_case. Tại sao? Bởi vì điều này giúp chúng tôi xây dựng các phụ kiện tốt hơn.

Accessor là các trường tùy chỉnh, chúng ta có thể xây dựng ngay từ mô hình của mình. Nếu cơ sở dữ liệu của chúng tôi chứa First_name, last_name và age, chúng tôi có thể thêm một trường tùy chỉnh có tên là tên nối liền với First_name và last_name. Đừng lo lắng, điều này đã thắng được viết trong DB bằng mọi cách. Nó chỉ là một thuộc tính tùy chỉnh mô hình cụ thể này có. Tất cả các bộ truy cập, như phạm vi, có một cú pháp đặt tên tùy chỉnh: getS SomethingAttribution:

lớp Người dùng mở rộng Mô hình
{
   ...
   Hàm công khai getNameAttribution (): chuỗi
   {
       trả lại $ this-> First_name. ' '. $ this-> last_name;
   }
}

Khi sử dụng $ user-> name, nó sẽ trả về kết nối.

Theo mặc định, thuộc tính name không được hiển thị nếu chúng tôi dd ($ user), nhưng chúng tôi có thể làm cho điều này thường khả dụng bằng cách sử dụng biến $ appends:

lớp Người dùng mở rộng Mô hình
{
   được bảo vệ $ appends = [
      'Tên',
   ];
   ...
   Hàm công khai getNameAttribution (): chuỗi
   {
       trả lại $ this-> First_name. ' '. $ this-> last_name;
   }
}

Bây giờ, mỗi lần chúng ta dd ($ user), chúng ta sẽ thấy biến đó ở đó (nhưng vẫn không có trong cơ sở dữ liệu)

Tuy nhiên, hãy cẩn thận: nếu bạn đã có trường tên, mọi thứ sẽ khác một chút: tên bên trong $ appends không còn cần thiết nữa và hàm thuộc tính chờ một tham số, đó là biến đã được lưu trữ (chúng tôi sẽ không còn sử dụng $ này).

Với cùng một ví dụ, chúng ta có thể muốn ucfirst () các tên:

lớp Người dùng mở rộng Mô hình
{
   được bảo vệ $ appends = [
      //
   ];
   ...
   Hàm công khai getFirstNameAttribution ($ FirstName): chuỗi
   {
       trả về ucfirst ($ FirstName);
   }
   Hàm công khai getLastNameAttribution ($ lastName): chuỗi
   {
      trả về ucfirst ($ lastName);
   }
}

Bây giờ, khi chúng ta sử dụng $ user-> first_name, nó sẽ trả về một chuỗi chữ hoa đầu tiên.

Do tính năng này, nó rất tốt để sử dụng Snake_case cho các trường cơ sở dữ liệu của bạn.

Không lưu trữ dữ liệu tĩnh liên quan đến mô hình trong cấu hình

Những gì tôi thích làm là lưu trữ dữ liệu tĩnh liên quan đến mô hình bên trong mô hình. Tôi se cho bạn xem.

Thay vì điều này:

BettingOdds.php

lớp BettingOdds mở rộng Mô hình
{
   ...
}

cấu hình / betOdds.php

trở về [
   'thể thao' => [
      'bóng đá' => 'thể thao: 1',
      'quần vợt' => 'thể thao: 2',
      'bóng rổ' => 'thể thao: 3',
      ...
   ],
];

Và truy cập chúng bằng cách sử dụng:

cấu hình (Cá cược cá cượcOdds.sports.soney,);

Tôi thích làm điều này:

BettingOdds.php

lớp BettingOdds mở rộng Mô hình
{
   bảo vệ tĩnh $ sports = [
      'bóng đá' => 'thể thao: 1',
      'quần vợt' => 'thể thao: 2',
      'bóng rổ' => 'thể thao: 3',
      ...
   ];
}

Và truy cập chúng bằng cách sử dụng:

BettingOdds :: $ sports ['bóng đá'];

Tại sao? Bởi vì nó dễ sử dụng hơn trong các hoạt động tiếp theo:

lớp BettingOdds mở rộng Mô hình
{
   bảo vệ tĩnh $ sports = [
      'bóng đá' => 'thể thao: 1',
      'quần vợt' => 'thể thao: 2',
      'bóng rổ' => 'thể thao: 3',
      ...
   ];
   scopeSport chức năng công cộng ($ truy vấn, chuỗi $ sport)
   {
      if (! isset (self :: $ sports [$ sport])) {
         trả về $ truy vấn;
      }
      
      trả về $ query-> where ('sport_id', self :: $ sports [$ sport]);
   }
}

Bây giờ chúng ta có thể thưởng thức phạm vi:

BettingOdds :: sport ('bóng đá') -> get ();

Sử dụng các bộ sưu tập thay vì xử lý mảng thô

Trước đây, chúng ta thường làm việc với các mảng theo cách thô:

$ trái cây = ['táo', 'lê', 'chuối', 'dâu'];
foreach ($ trái cây như $ trái cây) {
   tiếng vang 'tôi có'. $ trái cây;
}

Bây giờ, chúng ta có thể sử dụng các phương thức nâng cao sẽ giúp chúng ta xử lý dữ liệu trong các mảng. Chúng ta có thể lọc, biến đổi, lặp lại và sửa đổi dữ liệu trong một mảng:

$ trái cây = thu thập ($ trái cây);
$ fruit = $ fruit-> từ chối (hàm ($ fruit) {
   trả lại $ fruit === 'quả táo';
}) -> toArray ();
['lê', 'chuối', 'dâu']

Để biết thêm chi tiết, kiểm tra tài liệu mở rộng về Bộ sưu tập.

Khi làm việc với Trình tạo truy vấn, phương thức -> get () trả về một thể hiện Bộ sưu tập. Nhưng hãy cẩn thận để không nhầm Bộ sưu tập với trình tạo truy vấn:

  • Trong Trình tạo truy vấn, chúng tôi không truy xuất bất kỳ dữ liệu nào. Chúng tôi có rất nhiều phương thức liên quan đến truy vấn: orderBy (), where (), v.v.
  • Sau khi chúng tôi nhấn -> get (), dữ liệu được truy xuất, bộ nhớ đã được sử dụng, nó trả về một thể hiện Bộ sưu tập. Một số phương thức Trình tạo truy vấn không có sẵn hoặc chúng có nhưng tên chúng khác nhau. Kiểm tra các phương pháp có sẵn để biết thêm.

Nếu bạn có thể lọc dữ liệu ở cấp Trình tạo truy vấn, hãy làm điều đó! Không dựa vào tính năng lọc khi nói đến đối tượng Bộ sưu tập - bạn sẽ sử dụng quá nhiều bộ nhớ ở một số nơi và bạn không muốn. Giới hạn kết quả của bạn và sử dụng các chỉ mục ở cấp độ DB.

Sử dụng các gói và don lồng phát minh lại bánh xe

Dưới đây là một số gói tôi sử dụng:

  • Chỉ thị lưỡi dao
  • Laravel CORS (bảo vệ tuyến đường của bạn khỏi nguồn gốc khác)
  • Trình trợ giúp thẻ Laravel (sử dụng tốt hơn các thẻ HTML trong Blade)
  • Laravel Sluggable (hữu ích khi tạo sên)
  • Phản hồi của Laravel (xây dựng API JSON dễ dàng hơn)
  • Can thiệp hình ảnh (xử lý hình ảnh theo phong cách)
  • Horizon (giám sát hàng đợi với cấu hình tối thiểu)
  • Socialite (cấu hình tối thiểu để đăng nhập với phương tiện truyền thông xã hội)
  • Hộ chiếu (triển khai OAuth cho các tuyến đường)
  • Spatie từ ActivityLog (hoạt động theo dõi cho các mô hình)
  • Spatie từ sao lưu (tập tin sao lưu và cơ sở dữ liệu)
  • Spatie sườn Blade-X (xác định các thẻ HTML của riêng bạn; hoạt động tốt với Trình trợ giúp thẻ Laravel)
  • Thư viện phương tiện Spatie từ (cách dễ dàng để đính kèm tệp vào mô hình)
  • Spatie từ hồi đáp Cache (phản hồi của bộ điều khiển bộ đệm)
  • Spatie sườn Bộ sưu tập Macros (nhiều macro hơn trên các bộ sưu tập)

Dưới đây là một số gói tôi đã viết:

  • Kết bạn (thích, theo dõi và chặn như trên phương tiện truyền thông xã hội)
  • Lịch trình (tạo thời gian biểu và kiểm tra theo giờ và ngày)
  • Xếp hạng (mô hình tỷ lệ)
  • Người giám hộ (hệ thống cấp phép, cách dễ dàng)

Quá khó hiểu? Tiếp cận với tôi!

Nếu bạn có thêm câu hỏi về Laravel, nếu bạn cần trợ giúp với bất kỳ thông tin nào liên quan đến DevOps hoặc chỉ muốn nói một lời cảm ơn!, Bạn có thể tìm thấy tôi trên Twitter @rennokki!