Kiến trúc hệ thống trên Laravel – phần 10

Các bài viết trong series

Kiến trúc hệ thống trên Laravel – phần 1 : Tại sao phải áp dụng architect vào trong Laravel Kiến trúc hệ thống trên Laravel – phần 2 : OOP, Interface, Dependency Injection, IoC Kiến trúc hệ thống trên Laravel – phần 3 : Phân tích sâu vào việc sử dụng interface Kiến trúc hệ thống trên Laravel – phần 4 : Design Pattern – Decorator Kiến trúc hệ thống trên Laravel – phần 5 : Design Pattern – Adapter Kiến trúc hệ thống trên Laravel – phần 6 : Design Pattern – Repository Kiến trúc hệ thống trên Laravel – phần 7 : Design Pattern – Factory Kiến trúc hệ thống trên Laravel – phần 8 : Advance component trong Laravel Kiến trúc hệ thống trên Laravel – phần 9 : Mô hình kiến trúc cụ thể Part 1 Kiến trúc hệ thống trên Laravel – phần 10 : Mô hình kiến trúc cụ thể Part 2

Xin chào các bạn. Mình vào nghề lập trình cũng đã lâu, cũng có 1 số hiểu biết coi như là nâng cao về framework Laravel. Nên hôm nay mình xin chia sẻ 1 chút về kiến trúc hệ thống của mình được xây dựng trên Laravel như thế nào. Mong rằng có thể giúp ích cho các bạn 😃.


Nhắc lại phần trước, chúng ta đã tách ra được thành các phần xử lý khác nhau, nhưng với mục tiêu là tạo ra các component dạng plug n play – tức là khi cần thì cắm vào, ko cần thì bỏ đi – thì chúng ta chưa đạt được, còn cần phải copy paste bằng tay rất nhiều. Do vậy chúng ta phải đóng gói phần đã làm thành 1 package và install qua composer.

Điều kiện cần: các bạn đọc kỹ hướng dẫn tạo package của Laravel giúp mình https://laravel.com/docs/5.4/packages

Rồi, giờ chúng ta sẽ biến BookCRUD của phần trước thành package.

I. CHỈNH SỬA CODE

1. Tạo mới project laravel và install package “jeroen-g/laravel-packager” bằng câu lệnh sau:

composer require jeroen-g/laravel-packager

Rồi add dòng dưới đây vào providers array trong config/app.php

JeroenG\Packager\PackagerServiceProvider::class,

2. Tạo 1 package mới:

php artisan packager:new Laraviet BookCRUD

Chú ý: Laraviet sẽ là vendor name, còn BookCRUD sẽ là package name -> bạn sẽ cần phải update thông tin trong file “packages/Laraviet/BookCRUD/composer.json”

"name": "laraviet/book-crud",
"description": "Book CRUD package demo",
"authors": [
        {
            "name": "Nguyen Trung Thanh",
            "email": "[email protected]",
            "homepage": "http://portalbeanzvn.com",
            "role": "Technician"
        }
    ],

Những thông tin này là cần thiết để bạn có thể đăng ký với https://packagist.org/

Từ thời điểm này, chúng ta sẽ mặc định ở root folder là “packages/Laraviet/BookCRUD”, tất cả file và folder mình nói ở dưới sẽ trực thuộc root folder này nhá.

3. Tạo folder structure trong thư mục “src” tương ứng như sau

alt

Move file “src/BookCRUDServiceProvider.php” vào folder “src/Providers” và update namespace tương ứng

namespace Laraviet\BookCRUD\Providers;

4. Copy tất cả những file dưới đây (phần 9 chúng ta đã tạo) vào trong folder tương ứng. Kết quả cuối cùng sẽ được như sau

alt

5. Update tất cả namespace, import.

“Core\” –> “Laraviet\BookCRUD\”

Tip: Nếu sử dụng sublime text thì các bạn có thể sử dụng chức năng replace của editor này để replace all

alt

Tương tự chúng ta sẽ update:

“App\Http\Controllers” –> “Laraviet\BookCRUD\Controllers”

“App\Http\Requests” –> “Laraviet\BookCRUD\Requests”

Mở file “src/Models/Book.php” và update namespace thành

namespace Laraviet\BookCRUD\Models;

Mở file “src/Repositories/BookRepository.php” và sửa phần import thành:

use Laraviet\BookCRUD\Models\Book;

6. Update lại routes và thêm RouteServiceProvider

update “routes/web.php” chỉ giữ lại nội dung như sau

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::group(['middleware' => 'auth'], function () {
    Route::resource('/books', 'BooksController');
});

Thêm file “src/Providers/RouteServiceProvider.php” với nội dung sau:

<?php

namespace Laraviet\BookCRUD\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * This namespace is applied to your controller routes.
     *
     * In addition, it is set as the URL generator's root namespace.
     *
     * @var string
     */
    protected $namespace = 'Laraviet\BookCRUD\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        //

        parent::boot();
    }

    /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map()
    {
        //$this->mapApiRoutes();

        $this->mapWebRoutes();

        //
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(__DIR__ . '/../routes/web.php');
    }

    /**
     * Define the "api" routes for the application.
     *
     * These routes are typically stateless.
     *
     * @return void
     */
    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('api')
             ->namespace($this->namespace)
             ->group(__DIR__ . '/../routes/api.php');
    }
}

Các bạn đọc nội dung chắc cũng đoán được là file này dùng để áp namespace của package vào các routes tương ứng.

7. Chỉnh sửa lại nội dung file “Providers/BookCRUDServiceProvider.php”

<?php

namespace Laraviet\BookCRUD\Providers;

use Illuminate\Support\ServiceProvider;
use Laraviet\BookCRUD\Services\BookService;
use Laraviet\BookCRUD\Repositories\BookRepository;
use Laraviet\BookCRUD\Services\BookServiceContract;
use Laraviet\BookCRUD\Providers\RouteServiceProvider;
use Laraviet\BookCRUD\Repositories\BookRepositoryContract;

class BookCRUDServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        $package_name = "book-crud";

        //routes
        $this->loadRoutesFrom(__DIR__.'/../routes/web.php');

        //view
        $this->loadViewsFrom(__DIR__.'/../resources/views', $package_name);
        $this->publishes([
                __DIR__.'/../resources/views' => resource_path('views/vendor/' . $package_name),
            ]);

        //migrations
        $this->loadMigrationsFrom(__DIR__.'/../database/migrations');

        /*
        |--------------------------------------------------------------------------
        | Route Providers need on boot() method, others can be in register() method
        |--------------------------------------------------------------------------
        */
        $this->app->register(RouteServiceProvider::class);
    }

    /**
     * Register any package services.
     *
     * @return void
     */
    public function register()
    {
        // Binding from part 9
        $this->app->bind(BookRepositoryContract::class, BookRepository::class);
        $this->app->bind(BookServiceContract::class, BookService::class);
    }
}

Nếu các bạn đọc hướng dẫn package development của Laravel thì những đoạn code trên khá là dễ hiểu, chỉ là load route, view, migration từ trong package mà không cần phải đặt vào đúng vị trí folder default của Laravel -> chính vì vậy mà sau khi install package này và đăng ký provider trong Laravel, những thành phần trên sẽ tự động được load ^^.

8. Chỉnh sửa lại “src/Controllers/BookController.php”

thay đổi tất cả những đoạn có render view từ

return view(‘books….) –> return view(‘book-crud::books….)

** PHẦN CHỈNH SỬA CODE ** đến đây là chấm dứt. Các bạn có thể thử chạy lại ngay trong project hiện tại của mình xem package đã chạy ổn chưa. Nếu chạy ổn rồi thì làm theo hướng dẫn dưới đây để tạo 1 composer package mới của riêng mình

II. REGISTER COMPOSER PACKAGE

1. Push toàn bộ code trong package mới tạo bao gồm thư mục “src” lên trên github

Mình đã push code của mình lên đây: https://github.com/laraviet/BookCRUD

2. Đăng ký với packagist

Sau khi register và login xong thì bạn click vào nút submit và paste link github vào rồi nhấn button Check

alt

Sau đó hệ thống packagist sẽ đọc file composer.json của bạn và nhận ra package name, hệ thống sẽ thông báo, bạn thấy ok thì click nút submit là xong 🙂

alt

3. Config để auto update version

Ngay sau khi bạn submit package lên, sẽ có dòng thông báo này hiển thị ở sreen tiếp theo

alt

Bạn sẽ cần phải lấy token trong packagist và add hook vào trong github

Đầu tiên bạn vào profile của bạn trong packagist

alt

Click vào nút “Show Api Token” và copy token này

alt

Trở lại github, bạn vào phần setting của package

alt

Chọn “Integrations & services” rồi add packagist như theo hình vẽ

alt

Cuối cùng bạn chỉ cần paste lại token (bạn đã lưu từ packagist) vào rồi nhấn button “Add service” là xong

III. TEST LẠI PACKAGE VỚI NEW LARAVEL PROJECT

1. Tạo laravel project mới và chạy lại phần authen mặc định của Laravel (xem lại phần 9 để biết thêm chi tiết)

2. Cài đặt lại package mới được register ở packagist bằng câu lệnh

composer require laraviet/book-crud

3. Đăng ký package service provider bằng cách thêm vào config/app.php

Laraviet\BookCRUD\Providers\BookCRUDServiceProvider::class,

4. Chạy migration (nếu package có phần này)

 php artisan migrate

5. Test lại package bằng cách vào route tương ứng:

…./books

Verify lại các chức năng của package xem có chuẩn chưa.

Các bạn thấy không? Mình chỉ cần install package, update service provider và chạy migration là xong, toàn bộ các chức năng đã chạy được, hoàn toàn chẳng cần copy-paste gì –> mục tiêu plug n play đã đạt được ^^.


Cuối cùng cũng kết thúc được series. Mệt quá đi mất. Hi vọng mọi người đã rút ra được nhiều điều bổ ích cho bản thân.

Cũng xin nói thật với các bạn, các kiến thức mình nêu trong series không phải là quá cao siêu gì, nhưng mình tin răng cùng đã bổ sung được 1 vài phần tạm coi là khác với thường ngày cho các bạn. Các bạn nên rèn luyện hàng ngày để nhuyễn với các kiến thức trên trước khi ngâm cứu các kiến thức nâng cao khác. Mình nghĩ cách nâng cao skill tốt nhất là “chậm mà chắc”, làm tới đâu phải vững tới đấy.

Chúc các bạn tiến nhanh trên con đường đau khổ này ^^. Một lần nữa, cám ơn tất cả mọi người đã follow mình đi từ đầu tới cuối trong series này.