Can a Repository extend a Model?

3

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

I've seen some tutorials talk, that I have to create an abstract class with the same methods as Eloquent, does not that apply to KISS principles?

As I've 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);
    }
}
    
asked by anonymous 07.06.2017 / 21:00

1 answer

3

Create a% base% base that will serve as a contract for all other Repository classes in 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 this interface create your abstract base class with the basic commands of a interface :

<?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, ie for each entity ( CRUD ) it will have an abstract base class and a concrete one for its instance, 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 Illuminate\Database\Eloquent\Model and RepositoryNoticeBase classes being passed to its class corresponds, respectively, RepositoryUserBase and Notice , and all code made in the base is equal to its spelling and standardization, internally belongs to its User configuration that is set in the constructor of each base class and belongs to its given table, so for each new Repository created that is changed from one to the other and also the class names that must follow the same logic that the two of them followed. This guarantees the non-repetition of coding that is in your question, of course, also this model can be further improved, this would be an initial default.

In order to set% dependency injection and Dependency Injection open the file in the Model folder and set it as follows in the Container method:

<?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 that?

For injection to work in the constructors or methods of the app\Providers\AppServiceProvider.php class of your application, eg

<?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();
    }
}
If you do not want to do this part, just put the Concrete class directly 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();
    }
}

that will have the same effect.

08.06.2017 / 17:40