Laravel E-Commerce Application Development – Base Controller and Repository

Laravel E-Commerce Application Development – Base Controller and Repository

Laravel E-Commerce Application Development ( 26 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 – Wrap Up

This is the fifth part of the Laravel E-Commerce Application Development series, in this part we will create a base controller and repository. During the whole series, we will use this base controller and repository for our both admin and frontend area.

In the last part, we added the admin authentication so I assume you will have your project ready with a working admin login functionality.

Why Base Controller and Repository?

Sometime when creating any web application, we mostly make our code messy due to the repetition of the same steps again and again. For example, when we send a response from the controller we want to make sure if the request is Ajax then send JSON response and if it’s an Http request then send the normal response.

During returning responses, we want to perform some of our own actions which are the same for every Http request, I am willing to handle the below tasks in the base controller:

  • Setting view’s title from the controller
  • Setting flash messages to show in the view

When dealing with the database, we do exactly the same! Repeat our code again and again.. An example could be, mostly simple CRUD (Create Read Update Delete) requires mostly same logic for our models. We can handle this duplication using the repositories, our base repository will provide all the basic methods, in our model repository, we will simply extend this repository.

Read More

You can read more about why we should opt for repositories in this article.
How to use Repository Pattern in Laravel

Creating Flash Messages Trait

To show flash messages to users, you can simply use the Laravel’s flash messages helper session()->flash() or there are various Laravel’s packages which provides this functionality.

I always tend to use as fewer packages as I can because I really don’t want to depend on a huge number of packages which becomes very difficult to handle especially when you are trying to update your code base.

You can choose how you want to handle flash messages but I will be sharing how I mostly write code in my projects.

So without any delay, let’s start some coding!

Create a new folder inside app folder called Traits, and add a new php file in it named FlashMessages. Open this file and define FlashMessages trait like below:

namespace App\Traits;

trait FlashMessages
{
    //
}

In this trait firstly, we will define some private properties and set them as an array like below.

namespace App\Traits;

/**
 * Trait FlashMessages
 * @package App\Traits
 */
trait FlashMessages
{
    /**
     * @var array
     */
    protected $errorMessages = [];

    /**
     * @var array
     */
    protected $infoMessages = [];

    /**
     * @var array
     */
    protected $successMessages = [];

    /**
     * @var array
     */
    protected $warningMessages = [];
}

Now, we will need to add setter and getter functions for flash messages. Firstly, we will add a new setter method called setFlashMessage.

/**
 * @param $message
 * @param $type
 */
protected function setFlashMessage($message, $type)
{
    $model = 'infoMessages';

    switch ($type) {
        case 'info': {
            $model = 'infoMessages';
        }
            break;
        case 'error': {
            $model = 'errorMessages';
        }
            break;
        case 'success': {
            $model = 'successMessages';
        }
            break;
        case 'warning': {
            $model = 'warningMessages';
        }
            break;
    }

    if (is_array($message)) {
        foreach ($message as $key => $value)
        {
            array_push($this->$model, $value);
        }
    } else {
        array_push($this->$model, $message);
    }
}

In the setter function, we running the switch statement on $type and setting the right property based on type. Then we are checking if the $message is in array format if yes, then we are pushing all values from the array to our array property. If it is a single message then simply pushing the message to our property.

Next, we will add a getter function to get flash messages.

/**
 * @return array
 */
protected function getFlashMessage()
{
    return [
        'error'     =>  $this->errorMessages,
        'info'      =>  $this->infoMessages,
        'success'   =>  $this->successMessages,
        'warning'   =>  $this->warningMessages,
    ];
}

Our getter function will return an array of all flash messages properties like above. Pretty simple.

Now, we will add a new function to our FlashMessages trait called showFlashMessage.

/**
 * Flushing flash messages to Laravel's session
 */
protected function showFlashMessages()
{
    session()->flash('error', $this->errorMessages);
    session()->flash('info', $this->infoMessages);
    session()->flash('success', $this->successMessages);
    session()->flash('warning', $this->warningMessages);
}

In above function, we set the flash messages of all types to Laravel session.

That’s it for this flash messages trait. Now we will move on to the base controller.

Creating Base Controller

Open your terminal and run the below command to generate a controller called BaseController.

php artisan make:controller BaseController

Laravel will generate new controller in app/Http/Controller folder named BaseController. Open this controller an add the FlashMessages trait we created earlier like below:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Traits\FlashMessages;

class BaseController extends Controller
{
    use FlashMessages;

    //
}

Firstly, we will define a new property called $data and set it to null right after the use FlashMessages; statement.

protected $data = null;

Next, we create a new protected method in the BaseController to set the page title and subtitle like below:

/**
 * @param $title
 * @param $subTitle
 */
protected function setPageTitle($title, $subTitle)
{
    view()->share(['pageTitle' => $title, 'subTitle' => $subTitle]);
}

This function is taking two parameters $title and $subtitle. We use the view() helper function to attach them using share() method.

Now, we will add a new protected method to show error page with our custom message and type of error page we want to load.

/**
 * @param int $errorCode
 * @param null $message
 * @return \Illuminate\Http\Response
 */
protected function showErrorPage($errorCode = 404, $message = null)
{
    $data['message'] = $message;
    return response()->view('errors.'.$errorCode, $data, $errorCode);
}

In the above method, we are loading an error view from errors folder based on the error type, by default, it will be a 404 error page and passing the custom message to it using the $data property.

If we are using ajax or VueJs in our application, then we might need to send a JSON response, so we will add the responseJson method like below.

/**
 * @param bool $error
 * @param int $responseCode
 * @param array $message
 * @param null $data
 * @return \Illuminate\Http\JsonResponse
 */
protected function responseJson($error = true, $responseCode = 200, $message = [], $data = null)
{
    return response()->json([
        'error'         =>  $error,
        'response_code' => $responseCode,
        'message'       => $message,
        'data'          =>  $data
    ]);
}

Now we want to redirect to a page or route if the request is HTTP, so we will add a responseRedirect method.

 /**
 * @param $route
 * @param $message
 * @param string $type
 * @param bool $error
 * @param bool $withOldInputWhenError
 * @return \Illuminate\Http\RedirectResponse
 */
protected function responseRedirect($route, $message, $type = 'info', $error = false, $withOldInputWhenError = false)
{
    $this->setFlashMessage($message, $type);
    $this->showFlashMessages();

    if ($error && $withOldInputWhenError) {
        return redirect()->back()->withInput();
    }

    return redirect()->route($route);
}

As you can see firstly, we are setting the flash message using setFlashMessage function provided by the FlashMessages trait and then showing the messages which are actually setting the messages to the session.

Then we are returning back if there is an error with the input, if not we are simply redirecting it to the route provided.

In some cases, we might want to redirect the user to the previous page, for example when we update a category we should send the user to the same category view. For that, we will add a new function responseRedirectBack.

/**
 * @param $message
 * @param string $type
 * @param bool $error
 * @param bool $withOldInputWhenError
 * @return \Illuminate\Http\RedirectResponse
 */
protected function responseRedirectBack($message, $type = 'info', $error = false, $withOldInputWhenError = false)
{
    $this->setFlashMessage($message, $type);
    $this->showFlashMessages();

    return redirect()->back();
}

Above function is pretty simple, setting flash messages and then returning back.

How To Use Base Controller

By default all controllers extend Laravel’s App\Http\Controllers\Controller class, from now on when ever we will create a new controller, we will extend it with our BaseController class.

That’s it for base controller now we will move to the base repository.

Creating Base Repository

For base repository, we will need to create an interface which we will implement in our base repository. Create a new folder in app folder called Contracts and add a new file called BaseContract.php.

Once you have created the file, add below code in it.

namespace App\Contracts;

/**
 * Interface BaseContract
 * @package App\Contracts
 */
interface BaseContract
{
    /**
     * Create a model instance
     * @param array $attributes
     * @return mixed
     */
    public function create(array $attributes);

    /**
     * Update a model instance
     * @param array $attributes
     * @param int $id
     * @return mixed
     */
    public function update(array $attributes, int $id);

    /**
     * Return all model rows
     * @param array $columns
     * @param string $orderBy
     * @param string $sortBy
     * @return mixed
     */
    public function all($columns = array('*'), string $orderBy = 'id', string $sortBy = 'desc');

    /**
     * Find one by ID
     * @param int $id
     * @return mixed
     */
    public function find(int $id);

    /**
     * Find one by ID or throw exception
     * @param int $id
     * @return mixed
     */
    public function findOneOrFail(int $id);

    /**
     * Find based on a different column
     * @param array $data
     * @return mixed
     */
    public function findBy(array $data);

    /**
     * Find one based on a different column
     * @param array $data
     * @return mixed
     */
    public function findOneBy(array $data);

    /**
     * Find one based on a different column or through exception
     * @param array $data
     * @return mixed
     */
    public function findOneByOrFail(array $data);

    /**
     * Delete one by Id
     * @param int $id
     * @return mixed
     */
    public function delete(int $id);
}

I have added the comments for each method signature, just go through it.

Now, we will create a new folder in app folder, called Repositories and add a new file called BaseRepository.php. Define a new class in this file like below.

namespace App\Repositories;

/**
 * Class BaseRepository
 *
 * @package \App\Repositories
 */
class BaseRepository
{

}

Now we will implement the BaseContract in this class.

namespace App\Repositories;

use App\Contracts\BaseContract;
/**
 * Class BaseRepository
 *
 * @package \App\Repositories
 */
class BaseRepository implements BaseContract
{

}

Next, will define a $model property in this class and inject the eloquent model class using the class constructor.

namespace App\Repositories;

use App\Contracts\BaseContract;
use Illuminate\Database\Eloquent\Model;
/**
 * Class BaseRepository
 *
 * @package \App\Repositories
 */
class BaseRepository implements BaseContract
{
    protected $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }
}

Now we will implement all the methods we defined in the BaseContract like below. If you have some experience in Laravel, then you will be comfortable with the implementation of all below code.
Simply copy paste it to your class.

namespace App\Repositories;

use App\Contracts\BaseContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
/**
 * Class BaseRepository
 *
 * @package \App\Repositories
 */
class BaseRepository implements BaseContract
{
    /**
     * @var Model
     */
    protected $model;

    /**
     * BaseRepository constructor.
     * @param Model $model
     */
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * @param array $attributes
     * @return mixed
     */
    public function create(array $attributes)
    {
        return $this->model->create($attributes);
    }

    /**
     * @param array $attributes
     * @param int $id
     * @return bool
     */
    public function update(array $attributes, int $id) : bool
    {
        return $this->find($id)->update($attributes);
    }

    /**
     * @param array $columns
     * @param string $orderBy
     * @param string $sortBy
     * @return mixed
     */
    public function all($columns = array('*'), string $orderBy = 'id', string $sortBy = 'asc')
    {
        return $this->model->orderBy($orderBy, $sortBy)->get($columns);
    }

    /**
     * @param int $id
     * @return mixed
     */
    public function find(int $id)
    {
        return $this->model->find($id);
    }

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

    /**
     * @param array $data
     * @return mixed
     */
    public function findBy(array $data)
    {
        return $this->model->where($data)->all();
    }

    /**
     * @param array $data
     * @return mixed
     */
    public function findOneBy(array $data)
    {
        return $this->model->where($data)->first();
    }

    /**
     * @param array $data
     * @return mixed
     * @throws ModelNotFoundException
     */
    public function findOneByOrFail(array $data)
    {
        return $this->model->where($data)->firstOrFail();
    }

    /**
     * @param int $id
     * @return bool
     */
    public function delete(int $id) : bool
    {
        return $this->model->find($id)->delete();
    }
}

Conclusion

Now, we have our base repository and controller ready. In the next post, we will see how we can use the base repository and controller.

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.

13 comments on “Laravel E-Commerce Application Development – Base Controller and Repository

  1. There is a small typo:
    in responseRedirectBack() method we are calling method $this->setFlashMessages($message, $type); while it should be setFlashMessage($message, $type); as the method name defined in trai is setFlashMessage($message,$type) not setFlashMessages($message, $type);

  2. Thanks from your great series
    I would like to report that there is a mistake in ResponseRedirectBack method you added two extra unused parameters ( $error = false, $withOldInputWhenError = false) cause these two parameters are not used.

  3. Hi! Can you help me to understand how to implement the methods: showErrorPage, responseJson, responseRedirect, responseRedirectBack in a project which using VueJS and vue-router?

    Please, I’ll appreciate your help.

    Thanks for these articles.

  4. BadMethodCallException
    Call to undefined method Illuminate\Database\Eloquent\Builder::all()
    This error is here: return $this->model->where($data)->all(); in the method findBy(array $data) in BaseRepository.php…

    public function findBy(array $data)
    {
    return $this->model->where($data)->all();
    }

    when i change all() by get(), it work fine, i run laravel 5.8

    1. When you apply where() clause, you have to chain the get() method. all() return the all records for a model while if apply any condition to your query you have to use the get() method.

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.

Your little help will keep this site alive and help us to produce quality content for you.