Khóa học Newnet Framework

Bài 2: Các thành phần cốt lõi trong NewNet Framework

Các thành phần cốt lõi được tạo ra nhằm khai báo những cấu trúc (Design Pattern) và thành phần quan trọng không thể thiếu. Lượt qua thư mục lib, ta thấy những module được chúng mình viết sẵn ở đây.

Hiện tại trong file composer.json chúng mình đã khai báo sẵn "newnetcms/cms": "dev-main" nên khi chạy composer install các module cũng như package require được cài theo. Dần dần mình sẽ nói tới những phần này.

Các module sẽ tìm hiểu trong phần này: admin, admin-ui, asset, base, core, dashboard.

Có 2 module adminbase dùng để cài những module cần thiết nhất mà không cần phải cài từng module nhỏ vào nên có thể bỏ qua.

Lưu ý: Đừng xóa bất cứ gì bên trong thư mục lib.

ADMIN-UI

Assets

Trong này được khai báo tất các thư viện script cũng như style. Khi cài đặt xong chúng ta chạy lệnh: php artisan cms:link-admin-ui  để link thư mục này ra ngoài public. Một số server không hỗ trợ Symlink chúng ta có thể copy ra folder public hoặc sử dụng php artisan vendor:publish và tìm đế phần module-assets. Lúc này hệ thống sẽ tự động bế đống này ra giúp chúng ta.

Blade

Vào phần views, chúng ta có thể thấy những file được khai báo sẵn là các thành phần dùng trong trang admin, và được chuẩn hóa.

Các thành phần trong partials nhìn tên chúng ta cũng có thể biết chức năng và nới nó được hiển thị. Những thành phần này được khai báo mặc định vào file master.blade.php

Các thành phần trong form sẽ được sử dụng thường xuyên và auto fill dữ liệu vào ứng với từng model và có thể custom dễ dàng. Những file này được sử dụng thường xuyên trong các form dữ liệu nên được khai báo alias bên trong Service Provider. Nếu bạn từng tìm hiểu về Service Provider thì thể xem cách khai báo cũng như nạp mọi thứ vào trong container. Những bạn mới tiếp vận với Laravel có thể chưa tiếp cận với những khái niệm này, vì laravel đã nạp sẵn cho chúng ta cả rồi. Nhưng khi phát triển hơn, chúng ta không thể viết mãi bên trong những cái sẵn như vậy. Sau này rất khó phát triển tiếp để mở rộng cũng như quá trình debug gặp nhiều khó khăn.

    @input(['name' => 'demo_text', 'label' => __('Text')])
    @textarea(['name' => 'demo_textarea', 'label' => __('Textarea')])
    @checkbox(['name' => 'demo_checkbox', 'label' => __('Checkbox')])

    @select(['name' => 'demo_select', 'label' => __('Select'), 'options' => theme_demo_options()])
    @selecth(['name' => 'demo_selecth', 'label' => __('Select 2'), 'options' => theme_demo_options()])
    @sumoselect(['name' => 'demo_sumoselect', 'label' => __('Sumo Select'), 'options' => theme_demo_options()])
    @sumoselect(['name' => 'demo_select_multiple', 'label' => __('Multiple Select'), 'options' => theme_demo_options(), 'multiple' => true])

    @dateinput(['name' => 'demo_dateinput', 'label' => __('Date')])
    @datetimeinput(['name' => 'demo_datetimeinput', 'label' => __('Date Time')])
    @daterangeinput(['name' => 'demo_daterangeinput', 'label' => __('Date Range')])
    @datetimerangeinput(['name' => 'demo_datetimerangeinput', 'label' => __('Date Time Range')])

    @input(['name' => 'demo_money', 'label' => __('Money'), 'mask' => 'money'])

    @editor(['name' => 'demo_editor', 'label' => __('Editor')])

    @mediamanager(['name' => 'demo_mediamanager', 'label' => __('Media Manager')])
    @mediafile(['name' => 'demo_image', 'label' => __('Image')])
    @gallery(['name' => 'demo_gallery', 'label' => __('Gallery')])

Cách sử dụng blade như bên trên. Đi sâu vào những blade ta có thể thấy chúng ta cần khai báo những tham số như: name, label hay options đối với kiểu blade select. Bắt buộc phải có biến $item sử dụng trên page hoặc truyền biến $item vào blade. Phần name tương ứng với thuộc tính của $item. Ở đây chúng ta hay sử dụng model.

Chúng ta có thể tìm đến những file _field.blade.php đang sử dụng, từ controller, truyền qua view, từ view include _field, rồi từ field sử dụng đến những blade alias.

Dần dần chúng ta sẽ tìm hiểu thêm.

Menu

Module admin ui đã khai báo sẵn menu facades, dùng để mở rộng menu trang quảng trị dễ dàng, hạn chế phải khai báo. Việc tạo menu facades giống như những cái hook, khi tạo module chỉ cần inject vào là được. Không cần phải tìm tới view header để thêm từng menu dùng cho module đó nữa.

Thông thường chúng ta chẳng cần phải đụng tới phần này, vì chỉ cần khai báo route là nó tự động rồi. Nâng cao hơn, thì có thể vào phần partials view đã nói bên trên tìm đến những phần menu và chỉnh sửa. Nhưng cần tuân thủ facade đã khai báo, nếu không nó sẽ lỗi ngay.

Đi vào module CMS, ta thấy file menus.php trong routes. Đây chính là nơi khai báo menu cho module trong trang quản trị. Và có đã được tự động nạp rồi.

Trong này ta chỉ cần khai báo để add những menu vào phần header thôi, không cần quan tâm nhiều đâu. Menu này được xây dựng theo cấu trúc parent-child và order. Dựa vào param truyền vào mà hiển thị và sắp xếp thứ tự của menu

AdminMenu::addItem(__('cms::module.module_name'), [
    'id' => CmsAdminMenuKey::CONTENT,
    'icon' => 'fas fa-newspaper',
    'order' => 4000,
]);

AdminMenu::addItem(__('cms::post.model_name'), [
    'id' => CmsAdminMenuKey::POST,
    'parent' => CmsAdminMenuKey::CONTENT,
    'route' => 'cms.admin.post.index',
    'icon' => 'fas fa-pen-alt',
    'order' => 1,
]);
  • id: là string và là duy nhất, dùng để phân biệt cũng như map với các giá trị parent
  • parent: là id của menu cha, khi khai báo tham số này đồng nghĩa trở trành submenu. Nếu không truyền tham số parent, thì nó sẽ được hiển thị trực tiếp trên thanh menu trong trang quản trị.
  • route: là đường dẫn
  • icon: hiển thị ngay trước label. Label là tham số đầu truyền vào hàm addItem()
  • order: Là thứ tự hiển thị của menu item xếp từ nhỏ đến lớn.
  • permission: nếu tài khoản không có quyền đã được khai báo ở đây, item sẽ bị ẩn. Dù có truy cập vào cũng sẽ bị đá ra.

ASSETS

Module này không phải chứa assets như module admin ui, mà nó dùng để khai báo cũng như tiêm các thư viện hay file style hoặc script vào theo đúng thứ tự mà ta mong muốn.

Hiểu nôm na, ta đang có file a kế thừa từ file b. File b đang khai báo script url x và y. Vì hệ thống cần tối ưu hóa mặt giao diện nên những file assets nào cần thiết mới import vào. Và bây giờ trong file a ta cần khai báo script url z. Chẳng may ta muốn nó nằm ở giữa phần khai báo x và y thì như thế nào. Vì mình đang kế thừa (sử dụng @yield() ) nên không thể chèn vào như vậy. Từ đó, module assets được sinh ra vì mục đích sắp xếp thứ tự nạp các file assets.

Có thể áp dụng trên toàn hệ thống từ phần quản trị đến người dùng nếu muốn. Đương nhiên cách import thông thường vẫn không có vấn đề gì đâu nha. Ta nên áp dụng asset facade trong trường hợp cần tối ưu tốc độ. Nếu cảm thấy tải thêm vài file asset cũng không ảnh hưởng gì thì thôi, khỏi áp dụng cũng được.

Ở đây ta cũng áp dụng 1 tính năng tương tự như alias của Blade, đó là directive và đã được khai báo sẵn bên trong AssetServiceProvider rồi.

Để sử dụng, ta chỉ cần khai báo @assetadd ở các trang view là được.

Khi gọi assetadd tức là gọi đến hàm add bên trong class Asset (Asset.php)

@assetadd('jquery', asset('vendor/newnet-admin/plugins/jQuery/jquery-3.4.1.min.js'))

/**
     * Add an asset to the container.
     * The extension of the asset source will be used to determine the type
     * of asset being registered (CSS or JavaScript). When using a non-standard
     * extension, the style/script methods may be used to register assets.
     * <code>
     *     // Add an asset to the container
     *     Asset::add('jquery', 'js/jquery.js');
     *     // Add an asset that has dependencies on other assets
     *     Asset::add('jquery', 'js/jquery.js', 'jquery-ui');
     *     // Add an asset that should have attributes applied to its tags
     *     Asset::add('jquery', 'js/jquery.js', null, array('defer'));
     * </code>
     *
     * @param  string|array  $name
     * @param  string  $source
     * @param  string|array  $dependencies
     * @param  string|array  $attributes
     * @param  string|array  $replaces
     * @return $this
     */
    public function add(
        $name,
        string $source = null,
        $dependencies = [],
        $attributes = [],
        $replaces = []
    ) {
        if ($source) {
            $type = (strpos(pathinfo($source, PATHINFO_EXTENSION), 'css') === 0) ? 'style' : 'script';

            return $this->$type($name, $source, $dependencies, $attributes, $replaces);
        }

        return $this;
    }

Khi add vào, asset sẽ được phân nhóm thành script hoặc style để nạp vào đúng vị trí được khai báo bên trong file master 

{!! Asset::styles() !!} {!! Asset::scripts() !!}

Và nó sẽ được nạp vào biến $assets thành một mảng các giá trị và phụ thuộc nên các bạn cần đảm bảo khai báo đúng các giá trị truyền vào. Chẳng có gì mới mẻ cả, chẳng qua chúng ta chưa biết ý tưởng thôi. NewNet xây dựng chức năng dựa trên ý tưởng về cách Laravel nạp các file ngôn ngữ thôi.

Dựa vào phần khai báo chúng ta có thể thấy, có 5 tham số truyền vào nhưng chúng ta chỉ cần quan tâm đến 4 tham số đầu, và đã có ví dụ bên trên. 

CORE

Ở phần core này, khai báo rất nhiều cái khó hiểu, nhưng các bạn không cần quan tâm chi đâu. Trong đó khai báo một số script cho những ý tưởng ban đầu, dần dần được update cho đơn giản hơn nên thành ra không cần dùng đến.

Cái chúng ta cần quan tâm ở đây là base repository đã khai báo sẵn những function cho chức năng crud. Nhờ đó, khi ta tạo module sẽ có sẵn những chức năng và hoạt động bình thường.

TranslatableTrait: đa ngôn ngữ  trong database và TreeCacheableTrait: cache modal cũng thường xuyên sử dụng.

DASHBOARD

Khi vừa vào trang chủ, những thứ được show ra chính là từ module dashboard này. Chúng ta có thể phát triển thêm từ đây bằng cách khai báo thêm các Dashboard bên trong phần src.

Sau này khi hệ thống phát triển thêm, ta có thể bỏ thêm các chart hay report vào đây.