+1

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

Seeding

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 Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
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 // database/seeds/DatabaseSeeder.php
 
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
 
use Faker\Factory as Faker;
use Carbon\Carbon;
use App\Article;
 
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 artisan db:seed
Seeded: ArticlesTableSeeder

Để xác nhận kết quả lệnh trên ta có thể dùng tinker :

$ php artisan tinker
>>> App\Article::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

Ở 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 :

// 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 artisan make:controller ArticlesController --plain
// app/Http/Controllers/ArticlesController.php
use App\Article;
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.

<!-- resouces/views/articles/index.blade.php -->
@extends('layout') 
@section('content')
    <h1>Articles</h1>
    <hr/>     
    @foreach($articles as $article)
        <article>
            <h2>
                <a href="{{ url('articles', $article->id) }}">
                    {{ $article->title }}
                </a>
            </h2>
            <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() :

// 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.

<!-- resouces/views/articles/show.blade.php -->
@extends('layout')
@section('content')
    <h1>{{ $article->title }}</h1>
    <hr/>
    <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.

// resources/views/layout.blade.php
<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>My Blog</title>
 
    <!-- ① Thêm CSS-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
 
<body>
    <div class="container"><!-- ② Thêm -->
        @yield('content')
    </div>
     
   <!-- ③ Thêm Scripts -->
    <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.

composer require laravelcollective/html

Sau đó là sửa file config/app.php để cho gói laravelcollective/html vào.

<?php
// config/app.php
return [
    // Đăng kí service, provider
    'providers' => [ 
        // ... 
        Collective\Html\HtmlServiceProvider::class,  // Thêm
    ],
 
    // Đăng kí Facade
    'aliases' => [
 
        // ...
 
        'Form' => Collective\Html\FormFacade::class,  // Thêm
        'Html' => Collective\Html\HtmlFacade::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
// 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 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 :

// resources/views/articles/create.blade.php 
@extends('layout') 
@section('content')
    <h1>Write a New Article</h1> 
    <hr/> 
    {!! 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 Collective\Html\FormBuilder. Ở đâ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 Collective\Html\FormBuilder - đâ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 :

<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
// 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 namespace AppHttpControllers;
use AppArticle;
use App\Http\ControllersController;
 
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 :

// 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 :

<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 :

// resources/views/articles/index.blade.php 
@extends('layout')
@section('content')
    <h1>Articles</h1>
    <hr/>
    {!! 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ả.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí