The Category functionality is now added

Posted: 2025/03/10

This blog now has Category functionality implemented.

1. Create new Category Model

php artisan make:model Category -mc

2. Update the migration file to create new tables

 Schema::create('category_post', function (Blueprint $table) {
            $table->id();
            $table->foreignIdFor(Post::class)->constrained()->onDelete('cascade');
            $table->foreignIdFor(Category::class)->constrained()->onDelete('cascade');
            $table->timestamps();
        });

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

3. Migrate new tables

php artisan migrate

4. Define relationship in Post Model

public function categories(): BelongsToMany
    {
        return $this->belongsToMany(Category::class);
    }

5. Define relationship in Category Model

public function posts(): BelongsToMany
    {
        return $this->belongsToMany(Post::class);
    }

Update the PostController to pass all the Categories to the create view

public function create(Post $post) {
        $categories = Category::orderBy('name')->get();
        return view('post.create', compact('categories'));
    }

6. Add Category Selection and Add new Category to the create view

 <!-- Categories Section -->
         <div class="mb-4">
          <label class="block text-gray-700 font-medium mb-2">Categories</label>

          <!-- Existing Categories - With Empty State -->
          @if(count($categories) > 0)
              <div class="mb-3">
                  <p class="text-sm text-gray-600 mb-2">Select existing categories:</p>
                  <div class="max-h-40 overflow-y-auto p-3 border border-gray-300 rounded-lg">
                    @foreach ($categories as $category )
                    <input type="checkbox" id="{{ $category->id }}" name="categories[]" value="{{ $category->id }}" 
                    {{ (is_array(old('categories')) &&  in_array($category->id, old('categories'))) ? 'checked' : '' }} >
                    <label for="{{ $category->id }}">{{ $category->name }}</label><br>
                  @endforeach
                  </div>
              </div>
          @endif

          <!-- Add New Categories -->
          <div class="{{ count($categories) == 0 ? 'mt-0' : 'mt-4' }}">
              <p class="text-sm text-gray-600 mb-2">
                  @if(count($categories) == 0)
                      No categories exist yet. Create new categories (comma separated):
                  @else
                      Add new categories (comma separated):
                  @endif
              </p>
              <input type="text" id="new_categories" name="new_categories" value="{{ old('new_categories') }}"
                  class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:outline-none"
                  placeholder="Technology, Programming, Laravel...">
              <p class="text-xs text-gray-500 mt-1">Separate multiple categories with commas</p>
              <x-form-error name="new_categories"></x-form-error>
          </div>
      </div>

8. Update the store function in the PostController to save the categories assigned to post

public function store() {
        $validatedAttrs = request()->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string|min:20',
            'categories' => 'array|nullable',
            'new_categories' => 'string|nullable'
        ]);

        // Add the authenticated user's ID
        $validatedAttrs['user_id'] = Auth::id();
        //dd($validatedAttrs);
        // Create post using mass assignment
        $post = Post::create($validatedAttrs);

         // Attach existing categories
        if (!empty($validatedAttrs['categories'])) {
            $post->categories()->attach($validatedAttrs['categories']);
        }

        if (!empty($validatedAttrs['new_categories'])) {
            $categoryNames = array_map('trim', explode(',',$validatedAttrs['new_categories']));
            foreach ($categoryNames as $categoryName) {
                        // Check if category already exists or create it
                        $category = Category::firstOrCreate(['name' => $categoryName]);

                        //Attach to post if not already attached
                        if (!$post->categories->contains($category->id)) {
                            $post->categories()->attach($category->id);
                        }

            }
        }

        return redirect()->route('blog')->with('success', 'Post created successfully!');

    }

9. Repeat the same for the edit view and update view

10. Done

Next: Implement the index view for each Category

No comments yet

Leave your comment

Search
Side Widget
You can put anything you want inside of these side widgets. They are easy to use, and feature the Bootstrap 5 card component!