Steevy
Steevy

Reputation: 72

How to correctly extend and use other interfaces?

I'm trying to make use of a base interface for all my other interfaces as follows:

Base interface

<?php

namespace App\Repositories\Data;

interface IDataRepository
{
    public function getAll();
    public function getById($id);
    public function create($model);
    public function update($model);
    public function delete($id);
}

Implemented base interface

    <?php namespace App\Repositories\Data;

    use Illuminate\Database\Eloquent\Model;

    class DataRepository implements IDataRepository
    {
        // model property on class instances
        protected $model;

        // Constructor to bind model to repo
        public function __construct(Model $model)
        {
            $this->model = $model;
        }

        // Get all instances of model
        public function getAll()
        {
            return $this->model->all();
        }

        // create a new record in the database
        public function create($model)
        {
            return $this->model->create($model);
        }

        // update record in the database
        public function update($model)
        {
            $record = $this->find($model.id);
            return $record->update($model);
        }

        // remove record from the database
        public function delete($id)
        {
            return $this->model->destroy($id);
        }

        // show the record with the given id
        public function getById($id)
        {
            return $this->model-findOrFail($id);
        }
    }

The interface where i'm trying to make use of the base interface

<?php

namespace App\Repositories;

use App\Repositories\Data\IDataRepository;

interface ITestRepository extends IDataRepository
{
}

implementation

<?php namespace App\Repositories;

use App\Library\Classes\Test;
use Illuminate\Database\Eloquent\Model;

class TestRepository implements ITestRepository
{
}

In my controller i'm trying to just call test repository so i can use all the base repository functions:

class TestController extends Controller
{

    protected $testRepository;
    public function __construct(Test $test)
    {
        $this->testRepository = new TestRepository($test);
    }
    public function index()
    {
        $data['testData'] = $this->testRepository->getAll();
        return view('test', $data);
    }
}

But i get the following error:

Class App\Repositories\TestRepository contains 5 abstract methods and must therefore be declared abstract or implement the remaining methods

My application works fine if i only make use of my base interface and pass through a model. What would be the correct way to share functions from my base interface across all my other interfaces, so as to prevent code duplication? I appreciate any help.

Upvotes: 0

Views: 89

Answers (3)

Yogesh Nayi
Yogesh Nayi

Reputation: 11

<?php


namespace App\Repositories;


use App\Interfaces\ITestRepository;

class TestRepository implements ITestRepository
{

public function getAll()
{
    // TODO: Implement getAll() method.
}

public function getById($id)
{
    // TODO: Implement getById() method.
}

public function create($model)
{
    // TODO: Implement create() method.
}

public function update($model)
{
    // TODO: Implement update() method.
}

public function delete($id)
{
    // TODO: Implement delete() method.
}

}

Class must be declared abstract or implement methods 'getAll', 'getById', 'update', 'create', 'delete' So All the method is by default abstract method in interface and you have to define all method in this class.

Upvotes: 1

Josep Palet
Josep Palet

Reputation: 56

The class TestRepository should not implement any interface, but extend DataRepository:

<?php namespace App\Repositories;

use App\Repositories\Data\DataRepository;

class TestRepository extends DataRepository
{
}

DataRepository contains already the implementation of the interface IDataRepository. When you create a class implementing ITestRepository you will have to define the implementation of all the methods in the interface (which are the same as the base interface, in your case).

Upvotes: 0

marv255
marv255

Reputation: 818

I think that a Trait which will contains all methods of your interface declaration is the best choice. Something like (not sure about logic):

namespace App\Repositories;

trait TDataRepository
{
    // model property on class instances
    protected $model;

    // Constructor to bind model to repo
    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    // Get all instances of model
    public function getAll()
    {
        return $this->model->all();
    }

    // create a new record in the database
    public function create($model)
    {
        return $this->model->create($model);
    }

    // update record in the database
    public function update($model)
    {
        $record = $this->find($model.id);
        return $record->update($model);
    }

    // remove record from the database
    public function delete($id)
    {
        return $this->model->destroy($id);
    }

    // show the record with the given id
    public function getById($id)
    {
        return $this->model-findOrFail($id);
    }
}

And then just use it for classes with base interface:

namespace App\Repositories;

use App\Library\Classes\Test;
use Illuminate\Database\Eloquent\Model;

class TestRepository implements ITestRepository
{
    use TDataRepository;
}

Also there are some other options:

  1. abstract class with methods for base interface but it not so flexible like trait,
  2. composition but you should change base idea and create a new entity for composition.

Upvotes: 1

Related Questions