Laravel E-Commerce Application Development – Attributes 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- Laravel E-Commerce Application Development – Introduction
- Laravel E-Commerce Application Development – Initial Project Setup
- Laravel E-Commerce Application Development – Assets Setup Using Laravel Mix
- Laravel E-Commerce Application Development – Admin Model and Migration
- Laravel E-Commerce Application Development – Backend Admin Authentication
- Laravel E-Commerce Application Development – Base Controller and Repository
- Laravel E-Commerce Application Development – Settings Section Part 1
- Laravel E-Commerce Application Development – Settings Section Part 2
- Laravel E-Commerce Application Development – Categories Section Part 1
- Laravel E-Commerce Application Development – Categories Section Part 2
- Laravel E-Commerce Application Development – Attributes Section Part 1
- Laravel E-Commerce Application Development – Attributes Section Part 2
- Laravel E-Commerce Application Development – Attributes Section Part 3
- Laravel E-Commerce Application Development – Brands Section
- Laravel E-Commerce Application Development – Products Section Part 1
- Laravel E-Commerce Application Development – Products Section Part 2
- Laravel E-Commerce Application Development – Products Section Part 3
- Laravel E-Commerce Application Development – Products Section Part 4
- Laravel E-Commerce Application Development – Frontend Login & Registration
- Laravel E-Commerce Application Development – Categories Navigation
- Laravel E-Commerce Application Development – Catalog Listing
- Laravel E-Commerce Application Development – Product Details Page
- Laravel E-Commerce Application Development – Shopping Cart
- Laravel E-Commerce Application Development – Checkout
- Laravel E-Commerce Application Development – Payment Processing
- Laravel E-Commerce Application Development – Order Management
- Laravel E-Commerce Application Development – Wrap Up
This is part 11 of the Laravel E-Commerce Application Development series. In this part will add the admin section for our attributes CRUD.
So let’s start implementing this in our application.
Adding Menu Link for Attributes
First thing first, we need to add the attributes link to our menu in admin section. For that open the sidebar.blade.php
file from resources/views/admin/partials folder and add the below code snippets just right after the html block for our categories link.
<li> <a class="app-menu__item {{ Route::currentRouteName() == 'admin.attributes.index' ? 'active' : '' }}" href="{{ route('admin.attributes.index') }}"> <i class="app-menu__icon fa fa-th"></i> <span class="app-menu__label">Attributes</span> </a> </li>
Creating Attribute Contract
In this section, we will create an interface for our Attribute model. Create a new file called AttributeContract.php in app/Contracts
folder and add the below code block in it.
namespace App\Contracts; interface AttributeContract { /** * @param string $order * @param string $sort * @param array $columns * @return mixed */ public function listAttributes(string $order = 'id', string $sort = 'desc', array $columns = ['*']); /** * @param int $id * @return mixed */ public function findAttributeById(int $id); /** * @param array $params * @return mixed */ public function createAttribute(array $params); /** * @param array $params * @return mixed */ public function updateAttribute(array $params); /** * @param $id * @return bool */ public function deleteAttribute($id); }
In this contract, we have added some method signatures to deal with our Attribute model. Just like we did in the categories section.
Creating Attribute Repository
Next, create a new file in the app/Repositories folder and name it AttributeRepository. Add the below code in it so we will have a repository which will implement our AttributeContract interface and extend the base repository.
namespace App\Repositories; use App\Models\Attribute; use App\Contracts\AttributeContract; use Illuminate\Database\QueryException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Doctrine\Instantiator\Exception\InvalidArgumentException; class AttributeRepository extends BaseRepository implements AttributeContract { /** * AttributeRepository constructor. * @param Attribute $model */ public function __construct(Attribute $model) { parent::__construct($model); $this->model = $model; } /** * @param string $order * @param string $sort * @param array $columns * @return mixed */ public function listAttributes(string $order = 'id', string $sort = 'desc', array $columns = ['*']) { return $this->all($columns, $order, $sort); } /** * @param int $id * @return mixed * @throws ModelNotFoundException */ public function findAttributeById(int $id) { try { return $this->findOneOrFail($id); } catch (ModelNotFoundException $e) { throw new ModelNotFoundException($e); } } /** * @param array $params * @return Category|mixed */ public function createAttribute(array $params) { try { $collection = collect($params); $is_filterable = $collection->has('is_filterable') ? 1 : 0; $is_required = $collection->has('is_required') ? 1 : 0; $merge = $collection->merge(compact('is_filterable', 'is_required')); $attribute = new Attribute($merge->all()); $attribute->save(); return $attribute; } catch (QueryException $exception) { throw new InvalidArgumentException($exception->getMessage()); } } /** * @param array $params * @return mixed */ public function updateAttribute(array $params) { $attribute = $this->findAttributeById($params['id']); $collection = collect($params)->except('_token'); $is_filterable = $collection->has('is_filterable') ? 1 : 0; $is_required = $collection->has('is_required') ? 1 : 0; $merge = $collection->merge(compact('is_filterable', 'is_required')); $attribute->update($merge->all()); return $attribute; } /** * @param $id * @return bool|mixed */ public function deleteAttribute($id) { $attribute = $this->findAttributeById($id); $attribute->delete(); return $attribute; } }
In the above code block, we added the implementation of our AttributeContract signatures. Again, the whole functionality is similar to what we did for our categories, nothing fancy.
Binding Attribute Contract to Repository
Next, we need to bind the AttributeContract to our AttributeRepository. Open the RepositoryServiceProvider class from app/Providers
folder and include the interface and repository like below.
use App\Contracts\AttributeContract; use App\Repositories\AttributeRepository;
Next, update the $repositories
property like below.
protected $repositories = [ CategoryContract::class => CategoryRepository::class, AttributeContract::class => AttributeRepository::class, ];
Now, we can use the AttributeContract interface in our controllers which will provide the access to our repository methods.
Learn More
If you want to learn more about repositories and how we can use them in Laravel, read our post on How to Use Repository Pattern in Laravel.
Adding Attribute Routes
Next, we will add the required routes for our admin’s attribute section. For this, open the admin.php
file from routes folder and add the below routes in this file.
Route::group(['prefix' => 'attributes'], function() { Route::get('/', 'Admin\AttributeController@index')->name('admin.attributes.index'); Route::get('/create', 'Admin\AttributeController@create')->name('admin.attributes.create'); Route::post('/store', 'Admin\AttributeController@store')->name('admin.attributes.store'); Route::get('/{id}/edit', 'Admin\AttributeController@edit')->name('admin.attributes.edit'); Route::post('/update', 'Admin\AttributeController@update')->name('admin.attributes.update'); Route::get('/{id}/delete', 'Admin\AttributeController@delete')->name('admin.attributes.delete'); });
Creating Attribute Controller
Now we will add the AttributeController as you might have noticed all our routes in above section are pointing to AttributeController. Open your command line terminal and run the below artisan command to generate a controller.
php artisan make:controller Admin\AttributeController
This will generate a simple controller file for you in app/Http/Controllers/Admin folder. Just like Category controller, we will use our BaseController
to extend this Attribute controller.
namespace App\Http\Controllers\Admin; use Illuminate\Http\Request; use App\Http\Controllers\BaseController; use App\Contracts\AttributeContract; class AttributeController extends BaseController { // }
Firstly, we will add the $attributeRepository
property and inject our AttributeContract in it.
namespace App\Http\Controllers\Admin; use Illuminate\Http\Request; use App\Http\Controllers\BaseController; use App\Contracts\AttributeContract; class AttributeController extends BaseController { protected $attributeRepository; public function __construct(AttributeContract $attributeRepository) { $this->attributeRepository = $attributeRepository; } }
Now, we need to add the index()
, create()
, store()
, edit()
, update()
and delete()
method in it which we will do in the coming sections.
Creating Attribures List Page
First thing, we have to create an index()
method, which will load all the attributes. For that add the below code in your AttributeController
.
public function index() { $attributes = $this->attributeRepository->listAttributes(); $this->setPageTitle('Attributes', 'List of all attributes'); return view('admin.attributes.index', compact('attributes')); }
As you can see, firstly we are loading all attributes using the attribute repository, then setting thr page titile and subtitle and finally returning a view named index.blade.php
.
Create a new file in resources/views/admin/attributes
folder and name it index.blade.php
.
Now, copy paste the below code in it.
@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.attributes.create') }}" class="btn btn-primary pull-right">Add Attribute</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> Code </th> <th> Name </th> <th class="text-center"> Frontend Type </th> <th class="text-center"> Filterable </th> <th class="text-center"> Required </th> <th style="width:100px; min-width:100px;" class="text-center text-danger"><i class="fa fa-bolt"> </i></th> </tr> </thead> <tbody> @foreach($attributes as $attribute) <tr> <td>{{ $attribute->code }}</td> <td>{{ $attribute->name }}</td> <td>{{ $attribute->frontend_type }}</td> <td class="text-center"> @if ($attribute->is_filterable == 1) <span class="badge badge-success">Yes</span> @else <span class="badge badge-danger">No</span> @endif </td> <td class="text-center"> @if ($attribute->is_required == 1) <span class="badge badge-success">Yes</span> @else <span class="badge badge-danger">No</span> @endif </td> <td class="text-center"> <div class="btn-group" role="group" aria-label="Second group"> <a href="{{ route('admin.attributes.edit', $attribute->id) }}" class="btn btn-sm btn-primary"><i class="fa fa-edit"></i></a> <a href="{{ route('admin.attributes.delete', $attribute->id) }}" class="btn btn-sm btn-danger"><i class="fa fa-trash"></i></a> </div> </td> </tr> @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
In this view, we are looping through the $attributes
variable a listing all attributes.
Visit the /admin/attributes
route in your browser and you will be presented a page like below.

Creating Attributes Create Page
In this section, we will create a Create page, from where we will be able to create a new attribute. Open the AttributeController and add below function in it.
public function create() { $this->setPageTitle('Attributes', 'Create Attribute'); return view('admin.attributes.create'); }
Create a new file in the resources/views/admin/attributes
folder and name it create.blade.php. Add the below HTML markup in this file.
@extends('admin.app') @section('title') {{ $pageTitle }} @endsection @section('content') <div class="app-title"> <div> <h1><i class="fa fa-cogs"></i> {{ $pageTitle }}</h1> </div> </div> @include('admin.partials.flash') <div class="row user"> <div class="col-md-3"> <div class="tile p-0"> <ul class="nav flex-column nav-tabs user-tabs"> <li class="nav-item"><a class="nav-link active" href="#general" data-toggle="tab">General</a></li> </ul> </div> </div> <div class="col-md-9"> <div class="tab-content"> <div class="tab-pane active" id="general"> <div class="tile"> <form action="{{ route('admin.attributes.store') }}" method="POST" role="form"> @csrf <h3 class="tile-title">Attribute Information</h3> <hr> <div class="tile-body"> <div class="form-group"> <label class="control-label" for="code">Code</label> <input class="form-control" type="text" placeholder="Enter attribute code" id="code" name="code" value="{{ old('code') }}" /> </div> <div class="form-group"> <label class="control-label" for="name">Name</label> <input class="form-control" type="text" placeholder="Enter attribute name" id="name" name="name" value="{{ old('name') }}" /> </div> <div class="form-group"> <label class="control-label" for="frontend_type">Frontend Type</label> @php $types = ['select' => 'Select Box', 'radio' => 'Radio Button', 'text' => 'Text Field', 'text_area' => 'Text Area']; @endphp <select name="frontend_type" id="frontend_type" class="form-control"> @foreach($types as $key => $label) <option value="{{ $key }}">{{ $label }}</option> @endforeach </select> </div> <div class="form-group"> <div class="form-check"> <label class="form-check-label"> <input class="form-check-input" type="checkbox" id="is_filterable" name="is_filterable"/>Filterable </label> </div> </div> <div class="form-group"> <div class="form-check"> <label class="form-check-label"> <input class="form-check-input" type="checkbox" id="is_required" name="is_required"/>Required </label> </div> </div> </div> <div class="tile-footer"> <div class="row d-print-none mt-2"> <div class="col-12 text-right"> <button class="btn btn-success" type="submit"><i class="fa fa-fw fa-lg fa-check-circle"></i>Save Attribute</button> <a class="btn btn-danger" href="{{ route('admin.attributes.index') }}"><i class="fa fa-fw fa-lg fa-arrow-left"></i>Go Back</a> </div> </div> </div> </form> </div> </div> </div> </div> </div> @endsection
In this file, we added a form with the required fields for our attributes. This form is poiting to admin.attributes.store
route. So let’s create this function in our AttributeController controller.
public function store(Request $request) { $this->validate($request, [ 'code' => 'required', 'name' => 'required', 'frontend_type' => 'required' ]); $params = $request->except('_token'); $attribute = $this->attributeRepository->createAttribute($params); if (!$attribute) { return $this->responseRedirectBack('Error occurred while creating attribute.', 'error', true, true); } return $this->responseRedirect('admin.attributes.index', 'Attribute added successfully' ,'success',false, false); }
In this method, we are making some form validation and then passing all data to our AttributeRepository’s createAttribute()
method.
Now visit the /admin/attributes/create
route in your browser and you will be presented with the below page.

Try to enter some data in this form and hit save attribute button. Your form should be successfully submitted and you will be able to see a new attribute added to your attributes table.
Creating Attributes Edit Page
Now, we will add the edit attribute functionality in our admin area. Add the below edit()
method in your AttributeController class.
public function edit($id) { $attribute = $this->attributeRepository->findAttributeById($id); $this->setPageTitle('Attributes', 'Edit Attribute : '.$attribute->name); return view('admin.attributes.edit', compact('attribute')); }
You can see in this method we are finding the attribute by id
and then passing it on to our edit.blade.php
view.
Create a new file called edit.blade.php
in resources/views/admin/attributes folder. 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-cogs"></i> {{ $pageTitle }}</h1> </div> </div> @include('admin.partials.flash') <div class="row user"> <div class="col-md-3"> <div class="tile p-0"> <ul class="nav flex-column nav-tabs user-tabs"> <li class="nav-item"><a class="nav-link active" href="#general" data-toggle="tab">General</a></li> </ul> </div> </div> <div class="col-md-9"> <div class="tab-content"> <div class="tab-pane active" id="general"> <div class="tile"> <form action="{{ route('admin.attributes.update') }}" method="POST" role="form"> @csrf <h3 class="tile-title">Attribute Information</h3> <hr> <div class="tile-body"> <div class="form-group"> <label class="control-label" for="code">Code</label> <input class="form-control" type="text" placeholder="Enter attribute code" id="code" name="code" value="{{ old('code', $attribute->code) }}" /> </div> <input type="hidden" name="id" value="{{ $attribute->id }}"> <div class="form-group"> <label class="control-label" for="name">Name</label> <input class="form-control" type="text" placeholder="Enter attribute name" id="name" name="name" value="{{ old('name', $attribute->name) }}" /> </div> <div class="form-group"> <label class="control-label" for="frontend_type">Frontend Type</label> @php $types = ['select' => 'Select Box', 'radio' => 'Radio Button', 'text' => 'Text Field', 'text_area' => 'Text Area']; @endphp <select name="frontend_type" id="frontend_type" class="form-control"> @foreach($types as $key => $label) @if ($attribute->frontend_type == $key) <option value="{{ $key }}" selected>{{ $label }}</option> @else <option value="{{ $key }}">{{ $label }}</option> @endif @endforeach </select> </div> <div class="form-group"> <div class="form-check"> <label class="form-check-label"> <input class="form-check-input" type="checkbox" id="is_filterable" name="is_filterable" {{ $attribute->is_filterable == 1 ? 'checked' : '' }}/>Filterable </label> </div> </div> <div class="form-group"> <div class="form-check"> <label class="form-check-label"> <input class="form-check-input" type="checkbox" id="is_required" name="is_required" {{ $attribute->is_required == 1 ? 'checked' : '' }}/>Required </label> </div> </div> </div> <div class="tile-footer"> <div class="row d-print-none mt-2"> <div class="col-12 text-right"> <button class="btn btn-success" type="submit"><i class="fa fa-fw fa-lg fa-check-circle"></i>Update Attribute</button> <a class="btn btn-danger" href="{{ route('admin.attributes.index') }}"><i class="fa fa-fw fa-lg fa-arrow-left"></i>Go Back</a> </div> </div> </div> </form> </div> </div> </div> </div> </div> @endsection
Next, we will add the update()
method in our attribute controller.
public function update(Request $request) { $this->validate($request, [ 'code' => 'required', 'name' => 'required', 'frontend_type' => 'required' ]); $params = $request->except('_token'); $attribute = $this->attributeRepository->updateAttribute($params); if (!$attribute) { return $this->responseRedirectBack('Error occurred while updating attribute.', 'error', true, true); } return $this->responseRedirectBack('Attribute updated successfully' ,'success',false, false); }
Now if you edit any attribute from the attributes list page, you will have fully working edit page like below.

Deleting Attribute
Final functionality left for attributes section is the delete()
method. Add the below function in you attribute controller.
public function delete($id) { $attribute = $this->attributeRepository->deleteAttribute($id); if (!$attribute) { return $this->responseRedirectBack('Error occurred while deleting attribute.', 'error', true, true); } return $this->responseRedirect('admin.attributes.index', 'Attribute deleted successfully' ,'success',false, false); }
You can test this functionality, by clicking the delete button on the attributes list page.
Conclusion
That’s it for now, in the next post we will start enhancing the edit page of attributes section, from where we can define the attribute values.
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.