Laravel E-Commerce Application Development – Categories Section Part 2

Laravel E-Commerce Application Development – Categories Section Part 2

Laravel E-Commerce Application Development ( 27 Lessons )

In this course, you’ll learn how to create an E-Commerce Website from scratch in Laravel. The process has never been easier I’ll take you from the very beginning stages of setting up Laravel till the last steps of adding products to the cart. If you’ve good understanding & experience in PHP & MySQL then this course is for you.

see full series
  1. Laravel E-Commerce Application Development – Introduction
  2. Laravel E-Commerce Application Development – Initial Project Setup
  3. Laravel E-Commerce Application Development – Assets Setup Using Laravel Mix
  4. Laravel E-Commerce Application Development – Admin Model and Migration
  5. Laravel E-Commerce Application Development – Backend Admin Authentication
  6. Laravel E-Commerce Application Development – Base Controller and Repository
  7. Laravel E-Commerce Application Development – Settings Section Part 1
  8. Laravel E-Commerce Application Development – Settings Section Part 2
  9. Laravel E-Commerce Application Development – Categories Section Part 1
  10. Laravel E-Commerce Application Development – Categories Section Part 2
  11. Laravel E-Commerce Application Development – Attributes Section Part 1
  12. Laravel E-Commerce Application Development – Attributes Section Part 2
  13. Laravel E-Commerce Application Development – Attributes Section Part 3
  14. Laravel E-Commerce Application Development – Brands Section
  15. Laravel E-Commerce Application Development – Products Section Part 1
  16. Laravel E-Commerce Application Development – Products Section Part 2
  17. Laravel E-Commerce Application Development – Products Section Part 3
  18. Laravel E-Commerce Application Development – Products Section Part 4
  19. Laravel E-Commerce Application Development – Frontend Login & Registration
  20. Laravel E-Commerce Application Development – Categories Navigation
  21. Laravel E-Commerce Application Development – Catalog Listing
  22. Laravel E-Commerce Application Development – Product Details Page
  23. Laravel E-Commerce Application Development – Shopping Cart
  24. Laravel E-Commerce Application Development – Checkout
  25. Laravel E-Commerce Application Development – Payment Processing
  26. Laravel E-Commerce Application Development – Order Management
  27. Laravel E-Commerce Application Development – Wrap Up

This is part 9 of the Laravel E-Commerce Application Development series, in this part will complete the categories section by adding the categories list, create and edit pages in the admin area.

I assume you should have the e-commerce application project on your machine or you can grab it from Laravel E-Commerce Application repository, we will start from where we left it in the last part.

So let’s start some coding.

Adding Categories Routes

Firstly, we will add the following routes to our application:

  • List categories route /admin/categories
  • Create category route /admin/categories/create
  • Store category route /admin/categories/store
  • Edit category route /admin/categories/{id}/edit
  • Update category route /admin/categories/update
  • Delete category route /admin/categories/{id}/delete

Open the routes/admin.php file and add the below code just after the settings routes.

Route::group(['prefix'  =>   'categories'], function() {

    Route::get('/', 'Admin\[email protected]')->name('admin.categories.index');
    Route::get('/create', 'Admin\[email protected]')->name('admin.categories.create');
    Route::post('/store', 'Admin\[email protected]')->name('admin.categories.store');
    Route::get('/{id}/edit', 'Admin\[email protected]')->name('admin.categories.edit');
    Route::post('/update', 'Admin\[email protected]')->name('admin.categories.update');
    Route::get('/{id}/delete', 'Admin\[email protected]')->name('admin.categories.delete');

});

Adding Categories Menu to Sidebar

Now we will open the resources/views/admin/partials/sidebar.blade.php file and add the blow markup to add a Categories link to our admin menu.

<li>
    <a class="app-menu__item {{ Route::currentRouteName() == 'admin.categories.index' ? 'active' : '' }}"
        href="{{ route('admin.categories.index') }}">
        <i class="app-menu__icon fa fa-tags"></i>
        <span class="app-menu__label">Categories</span>
    </a>
</li>

After adding the above code if you visit the admin panel, you will be able to see the categories menu link.

Creating Category Controller

As we have seen above in our routes, our all routes are pointing to CategoryController, so let’s create a CategoryController using the artisan command.

php artisan make:controller Admin\CategoryController

First thing in our CategoryController we have to do is extend this controller class with our BaseController class so we can use our own redirect methods.

Your controller class will look like below.

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\BaseController;

/**
 * Class CategoryController
 * @package App\Http\Controllers\Admin
 */
class CategoryController extends BaseController
{
    //
}

Now we have extended the BaseController class which will enable us to use the flash messages and redirect methods we created earlier in this series. We will start adding required methods in this controller later on.

Creating Category Contract and Repository

Now, we will add a category contract which will be implemented in the category repository class, also our category repository class will extend the BaseRepository class. Using this technique we will be able to inherit the functions from base repository class.

Create a new file in app/Contracts folder and name it CategoryContract. Define an interface in this file and add the required method signatures in this interface like below.

namespace App\Contracts;

/**
 * Interface CategoryContract
 * @package App\Contracts
 */
interface CategoryContract
{
    /**
     * @param string $order
     * @param string $sort
     * @param array $columns
     * @return mixed
     */
    public function listCategories(string $order = 'id', string $sort = 'desc', array $columns = ['*']);

    /**
     * @param int $id
     * @return mixed
     */
    public function findCategoryById(int $id);

    /**
     * @param array $params
     * @return mixed
     */
    public function createCategory(array $params);

    /**
     * @param array $params
     * @return mixed
     */
    public function updateCategory(array $params);

    /**
     * @param $id
     * @return bool
     */
    public function deleteCategory($id);
}

As you can see, we have defined various method signatures in this interface. Now we will create a CategoryRepository class which will implement this interface and extends the BaseRepository class.

Create a new file in app/Repositories folder and name it CategoryRepository. Add the below code in it so we will have a repository which will implement our CategoryContract interface and extend the base repository.

namespace App\Repositories;

use App\Models\Category;
use App\Traits\UploadAble;
use Illuminate\Http\UploadedFile;
use App\Contracts\CategoryContract;
use Illuminate\Database\QueryException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Doctrine\Instantiator\Exception\InvalidArgumentException;

/**
 * Class CategoryRepository
 *
 * @package \App\Repositories
 */
class CategoryRepository extends BaseRepository implements CategoryContract
{
    use UploadAble;
}

As you can see we are implementing our category contract and extending our base repository in this class. Also notice, we have included our UploadAble trait in this class, so we can upload the files using our trait.

Instead of sharing the whole class with you, I will walk you through step by step.

Firstly, we will need to add a constructor to our class and inject the Category model in it. Add the below constructor method in your repository class.

/**
 * CategoryRepository constructor.
 * @param Category $model
 */
public function __construct(Category $model)
{
    parent::__construct($model);
    $this->model = $model;
}

Next, we will implement the listCategories() method in this class which we have declared in our CategoryContract.

/**
 * @param string $order
 * @param string $sort
 * @param array $columns
 * @return mixed
 */
public function listCategories(string $order = 'id', string $sort = 'desc', array $columns = ['*'])
{
    return $this->all($columns, $order, $sort);
}

The listCategories() method will return the all categories from database. You can notice that we are not using Category::all() to get all categories, instead we are using the all() method which we are inheriting from our BaseRepository class.

Now, we will implement the findCategoryById() method.

/**
 * @param int $id
 * @return mixed
 * @throws ModelNotFoundException
 */
public function findCategoryById(int $id)
{
    try {
        return $this->findOneOrFail($id);

    } catch (ModelNotFoundException $e) {

        throw new ModelNotFoundException($e);
    }
}

As you can see in this method we are find the model by id using the findOneOrFail() method provided by base repository. If no model returned from the query we are simply throwing the ModelNotFoundException exception.

Now, we will implement the createCategory() method in our category repository.

/**
 * @param array $params
 * @return Category|mixed
 */
public function createCategory(array $params)
{
    try {
        $collection = collect($params);
        
        $image = null;

        if ($collection->has('image') && ($params['image'] instanceof  UploadedFile)) {
            $image = $this->uploadOne($params['image'], 'categories');
        }

        $featured = $collection->has('featured') ? 1 : 0;
        $menu = $collection->has('menu') ? 1 : 0;

        $merge = $collection->merge(compact('menu', 'image', 'featured'));

        $category = new Category($merge->all());

        $category->save();

        return $category;

    } catch (QueryException $exception) {
        throw new InvalidArgumentException($exception->getMessage());
    }
}

As you can see there is alot going here. Firstly we are converting our $params array to collection, then checking if an image has been loaded or not and the image uploaded is an instance of UploadedFile class.

Next, we are uploading our image using uploadOne() method provided by our UploadAble trait. Next we are checking for featured and menu attribute and reassigning the boolean values based on their presence. Then we are merging all values in the collection and creating a new Category.

Now, we will implement our updateCategory() method.

/**
 * @param array $params
 * @return mixed
 */
public function updateCategory(array $params)
{
    $category = $this->findCategoryById($params['id']);

    $collection = collect($params)->except('_token');

    if ($collection->has('image') && ($params['image'] instanceof  UploadedFile)) {

        if ($category->image != null) {
            $this->deleteOne($category->image);
        }

        $image = $this->uploadOne($params['image'], 'categories');
    }

    $featured = $collection->has('featured') ? 1 : 0;
    $menu = $collection->has('menu') ? 1 : 0;

    $merge = $collection->merge(compact('menu', 'image', 'featured'));

    $category->update($merge->all());

    return $category;
}

As you can see in this method we are almost doing the same as we did in the createCategory() method, except we are not creating the new category we are updating an existing one.

Finally, we will add the implementation of our deleteCategory() method.

/**
 * @param $id
 * @return bool|mixed
 */
public function deleteCategory($id)
{
    $category = $this->findCategoryById($id);

    if ($category->image != null) {
        $this->deleteOne($category->image);
    }

    $category->delete();

    return $category;
}

In the above code example, we are getting the category by id then checking if there is an image for this category, if yes delete it. Then we are deleting the target category.

Adding Repository Service Provider

Before using the CategoryRepository, we will need to bind this category into Laravel’s Service Container. For that, we will create a new service provider. Run the below command in the terminal to generate a service provider.

php artisan make:provider RepositoryServiceProvider

Now, open the RepositoryServiceProvider class and replace with the below one.

namespace App\Providers;

use App\Contracts\CategoryContract;
use Illuminate\Support\ServiceProvider;
use App\Repositories\CategoryRepository;

class RepositoryServiceProvider extends ServiceProvider
{
    protected $repositories = [
        CategoryContract::class         =>          CategoryRepository::class,
    ];

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        foreach ($this->repositories as $interface => $implementation)
        {
            $this->app->bind($interface, $implementation);
        }
    }
}

As you can see that we have defined a $repositories array, which holds the interfaces and implementations. In the future, we can simply add the interface and repository in this array to bind into the service container.
In the register(), method we are running a loop on the $repositories array and binding the interfaces to repositories in the container.

Creating Categories List Page

In this section, we will add a category list view and list all our categories. For that we have already defined a route /admin/categories which points to index() method in CategoryController class.

Before adding the index() method, we have to inject our CategoryContract interface in this controller class.

Open your CategoryController class and add the below method in it.

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Contracts\CategoryContract;
use App\Http\Controllers\BaseController;

/**
 * Class CategoryController
 * @package App\Http\Controllers\Admin
 */
class CategoryController extends BaseController
{
    /**
     * @var CategoryContract
     */
    protected $categoryRepository;

    /**
     * CategoryController constructor.
     * @param CategoryContract $categoryRepository
     */
    public function __construct(CategoryContract $categoryRepository)
    {
        $this->categoryRepository = $categoryRepository;
    }

    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function index()
    {
        $categories = $this->categoryRepository->listCategories();

        $this->setPageTitle('Categories', 'List of all categories');
        return view('admin.categories.index', compact('categories'));
    }
}

Firstly we defined a $categoryRepository property and then injected the CategoryContract interface in our constructor method.

Next, we have added the index() method. In this method, we loading the categories from our category repository class and setting the page titles.

Finally, we are returning the admin.categories.index view with categories.

Create a new file in resources/views/admin/categories folder and name it index.blade.php. Add the below markup in thid page.

@extends('admin.app')
@section('title') {{ $pageTitle }} @endsection
@section('content')
    <div class="app-title">
        <div>
            <h1><i class="fa fa-tags"></i> {{ $pageTitle }}</h1>
            <p>{{ $subTitle }}</p>
        </div>
        <a href="{{ route('admin.categories.create') }}" class="btn btn-primary pull-right">Add Category</a>
    </div>
    @include('admin.partials.flash')
    <div class="row">
        <div class="col-md-12">
            <div class="tile">
                <div class="tile-body">
                    <table class="table table-hover table-bordered" id="sampleTable">
                        <thead>
                            <tr>
                                <th> # </th>
                                <th> Name </th>
                                <th> Slug </th>
                                <th class="text-center"> Parent </th>
                                <th class="text-center"> Featured </th>
                                <th class="text-center"> Menu </th>
                                <th class="text-center"> Order </th>
                                <th style="width:100px; min-width:100px;" class="text-center text-danger"><i class="fa fa-bolt"> </i></th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($categories as $category)
                                @if ($category->id != 1)
                                    <tr>
                                        <td>{{ $category->id }}</td>
                                        <td>{{ $category->name }}</td>
                                        <td>{{ $category->slug }}</td>
                                        <td>{{ $category->parent->name }}</td>
                                        <td class="text-center">
                                            @if ($category->featured == 1)
                                                <span class="badge badge-success">Yes</span>
                                            @else
                                                <span class="badge badge-danger">No</span>
                                            @endif
                                        </td>
                                        <td class="text-center">
                                            @if ($category->menu == 1)
                                                <span class="badge badge-success">Yes</span>
                                            @else
                                                <span class="badge badge-danger">No</span>
                                            @endif
                                        </td>
                                        <td class="text-center">
                                            {{ $category->order }}
                                        </td>
                                        <td class="text-center">
                                            <div class="btn-group" role="group" aria-label="Second group">
                                                <a href="{{ route('admin.categories.edit', $category->id) }}" class="btn btn-sm btn-primary"><i class="fa fa-edit"></i></a>
                                                <a href="{{ route('admin.categories.delete', $category->id) }}" class="btn btn-sm btn-danger"><i class="fa fa-trash"></i></a>
                                            </div>
                                        </td>
                                    </tr>
                                @endif
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
@endsection
@push('scripts')
    <script type="text/javascript" src="{{ asset('backend/js/plugins/jquery.dataTables.min.js') }}"></script>
    <script type="text/javascript" src="{{ asset('backend/js/plugins/dataTables.bootstrap.min.js') }}"></script>
    <script type="text/javascript">$('#sampleTable').DataTable();</script>
@endpush

This view is pretty much easier. We are simply running a loop in the table to list our all categories. We are using the jQuery Datatables in this view so we don’t need to add the pagination and search functionality separately.

Now if you visit the /admin/categories route, you will be presented a view like below.

Categories List Views
Categories List Views

Creating Create Category Page

Next, we will add a view from where we can create a category. Open your CategoryController again and add the below method in it.

/**
 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 */
public function create()
{
    $categories = $this->categoryRepository->listCategories('id', 'asc');

    $this->setPageTitle('Categories', 'Create Category');
    return view('admin.categories.create', compact('categories'));
}

Now create a new view in resources/admin/categories folder and name it create.blade.php. Add the below markup in this view.

@extends('admin.app')
@section('title') {{ $pageTitle }} @endsection
@section('content')
    <div class="app-title">
        <div>
            <h1><i class="fa fa-tags"></i> {{ $pageTitle }}</h1>
        </div>
    </div>
    @include('admin.partials.flash')
    <div class="row">
        <div class="col-md-8 mx-auto">
            <div class="tile">
                <h3 class="tile-title">{{ $subTitle }}</h3>
                <form action="{{ route('admin.categories.store') }}" method="POST" role="form" enctype="multipart/form-data">
                    @csrf
                    <div class="tile-body">
                        <div class="form-group">
                            <label class="control-label" for="name">Name <span class="m-l-5 text-danger"> *</span></label>
                            <input class="form-control @error('name') is-invalid @enderror" type="text" name="name" id="name" value="{{ old('name') }}"/>
                            @error('name') {{ $message }} @enderror
                        </div>
                        <div class="form-group">
                            <label class="control-label" for="description">Description</label>
                            <textarea class="form-control" rows="4" name="description" id="description">{{ old('description') }}</textarea>
                        </div>
                        <div class="form-group">
                            <label for="parent">Parent Category <span class="m-l-5 text-danger"> *</span></label>
                            <select id=parent class="form-control custom-select mt-15 @error('parent_id') is-invalid @enderror" name="parent_id">
                                <option value="0">Select a parent category</option>
                                @foreach($categories as $category)
                                    <option value="{{ $category->id }}"> {{ $category->name }} </option>
                                @endforeach
                            </select>
                            @error('parent_id') {{ $message }} @enderror
                        </div>
                        <div class="form-group">
                            <div class="form-check">
                                <label class="form-check-label">
                                    <input class="form-check-input" type="checkbox" id="featured" name="featured"/>Featured Category
                                </label>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="form-check">
                                <label class="form-check-label">
                                    <input class="form-check-input" type="checkbox" id="menu" name="menu"/>Show in Menu
                                </label>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="control-label">Category Image</label>
                            <input class="form-control @error('image') is-invalid @enderror" type="file" id="image" name="image"/>
                            @error('image') {{ $message }} @enderror
                        </div>
                    </div>
                    <div class="tile-footer">
                        <button class="btn btn-primary" type="submit"><i class="fa fa-fw fa-lg fa-check-circle"></i>Save Category</button>
                        &nbsp;&nbsp;&nbsp;
                        <a class="btn btn-secondary" href="{{ route('admin.categories.index') }}"><i class="fa fa-fw fa-lg fa-times-circle"></i>Cancel</a>
                    </div>
                </form>
            </div>
        </div>
    </div>
@endsection

This view contains a form which is pointing to our admin.categories.store route.

Next we will add the store() method in our CategoryController class.

    /**
 * @param Request $request
 * @return \Illuminate\Http\RedirectResponse
 * @throws \Illuminate\Validation\ValidationException
 */
public function store(Request $request)
{
    $this->validate($request, [
        'name'      =>  'required|max:191',
        'parent_id' =>  'required|not_in:0',
        'image'     =>  'mimes:jpg,jpeg,png|max:1000'
    ]);

    $params = $request->except('_token');

    $category = $this->categoryRepository->createCategory($params);

    if (!$category) {
        return $this->responseRedirectBack('Error occurred while creating category.', 'error', true, true);
    }
    return $this->responseRedirect('admin.categories.index', 'Category added successfully' ,'success',false, false);
}

In this method, we firstly validating the input submitted by the form, then sending the form data to our category repository to create a new category. Then we simply redirecting the user to our categories list page.

Now if your visit /admin/categories/create route, you will be presented with the below view.

Categories Create View
Categories Create View

And validation errors will look like something below:

Categories Create View with Validation Messages
Categories Create View with Validation Messages

Creating Edit Category Page

In this section of this post, we will add the edit page for categories section. Firstly add the below edit() method in your CategoryController.

/**
 * @param $id
 * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 */
public function edit($id)
{
    $targetCategory = $this->categoryRepository->findCategoryById($id);
    $categories = $this->categoryRepository->listCategories();

    $this->setPageTitle('Categories', 'Edit Category : '.$targetCategory->name);
    return view('admin.categories.edit', compact('categories', 'targetCategory'));
}

Now create a new file in categories folder and name it edit.blade.php, add the below markup in this file.

@extends('admin.app')
@section('title') {{ $pageTitle }} @endsection
@section('content')
    <div class="app-title">
        <div>
            <h1><i class="fa fa-tags"></i> {{ $pageTitle }}</h1>
        </div>
    </div>
    @include('admin.partials.flash')
    <div class="row">
        <div class="col-md-8 mx-auto">
            <div class="tile">
                <h3 class="tile-title">{{ $subTitle }}</h3>
                <form action="{{ route('admin.categories.update') }}" method="POST" role="form" enctype="multipart/form-data">
                    @csrf
                    <div class="tile-body">
                        <div class="form-group">
                            <label class="control-label" for="name">Name <span class="m-l-5 text-danger"> *</span></label>
                            <input class="form-control @error('name') is-invalid @enderror" type="text" name="name" id="name" value="{{ old('name', $targetCategory->name) }}"/>
                            <input type="hidden" name="id" value="{{ $targetCategory->id }}">
                            @error('name') {{ $message }} @enderror
                        </div>
                        <div class="form-group">
                            <label class="control-label" for="description">Description</label>
                            <textarea class="form-control" rows="4" name="description" id="description">{{ old('description', $targetCategory->description) }}</textarea>
                        </div>
                        <div class="form-group">
                            <label for="parent">Parent Category <span class="m-l-5 text-danger"> *</span></label>
                            <select id=parent class="form-control custom-select mt-15 @error('parent_id') is-invalid @enderror" name="parent_id">
                                <option value="0">Select a parent category</option>
                                @foreach($categories as $category)
                                    @if ($targetCategory->parent_id == $category->id)
                                        <option value="{{ $category->id }}" selected> {{ $category->name }} </option>
                                    @else
                                        <option value="{{ $category->id }}"> {{ $category->name }} </option>
                                    @endif
                                @endforeach
                            </select>
                            @error('parent_id') {{ $message }} @enderror
                        </div>
                        <div class="form-group">
                            <div class="form-check">
                                <label class="form-check-label">
                                    <input class="form-check-input" type="checkbox" id="featured" name="featured"
                                    {{ $targetCategory->featured == 1 ? 'checked' : '' }}
                                    />Featured Category
                                </label>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="form-check">
                                <label class="form-check-label">
                                    <input class="form-check-input" type="checkbox" id="menu" name="menu"
                                    {{ $targetCategory->menu == 1 ? 'checked' : '' }}
                                    />Show in Menu
                                </label>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="row">
                                <div class="col-md-2">
                                    @if ($targetCategory->image != null)
                                        <figure class="mt-2" style="width: 80px; height: auto;">
                                            <img src="{{ asset('storage/'.$targetCategory->image) }}" id="categoryImage" class="img-fluid" alt="img">
                                        </figure>
                                    @endif
                                </div>
                                <div class="col-md-10">
                                    <label class="control-label">Category Image</label>
                                    <input class="form-control @error('image') is-invalid @enderror" type="file" id="image" name="image"/>
                                    @error('image') {{ $message }} @enderror
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="tile-footer">
                        <button class="btn btn-primary" type="submit"><i class="fa fa-fw fa-lg fa-check-circle"></i>Update Category</button>
                        &nbsp;&nbsp;&nbsp;
                        <a class="btn btn-secondary" href="{{ route('admin.categories.index') }}"><i class="fa fa-fw fa-lg fa-times-circle"></i>Cancel</a>
                    </div>
                </form>
            </div>
        </div>
    </div>
@endsection

Now we will add the update() method in our category controller which will be pretty much same as the store() method.

/**
 * @param Request $request
 * @return \Illuminate\Http\RedirectResponse
 * @throws \Illuminate\Validation\ValidationException
 */
public function update(Request $request)
{
    $this->validate($request, [
        'name'      =>  'required|max:191',
        'parent_id' =>  'required|not_in:0',
        'image'     =>  'mimes:jpg,jpeg,png|max:1000'
    ]);

    $params = $request->except('_token');

    $category = $this->categoryRepository->updateCategory($params);

    if (!$category) {
        return $this->responseRedirectBack('Error occurred while updating category.', 'error', true, true);
    }
    return $this->responseRedirectBack('Category updated successfully' ,'success',false, false);
}

Above method will handle the update functionality for categories by using the updateCategory() method from repository class. If you try to edit a category from the categories list page, you will be presented with the category edit page like below.

Categories Edit View
Categories Edit View

Deleting A Category

We have already defined the route for delete a category and added a deleteCategory() method in our repository. We need to add a delete() method in our controller to serve the delete route.

/**
 * @param $id
 * @return \Illuminate\Http\RedirectResponse
 */
public function delete($id)
{
    $category = $this->categoryRepository->deleteCategory($id);

    if (!$category) {
        return $this->responseRedirectBack('Error occurred while deleting category.', 'error', true, true);
    }
    return $this->responseRedirect('admin.categories.index', 'Category deleted successfully' ,'success',false, false);
}

Above method will take the category id and pass it to deleteCategory() method to delete a category.

Conclusion

That’s it for now, in the next post we will start making some progress to our next section.

Code Repository

You can find the code base of this series on Laravel eCommerce Application repository.

If you have any question about this post, please leave a comment in the comment box below.

48 comments on “Laravel E-Commerce Application Development – Categories Section Part 2

  1. Help me here;

    Target [App\Contracts\CategoryContract] is not instantiable while building [App\Http\Controllers\Admin\CategoryController].

    1. Add your repository service provider to config/app.php file like below.

      App\Providers\RepositoryServiceProvider::class,

  2. Hi, I don’t know what I did wrong everything is working fine only the image is not showing. I checked in the public folder and there is no folder for the image.

    1. Hi,

      you need to load the SettingsServiceProvider in the config/app.php file. Add the settings service provider to $providers array in the app.php config file.

      Hopefully, that will solve this issue.
      If no luck, let me know.

      Thanks

  3. Hi! Thanks for the amazing work!

    I’ve noticed that if no image is provided, the CategoryRepository fails with the message: “compact(): Undefined variable: image”

    To fix this, I’ve added $image = null; bellow the $collection = collect($params).

  4. “SQLSTATE[42S02]: Base table or view not found: 1146 Table ‘online_soko.categories’ doesn’t exist (SQL: select * from `categories` order by `id` desc)”

    how get around this?

  5. Hello, am encountering this error. “Class App\Contracts\CategoryContract does not exist”, what might be the problem

  6. I am getting an error

    After updating any category, I am getting success flash message but it is not redirecting to the index page, coming on the same page after update form submit,

  7. Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_RECOVERABLE_ERROR)
    Argument 1 passed to App\Repositories\BaseRepository::__construct() must be an instance of App\Repositories\Model, instance of App\Models\Category given, called in C:\xampp\xampp2\htdocs\ecommerce-application\app\Repositories\CategoryRepository.php on line 26

  8. Call to undefined function App\Models\str_slug()

    at C:\xampp\htdocs\ecr\app\Models\Category.php:24
    20|
    21| public function setNameAttribute($value)
    22| {
    23| $this->attributes[‘name’] = $value;
    > 24| $this->attributes[‘slug’] = str_slug($value);
    25| }
    26| public function parent()
    27| {
    28| return $this->belongsTo(Category::class, ‘parent_id’);

    1. The str_slug() function has been depriciated. You have to use the facade class, before the model class include facade like:

      use Illuminate\Support\Str;

      Then use it like Str::slug().

      It will fix the error.

  9. Hi, this series is really awesome for me. I am a newbie in Laravel & I am getting this error. Please help me.
    Illuminate\Contracts\Container\BindingResolutionException
    Target [App\Contracts\CategoryContract] is not instantiable while building [App\Http\Controllers\Admin\CategoryController].
    How can I solve this?

  10. Hi. Thanks for this great tutorial. I’m getting this error “compact(): Undefined variable:image”. It’s pointing to the updateCategory method of the CategoryRepository in the line “$merge = $collection->merge(compact(‘menu’, ‘image’, ‘featured’));” This happens when I tried to update a category and didn’t upload any image. How to fix this? Thanks

  11. I have faced this error:

    ErrorException (E_ERROR)
    Undefined variable: message (View: C:\xampp\htdocs\metropolitanShop\resources\views\admin\categories\create.blade.php)
    Previous exceptions
    Undefined variable: message (0)

  12. Hello, The tutorial is awesome, but I got this error while trying to add category and upload image Symfony\Component\Debug\Exception\FatalThrowableError
    Call to undefined function App\Traits\str_random()
    How can I solve this error

  13. when running admin/categories i will get error like this
    Method App\Http\Controllers\Admin\CategoryController::setPageTitle does not exist.

  14. Hello,at first, very good tutorial. Thank you.
    But I have problem with uploading files. On localhost it works perfectly but not on server. I think this is problem with rights but my destination folder has 775 rights. So I do not know where is the problem. Do you have any suggestions please?

  15. Hi,
    When I add the same category record for second time, like duplicate. I get this error:
    Doctrine\Instantiator\Exception\InvalidArgumentException thrown with message “SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ‘test-teraz’ for key ‘categories_slug_unique’ (SQL: insert into `categories` (`name`, `slug`, `description`, `parent_id`, `menu`, `image`, `featured`, `updated_at`, `created_at`) values (TEST TERAZ, test-teraz, ddd, 1, 0, ?, 0, 2019-10-12 21:23:55, 2019-10-12 21:23:55))”
    Can you please add solution to handle this error?

    1. You have to add a check in your controller or model to check category before saving. If category exists then concatenate a unique string to the slug to make it unique.

      Thanks

  16. I deleted all of the seeded categories except the root. But when I try and create a new category via admin I receive the following error:

    Facade\Ignition\Exceptions\ViewException
    Trying to get property ‘id’ of non-object (View: G:\laragon\www\ecommerce-application\resources\views\admin\categories\create.blade.php)

    I think I have an idea why but I’m too new to troubleshoot the problem.

  17. Hi Thanks alot for this awesome Project 100% worth.

    However I have a confusion that why we are associating Contracts & Repository for every Controller as there are almost same methods for CRUD, why can’t we make one for all. Please explain.

    Thanks

    1. You can make one repository and use it for all of your model. The way I have implemented in this series is the way I use personally. I try to keep separate repositories for each model.

      In my professional projects, some time I have specific action based methods which are not applicable to other models, using separate repositories just make it easier to manage.

      It’s totally up to you how you want to structure your application.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

When sharing a code snippet please wrap you code with pre tag and add a class code-block to it like below.
<pre class="code-block">you code here</pre>

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.