Hướng dẫn Laravel cho người mới bắt đầu

Laravel là gì?

Laravel là một khung công tác web MVC mã nguồn mở dành cho PHP. Laravel là một framework mạnh mẽ giúp phát triển dễ dàng các ứng dụng web PHP với các tính năng như hệ thống đóng gói mô-đun với trình quản lý phụ thuộc chuyên dụng, quyền truy cập vào cơ sở dữ liệu quan hệ và các tiện ích khác để triển khai và bảo trì ứng dụng.

Laravel được tạo ra bởi Taylor Otwell. Kể từ khi phát hành lần đầu vào tháng 2011 năm 1 (phiên bản XNUMX), nó ngày càng trở nên phổ biến hơn trong lĩnh vực khung PHP của ngành phát triển web. Phần lớn sự phổ biến này có thể là do nhiều tính năng dành cho nhà phát triển đi kèm với sản phẩm.

Tại sao lại là Laravel?

Khoảng năm 2000, hầu hết Mã PHP mang tính thủ tục và có thể được tìm thấy ở dạng “tập lệnh” có một mớ mã spaghetti lộn xộn. Ngay cả những trang đơn giản nhất cũng không có tách biệt các mối quan tâm, và do đó, khá dễ dàng để một ứng dụng nhanh chóng trở thành cơn ác mộng về bảo trì. Thế giới cần thứ gì đó tốt hơn…Nhập PHP phiên bản 5 và nhiều khung PHP khác nhau đang cố gắng mang lại một số giải pháp rất cần thiết và giải pháp tốt hơn cho các mối quan tâm khác nhau về ứng dụng web.

Kể từ đó, chúng tôi đã thấy nhiều khung công tác được phát hành sẽ mở đường cho các khung công tác phổ biến hiện có và đang được sử dụng ngày nay. Ngày nay, ba công ty hàng đầu (theo ý kiến ​​của chúng tôi) sẽ là Zend Framework, Symfony và tất nhiên là Laravel. Mặc dù mỗi khung này đều được thành lập dựa trên các nguyên tắc tương tự và đều hướng đến việc giải quyết (về cơ bản) các vấn đề chung giống nhau, nhưng điểm khác biệt chính của chúng nằm ở việc triển khai. Mỗi người đều có những đặc điểm riêng về cách giải quyết vấn đề. Khi bạn nhìn vào mã do mỗi người trong số họ tạo ra, bạn sẽ thấy rằng có một đường khá liền mạch ngăn cách chúng với nhau. Theo quan điểm khiêm tốn của chúng tôi, Laravel framework là tốt nhất.

Tìm hiểu thêm về Sự khác biệt giữa Laravel và CodeIgniter

Cách tải xuống và cài đặt Laravel với Composer

LƯU Ý Giả định rằng bạn đã cài đặt bản sao PHP trên hệ thống cục bộ của mình. Nếu không, bạn có thể đọc cách cài đặt nó vào đây

Composer vừa là trình quản lý gói vừa là trình quản lý phụ thuộc. Để cài đặt nó, hãy mở terminal và cd vào một thư mục mới. Chạy lệnh này:

curl -Ss getcomposer.org/installer | php

Kết quả của lệnh này sẽ như thế này:

Tải xuống và cài đặt Laravel với Trình soạn thảo

Chú thích Để biết thêm hướng dẫn chi tiết về cách thiết lập Laravel, hãy tham khảo tài liệu Laravel vào đây.

Bạn sẽ thấy nó tải xuống và biên dịch tập lệnh Composer.phar, đây là tập lệnh chúng tôi sử dụng để cài đặt Laravel. Mặc dù có rất nhiều cách để thiết lập một ứng dụng Laravel mới, nhưng chúng tôi sẽ thực hiện điều đó thông qua tập lệnh soạn thảo của Laravel. Để cài đặt tập lệnh này, hãy chạy:

composer global require laravel/installer

Nó sẽ trông giống như thế này:

Tải xuống và cài đặt Laravel với Trình soạn thảo

Điều này sẽ tải xuống và cài đặt tất cả các tệp khung cũng như tất cả các phụ thuộc mà nó yêu cầu. Các gói sẽ được lưu bên trong thư mục nhà cung cấp. Sau khi tải xuống và cài đặt, bạn chỉ cần thực hiện lệnh sau:

laravel new uploadApp

Bạn sẽ thấy kết quả tương tự như sau:

Tải xuống và cài đặt Laravel với Trình soạn thảo

Composer đang cài đặt tất cả các gói mà Laravel cần để chạy. Có thể mất vài phút vì vậy hãy kiên nhẫn. Sau khi hoàn tất, hãy chạy lệnh ls -al để xem những gì đã được cài đặt.

Dưới đây là bảng phân tích ngắn gọn về các thư mục trong một ứng dụng Laravel phổ biến:

  • ứng dụng/ : Đây là thư mục nguồn chứa mã ứng dụng của chúng tôi. Tất cả các bộ điều khiển, chính sách và mô hình đều nằm trong thư mục này
  • khởi động/ : Giữ tập lệnh khởi động của ứng dụng và một số tệp bản đồ lớp
  • cấu hình/ : Giữ các tập tin cấu hình của ứng dụng. Chúng thường không được sửa đổi trực tiếp mà thay vào đó, dựa vào các giá trị được thiết lập trong tệp .env (môi trường) ở thư mục gốc của ứng dụng
  • cơ sở dữ liệu/ : Chứa các tệp cơ sở dữ liệu bao gồm di chuyển, hạt giống và nhà máy thử nghiệm
  • công cộng/ : Thư mục có thể truy cập công khai chứa các tài sản được biên dịch và tất nhiên là tệp index.php
  • tài nguyên/ : Chứa các nội dung giao diện người dùng như tệp javascript, tệp ngôn ngữ, tệp CSS/SASS và tất cả các mẫu được sử dụng trong ứng dụng (được gọi là mẫu lưỡi)
  • tuyến đường/ : Tất cả các tuyến đường trong ứng dụng đều ở bên trong đây. Có một vài “phạm vi” khác nhau của các tuyến đường nhưng phạm vi chúng tôi sẽ tập trung vào là tệp web.php
  • kho/ : Tất cả các tệp bộ đệm tạm thời được ứng dụng sử dụng, tệp phiên, tập lệnh xem được biên dịch và tệp nhật ký
  • kiểm tra/ : Chứa các tệp kiểm tra cho ứng dụng như kiểm tra đơn vị và kiểm tra chức năng.
  • người bán/ : Tất cả các gói phụ thuộc được cài đặt bằng trình soạn thảo

Bây giờ, hãy xây dựng phần còn lại của ứng dụng và chạy nó bằng lệnh thủ công đặc biệt (để tránh rắc rối khi cài đặt và định cấu hình máy chủ web như Apache hoặc nginx). Tệp .env chứa tất cả các giá trị cấu hình mà các tệp trong thư mục /config sử dụng để định cấu hình ứng dụng. Bên trong nó, bạn sẽ nhận thấy rằng giá trị cấu hình cho các tham số khác nhau được sử dụng bởi phần bên trong của ứng dụng.

Thiết kế ứng dụng: Tóm tắt nhanh các yêu cầu của chúng tôi

Trong hướng dẫn Laravel trực tuyến này, chúng ta sẽ xây dựng một ứng dụng rất đơn giản chỉ thực hiện hai việc:

  1. xử lý tải lên tệp từ biểu mẫu web
  2. hiển thị các tập tin đã tải lên trước đó trên một trang khác.

Đối với dự án này, ứng dụng của chúng tôi sẽ ở chế độ chỉ ghi, nghĩa là người dùng chỉ có thể ghi tệp và xem danh sách tệp mà họ đã tải lên. Ứng dụng này cực kỳ cơ bản nhưng sẽ là một phương pháp hay để bạn bắt đầu xây dựng các kỹ năng và kiến ​​thức về Laravel của mình. Lưu ý rằng để cho ngắn gọn, tôi đã loại trừ mọi hoạt động lập mô hình, di chuyển và xác thực cơ sở dữ liệu, nhưng trong ứng dụng thực tế, đây là những điều bổ sung mà bạn sẽ muốn xem xét.

Dưới đây là danh sách các thành phần mà chúng ta sẽ cần để làm cho ứng dụng hoạt động như mong đợi:

  • A tuyến đường điều đó sẽ cho phép thế giới bên ngoài (internet) sử dụng ứng dụng cũng như chỉ định điểm cuối sẽ trỏ đến vị trí logic để lưu tệp đã tải lên
  • A điều khiển xử lý luồng yêu cầu phản hồi
  • A mẫu sẽ được sử dụng để hiển thị danh sách các tệp đã tải lên trước đó và chính biểu mẫu tải lên thực tế
  • A yêu cầu mà bộ điều khiển sẽ sử dụng để xác thực dữ liệu được truyền vào từ biểu mẫu web

Tuyến đường là gì?

Một tuyến đường trong Laravel về cơ bản là một điểm cuối được chỉ định bởi một URI hoạt động như một “con trỏ” tới một số chức năng do ứng dụng cung cấp. Thông thường nhất, một tuyến đường chỉ đơn giản trỏ đến một phương thức trên bộ điều khiển và cũng chỉ ra phương thức HTTP nào có thể truy cập URI đó. Một tuyến đường không phải lúc nào cũng có nghĩa là phương pháp điều khiển; nó cũng có thể chuyển việc thực thi ứng dụng sang một hàm Closure hoặc hàm ẩn danh được xác định.

Tại sao nên sử dụng Tuyến đường?

Các tuyến đường được lưu trữ bên trong các tệp trong thư mục /routes bên trong thư mục gốc của dự án. Theo mặc định, có một số tệp khác nhau tương ứng với các "mặt" khác nhau của ứng dụng ("mặt" xuất phát từ phương pháp kiến ​​trúc lục giác). Chúng bao gồm:

  • web.php Các tuyến đường dựa trên "trình duyệt" đối mặt với công chúng. Đây là những lỗi phổ biến nhất và là thứ bị trình duyệt web tấn công. Chúng chạy qua nhóm phần mềm trung gian web và cũng chứa các tiện ích cho bảo vệ csrf (giúp bảo vệ chống lại các cuộc tấn công và hack độc hại dựa trên biểu mẫu) và thường chứa một mức độ “trạng thái” (ý tôi là họ sử dụng các phiên)
  • Các tuyến api.php tương ứng với một nhóm API và do đó có phần mềm trung gian API được bật theo mặc định. Các tuyến này không có trạng thái và không có phiên hoặc bộ nhớ yêu cầu chéo (một yêu cầu không chia sẻ dữ liệu hoặc bộ nhớ với bất kỳ yêu cầu nào khác - mỗi yêu cầu được tự đóng gói).
  • console.php Các tuyến này tương ứng với các lệnh thủ công tùy chỉnh mà bạn đã tạo cho ứng dụng của mình
  • channels.php Đăng ký các tuyến để phát sóng sự kiện

Tệp chính cần quan tâm lúc này là tệp dành riêng cho trình duyệt, web.php . Đã có một tuyến được xác định theo mặc định, đó là tuyến bạn nhấn ngay khi điều hướng đến web root của ứng dụng (web root nằm trong thư mục chung). Chúng tôi sẽ cần ba tuyến đường khác nhau để ứng dụng tải lên của chúng tôi hoạt động:

  • /upload Đây sẽ là URI của trang chính hiển thị biểu mẫu web của chúng tôi để tải tệp lên.
  • /process Đây sẽ là nơi biểu mẫu nằm tại /upload URI đăng dữ liệu do biểu mẫu gửi lên ("hành động" của biểu mẫu)
  • /list Điều này sẽ liệt kê tất cả các tập tin được tải lên trang web

ghi Điểm cuối /list có thể không cần thiết nếu chúng tôi muốn đặt tất cả logic để hiển thị biểu mẫu tải lên và danh sách các tệp trên một trang, tuy nhiên, hiện tại chúng tôi đã tách chúng ra để bổ sung thêm một chút vấn đề cho chủ đề hiện tại .

//inside routes/web.php
Route::get('/upload', 'UploadController@upload')->name('upload');
Route::get('/download, 'UploadController@download)->name(‘download');
Route::post('/process', 'UploadController@process')->name('process');
Route::get('/list', 'UploadController@list')->name('list');

Trong hướng dẫn về framework Laravel này, đối với mỗi tuyến đường mong muốn, chúng tôi sẽ liệt kê nó một cách rõ ràng trong tệp tuyến đường web.php bằng cách sử dụng một trong các phương thức yêu cầu dành riêng cho HTTP có sẵn (get(), post(), put() , delete(), patch() hoặc tùy chọn() ). Để biết chi tiết về từng điều này, hãy kiểm tra điều này ngoài. Những gì các phương thức này làm là chỉ định động từ HTTP nào được phép truy cập vào tuyến đường nhất định đó. Nếu bạn cần một tuyến đường để có thể chấp nhận nhiều động từ HTTP (điều này có thể xảy ra nếu bạn đang sử dụng một trang duy nhất để vừa hiển thị dữ liệu ban đầu vừa đăng dữ liệu biểu mẫu đã gửi), bạn có thể sử dụng Route::any( ) phương pháp.

Đối số thứ hai cho cả phương thức Route::get() và Route::post() (và bất kỳ phương thức nào khác liên quan đến động từ HTTP trên mặt tiền Route) là tên của Bộ điều khiển và phương thức cụ thể được lưu trữ bên trong bộ điều khiển đó, được thực thi khi đến điểm cuối của tuyến đường với yêu cầu HTTP được phép (GET, POST, PATCH, v.v.). Chúng tôi đang sử dụng UploadController cho cả ba tuyến đường và đã chỉ định chúng theo cách sau:

Tuyến đường là gì

Phương thức cuối cùng mà chúng tôi gọi trên mỗi tuyến đường là hàm name() của nó, hàm này chấp nhận một chuỗi làm đối số và được sử dụng để ít nhiều “gắn thẻ” một tuyến đường cụ thể với tên dễ nhớ (trong trường hợp của chúng tôi, tải lên, xử lý và liệt kê). Tôi nhận thấy rằng tính năng đặt tên riêng cho mỗi tuyến đường có vẻ không tuyệt vời cho lắm khi URL được đặt tên giống hệt nhau, nhưng nó thực sự hữu ích khi bạn có một tuyến đường cụ thể như /users/profile/dashboard/config, sẽ dễ nhớ hơn là profile-admin hoặc user-config.

Một lưu ý về Mặt tiền :

  • Mặt tiền cung cấp giao diện “tĩnh” cho các lớp có sẵn trong vùng chứa dịch vụ của ứng dụng.”
  • Chúng cung cấp một cú pháp ngắn gọn, dễ nhớ cho phép bạn sử dụng các tính năng của Laravel mà không cần nhớ những tên lớp dài dòng phải được chèn hoặc cấu hình thủ công.

Các định nghĩa tuyến đường ở trên trong hướng dẫn khung Laravel này, chúng tôi sử dụng mặt tiền Tuyến đường thay vì khởi tạo thủ công một đối tượng Illuminate/Routing/Router mới và gọi các phương thức tương ứng trên đối tượng đó. Nó chỉ là một phím tắt giúp tiết kiệm việc gõ phím. Facades được sử dụng rất nhiều trong Laravel framework – bạn có thể và nên làm quen với chúng nhiều hơn. Các tài liệu về Mặt tiền có thể được tìm thấy vào đây.

Bộ điều khiển là gì?

Controller là “C” trong kiến ​​trúc “MVC” (Model-View-Controller), là kiến ​​trúc mà Laravel dựa trên. Công việc của controller có thể được tóm gọn trong định nghĩa đơn giản này: Nó nhận yêu cầu từ client và trả về phản hồi cho client. Đây là định nghĩa cơ bản và cũng là yêu cầu tối thiểu của bất kỳ bộ điều khiển cụ thể nào. Những gì nó thực hiện ở giữa hai điều đó thường được coi là “hành động” của bộ điều khiển (hoặc “việc triển khai tuyến đường”). Nó hoạt động như điểm truy cập thứ hai vào ứng dụng (điểm đầu tiên là yêu cầu) tới khách hàng, người sẽ gửi trọng tải yêu cầu (mà chúng ta sẽ đề cập tiếp theo) tới ứng dụng, mong đợi một số loại phản hồi (dưới dạng một trang thành công, trang chuyển hướng, trang lỗi hoặc bất kỳ loại phản hồi HTTP nào khác).

Một bộ điều khiển thực hiện (về cơ bản) tương tự như định nghĩa tuyến đường với chức năng ẩn danh được đặt làm “hành động” khi tuyến đường đó bị tấn công. Sự khác biệt là bộ điều khiển xử lý tốt việc phân tách các mối quan tâm trong khi một tuyến được xác định nội tuyến với định nghĩa url thực tế, về cơ bản có nghĩa là chúng tôi đang ghép URI được chỉ định của tuyến với việc triển khai tuyến hoặc mã thực thi khi tuyến đó được đánh.

Ví dụ, hai đoạn mã sau sẽ đạt được mục đích giống nhau:

Ví dụ #1: Định nghĩa và triển khai tuyến đường bên trong một lệnh gọi phương thức duy nhất (trong tệp tuyến đường web.php)

//inside routes/web.php
<?php
Route::get('/hello-world', function(Request $request) {
   $name = $request->name;
   return response()->make("<h1>Hello World! This is ".$name, 200);
});

Ví dụ #2: Định nghĩa của Route nằm bên trong Routes/web.php, nhưng việc triển khai nó nằm bên trong lớp /app/Http/Controllers/HelloWorldController

//inside routes/web.php
<?php

Route::get('/hello-world', 'HelloWorldController@index')->name('hello-world');

------------------------------------------------------------------------------------
//inside app/Http/Controllers/HelloWorldController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

class HelloWorldController extends Controller
{
   public function index(Request $request)
   {
       $name = $request->name;
       return response()->make("<h1>Hello World! This is ".$name, 200);
   }
}

Mặc dù ví dụ Laravel # 2 có vẻ cần nhiều công việc hơn (không phải vậy - chỉ cần thêm một chút mã nữa thôi), hãy xem những lợi ích mà chúng ta đạt được bằng cách đặt logic hành động của mình cho tuyến đường “hello-world” đã cho bên trong bộ điều khiển thay thế of với định nghĩa của tuyến đường là hàm gọi lại:

  1. Logic của chúng tôi được tách biệt rõ ràng thành lớp riêng của nó (tách các mối quan tâm)
  2. Bộ điều khiển của chúng tôi được thiết lập để mở rộng sau này nếu chúng tôi cần thêm các khả năng bổ sung vào nó… Giả sử chúng tôi muốn thêm tính năng “goodbye-world”… Trong trường hợp này, chúng tôi sẽ đổi tên bộ điều khiển thành “HelloController” chung chung hơn, sau đó xác định hai phương thức riêng biệt, xin chào() tạm biệt(). Chúng ta cũng cần xác định hai tuyến đường riêng biệt để ánh xạ /Xin chào / Tạm biệt URI theo phương thức thích hợp của chúng trên bộ điều khiển. Điều này là đáng mong đợi so với việc tăng cường một tệp tuyến đường với việc triển khai của mỗi tuyến đường được xác định dưới dạng các hàm gọi lại.
  3. Laravel có khả năng tích hợp để lưu trữ tất cả các định nghĩa tuyến đường trong ứng dụng để tăng tốc thời gian tìm tuyến đường nhất định (tăng hiệu suất ứng dụng); Tuy nhiên, bạn sẽ chỉ có thể tận dụng lợi thế đó nếu tất cả các tuyến đã xác định bên trong ứng dụng được định cấu hình bằng cách sử dụng ánh xạ dành riêng cho bộ điều khiển (xem Ví dụ #2 ở trên)

Hãy chạy lệnh này để tạo bộ điều khiển mới cho chúng ta.

// ...inside the project's root directory:
php artisan make:controller UploadController   

Về cơ bản, lệnh này thực hiện là tạo ra một nhánh cho bộ điều khiển có tên “UploadController” bên trong thư mục bộ điều khiển chính tại /app/Http/Controllers/UploadController.php. Hãy mở tệp đó và xem thử. Nó rất đơn giản vì nó chỉ là một phiên bản sơ khai của bộ điều khiển, với đường dẫn vùng tên chính xác và các lớp bắt buộc mà nó mở rộng từ đó.

Tạo yêu cầu

Trước khi chúng ta tiếp tục hướng dẫn PHP Laravel này và thực hiện một vài thay đổi đối với stub được tạo ra của UploadController, tôi nghĩ sẽ hợp lý hơn nếu tạo lớp yêu cầu trước. Điều này là do phương thức controller xử lý yêu cầu phải gợi ý kiểu cho đối tượng yêu cầu trong chữ ký của nó, cho phép nó tự động xác thực dữ liệu biểu mẫu đến (như được chỉ định trong phương thức rules(). Sẽ nói thêm về điều đó sau…) Bây giờ, hãy sử dụng lại lệnh artisan để tạo stub yêu cầu của chúng ta:

php artisan make:request UploadFileRequest

Lệnh này sẽ tạo một tệp có tên UploadFileRequest bên trong app/Http/Requests/UploadFileRequest. Hãy mở sơ khai và xem qua… Bạn sẽ thấy nó rất đơn giản, chỉ chứa hai phương thức, ủy quyền () và quy tắc.

Tạo logic xác thực

Hãy sửa đổi sơ khai yêu cầu để đáp ứng nhu cầu của ứng dụng của chúng tôi. Sửa đổi tập tin để nó trông như thế này:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UploadFileRequest extends FormRequest
{
   /**
    * Determine if the user is authorized to make this request.
    *
    * @return bool
    */
   public function authorize()
   {
       return true;
   }

   /**
    * Get the validation rules that apply to the request.
    *
    * @return array
    */
   public function rules()
   {
       return [
           'fileName' => 'required|string',
           'userFile' => 'required|file'
       ];
   }
}

Không có nhiều thay đổi nhưng hãy lưu ý rằng phương thức Authorize() hiện trả về true thay vì false. Phương pháp này quyết định có cho phép yêu cầu đi vào ứng dụng hay không. Nếu nó được đặt thành sai, nó sẽ dừng yêu cầu vào hệ thống (thường là một phương thức trên bộ điều khiển). Đây sẽ là một nơi rất thuận tiện để thực hiện bất kỳ kiểm tra ủy quyền nào đối với người dùng hoặc bất kỳ logic nào khác có thể quyết định xem yêu cầu có thể chuyển tiếp tới bộ điều khiển hay không. Hiện tại, chúng tôi chỉ trả về true ở đây để cho phép mọi thứ và mọi thứ sử dụng yêu cầu.

Phương pháp khác, quy tắc () là nơi tất cả các điều kỳ diệu phát huy tác dụng liên quan đến việc xác thực. Ý tưởng rất đơn giản: trả về một mảng chứa một bộ quy tắc có dạng:

'formFieldName' => 'constraints this field has separated by pipe characters (|)'

Có nhiều ràng buộc xác thực khác nhau được Laravel hỗ trợ ngay từ đầu. Để biết danh sách đầy đủ, hãy xem tài liệu trực tuyến vào đây. Đối với ứng dụng tải lên của chúng tôi, sẽ có hai trường được truyền vào qua yêu cầu POST từ một biểu mẫu ở giao diện người dùng. Tham số fileName phải được bao gồm bên trong phần thân biểu mẫu (tức là bắt buộc) và được sử dụng làm tên tệp mà chúng tôi sẽ lưu trữ tệp bên trong bộ lưu trữ (điều này được thực hiện trong bộ điều khiển - chúng tôi sẽ tìm hiểu về nó sau một chút). Chúng tôi cũng chỉ định rằng tên tệp phải là một chuỗi bằng cách thêm ký tự đường ống (|) và từ 'chuỗi'. Các ràng buộc luôn được phân định bằng đường ống, cho phép bạn chỉ định bất kỳ tiêu chí bổ sung nào cho trường đã cho trong một dòng! Thật tuyệt vời!

Tham số thứ hai, userFile , là tệp thực tế mà người dùng tải lên từ một biểu mẫu trên trang web. UserFile cũng được yêu cầu và phải là một tập tin. Lưu ý: Nếu chúng tôi mong đợi tệp đã tải lên là một hình ảnh thì thay vào đó, chúng tôi sẽ sử dụng ràng buộc hình ảnh, điều này sẽ giới hạn các loại tệp được chấp nhận là một trong những loại hình ảnh phổ biến (jpeg, png, bmp, gif hoặc svg). Vì chúng tôi muốn cho phép người dùng tải lên bất kỳ loại tệp nào nên chúng tôi sẽ chỉ tuân theo ràng buộc xác thực tệp.

Đó là tất cả những gì có về đối tượng yêu cầu. Công việc chính của nó chỉ đơn giản là giữ bộ tiêu chí (ràng buộc) có thể chấp nhận được mà các tham số nội dung của biểu mẫu phải đáp ứng để tiến sâu hơn vào ứng dụng. Một điều cần lưu ý nữa là hai trường này (userFile và filename) cũng phải được chỉ định bên trong mã HTML dưới dạng trường đầu vào (với tên trường tương ứng với tên bên trong đối tượng yêu cầu).

Bạn có thể hỏi: chắc chắn điều này xác định các đặc điểm của những gì một yêu cầu biểu mẫu nên chứa, nhưng việc kiểm tra thực tế những ràng buộc này được thực hiện ở đâu? Chúng ta sẽ đi sâu vào vấn đề đó tiếp theo.

Sửa đổi bộ điều khiển

Mở app/Http/Controllers/UploadController và thực hiện những thay đổi sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\Request;
use App\Http\Requests\UploadFileRequest; //our new request class
use Illuminate\Support\Facades\Storage; 

class UploadController extends Controller
{
   /**
    * This is the method that will simply list all the files uploaded by name and provide a
    * link to each one so they may be downloaded
    *
    * @param $request : A standard form request object
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function list(Request $request)
   {
       $uploads = Storage::allFiles('uploads');

       return view('list', ['files' => $uploads]);
   }

   /**
    * @param $file
    * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
    * @throws BindingResolutionException
    */
   public function download($file)
   {
       return response()->download(storage_path('app/'.$file));
   }

   /**
    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
    * @throws BindingResolutionException
    */
   public function upload()
   {
       return view('upload');
   }

   /**
    * This method will handle the file uploads. Notice that the parameter's typehint
    * is the exact request class we generated in the last step. There is a reason for this!
    *
    * @param $request : The special form request for our upload application
    * @return array|\Illuminate\Http\UploadedFile|\Illuminate\Http\UploadedFile[]|null
    * @throws BindingResolutionException
    */
   public function store(UploadFileRequest $request)
   {
       //At this point, the parameters passed into the $request (from form) are
       //valid--they satisfy each of the conditions inside the rules() method

       $filename = $request->fileName;    //parameters have already been validated
       $file = $request->file('userFile'); //that we don't need any additional isset()

       $extension = $file->getClientOriginalExtension(); //grab the file extension
       $saveAs = $filename . "." . $extension; //filename to save file under

       $file->storeAs('uploads', $saveAs, 'local'); //save the file to local folder

       return response()->json(['success' => true]); //return a success message
   }
}

Vì vậy, đây là một cách tiếp cận khá đơn giản để lưu các tệp đã tải lên vào đĩa. Đây là bảng phân tích của phương thức upload() ở trên:

  • Gõ gợi ý lớp yêu cầu trong phương thức điều khiển đang thực hiện chức năng 'thịt và khoai tây' để chúng tôi có thể tự động xác thực dữ liệu đến
  • Lấy tệp ra khỏi đối tượng yêu cầu (hiện đã được xác thực) bên trong phương thức điều khiển (trong trường hợp này chúng tôi đặt tên là upload() nhưng nó cũng có thể được đặt tên theo tên chuẩn hơn như store()).
  • Lấy tên tệp ra khỏi yêu cầu
  • Tạo tên tệp cuối cùng sẽ được sử dụng để lưu tệp bên dưới. Phương thức getClientOriginalExtension() chỉ cần lấy phần mở rộng gốc của tệp đã tải lên.
  • Lưu trữ tệp vào hệ thống tệp cục bộ bằng phương thức storeAs() của nó, chuyển vào đường dẫn được đặt tên bên trong thư mục /storage làm đối số thứ nhất và tên tệp để lưu nó làm đối số thứ hai.
  • Trả về phản hồi JSON cho biết yêu cầu đã thành công

Mẫu lưỡi dao

Mảnh ghép quan trọng cuối cùng của câu đố này là mẫu blade, sẽ chứa tất cả HTML, CSS và javascript cho ứng dụng đơn giản của chúng ta. Đây là mã - Chúng tôi sẽ giải thích sau.

<body>
   <h1>Upload a file</h1>
   <form id="uploadForm" name="uploadForm" action="{{route('upload')}}" enctype="multipart/form-data">
       @csrf
       <label for="fileName">File Name:</label>
       <input type="text" name="fileName" id="fileName" required /><br />
       <label for="userFile">Select a File</label>
       <input type="file" name="userFile" id="userFile" required />
       <button type="submit" name="submit">Submit</button>
   </form>
   <h2 id="success" style="color:green;display:none">Successfully uploaded file</h2>
   <h2 id="error" style="color:red;display:none">Error Submitting File</h2>
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
   <script>
        $('#uploadForm').on('submit', function(e) {
            e.preventDefault();
            var form = $(this);
            var url = form.attr('action');
            $.ajax({
                url: url,
                type: "POST",
                data: new FormData(this),
                processData: false,
                contentType: false,
                dataType: "JSON",
                success: function(data) {
                    $("#fileName").val("");
                    $("#userFile").val("");
                }
            }).done(function() {
                $('#success').css('display', 'block');
                window.setTimeout(()=>($("#success").css('display', 'none')), 5000);
            }).fail(function() {
                $('#error').css('display', 'block');
                window.setTimeout(()=>($("#error").css('display', 'none')), 5000);
            });
        });
   </script>
</body>
</html>

Đây là những gì chúng tôi /tải lên trang trông giống như:

Mẫu lưỡi dao

Đây là một ví dụ rất điển hình về tệp blade chứa biểu mẫu HTML và javascript/jQuery để thêm chức năng không đồng bộ (do đó trang không làm mới). Có một thẻ không có thuộc tính phương thức (tôi sẽ giải thích sau một giây) và có thuộc tính hành động kỳ lạ với giá trị {{route('file.upload')}}. Trong blade, đây là thứ được gọi là Chỉ thị. Lệnh chỉ là một cái tên ưa thích cho hàm – chúng là các hàm dành riêng cho các mẫu phiến thực hiện các hoạt động khác nhau phổ biến để xây dựng các trang web và ứng dụng web. Để hiểu rõ hơn về tất cả những điều thú vị mà lưỡi kiếm có thể làm, hãy xem tài liệu vào đây. Trong trường hợp trên, chúng tôi đang sử dụng chỉ thị tuyến đường để tạo URL cho việc gửi biểu mẫu của mình.

Hãy nhớ rằng chúng ta đã xác định các tuyến đường trước đó trong ứng dụng bên trong tệp web.php, chỉ định tên dễ nhớ cho mỗi tuyến đường. Lệnh {{route()}} chấp nhận tên của một tuyến đường, tra cứu nó trong danh sách các tuyến đường được lưu trong bộ nhớ đệm nội bộ và tạo một URL đầy đủ dựa trên định nghĩa của tuyến đường đó trong tệp web.php. Đối với trường hợp đầu tiên này, chúng tôi xác định rằng chúng tôi muốn biểu mẫu gửi dữ liệu đã gửi đến URL /process của ứng dụng của chúng tôi, được xác định là một POST tuyến đường.

Điều kỳ lạ tiếp theo mà bạn có thể nhận thấy là thẻ @csrf ngay bên dưới thẻ biểu mẫu mở. Trong Blade, thẻ này tạo ra một tham số _token trên biểu mẫu, tham số này được kiểm tra bên trong ứng dụng trước khi dữ liệu biểu mẫu được phép xử lý. Điều này đảm bảo rằng dữ liệu bên trong biểu mẫu có nguồn gốc hợp lệ và ngăn chặn các cuộc tấn công giả mạo yêu cầu trên nhiều trang web. Để biết thêm thông tin về điều này, hãy xem tài liệu.

Sau này, chúng tôi xác định biểu mẫu của mình như bình thường, tuy nhiên, xin lưu ý rằng tên của các tham số biểu mẫu, userFile và fileName là hoàn toàn giống nhau như được định nghĩa bên trong đối tượng yêu cầu của chúng tôi. Nếu chúng tôi quên bao gồm đầu vào cho một tham số nhất định đã được xác định trong đối tượng yêu cầu (hoặc viết sai chính tả), yêu cầu sẽ không thành công và lỗi sẽ được trả về, ngăn không cho yêu cầu biểu mẫu ban đầu chạm vào phương thức điều khiển có tại UploadController@ quá trình .

Hãy tiếp tục dùng thử và gửi một vài tệp tới ứng dụng bằng biểu mẫu này. Sau đó, điều hướng đến /danh sách để xem nội dung của thư mục tải lên, với các tệp bạn đã tải lên được liệt kê trong bảng:

Mẫu lưỡi dao

The Bigger Picture

Hãy lùi lại một bước và xem những gì chúng ta đã làm trong hướng dẫn Laravel này.

Sơ đồ này mô tả ứng dụng ở thời điểm hiện tại (không bao gồm các chi tiết cấp cao):

Sơ đồ hướng dẫn Laravel

Bạn nên nhớ lại rằng đối tượng yêu cầu mà chúng ta đã xây dựng ở phần đầu của hướng dẫn Laravel này phải có cùng các tham số được xác định trong phương thức quy tắc của nó giống như trên biểu mẫu trong mẫu phiến (nếu không đọc lại phần “Tạo logic xác thực”) . Người dùng nhập biểu mẫu vào một trang web được hiển thị thông qua công cụ mẫu phiến (tất nhiên quá trình này là tự động điều khiển nên chúng tôi thậm chí không cần phải suy nghĩ về nó) và gửi biểu mẫu. Mã jQuery của mẫu ở dưới cùng dừng việc gửi mặc định (sẽ tự động chuyển hướng đến một trang riêng), tạo yêu cầu ajax, tải yêu cầu với dữ liệu biểu mẫu và tải tệp lên rồi gửi toàn bộ nội dung vào lớp đầu tiên của chúng tôi ứng dụng: yêu cầu.

Đối tượng yêu cầu được điền bằng cách liên kết các tham số bên trong phương thức Rules() với các tham số của biểu mẫu đã gửi, sau đó xác thực dữ liệu theo từng quy tắc được chỉ định. Nếu tất cả các quy tắc đều được thỏa mãn, yêu cầu sẽ được chuyển đến bất kỳ phương thức điều khiển nào tương ứng với các giá trị được xác định trong tệp tuyến web.php. Trong trường hợp này, chính phương thức process() của UploadController thực hiện công việc. Sau khi nhấn bộ điều khiển, chúng tôi đã biết rằng yêu cầu đã vượt qua xác thực nên chúng tôi không phải kiểm tra lại xem tên tệp đã cho trên thực tế có phải là một chuỗi hoặc tham số userFile thực sự chứa một số loại tệp hay không… Chúng tôi có thể tiếp tục như Bình thường.

Sau đó, phương thức điều khiển lấy các tham số đã được xác thực ra khỏi đối tượng yêu cầu, tạo tên tệp đầy đủ bằng cách nối tham số fileName đã truyền với phần mở rộng ban đầu của userFile, lưu trữ tệp bên trong một thư mục trong ứng dụng của chúng ta, sau đó trả về một mã hóa JSON đơn giản phản hồi xác minh rằng yêu cầu đã thành công. Logic jQuery nhận được phản hồi, logic này thực hiện thêm một số tác vụ liên quan đến giao diện người dùng như hiển thị thông báo thành công (hoặc lỗi) trong 5 giây rồi ẩn nó cũng như xóa các mục nhập biểu mẫu trước đó…điều này là để người dùng biết chắc chắn rằng yêu cầu đã thành công và có thể tải lên một tệp khác nếu họ muốn.

Ngoài ra, hãy lưu ý trong sơ đồ ở trên chính xác nơi đường phân cách giữa máy khách và máy chủ. Khái niệm này hoàn toàn quan trọng để bạn hiểu và sẽ giúp bạn giải quyết các vấn đề và sự cố mà bạn có thể gặp phải trong tương lai khi xử lý, ví dụ, nhiều yêu cầu không đồng bộ có thể xảy ra tại bất kỳ thời điểm nào. Sự phân tách nằm ngay tại ranh giới của đối tượng yêu cầu. Bản thân đối tượng yêu cầu có thể được coi là "cổng" đến phần còn lại của ứng dụng… Nó thực hiện xác thực ban đầu và đăng ký các giá trị biểu mẫu được truyền vào từ trình duyệt web. Nếu chúng được coi là hợp lệ, thì nó sẽ tiếp tục đến bộ điều khiển. Mọi thứ trước đó đều ở phía trước (theo nghĩa đen, "máy khách" có nghĩa là "trên máy tính của người dùng"). Phản hồi được trả về từ ứng dụng trở lại phía máy khách, nơi mã jQuery của chúng ta kiên nhẫn lắng nghe sự xuất hiện của nó và thực hiện một vài tác vụ UI đơn giản sau khi nhận được.

Chúng tôi đã đề cập đến gần 90+ câu hỏi quan trọng thường gặp Câu hỏi phỏng vấn liên quan đến Laravel và PHP dành cho sinh viên mới ra trường cũng như những ứng viên có kinh nghiệm để có được công việc phù hợp.