X
    Categories: Laravel

Custom repository pattern in Laravel 5.4

Custom repository pattern in Laravel 5.4

Custom repository pattern in Laravel 5.4 ,Why do we want to use some packages and want to increase page load time. Lets create simple repository pattern by own in laravel 5.4. Lets see how to create repository pattern.

Step 1 : Create Repository Interface

My folder structure is : App\Contracts\Repository

App\Contracts\Repository\RepositoryInterface.php

<?php
namespace App\Contracts\Repository;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Pagination\Paginator;

interface RepositoryInterface
{
    ////////////////////////////////////////////////////////////////////
    ////////////////////////////// CORE DATA ///////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Eager load relations on the base Query.
     *
     * @param array $relations
     *
     * @return self
     */
    public function eagerLoad($relations);

    /**
     * Change the core items.
     *
     * @param AbstractModel $items
     *
     * @return \Arrounded\Abstracts\AbstractRepository
     */
    public function setItems($items);

    /**
     * Get the core items query.
     *
     * @return AbstractModel
     */
    public function items();

    ////////////////////////////////////////////////////////////////////
    //////////////////////////////// SINGLE ////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Find a particular item.
     *
     * @param int $item
     *
     * @return AbstractModel
     */
    public function find($item);

    /**
     * Find a particular item.
     *
     * @param int $item
     *
     * @return AbstractModel
     */
    public function findBySlug($item);

    /**
     * Find or instantiate an instance of an item from a set of attributes.
     *
     * @param array $attributes
     *
     * @return AbstractModel
     */
    public function findOrNew($attributes = []);

    /**
     * Create an entry from an array of attributes.
     *
     * @param array $attributes
     *
     * @return AbstractModel
     */
    public function create(array $attributes = []);

    /**
     * Update an item.
     *
     * @param AbstractModel|int $item
     * @param array             $attributes
     *
     * @return AbstractModel
     */
    public function update($item, array $attributes = []);

    /**
     * Delete an item.
     *
     * @param AbstractModel|int $item
     * @param bool              $force
     *
     * @return bool
     */
    public function delete($item, $force);

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////// MULTIPLE ////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Return all items.
     *
     * @param int|null $perPage
     *
     * @return Collection
     */
    public function all($perPage = null);

    /**
     * Get all items, paginated.
     *
     * @param int $perPage
     *
     * @return Paginator
     */
    public function getPaginated($perPage = 25);
}

Step 2 : Create BaseRepository which implements Repository interface

My Folder Structure is  : App\Repositories

App\Repositories\BaseRepository.php

<?php
namespace App\Repositories;

use App\Contracts\Repository\RepositoryInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class BaseRepository implements RepositoryInterface
{
    /**
     * The items to fetch from.
     *
     * @type AbstractModel|Builder
     */
    protected $items;

    /**
     * Default number of results per page.
     *
     * @type int
     */
    protected $perPage = 25;

    /**
     * Get the core model instance.
     *
     * @return AbstractModel 
     */
    public function getModelInstance()
    {
        return $this->unwrapQueries($this->items);
    }

    /**
     * Get the name of the model.
     *
     * @return string
     */
    public function getModel()
    {
        return get_class($this->getModelInstance());
    }

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////// CORE DATA ///////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Eager load relations on the base Query.
     *
     * @param array $relations
     *
     * @return self
     */
    public function eagerLoad($relations)
    {
        $this->items = $this->items->with($relations);

        return $this;
    }

    /**
     * Set the number of results to display per page.
     *
     * @param int|null $perPage
     *
     * @return self
     */
    public function setPerPage($perPage = null)
    {
        if ($perPage) {
            $this->perPage = $perPage;
        }

        return $this;
    }

    /**
     * Change the core items.
     *
     * @param AbstractModel|Builder $items
     *
     * @return $this
     */
    public function setItems($items)
    {
        $this->items = $items;

        return $this;
    }

    /**
     * Get the core items query.
     *
     * @return AbstractModel
     */
    public function items()
    {
        return clone $this->getModelInstance();
    }

    ////////////////////////////////////////////////////////////////////
    //////////////////////////////// SINGLE ////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Return a new instance.
     *
     * @param array $attributes
     *
     * @return AbstractModel
     */
    public function instance(array $attributes = [])
    {
        $model = $this->getModel();

        return new $model($attributes);
    }

    /**
     * Find a particular item.
     *
     * @param AbstractModel|array|string|int $item
     *
     * @return AbstractModel
     */
    public function find($item)
    {
        return  $this->findFromQuery($this->items(), $item);
    }

    /**
     * Find a particular item.
     *
     * @param AbstractModel|array|string|int $item
     *
     * @return AbstractModel
     */
    public function findBySlug($slug)
    {
        return $this->items()->whereSlug($slug)->first();
    }

    /**
     * Search for a model in the trash.
     *
     * @param AbstractModel|array|string|int $item
     *
     * @return AbstractModel
     */
    public function findInTrash($item)
    {
        // Cancel if model doesn't soft-delete
        if (!$this->getModelInstance()->softDeletes()) {
            return $this->find($item);
        }

        return $this->findFromQuery($this->items()->withTrashed(), $item);
    }

    /**
     * Find or instantiate an instance of an item from a set of attributes.
     *
     * @param array $attributes
     *
     * @return AbstractModel
     */
    public function findOrNew($attributes = [])
    {
        $item = array_get($attributes, 'id');

        return $item
            ? $this->find($item)->fill($attributes)
            : $this->items()->newInstance($attributes);
    }

    /**
     * Get the first model matching attributes or create it.
     *
     * @param array $attributes
     *
     * @return \Illuminate\Database\Eloquent\Model
     */
    public function firstOrCreate(array $attributes = [])
    {
        return $this->items()->firstOrCreate($attributes);
    }

    /**
     * Create an entry from an array of attributes.
     *
     * @param array $attributes
     *
     * @return AbstractModel
     */
    public function create(array $attributes = [])
    {
        // Create model and fetch it back
        $item = $this->items()->create($attributes);
        $item = $this->find($item->id);
        $item = $this->onUpdate($item, $attributes);

        return $item;
    }

    /**
     * Update an item.
     *
     * @param AbstractModel|int $item
     * @param array             $attributes
     *
     * @return AbstractModel
     */
    public function update($item, array $attributes = [])
    {
        $item = $this->find($item);
        $item->fill($attributes)->save();
        $item = $this->onUpdate($item, $attributes);

        return $item;
    }

    /**
     * Delete an item.
     *
     * @param AbstractModel|int $item
     * @param bool              $force Force delete or not
     *
     * @return bool
     */
    public function delete($item, $force = false)
    {
        // Check if the model soft deletes or not
        $method      = $force && in_array('Illuminate\Database\Eloquent\SoftDeletes', $this->getClassUses() ) ? 'forceDelete' : 'delete';
        $item = $this->find($item);

        return $item->$method();
        //
    }


    ////////////////////////////////////////////////////////////////////
    //////////////////////////////// HOOKS /////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Hook for when a model is created/updated.
     *
     * @param AbstractModel $model
     * @param array         $attributes
     *
     * @return AbstractModel
     */
    protected function onUpdate($model, $attributes)
    {
        return $model;
    }

    ////////////////////////////////////////////////////////////////////
    ////////////////////////////// MULTIPLE ////////////////////////////
    ////////////////////////////////////////////////////////////////////

    /**
     * Return all items.
     *
     * @param int|null $perPage
     *
     * @return Collection
     */
    public function all($perPage = null)
    {
        return $perPage
            ? $this->getPaginated($perPage)
            : $this->items->get();
    }

    /**
     * Get all items, paginated.
     *
     * @param int|null $perPage
     *
     * @return \Illuminate\Pagination\Paginator
     */
    public function getPaginated($perPage = null)
    {
        $perPage = $perPage ?: $this->perPage;

        return $this->items->paginate($perPage);
    }

    //////////////////////////////////////////////////////////////////////
    ////////////////////////////// HELPERS ///////////////////////////////
    //////////////////////////////////////////////////////////////////////

    /**
     * @param Builder                  $query
     * @param int|string|AbstractModel $item
     *
     * @return AbstractModel
     */
    protected function findFromQuery($query, $item)
    {
        $columns = null;

        // If we have an instance already, return it
        if ($item instanceof Model) {
            return $item;
        }

        if ($this->items instanceof BelongsToMany) {
            $columns = [$this->items->getRelated()->getTable().'.*'];
        }
        // Find by slug
        if (!is_array($item)) {
            if (!preg_match('/^[0-9]+$/', (string) $item) &&  in_array('Cviebrock\EloquentSluggable\Sluggable', $this->getClassUses()) ) {
                return $query->whereSlug($item)->firstOrFail();
            }
        }

        return $query->findOrFail($item, $columns);
    }

    /**
     * @param AbstractModel|Builder $query
     *
     * @return Model
     */
    protected function unwrapQueries($query)
    {
        if ($query instanceof Builder) {
            return $query->getModel();
        }
        return $query;
    }

    /**
     * @param Get Model Using Classes
     *
     * @return Model
     */
    protected function getClassUses()
    {
        return class_uses($this->getModel());
    }
}

Step 3 : Create Artisan Command and Stubs to make custom artisan command. By running this artisan command you can create a repository file

Create Commands folder under App\Console :

Create MakeRepositoryCommand.php inside commands folder Which will help to create artisan command

 App\Console\Commands\MakeRepositoryCommand.php

<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
class MakeRepositoryCommand extends GeneratorCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'make:repository {name}';
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a new repository class';
    /**
     * The type of class being generated.
     *
     * @var string
     */
    protected $type = 'Repository';
    /**
     * Get the stub file for the generator.
     *
     * @return string
     */
    protected function getStub()
    {
        return __DIR__.'/stubs/repository.stub';
    }
    /**
     * Get the default namespace for the class.
     *
     * @param string $rootNamespace
     *
     * @return string
     */
    protected function getDefaultNamespace($rootNamespace)
    {
        return $rootNamespace.'\Repositories';
    }
}

make:repository {name} // Usage example : php artisan make:repository ExampleRepository => It will create a ExampleRepository.php under Repositories folder.
getStub() It will get dummy file from given path and create a file based on artisan command

Create repository.stub folder under Commands\stubs\repository.stub

App\Console\Commands\stubs\repository.stub

<?php

namespace DummyNamespace;

use Illuminate\Database\Eloquent\Model;

class DummyClass extends BaseRepository
{
    	/**
	 * @param Model $items
	 */
	public function __construct(Model $items)
	{
		$this->items = $items;
	}
}

//DummyClass Will replace with artisan Repository Name.

Now Run ” php artisan ” in terminal it will show php artisan:make repository command.

Example and Usage : run php artisan make:repository ExampleRepository in termianl

Your ExampleRepository.php looks like below : Here inject your model.

App\Repository\ExampleRepository.php

<?php

namespace App\Repositories;

use Illuminate\Database\Eloquent\Model;
use App\Models\Example;
class ExampleRepository extends BaseRepository
{
    	/**
	 * @param Example $items
	 */
	public function __construct(Example $items)
	{
		$this->items = $items;
	}
}

How to Inject Repository  Pattern in controller

<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Repositories\ExampleRepository;

class ExampleController extends Controller
{
    /**
     * @param Example Repository
     */
    public function __construct(ExampleRepository $example)
    {
        $this->example = $example;
    }
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $example = $this->example->all(); // Return all  an items
        $example = $this->example->find(id); // Return single an item
        $example = $this->example->create( [] ); // Create an item
        $example = $this->example->update( $id, [] ); // Update an item
        $example = $this->example->delete( $id ); // Delete an item

        // You can see rest of the function in BaseRepository.php
        
    }

 

Thats it now you have created repository pattern for your model.

You can create and inject individual repository pattern for each models by running php artisan make:repository command.

Hope it will help someone.
Thanks!.

 

Marimuthu:

View Comments

  • Nice Work. I havent go through but a quick question.
    Can I create a repository as
    php artisan make:repository App\Repositoies\Or\What\Ever\NameSpace\ExampleRepository ?

    • Thanks.

      You can set the repository path at AppConsoleCommandsMakeRepositoryCommand.php
      protected function getDefaultNamespace($rootNamespace)
      {
      return $rootNamespace.'Repositories';
      }

      You can change your namespace here Based on this php artisan make:repositorycommand will create the file at mentioned folder.

      If you given php artisan make:repository What\Ever\NameSpac

      It will create the folder and files under the Repository path what you have mentioned above.

  • Hi, not work

    In my Drawcontroller have this:

    $draw = $this->draw->create([
    $request->input('nombre'),
    $request->input('descripcion'),
    $request->input('metadescription'),
    $fecha_inicio,
    $fecha_fin,
    $request->input('fecha_de_resultado'),
    $imagen,
    $request->input('descripcion_de_la_imagen'),
    ]);

    in my DrawRepository

    class DrawRepository extends BaseRepository
    {
    /**
    * @param Draw $items
    */
    protected $items;
    public function __construct(Draw $items)
    {

    $this->items = $items;
    }

    }

    My error is:
    SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "name" violates not-null constraint DETAIL: Failing row contains (5, null, null, null, null, null, null, default.gif, null, null, t, f, 2017-09-26 16:15:14, 2017-09-26 16:15:14). (SQL: insert into "draws" ("updated_at", "created_at") values (2017-09-26 16:15:14, 2017-09-26 16:15:14) returning "id")

    help me, please

    • Your error says, You are passing empty value to "name" field. Actually your "name" filed is set to not null. You should pass value for "name" field.

      Try below code in your controller :

      $draw = $this->draw->create($request->all());