Controller and Repository pattern query

Hi,

I'm currently trying to integrate the repository pattern into my own MVC framework.

I'm working on the basis of having a 'BaseModel' and each Model/Entity will extends that.

class User extends BaseModel {}

Open in new window


In the past I've have the Model talk directly to a database class, I believe this would be called the Active Record Pattern. I'm trying to move away from it for a project.

I've created a BaseRepository class which will contain generic methods such as all(), get(), save(), delete(). Repositories will extends this class.

class UserRepository extends BaseRepository {}

Open in new window


The general methods(all,get,save,delete) will use the Repository name to work out which Model it should create when returning objects, i.e. UserRepository becomes User ($object = new $className()).

Anyway, my main questions is what would be considered the best way (best practice) of using the Repositories in a controller?

The first, uses static method on the Repository class. In this case, the static class would talk to a database class, get the rows, and for each row create a new User object and return these in an array.
public function index() {
     $users = UserRepository::all();
}

Open in new window


The second way is to not use static methods.
public function index() {
     $userRepo = new UserRepository();
     $users = $userRepo->all();
}

Open in new window


The third way is to initiate the repository in the __construct() method of the controller.
class UserController {
     private $UserRepository;

     public function __construct() {
          $this->UserRepository = new UserRepository();
     }

     public function index() {
          $users = $this->UserRepository->all();
     }
}

Open in new window


I believe there is a fourth way, which would involve injecting the Repository into the controller, which I guess is better for testing as you can pass over a different repository(i.e. one that simply uses arrays). I don't really understand how this works when you need to use multiple repositories in your Controller.
class UserController {
     private $UserRepository;

     public function __construct(UserRepository $repository) {
          $this->UserRepository = $repository
     }

     public function index() {
          $users = $this->UserRepository->all();
     }
}

Open in new window


I do wonder if it could be best to use a mixture of the 3rd and 4th way.
class UserController {
     private $userRepository;
     private $DepartmentRepository;

     public function __construct() {
          $this->UserRepository = new UserRepository;
          $this->DepartmentRepository = new DepartmentRepository;
     }

     public function overrideRepositories(UserRepository $userRepository,DepartmentRepository $deptRepository) {
          $this->userRepository = $userRepository;
          $this->departmentRepository = $deptRepository;
     }

     public function index() {
          $users = $this->UserRepository->all();
     }
}

$controller = new UserController();
$controller->overrideRepositories(new UserRepository(),new DepartmentRepository());
$controller->index();

Open in new window

Above above code means that during normal usage, the construct() method creates the Repositories, but when testing the overrideRepositories() method can be used to override those set by the construct() method, and we could pass over a repository that uses arrays or MongoDB.

I'm really just looking for some feedback on the above and which you would recommend. Am I even going about things the write way?
SheppardDigitalAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Slick812Commented:
greetings  SheppardDigital, , I read over your possibilities, and I will start by saying the Static method, is what I consider NON OOP programming, and it has no advantage for this project. The third way could work but does not have built in flexibility, that the fourth way does , as you can change the type of repository (mySql, Mongo, arrays) at creation. In the "mixture of the 3rd and 4th way", you do have the ability to change the type of repository, by overriding and replacing . Depending on When, you could be able to override, You may not be able to change repositories, once data exchanges are set in the php object, but could be the repositories take the same input types and numbers for all of the instances (mySql, mongo, arrays). If you only can change repositories when to create an instance, you might go with your fourth way.


something that I have done to a great extent, is to do a modified creation "Factory" approach, like -

public function __construct($repType = 'mysql') {
   switch($repType) {
      case 'arrays' : $this->UserRepository = new UserRepositoryArray;
         this.dbType = 'arrays'; break;
      case 'mongo' : $this->UserRepository = new UserRepositoryMongo;
         this.dbType = 'mongo'; break;
      default : $this->UserRepository = new UserRepositoryMySql;
          this.dbType = 'mysql';
  }

}

then you just set the repository type at creation -
   $ur = new UserController('mongo');
and even do divergent programming paths later by -
if ($ur->dbType == 'mysql') { $mysqlUR->flac($ur); } else {$miscUR->flac($ur); }

I usually have at least two factory call variables in the creation -
public function __construct($full = 'partial', $repType = 'mysql') {

the 'partial' would use an abbreviated output, compared to the 'full'. And would affect how several methods treated the length of the return from them.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Ray PaseurCommented:
In a nutshell, the repository passes data to the controller, and the controller does not need to know where the data came from.  The controller uses the defined methods of the repository interface.  Any concrete class that implements the interface must provide these methods. This allows you to change the source of the data without breaking your controller. You could pull the data from a file, a cache, a database, an API, etc.  This separates the controller from the data source in a good way, providing independence between these components.  For testing, the repository can be a mock object.

Rather than re-write an excellent piece of explanation, I'll just leave this here for you.  His blog is pretty good.  But before you jump in and start using his design, read the comments at the end of the article!
http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories/

This article expands on it some.
http://culttt.com/2014/09/08/benefits-using-repositories/

And there is this, from the "horse's mouth"
https://vimeo.com/53029232
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.