Xây dựng website bán hàng bằng Laravel - Tổ chức và Phân loại Sản phẩm

Ngày đăng
Tác giả
Tran Thanh Long

Một sản phẩm có thể nằm trong một hoặc nhiều danh mục khác nhau. Để phân phối sản phẩm vào các danh mục chúng ta cần thêm một tính năng trong phần quản lý sản phẩm, hãy cùng tìm hiểu cách thực hiện trong bài viết này nhé!


E-commerce với Laravel là loạt bài ghi lại toàn bộ quá trình xây dựng hệ thống thương mại điện tử được thực hiện bởi Transmoni team nhắm hướng dẫn mọi người làm quen với Laravel, Livewire, Alpine.js và Tailwind CSS. Hiện dự án đang được cập nhật liên tục, toàn bộ mã nguồn của dự án sẽ được công khai miễn phí theo hình thức mã nguồn mở trên trang Github của Transmoni sau khi hoàn tất loạt bài hướng dẫn này.

Quay trở lại với bài viết Xây dựng Danh mục cho Sản phẩm chúng ta đã có thể tạo danh sách các danh mục cần có trong website thương mại điện tử của mình. Việc tiếp theo cần làm là thêm tính năng để tổ chức và phân loại sản phẩm theo danh mục hoặc theo thương hiệu. Tuy nhiên hiện tại chúng ta mới chỉ có phần danh mục nên trước hết hãy tập trung vào phân loại theo danh mục trước nhé!

Nếu như bạn để ý trong phần tạo migration tại bài viết Xây dựng thông tin sản phẩm chúng ta không có cột dành riêng cho việc xử lý quan hệ giữa sản phẩm và danh mục. Lý do là vì một sản phẩm có thể nằm trong một hoặc nhiều danh mục và ngược lại một danh mục sẽ có nhiều sản phẩm khác nhau (quan hệ n-n), vì vậy chúng ta sẽ cần tạo một bảng mới trên cơ sở dữ liệu để quản lý mối quan hệ này.

Bắt đầu tạo migration với make:migration

php artisan make:migration create_category_product_table

Chúng ta sẽ không cần sử dụng đến model để quản lý bảng này vì nó chỉ đóng vai trò là trung gian lưu trữ các khóa ngoại đến hai bảng categoriesproducts mà thôi. Nội dung của nó sẽ như sau:

public function up()
{
    Schema::create('category_product', function (Blueprint $table) {
        $table->foreignIdFor(\App\Models\Category::class)->constrained()->cascadeOnDelete();
        $table->foreignIdFor(\App\Models\Product::class)->constrained()->cascadeOnDelete();
    });
}

Và chạy migrate để tiến hành tạo bảng

php artisan migrate

Tiếp đến chúng ta tiến hành khai báo về mối quan hệ giữa sản phẩm và danh mục như sau:

tại App/Models/Category.php:

public function products(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
    return $this->belongsToMany(Product::class);
}

App/Models/Product.php:

public function categories(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
    return $this->belongsToMany(Category::class);
}

Ok, vậy là xong phần cơ sở dữ liệu và thiết lập quan hệ. Tiếp theo chúng ta sẽ tạo livewire component để thực hiện thao tác gán sản phẩm vào các danh mục đã tạo. Bắt đầu bằng lệnh livewire:make:

php artisan livewire:make ProductOrganization

Tiến hành khai báo biến $product như thường lệ, và tại phương thức render lúc này chúng ta thực hiện nhúng danh sách toàn bộ các danh mục đã tạo với biến $categories để tạo một select box trên phần quản lý như sau:

class ProductOrganizationForm extends Component
{
    public Product $product;
    public $selectedCategories = [];

    public function mount()
    {
        $this->selectedCategories = $this->product->categories->pluck('id')->toArray();
    }

    public function save()
    {
        $this->product->categories()->sync($this->selectedCategories);
        $this->emitSelf('saved');
    }

    public function render()
    {
        return view('livewire.admin.product-organization-form', ['categories' => Category::all()]);
    }
}

Ngoài ra thì trên đây tôi cũng đồng thời khai báo một biến là $selectedCategories và truyền vào nó danh sách ID của các danh mục đã gán cho sản phẩm này, và một phương thức save để lưu lại các danh mục đã chọn.

Tại phần view của component này chúng ta sẽ tạo một html select với thuộc tính là multiple (chọn nhiều) như sau:

<div>
    <form wire:submit.prevent="save">
        <x-card class="-mx-4 mt-5 sm:-mx-0">
            <x-slot name="header">
                <div class="ml-4 mt-2">
                    <h3 class="text-lg leading-6 font-medium text-gray-900">Organization</h3>
                </div>
            </x-slot>
            <x-slot name="content">
                <div>
                    <x-label
                        for="categories"
                        value="{{ __('Categories') }}"
                    />
                    <x-select
                        wire:model.defer="selectedCategories"
                        class="mt-1 block w-full"
                        multiple
                    >
                        @foreach($categories as $category)
                            <option
                                value="{{ $category->id }}"
                                @selected(in_array($category->id, $product->categories->pluck('id')->toArray()))
                            >
                                {{ $category->name }}
                            </option>
                        @endforeach
                    </x-select>
                </div>
            </x-slot>
            <x-slot name="footer">
                <div class="flex items-center justify-end">
                    <x-action-message on="saved" class="mr-2" />
                    <x-primary-button wire:loading.attr="disabled">
                        {{ __('Save') }}
                    </x-primary-button>
                </div>
            </x-slot>
        </x-card>
    </form>
</div>

Để giải thích thêm một chút trong thẻ option, tại đây tôi sử dụng @checked blade directive và tiến hành kiểm tra nếu ID của danh mục có nằm trong danh sách các danh mục của sản phẩm đó hay không. Directive này sẽ tự động gán thuộc tính selected vào thẻ option của chúng ta nếu điều kiện kiểm tra cho ra kết quả đúng.

Và tiến hành nhúng view này vào view của ProductManager component

<div class="col-span-3 xl:col-span-1">
    <livewire:admin.product-organization-form :product="$product" />
</div>

Kết quả

Phân loại sản phẩm theo danh mục

Thông báo biến động số dư qua API & Webhook.

Hỗ trợ tích hợp giao dịch chuyển khoản vào hệ thống thanh toán trực tuyến Tự động, Nhanh chóng, Chính xác.

Đăng ký dùng thử trong 14 ngày
Bài viết mới nhất

Xây dựng website bán hàng bằng Laravel - Dựng trang thông tin Sản phẩm

Để Khách hàng có thể xem và tìm hiểu kỹ hơn về thông tin của một Sản phẩm bao gồm giá bán, số lượng tồn kho hay các mô tả về những đặc tính kỹ thuật ví dụ chất liệu, kiểu dáng... chúng ta sẽ cần đến một trang riêng cho mỗi sản phẩm, hãy cùng tìm hiểu cách để tạo một trang như vậy trong bài viết này.

Xây dựng website bán hàng bằng Laravel - Thiết lập và quản lý đơn hàng

Quản lý đơn hàng là quy trình back-end để quản lý và kiện toàn các đơn hàng trực tuyến. Việc này bao gồm mọi thứ từ định tuyến đơn hàng, in nhãn vận chuyển cho đến đến trả hàng cho khách. Trong bài viết của ngày hôm nay chúng ta sẽ cùng tìm hiểu cách để tạo và quản lý các đơn đặt hàng.