12/08/2018, 15:11

Tìm hiểu Laravel từ số 0 (P5)

Trong phần 4 chúng ta đã đi đến nội dung về Mutators, ở phần này tôi sẽ tiếp tục với các nội dung mới sau đây : Seeding MVC Install Bootstrap 3 Create Form Với Laravel bạn có thể dùng command artisan db:seed để có thể sinh ra những dữ liệu khởi tạo vào DB. Việc này sẽ giúp cho công ...

Trong phần 4 chúng ta đã đi đến nội dung về Mutators, ở phần này tôi sẽ tiếp tục với các nội dung mới sau đây :

  • Seeding
  • MVC
  • Install Bootstrap 3
  • Create Form

Với Laravel bạn có thể dùng command artisan db:seed để có thể sinh ra những dữ liệu khởi tạo vào DB. Việc này sẽ giúp cho công việc tạo dữ liệu sample sử dụng cho development được nhanh hơn. Tôi sẽ tạo ra dữ liệu ví dụ vào bảng articles trong bài này.

DATABASESEEDER File

Để mà làm được việc đó thì ta sẽ cần thay đổi file bên dưới :

database
└── seeds
    └── DatabaseSeeder.php
<?php // database/seeds/DatabaseSeeder.php use IlluminateDatabaseSeeder; use IlluminateDatabaseEloquentModel; ```PHP class DatabaseSeeder extends Seeder { public function run() { Model::unguard(); // ① // $this->call('UserTableSeeder'); Model::reguard(); // ② } } ``` ①unguard() là phương thức sẽ thiết lập tắt đi mass assignment của Eloquent. ②reguard() là phương thức sẽ bật lại chức năng đó. ## Ví dụ ```PHP <?php // database/seeds/DatabaseSeeder.php use IlluminateDatabaseSeeder; use IlluminateDatabaseEloquentModel; use IlluminateSupportFacadesDB; use FakerFactory as Faker; use CarbonCarbon; use AppArticle; class DatabaseSeeder extends Seeder { public function run() // ① { Model::unguard(); $this->call('ArticlesTableSeeder'); // ② Model::reguard(); } } class ArticlesTableSeeder extends Seeder // ③ { public function run() { DB::table('articles')->delete(); // ④ $faker = Faker::create('en_US'); // ⑤ for ($i = 0; $i < 10; $i++) { // ⑥ Article::create([ 'title' => $faker->sentence(), 'body' => $faker->paragraph(), 'published_at' => Carbon::today() ]); } } } ``` Việc thực hiện cụ thể có ý nghĩa như dưới : ① Nếu thực hiện `php artisan db:seed` thì phương thức run() của lớp DatabaseSeeder sẽ được chạy. ② Từ trog phương thức đó sẽ gọi đến ArticlesTableSeeder. ③ Nếu mà với mỗi bảng ta tạo ra một lớp thì việc quản lý sẽ dễ dàng hơn. ④ Sử dụng Query Builder để xoá hết bản ghi (nếu có) trong bảng Articles. ⑤ Dùng Faker sẽ giúp ta tạo ra dummy data. ⑥ Và vòng lặp sẽ tạo ra số bản ghi mong muốn. ## Chạy SEED ```PHP $ php artisan db:seed Seeded: ArticlesTableSeeder ``` Để xác nhận kết quả lệnh trên ta có thể dùng `tinker` : ```PHP $ php artisan tinker >>> AppArticle::all()->toArray(); => [ [ "id" => "1", "title" => "Voluptates repellendus libero quia provident officiis laudantium nesciunt.", "body" => "Ut ab non dolor et nulla mollitia illo. Est quidem saepe adipisci magni unde pariatur animi. Porro vel laboriosam excepturi excepturi dolores. Non doloremque sapiente aut id.", "created_at" => "2015-02-24 17:35:48", "updated_at" => "2015-02-24 17:35:48", "published_at" => "2015-02-24 17:35:48" ], [ "id" => "2", "title" => "Accusamus ut repellendus reprehenderit explicabo eos qui qui nobis.", "body" => "Veritatis fugiat qui ut sint velit. Perspiciatis recusandae laudantium quo voluptatum aliquid distinctio rerum. Assumenda consequatur voluptas aut eos recusandae. Suscipit deleniti aliquid quaerat sapiente numquam consectetur nisi aliquam.", "created_at" => "2015-02-24 17:35:48", "updated_at" => "2015-02-24 17:35:48", "published_at" => "2015-02-24 17:35:48" ], ... ``` Rất đơn giản ! Bạn đã có một lượng dữ liệu theo ý muốn. # MVC ![](https://viblo.asia/uploads/ee5d2632-5089-413f-a5e9-2e53981e91fe.png) Ở các bài trước tôi chỉ nói đến phần hiển thị View từ Controller nhưng lần này tôi sẽ thông qua Model để lấy dữ liệu từ DB và truyền chúng đến View để hiện thị trên màn hình, hoàn thiện đủ flow mô hình MVC. ## ROUTING Tôi sẽ thêm vào file `routes.php` 2 dòng như dưới đây : ```PHP // app/Http/routes.php Route::get('articles', 'ArticlesController@index'); Route::get('articles/{id}', 'ArticlesController@show'); ``` Phần `{id}` ở đây là chỉ việc sẽ nhận vào tham số `id` trong phương thức `show()`. ## HIển thị danh sách bài viết ### CONTROLLER Chúng ta sẽ cần tạo `ArticlesController` và trong nó sẽ có 2 phương thức đã routing như ở trên. ```PHP php artisan make:controller ArticlesController --plain ``` ```PHP // app/Http/Controllers/ArticlesController.php use AppArticle; class ArticlesController extends Controller { public function index() { $articles = Article::all(); return view('articles.index', compact('articles')); } public function show($id) { return $id; } } ``` Phương thức `index()` ở đây sẽ lấy ra tất cả các bài trong bảng Articles để đưa lên View. Còn phương thức `show()` trước mắt là sẽ chỉ hiển thị ra `$id` mà đã nhận được qua tham số truyền đến. Sau đó ta sẽ tạo đến View `articles.index`. ```PHP   @extends('layout') @section('content') @foreach($articles as $article) <article>

<a href="{{ url('articles', $article->id) }}"> {{ $article->title }} </a>

<div class="body"> {{ $article->body }} </div> </article> @endforeach @endsection ``` Phần này đang kế thừa `layout` View mà đã tạo ra trước đây. Và bằng vòng lặp @foreach sẽ lặp lại việc tạo từng bài một. Riêng tiêu đề của bài thì tôi dùng Helper là `url` để gắn link chuyển đến trang với từng `id` một. Bạn hãy thử access vào địa chỉ `http://localhost:8000/articles` để xác nhận việc danh sách các bài có được hiển thị hay không. Nếu có thì bằng việc click vào tiêu đề bài nào sẽ dẫn đến trang hiển thị của bài đó. Nhưng lúc này ta chỉ thấy `id` của bài mà thôi. ### Hiển thị bài viết Do đó ta cần implement cho phương thức `show()` : ```PHP // app/Http/Controllers/ArticlesController.php class ArticlesController extends Controller { // ... public function show($id) { $article = Article::findOrFail($id); return view('articles.show', compact('article')); } } ``` Bằng việc dùng đến phương thức `findOfFail` tôi đang lấy ra bài viết theo `id` từ Articles. Kế đó sẽ làm View `articles.show`. ```PHP   @extends('layout') @section('content') <article> <div class="body">{{ $article->body }}</div> </article> @endsection ``` Giờ thì khi truy cập đến địa chỉ `http://localhost:8000/articles`, rồi click vào 1 bài bất kì nào, thay vì thấy `id` như trước bạn sẽ thấy được cả tiêu đề và nội dung của một bài viết. Đến đây ta đã hoàn thiện mô hình MVC trong Laravel. # Boostrap 3 Nhưng cái bạn thấy khi này chưa hề có CSS nào được thiết lập cả nên tôi sẽ đưa Boostrap3 vào để tinh chỉnh phần hiển thị màn hình. Về cách đưa boostrp vào ta có thể thực hiện theo một vài cách khác nhau. 1. Sử dụng Bootstrap CDN : Download về bản Bootstrap mà đã được biên dịch và đặt vào bên dưới thư mục `public`. 2. Sử dụng source code : Download source của Bootstrap đặt vào thư mục `resources/assets` rồi dùng `Elixir` để biên dịch và đặt vào thư mục `public`. 3. Cách thích hợp nhất nhưng nhiều bước nên cũng phức tạp nhất : Tôi sẽ nói ở bài sắp tới. Trong phạm vi bài này tôi sẽ dùng cách đơn giản nhất là qua Bootstrap CDN. Và khi đã xong hãy thử sửa lại `layout` View để xác nhận xem Bootstrap đã được chạy đúng chưa. ```PHP // resources/views/layout.blade.php <!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <title>My Blog</title>   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> </head> <body> <div class="container">  @yield('content') </div>   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> </body> </html> ``` ① Là bước thêm vào xử lý đọc CSS của Bootstrap CDN. ② Thêm vào `div.container` bao quanh `@yield(‘content’)`. Nếu mà chỉ định `class=”container”`thì Bootstrap sẽ hiển thị margin trái phải. Chi tiết hơn về Bootstrap thì bạn có thể tham khảo thêm ở trang chủ. ③ Thêm vào jQuery CDN và Javascript của Bootstrap CDN. Chỉ đơn giản như vậy là bạn đã kết thúc việc đưa Bootstrap vào sử dụng. Để thấy được sự thay đổi hãy vào lại `http://localhost:8000/articles/`, nếu bạn thấy bên trái phải có margin một khoảng trống thì đã ok rồi. Sự thay đổi này thực sự rất đơn giản, nhưng dần dần ở các bài sau khi tạo ra menu hay form bạn sẽ thấy rõ hơn tác dụng `làm đẹp` của Bootstrap. # Tạo Form ## Thêm vào gói LARAVELCOLLECTIVE/HTML Ở trên View của Laravel ta sẽ có hai cách thực hiện việc mô tả Form đó là trực tiếp viết HTML vào hoặc dùng đến các hàm của Helper. Còn trong bài này tôi sẽ cài đặt gói `laravelcollective/html`, sử dụng đến các hàm Helper. Gói này đã được tách riêng biệt từ bản Laravel 5 không còn đi kèm như bản 4 nữa. Và gói này được phát triển bởi cộng đồng sử dụng. http://laravelcollective.com/ Còn một gói khác là `illuminate/html` nhưng mà nó đã không còn được maintain nữa nên nếu bạn sử dụng thì hãy chú ý điều này. Trước tiên là cài đặt nó bằng `composer`. ```PHP composer require laravelcollective/html ``` Sau đó là sửa file `config/app.php` để cho gói `laravelcollective/html` vào. ```PHP <?php // config/app.php return [ // Đăng kí service, provider 'providers' => [ // ... CollectiveHtmlHtmlServiceProvider::class, // Thêm ], // Đăng kí Facade 'aliases' => [ // ... 'Form' => CollectiveHtmlFormFacade::class, // Thêm 'Html' => CollectiveHtmlHtmlFacade::class, // Thêm ], ]; ``` Đến đây bạn sẽ thấy phần service provider hay facade nhưng hãy tạm bỏ qua nó, cứ hiểu để thêm vào gói `laravelcollective/html` thì cần thiết lập những phần đó là được. ## ROUTING Ta cần thêm vào route đến ArticlesController@create như sau : ```PHP <?php // app/Http/routes.php // ... Route::get('articles', 'ArticlesController@index'); // Thêm Route::get('articles/create', 'ArticlesController@create'); // ① Route::get('articles/{id}', 'ArticlesController@show'); // (a) // ... ``` Điều bạn cần chú ý ở đây như tôi đã đánh dấu ở trên là phần ① cần ở trước (a). Nếu như không làm vậy thì khi mà có GET request đến `articles/create` phần `articles/{id}` sẽ match trước mất, nên `ArticlesController@show` sẽ được thực thi. Vì thứ tự route là matching từ trên xuống. ## CONTROLLER Ta sẽ implement phương thức `create` trong `ArticlesController.php`. Đơn giản chỉ là hiển thị ra View. ```PHP <?php namespace AppHttpControllers; // app/Http/Controllers/ArticlesController.php // ... class ArticlesController extends Controller { // ... public function create() { return view('articles.create'); } } ``` ## VIEW Bạn hãy tạo mới file `create.blade.php` như dưới đây : ```PHP // resources/views/articles/create.blade.php @extends('layout') @section('content') {!! Form::open() !!} <div class="form-group"> {!! Form::label('title', 'Title:') !!} {!! Form::text('title', null, ['class' => 'form-control']) !!} </div> <div class="form-group"> {!! Form::label('body', 'Body:') !!} {!! Form::textarea('body', null, ['class' => 'form-control']) !!} </div> <div class="form-group"> {!! Form::label('published_at', 'Publish On:') !!} {!! Form::input('date', 'published_at', date('Y-m-d'), ['class' => 'form-control']) !!} </div> <div class="form-group"> {!! Form::submit('Add Article', ['class' => 'btn btn-primary form-control']) !!} </div> {!! Form::close() !!} @endsection ``` Bạn có nhận ra sự mới mẻ trong chỗ này. Thứ nhất là mô tả {!! XXX !!}, nó là mô tả của blade template, sử dụng khi mà hiển thị ra kết quả đã được PHP xử lý. Trước bạn đã gặp dạng mô tả `{{ XXXX }}` nhưng mà `{!! XXXX !!}` có cái khác là không xử lý escape. Lý do là vì lần này HTML của Form được sinh ra bằng PHP nên không cần phải escape. Thứ hai là mô tả `Form::XXX`, phần này có nghĩa là bạn đang dùng đến gói `laravelcollective/html` đã cài đặt bước trên rồi. Dù nhìn qua thì nó đang gọi đến phương thức static của lớp Form nhưng thực ra là đang gọi đến instance method của lớp `CollectiveHtmlFormBuilder`. Ở đây ta dùng một cái tên gọi khác là `alias`, có thể hiểu là nó đang access vào instance của `CollectiveHtmlFormBuilder` - đây gọi là Facade. Hãy cùng đi vào chi tiết : * Tạo tag bắt đầu của form : Form::open() * Tạo tag kết thức của form : Form::close() * Tạo tag label : Form::label() * Tạo tag input : Form::input() input * Tạo tag là input[type=text] : Form::text() * Tạo rag textarea : Form::textarea() * Tạo tag là input[type=submit] : Form::submit() Bạn có thể xem chi tiết hơn nữa ở trên docs API reference theo link dưới. http://laravelcollective.com/docs/5.1/html Và việc chỉ đinh `class=”xxxx”` ở đây là việc chỉ định class của Bootstrap3 đã được đưa vào ở phần bên trên. Lúc này form của bạn sẽ được đẹp hơn so với mặc định. Hãy vào `http://localhost:8000/articles/create` để xem. Còn phần source bạn có thể View Source sẽ thấy HTMK như sau : ```PHP <form method="POST" action="http://localhost:8000/articles/create" accept-charset="UTF-8"> <input name="_token" type="hidden" value="pEUyvKqFqjlcEfh2lvIkGEeI3rWAAwdbgo3XicvW"> <div class="form-group"> <label for="title">Title:</label> <input class="form-control" name="title" type="text" id="title"> </div> <div class="form-group"> <label for="body">Body:</label> <textarea class="form-control" name="body" cols="50" rows="10" id="body"></textarea> </div> <div class="form-group"> <label for="published_at">Publish On:</label> <input class="form-control" name="published_at" type="date" value="2015-03-04" id="published_at"> </div> <div class="form-group"> <input class="btn btn-primary form-control" type="submit" value="Add Article"> </div> </form> ``` Hãy để ý phần `method` đã được thiết lập là `POST`, phần ` action` được thiết lập URL hiện tại nhưng ta sẽ thay đổi ngay sau đây. ## Save Khi mà Form được Submit thì sẽ thực hiện xử lý đến DB. Hãy thêm route đến `ArticlesController@store` và lưu ý là sẽ dùng `POST` chứ không dùng `GET`. ```PHP <?php // app/Http/routes.php // ... Route::get('articles', 'ArticlesController@index'); Route::get('articles/create', 'ArticlesController@create'); Route::get('articles/{id}', 'ArticlesController@show'); // Thêm Route::post('articles', 'ArticlesController@store'); // ... ``` Tiếp đến phần implement phương thức `store` trong `ArticlesController.php`. ```PHP <?php namespace AppHttpControllers; use AppArticle; use AppHttpControllersController; class ArticlesController extends Controller { // ... public function create() { return view('articles.create'); } public function store() { // ① Get giá trị vào của Form $inputs = Request::all(); // ② Sử dụng Mass assignment tạo bài viết trong DB Article::create($inputs); // ③ Chuyển hướng đến danh sách bài viết return redirect('articles'); } } ``` ① Ở phần `Request::all()` này đang lấy ra tất cả giá trị nhập vào của Form. Lớp `Request` này cũng là một Facade - `Illuminate/Http/Request`. Và vì ta cần phải chỉ định nó như là một lớp global để dùng lớp Facade ở trong controller name space nên bạn đừng quên gắn thêm dấu gạch ngược `` ở trước tên lớp. Chi tiết hơn bạn có thể tham khảo theo link dưới. http://laravel.com/docs/5.1/requests http://laravel.com/api/5.1/Illuminate/Http/Request.html ② Tôi dùng chức năng Mass assignment đã từng đề cập trong bài trước để tạo dữ liệu vào bảng Articles, bạn chú ý đừng quên thiết lập biến `fillable` ở Article model. ③ Cuối cùng sau khi thực hiện xong lưu trữ bài viết, ta chuyển hướng người dùng đến danh sách để có thể xem được kết quả bằng cách dùng hàm `redirect()`. Và tôi sẽ đi sửa một chút file View `create.blade.php` đã tạo thành : ```PHP // resources/views/articles/create.blade.php // ... {!! Form::open(['url' => 'articles']) !!} // Truyền tham số vào Form::open() để chỉ định url sẽ mở // ... ``` Khi bạn xác nhận nội dung của HTML đươc tạo ra nó sẽ như sau : ```PHP <form method="POST" action="http://localhost:8000/articles" accept-charset="UTF-8"> ... ``` Bạn thấy `url` của `action` đã được thay đổi, khi mà click submit thì phướng thức `ArticlesController@store` được thực hiện. Tôi sẽ đặt một nút dùng để tạo mới bài viết ở trên danh sách như sau : ```PHP // resources/views/articles/index.blade.php @extends('layout') @section('content') {!! link_to('articles/create', 'Add new article', ['class' => 'btn btn-primary']) !!} @foreach($articles as $article) ... ... @endforeach @stop ``` Dùng hàm `link_to` sẽ tạo ra một tag link dẫn đến `articles/create` và kết hợp với lớp của bootstrap3 sẽ tạo style cho link thành giống một nút. Đến đây ta đã hoàn tất những màn hình, chức năng từ danh sách, nút tạo mới, màn hình tạo mới bài viết rồi tạo xong sẽ chuyển hướng người dùng về lại danh sách để xem kết quả.
0