Laravel E-Commerce Application Development – Brands Section
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 13 of the Laravel E-Commerce Application Development series. In this part, we will add the brands’ section to our backend panel.
As this section work will be much similar to the categories section, I will keep it very simple.
Adding Routes
Firstly, we will add the required routes for our Brands section. For this, open the admin.php
file from the routes folder and add the below routes right after the attributes routes.
Route::group(['prefix' => 'brands'], function() { Route::get('/', 'Admin\BrandController@index')->name('admin.brands.index'); Route::get('/create', 'Admin\BrandController@create')->name('admin.brands.create'); Route::post('/store', 'Admin\BrandController@store')->name('admin.brands.store'); Route::get('/{id}/edit', 'Admin\BrandController@edit')->name('admin.brands.edit'); Route::post('/update', 'Admin\BrandController@update')->name('admin.brands.update'); Route::get('/{id}/delete', 'Admin\BrandController@delete')->name('admin.brands.delete'); });
Adding Sidebar Link
First thing first, we need to add the brands’ link to our menu in the 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 dashboard link.
<li> <a class="app-menu__item {{ Route::currentRouteName() == 'admin.brands.index' ? 'active' : '' }}" href="{{ route('admin.brands.index') }}"> <i class="app-menu__icon fa fa-briefcase"></i> <span class="app-menu__label">Brands</span> </a> </li>
Creating Brand Controller
We have already added the routes to our admin.php
file, which all points to the BrandController. Let’s create this controller using the below command.
php artisan make:controller Admin\BrandController
Above command will generate the BrandController in app/Http/Controllers/Admin folder, open this file and replace the content with the below one.
namespace App\Http\Controllers\Admin; use Illuminate\Http\Request; use App\Contracts\BrandContract; use App\Http\Controllers\BaseController; class BrandController extends BaseController { // }
We will leave this controller as it is and will be adding the required methods in the upcoming sections.
Creating Brand Model and Migration
To save our brands data into the database, we will need to create a migration and model for Brand. Run the below command in the terminal to generate a model and migration.
php artisan make:model Models\Brand -m
The -m
flag will create a migration file for our Brand model. Above command will generate a Brand model in app/Models
folder and a migration file for this model in database/migrations
folder.
Open your migration file and update with the below class.
use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateBrandsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('brands', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name', 45); $table->string('slug'); $table->string('logo')->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('brands'); } }
Now run the below command to generate the brands
table in your database.
php artisan migrate
Above migration will create the brands’ table with name and logo it’s fields.
Now, open you Brand model from app/Models
folder and update the whole class with the below one.
namespace App\Models; use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Model; /** * Class Brand * @package App\Models */ class Brand extends Model { /** * @var string */ protected $table = 'brands'; /** * @var array */ protected $fillable = ['name', 'slug', 'logo']; /** * @param $value */ public function setNameAttribute($value) { $this->attributes['name'] = $value; $this->attributes['slug'] = Str::slug($value); } }
In the above model class, we have defined the table for our brands and fillable property for mass assignment.
Creating Brand Contract and Repository
Now, we will create an interface for our Brand model. Create a new file called BrandContract.php in app/Contracts
folder and add the below code block in it.
namespace App\Contracts; /** * Interface BrandContract * @package App\Contracts */ interface BrandContract { /** * @param string $order * @param string $sort * @param array $columns * @return mixed */ public function listBrands(string $order = 'id', string $sort = 'desc', array $columns = ['*']); /** * @param int $id * @return mixed */ public function findBrandById(int $id); /** * @param array $params * @return mixed */ public function createBrand(array $params); /** * @param array $params * @return mixed */ public function updateBrand(array $params); /** * @param $id * @return bool */ public function deleteBrand($id); }
In this contract, we have added some method signatures to deal with our Brand model. Just like we did in the categories section.
Next, create a new file in the app/Repositories folder and name it BrandRepository. Add the below code in it so we will have a repository which will implement our BrandContract interface and extend the base repository.
namespace App\Repositories; use App\Models\Brand; use App\Traits\UploadAble; use Illuminate\Http\UploadedFile; use App\Contracts\BrandContract; use Illuminate\Database\QueryException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Doctrine\Instantiator\Exception\InvalidArgumentException; /** * Class CategoryRepository * * @package \App\Repositories */ class BrandRepository extends BaseRepository implements BrandContract { use UploadAble; /** * CategoryRepository constructor. * @param Brand $model */ public function __construct(Brand $model) { parent::__construct($model); $this->model = $model; } /** * @param string $order * @param string $sort * @param array $columns * @return mixed */ public function listBrands(string $order = 'id', string $sort = 'desc', array $columns = ['*']) { return $this->all($columns, $order, $sort); } /** * @param int $id * @return mixed * @throws ModelNotFoundException */ public function findBrandById(int $id) { try { return $this->findOneOrFail($id); } catch (ModelNotFoundException $e) { throw new ModelNotFoundException($e); } } /** * @param array $params * @return Brand|mixed */ public function createBrand(array $params) { try { $collection = collect($params); $logo = null; if ($collection->has('logo') && ($params['logo'] instanceof UploadedFile)) { $logo = $this->uploadOne($params['logo'], 'brands'); } $merge = $collection->merge(compact('logo')); $brand = new Brand($merge->all()); $brand->save(); return $brand; } catch (QueryException $exception) { throw new InvalidArgumentException($exception->getMessage()); } } /** * @param array $params * @return mixed */ public function updateBrand(array $params) { $brand = $this->findBrandById($params['id']); $collection = collect($params)->except('_token'); if ($collection->has('logo') && ($params['logo'] instanceof UploadedFile)) { if ($brand->logo != null) { $this->deleteOne($brand->logo); } $logo = $this->uploadOne($params['logo'], 'brands'); } $merge = $collection->merge(compact('logo')); $brand->update($merge->all()); return $brand; } /** * @param $id * @return bool|mixed */ public function deleteBrand($id) { $brand = $this->findBrandById($id); if ($brand->logo != null) { $this->deleteOne($brand->logo); } $brand->delete(); return $brand; } }
In the above code block, we added the implementation of our BrandContract signatures. Again, the whole functionality is similar to what we did for our categories, nothing fancy.
Next, we need to bind the BrandContract to our BrandRepository. Open the RepositoryServiceProvider class from app/Providers
folder and include the interface and repository like below.
use App\Contracts\BrandContract; use App\Repositories\BrandRepository;
Next, update the $repositories
property like below.
protected $repositories = [ CategoryContract::class => CategoryRepository::class, AttributeContract::class => AttributeRepository::class, BrandContract::class => BrandRepository::class, ];
Now, we can use the BrandContract interface in our controllers which will provide access to our repository methods.
Open the BrandController file and update with the below one.
namespace App\Http\Controllers\Admin; use Illuminate\Http\Request; use App\Contracts\BrandContract; use App\Http\Controllers\BaseController; class BrandController extends BaseController { /** * @var BrandContract */ protected $brandRepository; /** * CategoryController constructor. * @param BrandContract $brandRepository */ public function __construct(BrandContract $brandRepository) { $this->brandRepository = $brandRepository; } }
Creating Brand Listing Page
First thing, we have to create an index()
method, which will load all the brands. For that add the below code in your BrandController
.
/** * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function index() { $brands = $this->brandRepository->listBrands(); $this->setPageTitle('Brands', 'List of all brands'); return view('admin.brands.index', compact('brands')); }
As you can see, firstly we are loading all brands using the brand repository, then setting the page title and subtitle and finally returning a view named index.blade.php
.
Create a new file in resources/views/admin/brands
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-briefcase"></i> {{ $pageTitle }}</h1> <p>{{ $subTitle }}</p> </div> <a href="{{ route('admin.brands.create') }}" class="btn btn-primary pull-right">Add Brand</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 style="width:100px; min-width:100px;" class="text-center text-danger"><i class="fa fa-bolt"> </i></th> </tr> </thead> <tbody> @foreach($brands as $brand) <tr> <td>{{ $brand->id }}</td> <td>{{ $brand->name }}</td> <td>{{ $brand->slug }}</td> <td class="text-center"> <div class="btn-group" role="group" aria-label="Second group"> <a href="{{ route('admin.brands.edit', $brand->id) }}" class="btn btn-sm btn-primary"><i class="fa fa-edit"></i></a> <a href="{{ route('admin.brands.delete', $brand->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 $brands
variable passed throught the BrandController which listing all brands.
Creating Brand
In this section, we will create a Create page, from where we will be able to create a new brand. Open the BrandController and add below function in it.
/** * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function create() { $this->setPageTitle('Brands', 'Create Brand'); return view('admin.brands.create'); }
Create a new file in the resources/views/admin/brands
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-briefcase"></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.brands.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">Brand Logo</label> <input class="form-control @error('logo') is-invalid @enderror" type="file" id="logo" name="logo"/> @error('logo') {{ $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 Brand</button> <a class="btn btn-secondary" href="{{ route('admin.brands.index') }}"><i class="fa fa-fw fa-lg fa-times-circle"></i>Cancel</a> </div> </form> </div> </div> </div> @endsection
In this file, we added a form with the required fields for our brand. This form is poiting to admin.brands.store
route. So let’s create this function in our BrandController controller.
/** * @param Request $request * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Validation\ValidationException */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:191', 'image' => 'mimes:jpg,jpeg,png|max:1000' ]); $params = $request->except('_token'); $brand = $this->brandRepository->createBrand($params); if (!$brand) { return $this->responseRedirectBack('Error occurred while creating brand.', 'error', true, true); } return $this->responseRedirect('admin.brands.index', 'Brand added successfully' ,'success',false, false); }
In this method, we are making some form validation and then passing all data to our BrandRepository’s createBrand()
method.
Now visit the /admin/brands/create
route in your browser and you will be presented with form to create a brand.
Try to enter some data in this form and hit save brand button. Your form should be successfully submitted and you will be able to see a new brand added to your brands
table.
Editing Brand
Now, we will add the edit brand functionality in our admin area. Add the below edit()
method in your BrandController class.
/** * @param $id * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function edit($id) { $brand = $this->brandRepository->findBrandById($id); $this->setPageTitle('Brands', 'Edit Brand : '.$brand->name); return view('admin.brands.edit', compact('brand')); }
You can see in this method we are finding the brand 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/brands 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-briefcase"></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.brands.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', $brand->name) }}"/> <input type="hidden" name="id" value="{{ $brand->id }}"> @error('name') {{ $message }} @enderror </div> <div class="form-group"> <div class="row"> @if ($brand->logo != null) <div class="col-md-2"> <figure class="mt-2" style="width: 80px; height: auto;"> <img src="{{ asset('storage/'.$brand->logo) }}" id="brandLogo" class="img-fluid" alt="img"> </figure> </div> @endif <div class="col-md-10"> <label class="control-label">Brand Logo</label> <input class="form-control @error('logo') is-invalid @enderror" type="file" id="logo" name="logo"/> @error('logo') {{ $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>Save Brand</button> <a class="btn btn-secondary" href="{{ route('admin.brands.index') }}"><i class="fa fa-fw fa-lg fa-times-circle"></i>Cancel</a> </div> </form> </div> </div> </div> @endsection
Next, we will add the update()
method in our brand controller.
/** * @param Request $request * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Validation\ValidationException */ public function update(Request $request) { $this->validate($request, [ 'name' => 'required|max:191', 'image' => 'mimes:jpg,jpeg,png|max:1000' ]); $params = $request->except('_token'); $brand = $this->brandRepository->updateBrand($params); if (!$brand) { return $this->responseRedirectBack('Error occurred while updating brand.', 'error', true, true); } return $this->responseRedirectBack('Brand updated successfully' ,'success',false, false); }
Now if you edit any brand from the brands’ list page, you will have fully working edit page.
Deleting a Brand
Final functionality left for brands section is the delete()
method. Add the below function in you brand controller.
/** * @param $id * @return \Illuminate\Http\RedirectResponse */ public function delete($id) { $brand = $this->brandRepository->deleteBrand($id); if (!$brand) { return $this->responseRedirectBack('Error occurred while deleting brand.', 'error', true, true); } return $this->responseRedirect('admin.brands.index', 'Brand deleted successfully' ,'success',false, false); }
You can test this functionality, by clicking the delete button on the brands’ list page.
Conclusion
That’s it for now, in the next post we will start to continue working on the Product 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 and I will try my best to answer your questions.