Tập tành Build Category đa cấp trong Laravel

2nd Nov 2022
Tập tành Build Category đa cấp trong Laravel
Table of contents

Sau 1 thời gian nghỉ code để tập trung làm việc cho công ty đa quốc gia trong chuyên ngành đa cấp và bây giờ ngay lúc này đây tôi đã quay trở lại và đồi bại hơn xưa với chủ đề Category đa cấp trong Laravel

Về hướng giải quyết có nhiều bạn sẽ nghĩ đến việc dùng đệ quy để làm . Đệ quy là phương pháp không được khuyến khích dùng cho lắm vì nó rất hao tốn tài nguyên. Vậy có cách nào khác tối ưu hơn để giải quyết việc này?

Hướng tôi đang muốn đề cập cho các bạn sau đây là dùng tree - tức là cấu trúc database sẽ theo cấu trúc cây nhị phân - 1 phương pháp khác để giải quyết bài toán này đó là ứng dụng của mô hình nested set model để xây dựng danh mục đa cấp, mô hình tạm thời nó sẽ thế này:

cay nhi phan

Ở đây Clothing là gốc và nó sẽ có mẹ tức parent_id là null, _lft = 1, rgt = 20, việc sắp xếp này ko phải ko theo quy luật nào, mà là từ trái qua phải, rồi từ dưới luồn lách lên trên rồi lại từ trái qua phải dưới lên trên ( ^^) cho đến hết tức là Sun Dresses và vòng về Clothing. Nói đến đây tôi tự cảm thấy nó khá loàng ngoàng nên quyết định quay lại với chủ đề chính:

Tôi đang dùng thư viện này để build

https://github.com/lazychaser/laravel-nestedset

Bạn nào thấy bài viết có ích hãy Donate cho tôi và tôi sẽ chuyển khoản lại cho tác giả của lib trên.

composer require kalnoy/nestedset

migrate cho nó

public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->increments('id');
            $table->string("name");
            NestedSet::columns($table);
            $table->timestamps();
        });
    }

bạn nhớ use thêm

use Kalnoy\Nestedset\NestedSet;

seed db cho em nó, phần này tôi lấy trong soucre code của ổng viết lib bên trên

public function run()
    {
        $data =  array(
            array('id' => 1, 'name' => 'store', '_lft' => 1, '_rgt' => 20, 'parent_id' => null, 'category_type' => 1),
                array('id' => 2, 'name' => 'notebooks', '_lft' => 2, '_rgt' => 7, 'parent_id' => 1, 'category_type' => 1),
                    array('id' => 3, 'name' => 'apple', '_lft' => 3, '_rgt' => 4, 'parent_id' => 2, 'category_type' => 2),
                    array('id' => 4, 'name' => 'lenovo', '_lft' => 5, '_rgt' => 6, 'parent_id' => 2, 'category_type' => 1),
                array('id' => 5, 'name' => 'mobile', '_lft' => 8, '_rgt' => 19, 'parent_id' => 1, 'category_type' => 1),
                    array('id' => 6, 'name' => 'nokia', '_lft' => 9, '_rgt' => 10, 'parent_id' => 5, 'category_type' => 1),
                    array('id' => 7, 'name' => 'samsung', '_lft' => 11, '_rgt' => 14, 'parent_id' => 5, 'category_type' => 1),
                        array('id' => 8, 'name' => 'galaxy', '_lft' => 12, '_rgt' => 13, 'parent_id' => 7, 'category_type' => 2),
                    array('id' => 9, 'name' => 'sony', '_lft' => 15, '_rgt' => 16, 'parent_id' => 5, 'category_type' => 1),
                    array('id' => 10, 'name' => 'lenovo', '_lft' => 17, '_rgt' => 18, 'parent_id' => 5, 'category_type' => 1),
            array('id' => 11, 'name' => 'store_2', '_lft' => 21, '_rgt' => 22, 'parent_id' => null, 'category_type' => 1),
        );
        \DB::table('categories')->insert($data);
    }

Model vẫn như thường lệ và bạn thêm

use Kalnoy\Nestedset\NodeTrait;

và có thêm vào function tùy biến name và set lại parent id

public function getLftName()
    {
        return '_lft';
    }

    public function getRgtName()
    {
        return '_rgt';
    }

    public function getParentIdName()
    {
        return 'parent_id';
    }

    // Specify parent id attribute mutator
    public function setParentAttribute($value)
    {
        $this->setParentIdAttribute($value);
    }

Tiếp đến sẽ là CategoryController

public function index()
    {
        $categories = Category::get()->toTree();
        $data = [
            'categories' => $categories
        ];
        return view('admin.category.index', $data);
    }

dữ liệu sẽ build ra dạng thế này, bạn tùy biến if else dưới view

cay nhi phan
public function store(CreateCategoryRequest $request)
    {
        if ($request->id) {
            $target =  Category::find($request->id);
            if($target) {
                $node = new Category([
                    'name' => $request->name
                ]);
                $node->appendToNode($target)->save();
            }
        } else {
            $category = Category::create([
                'name' => $request->name,
            ]);
        }

        return response()->json([
                'result' => 'OK',
            ], 200);
    }

Ở hàm store bạn phải phân biệt được việc tạo 1 node gốc mới (tức là parent_id = null) hay là thêm 1 node cho 1 node đã có (tức là parent_id = nút mẹ)
2 case đó nằm trong if else bên trên

public function update(UpdateCategoryRequest $request)
    {
        $category = Category::find((int)$request->id);
        if($category) {
            $category->name = $request->name;
            $category->save();
            return response()->json([
                'result' => 'OK',
            ], 200);
        }
    }

Việc update cần có id nên trong UpdateCategoryRequest bạn khai báo

id là required

Phần view tôi đang dùng thư viện này để build ra cây

https://dbushell.com/Nestable/

Bài viết tiếp theo nếu cố gắng sẽ làm về phần move kéo thả để cắt di chuyển 1 node. Hẹn gặp lại mọi người.

Bạn thấy bài viết này như thế nào?
1 reaction

Add new comment

Image CAPTCHA
Enter the characters shown in the image.

Related Articles

Danh sách này có 4 sản phẩm nên chưa cần phân trang, nếu số lượng sản phẩm lên đến vài chục sản phẩm

Hiện nay kiến trúc Microservices đang là chủ đề được cộng đồng Developer vô cùng quan tâm

Hôm nay chúng ta cùng tìm hiểu về Eloquent trong Laravel với mối quan hệ nhiều - nhiều (many to many relationship)

Kiểm soát hợp lí truy cập nội dung trang web là yếu tố quyết định trong việc điều hành một máy chủ bảo mật.

Trong lập trình web, authorization (phân quyền) là chức năng vô cùng quan trọng và không thể thiếu