Can a Repository extend a Model?

Asked

Viewed 283 times

3

If Repository extends the Model User, I’m breaking some of the principles of S.O.L.I.D?

I saw in some tutorials talk, that I have to create an abstract class with the same methods as Eloquent, this does not measure the principles of KISS?

As I have done so far:

<?php

namespace Account\Infrastructures\Domains\Models\User;

use Account\Domains\Models\User\User as UserModel;
use Account\Domains\Models\User\UserRepository;

class EloquentUserRepository extends UserModel implements UserRepository
{
    public function add(array $data)
    {
        return $this->create($data);
    }
}
  • 1

    I face would not do a extends in Model that I think wrong by repeating all the codes you will do in the other classes.

  • @Virgilionovic, what do you suggest? Since I want to avoid calling in the controller s the models, so I’m separating the responsibilities, in services and repositories.

  • I’ll propose an example with repository to see if you understand this part !!!

1 answer

3


Create a interface basis that will serve as contract for all other Repository classes bases of your program, example:

<?php namespace App\Repositories\Base;

interface IRepositoryBase
{
    public function create(array $data);
    public function edit(array $data, $id);
    public function find($id);    
    public function all();
    public function delete($id);
}

With that interface create your abstract class based on the basic commands of a CRUD:

<?php namespace App\Repositories\Base;

use Illuminate\Database\Eloquent\Model;

abstract class RepositoryBase implements IRepositoryBase
{
    protected $model;

    public function __construct($model)
    {
        if (($model instanceof Model) === false)
            throw new \Exception("Model is invalid");
        $this->model = $model;
    }
    public function create(array $array)
    {
        return $this->model->create($array);
    }
    public function edit(array $array, $id)
    {
        $m = $this->find($id);
        if ($m)
        {
            $m->fill($array);
            if ($m->save()) return $m;
        }
        return null;
    }
    public function find($id)
    {
        return $this->model->find($id);
    }
    public function delete($id)
    {
        $m = $this->find($id);
        if ($m) return $m->delete();
        return false;
    }    
    public function all()
    {
        return $this->model->all();
    }
}

This code will be used by all its entity classes, i.e., for each entity (Illuminate\Database\Eloquent\Model) will possess an abstract base class and another concrete for its instacing, examples:

User

Model User

<?php namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;
    protected $table = "users";    
    protected $fillable = ['name', 'email', 'password'];
    protected $hidden = ['password', 'remember_token'];
}

Abstract base class:

<?php namespace App\Repositories\Base;

use App\Models\User;

abstract class RepositoryUserBase extends RepositoryBase implements IRepositoryBase
{
    public function __construct(User $model)
    {
        parent::__construct($model);
    }
}

Concrete class:

<?php namespace App\Repositories;

use App\Repositories\Base\RepositoryUserBase;

class RepositoryUser extends RepositoryUserBase
{
}

Notice

Model Notice

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Notice extends Model
{
    protected $table = "notices";
    protected $primaryKey = "id";
    protected $fillable = ['title'];
}

Abstract base class:

<?php namespace App\Repositories\Base;

use App\Models\Notice;

abstract class RepositoryNoticeBase extends RepositoryBase implements IRepositoryBase
{
    public function __construct(Notice $model)
    {
        parent::__construct($model);
    }
}

Concrete class:

<?php namespace App\Repositories;

use App\Repositories\Base\RepositoryNoticeBase;

class RepositoryNotice extends RepositoryNoticeBase
{
}

Note that the constructor of the Base classes RepositoryNoticeBase and RepositoryUserBase is being passed its class corresponds, respectively, Notice and User and all code made in the base is equal to its spelling and standardization, but internally belongs to its configuration of Model which is configured in the constructor of each base class and belongs to its particular table, so for each new Repository created this which is changes from one to the other and also the names of the classes which must follow the same logic that the two followed. This ensures no repetition of coding that is in your question, of course, also this model can be further improved, this would be an initial standard.

So that the Container and Dependency Injection is set open the file in the folder app\Providers\AppServiceProvider.php and configure as follows in the method register():

<?php namespace App\Providers;

use App\Repositories\Base\RepositoryNoticeBase;
use App\Repositories\Base\RepositoryUserBase;
use App\Repositories\RepositoryNotice;
use App\Repositories\RepositoryUser;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{    
    public function boot()
    {    
    }
    public function register()
    {
        //
        app()->singleton(RepositoryNoticeBase::class, RepositoryNotice::class);
        app()->singleton(RepositoryUserBase::class, RepositoryUser::class);
    }
}

Why do this?

For injection to work in the manufacturers or methods of the controller of its application, example:

<?php namespace App\Http\Controllers;

use App\Repositories\Base\RepositoryNoticeBase;
use App\Repositories\Base\RepositoryUserBase;
use Illuminate\Http\Request;

class TestController extends Controller
{
    private $notice;
    private $user;
    private $request;

    public function __construct(
        RepositoryNoticeBase $notice,
        RepositoryUserBase $user,
        Request $request)
    {
        $this->notice = $notice;
        $this->user = $user;
        $this->request = $request;
    }

    public function index()
    {       
        return $this->user->all();
    }
}

Observing: if you do not want to do this part just put the direct concrete class in the constructors or methods instead of the base classes, example:

<?php namespace App\Http\Controllers;

use App\Repositories\Base\RepositoryNoticeBase;
use App\Repositories\Base\RepositoryUserBase;
use Illuminate\Http\Request;

class TestController extends Controller
{
    private $notice;
    private $user;
    private $request;

    public function __construct(
        RepositoryNotice $notice,
        RepositoryUser $user,
        Request $request)
    {
        $this->notice = $notice;
        $this->user = $user;
        $this->request = $request;
    }

    public function index()
    {       
        return $this->user->all();
    }
}

which will have the same effect.

Reference:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.