এক্সিস্টিং ল্যারাভেল প্রজেক্টে নতুন টেবিল যোগ করা

ল্যারাভেল নিয়ে আমরা অনেক গুলো প্রজেক্ট করেছি। যার সব গুলো পাওয়া যাবে বাংলায় ল্যারাভেল টিউটোরিয়াল পেইজে। যেমন আমরা ল্যারাভেলে মিনিমাল ইকমার্স অ্যাপ তৈরি করেছি। যেখানে কিভাবে সিম্পল একটা ইকমার্স অ্যাপ তৈরি করা যায়, তা শিখেছি। এর পর শিখেছি কিভাবে এই প্রজেক্টে ইমেজ নিয়ে কাজ করা যায়। এবার এই লেখায় আমরা দেখব কিভাবে ক্যাটেগরি যোগ করা যায়। যেন প্রোডাক্ট গুলো নির্দিষ্ট ক্যাটাগরি অনুযায়ী সাজানো যায়। প্রজেক্ট পাওয়া যাবে গিটহাবে। image নামক ব্রাঞ্চের কোড গুলোর উপর আমরা কাজ করব। গিট ব্যবহার করে কিভাবে আলাদা আলাদা ব্রাঞ্চে কাজ করা যায়, তা শেখা যাবে গিট সম্পর্কে ধারণা, গিট ইন্সটল, ব্যবহার লেখায়। এছাড়া কিভাবে অন্যের তৈরি ল্যারাভেল প্রজেক্টে কাজ করা যায়, তা শেখা যাবে ওপেন সোর্স ল্যারাভেল প্রজেক্ট ব্যবহার করা লেখায়।

প্রোডাক্টে ক্যাটাগরি যোগ করব নতুন একটা টেবিলের মাধ্যমে। এর আগে আমরা আরেকটা লেখায় পিভট নিয়ে কাজ করেছি। ল্যারাভেল পিভট টেবিল – নোট অ্যাপে ট্যাগ যোগ করা। যেখানে many-to-many রিলেশন নিয়ে কাজ করেছি। এই লেখায় one-to-many রিলেশন নিয়ে কাজ করব।

যেমন শুরুতে Category নামে একটা মডেল তৈরি করব। পাশা পাশি মাইগ্রেশন ফাইলও তৈরি করবঃ

php artisan make:model Category -m

প্রতিটা ক্যাটেগরির একটা নাম থাকবে। তাই …create_categories_table.php তে up() মেথড এভাবে লিখবঃ

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

মডেল আপডেটঃ

App> Model > Category.php মডেল ফাইল এভাবে লিখবঃ

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
    protected $fillable = ['name'];

    public function products()
    {
        return $this->hasMany(Product::class);
    }
}

App> Model > Product.php মডেল ফাইল এভাবে লিখবঃ

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;
    protected $fillable = ['title', 'price', 'image', 'category_id'];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }
}

এখানে প্রোডাক্টের সাথে ক্যাটেগরির সম্পর্ক যোগ করেছি। এবং fillable প্রোপার্টিতে ‘category_id’ ফিল্ড যোগ করেছি।

প্রোডাক্ট টেবিলে ক্যাটেগরি যুক্ত একটা জন্য একটা মাইগ্রেশন ফাইল তৈরি করে নিবঃ

php artisan make:migration add_category_id_to_products_table --table=products

…add_category_id_to_products_table.php ফাইল নিচের মত করে লিখবঃ

    public function up(): void
    {
        Schema::table('products', function (Blueprint $table) {
            $table->unsignedBigInteger('category_id')->nullable();
            // Add a foreign key constraint
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
        });
    }

এরপর ডেটাবেজ মাইগ্রেট করে নিবঃ

php artisan migrate

এবার আমরা প্রোডাক্টে ক্যাটেগরি যোগ করতে পারব। ক্যাটেগরি তৈরি করার জন্য আমাদের প্রথমে ক্যাটেগরি যোগ করে নিতে হবে। তার জন্য ব্যাসিক CRUD অপারেশন যেভাবে করে, ঐ প্রসেস ফলো করব। যেমন সবার আগে CategoryController তৈরি করে নিবঃ

php artisan make:controller CategoryController --resource

এরপর web.php রুট ফাইলে এই রিসোর্স রুট যোগ করব। যেন আমরা সহজে ক্যাটেগরির বিভিন্ন রুট ব্যবহার করতে পারিঃ

Route::resource('category', CategoryController::class);

resources > view ফোল্ডারে category নামে নতুন একটা ডিরেক্টরি তৈরি করব। এর ভেতরে create.blade.php নামে একটা ফাইল তৈরি করবঃ

<x-layout>
    <div class="text-left mr-auto w-full">

        <h2 class="text-2xl font-bold">Add Category</h2>
        <form action="{{ route('category.store') }}" method="POST" class="space-y-4">
            @csrf
            <div class="form-group">
                <label for="name">Category Name</label>
                <input type="text"
                    class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
                id="name" name="name" value="{{ old('name') }}" required>
            </div>
            <button type="submit" class="inline-flex items-center px-5 py-2.5 text-sm font-medium text-center text-white bg-blue-700 rounded-lg focus:ring-4 focus:ring-blue-200 hover:bg-blue-800">

            Add Category</button>
        </form>

    </div>
</x-layout>

CategoryController.php ফাইল ওপেন করব। এরপর এর ক্রিয়েট মেথডে এই ভিউ রিটার্ণ করবঃ

 return view('category.create');

তাহলে আমরা নতুন ক্যাটেগরি যোগ করার ফরম দেখব। উপরের ফরম হিবিজিবি মনে হতে পারে। টেলউইন্ড সিএসএস এর কারণে এমন মনে হচ্ছে। এখানে শুধু একটা বাটন, এবং একটা ফরম। এই তো।

উপরের Add Category বাটনে ক্লিক করলে category.store রুটে কল করবে। তাই CategoryController.php ফাইলের store মেথড এভাবে লিখবঃ


    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255'
        ]);

        Category::create([
            'name' => $request->name
        ]);

        return redirect()->route('category.index')->with('success', 'Category added successfully.');
    }

use App\Models\Category; ইনক্লুড করে নিতে হবে। এখন আমরা যদি ক্যাটেগরি এড করি, ডেটাবেজে তা দেখাবে। যদিও ক্যাটেগরি তৈরি পর category.index রুটে আমাদের নিয়ে যাচ্ছে। এবং আমরা একটা ব্ল্যাংক পেইজ দেখছি। এর কারণ হচ্ছে আমরা index মেথড এখনো লিখিনি। তার জন্য resource > views > category ডিরেক্টরিতে index.blade.php নামে একটা ফাইল তৈরি করিঃ

<x-layout>
    <div class="space-y-5">
<h2 class="mb-2 text-lg font-semibold text-gray-900 dark:text-white">Categories</h2>

@forelse($categories as $category)
    <div class="flex  max-w-sm flex-row  items-start justify-center">
        <div class="basis-1/2"> <h2 class="text-xl font-bold">{{ $category->name }}</h2></div>
        <div class="basis-1/4">
            <a class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5  "
            href="{{ route('category.edit', $category->id) }}"
                class="btn btn-primary">Edit</a></div>
        <div class="basis-1/4">

            <form action="{{ route('category.destroy', $category->id) }}" method="POST"
                style="display:inline-block;">
                @csrf
                @method('DELETE')
                <button type="submit" class="focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 ">Delete</button>
            </form>
        </div>
    </div>
@empty
    <p>No categories available.</p>
@endforelse
    </div>
</x-layout>


এখন আমরা যদি http://127.0.0.1:8000/category/create রুটে যাই, আমরা ক্যাটেগরি যোগ করতে পারব। এবং ক্যাটেগরি যোগ করার পর /category রুটে রিডারেইক্ট করবে। যে ক্যাটেগরি গুলো যোগ করেছি, সেগুলো দেখতে পাবো। উপরে আমি ক্যাটেগরি এডিট করা এবং ডিলেট করার বাটন যোগ করেছি। যা আমরা পরবর্তীতে ইমপ্লিমেন্ট করব। এবার দেখি কিভাবে প্রোডাক্টে ক্যাটেগরি যোগ করা যায়।

প্রোডাক্টে ক্যাটেগরি যোগ করা

resource>views>create.blade.php ফাইল ওপেন করি। এখানে প্রোডাক্ট তৈরি করার ফরম রয়েছে। সাবমিট বাটনের পূর্বে নিচের কোড যোগ করি। যা মূলত ক্যাটেগরি সিলেক্ট করার জন্য একটা ড্রপডাউন মেন্যুঃ

           <div class="form-group">
                    <label for="category_id">Category</label>
                    <select name="category_id" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required>
                        <option value="" disabled selected>Select a Category</option>
                        @foreach ($categories as $category)
                            <option value="{{ $category->id }}" {{ old('category_id') == $category->id ? 'selected' : '' }}>
                                {{ $category->name }}
                            </option>
                        @endforeach
                    </select>
                </div>

এখ যদি http://127.0.0.1:8000/product/create রুটে যাই, তাহলে নিচের মত করে এরর দেখাবে।

Undefined variable $categories

এর কারণ এই ক্রিয়েট ভিউতে $categories গুলো পাস করতে হবে। ProductController.php ফাইল ওপেন করি। create() মেথড এভাবে লিখিঃ

   public function create()
    {
       $categories = Category::all();

       return view('create', compact('categories'));
    }

আগে শুধু মাত্র ভিউ পাস করেছি। এখন ভিউ এর সাথে ক্যাটেগরি লিস্টও পাস করেছি। use App\Models\Category; ইনক্লুড করে নিতে হবে। এখন আমরা যদি /product/create রুটে ভিজিট করি, আমরা দেখব প্রোডাক্ট তইরির ফরম ঠিক মত কাজ করছে। আমরা চাইলে প্রোডাক্ট যোগ করতে পারব। তব ক্যাটেগরি এখনো প্রোডাক্টে যোগ হয়নি। তার জন্য store() মেথড আপডেট করতে হবে। আমাদের শুধু দুইটা লাইন যোগ করতে হবে। ভ্যালিডেশনে ‘category_id’ => ‘required|exists:categories,id’, ভ্যালিডেট করে নিব। এবং প্রোডাক্ট তৈরির সময় অন্যান্য ফিল্ডের পাশা পাশি ক্যাটেগরি আইডি পাস করব ‘category_id’ => $data[‘category_id’] এর মাধ্যমে। আমি পুরা store() মেথড এখানে দিচ্ছিঃ

    public function store(Request $request)
    {
        $data = $request->validate([
            'title' => ['required', 'string'],
            'price' => ['required', 'numeric'],
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
            'category_id' => 'required|exists:categories,id', // new feild for adding category
        ]);
             // Handle the image upload if there is an image
             $imagePath = null;
             if ($request->hasFile('image')) {
                 $imagePath = $request->file('image')->store('images/products', 'public'); // Store the image in the public disk
             }

        $product =  Product::create([
            'title' => $request->input('title'),
            'price' => $request->input('price'),
            'image' => $imagePath,
            'category_id' => $data['category_id'], // creating product with category
        ]);

        return to_route('product.show', $product);
    }

যদিও এখনো ক্যাটেগরি দেখাবেনা প্রোডাক্টে। তার জন্য ভিউ ফাইল আপডেট করতে হবে। তবে আমরা যদি এখন ডেটাবেজে দেখি, দেখব ডেটবেজে ক্যাটেগরি আইডি যোগ হচ্ছে। এই আইডি ব্যবহার করে ক্যাটেগরির নাম আমরা বের করতে পারব।

প্রডাক্টের ডেসক্রিপশনে ক্যাটেগরি দেখানোঃ

single-product.blade.php ফাইল ওপেন করে নিচের কোড যে কোন যায়গায় যোগ করিঃ

 <h4>Category:</h4>
  <p>{{ $product->category ? $product->category->name : 'No Category' }}</p>

তাহলে প্রোডাক্টটি কোন ক্যাটেগরির, তা দেখাবে। চাইলে index.blade.php তেও যোগ করতে পারি।

 <p>Category: {{ $product->category ? $product->category->name : 'No Category' }}</p>

ক্যাটেগরি এডিট করা এবং ডিলিট করার ফাংশনালিটি যোগ করতে পারবেন না? আশা করি পারবেন। এডিট এবং ডিলিট করার ফাংশন যোগ করে গিটহাবে আপলোড করেছি। category ব্রাঞ্চে পাবেন। এছাড়া category.index রুট থেকেই ক্যাটেগরি যোগ করার অপশন যোগ করে দিয়েছি ঐখানে।

বিভিন্ন কন্টেন্ট ম্যানেজমেন্ট সিস্টেমে সাধারণ ডিফল্ট ক্যাটেগরি যোগ করা থাকে। আমরা চাইলে আমাদের প্রজেক্টেও যেন ডিফল্ট একটা ক্যাটেগরি যোগ থাকে, তার কোড লিখতে পারি। আর এ জন্য নিচের প্রসেস ফলো করতে পারি।

ল্যারাভেলে নতুন সিডার ক্লাস তৈরি

নতুন সিডার ক্লাস তৈরি করার জন্য নির্দিষ্ট মডেলের নাম দিয়ে তৈরি করে নিব। যেমনঃ

php artisan make:seeder DefaultCategorySeeder

এই ফাইলটি পাওয়া যাবে database> seeders ফোল্ডারে। ডিফল্ট ক্যাটেগরি যোগ করার জন্য সিডার ফাইল এভাবে লিখবঃ

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class DefaultCategorySeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        DB::table('categories')->insert([
            'name' => 'Default Category',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }
}

এরপর নিচের কমান্ড রান করলেই ডেটাবেজ সিড হবেঃ

php artisan db:seed --class=CategorySeeder

যদি ডেটাবেজ রিফ্রেশ করি, এবং চাই এই ক্লাসটাও সিড করতে, তাহলে নিচের কোড database> seeders> DatabaseSeeder.php ফাইলে যোগ করে দিব। use Database\Seeders\DefaultCategorySeeder; ইনক্লুড করতে হবে।

public function run()
{
    // Call the DefaultCategorySeeder
    $this->call(DefaultCategorySeeder::class);
}

প্রজেক্টের ফাইল গুলো পাওয়া যাবে গিটহাবে। Laravel-mini-ecommerce। এই লেখার কোড গুলো পাওয়া যাবে category ব্রাঞ্চে। প্রজেক্ট ডাউনলোড করার পর নিচের কমান্ড রান করলে কোড গুলো দেখা যাবেঃ

git checkout category

Leave a Reply