Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

arifulhb's avatar

SOLID Principle In Laravel with Repository Pattern

Hi, Recently I've seen SOLID principle and Repository Pattern Videos in Laracast and I want to start implementing these approaches. I've some confession about SRP.. I'll try to explain all bellow.

My system has two types of User Consider.. Normal User and Admin User. So I created an Interface

interface UserRepositoryInterface
{
    public function save(array $array);
}

and created two Classes

class UserRepository implements UserRepositoryInterface
{
    public function save(array $array)
     {
      // Save User here
     }
}

and

class AdminRepository implements UserRepositoryInterface
{
    public function save(array $array)
     {
      // Save Admin here
     }
}

User and Admin has different roles and different property to store in Database which are implemented in each class. Now in my UserController if I code like

if($inputs['type']=='user'){
   $repo = new UserRepository;
   $repo->save($inputs);
} elseif($inputs['type']=='admin'){
   $repo = new AdminRepository;
   $repo->save($inputs); 
}

Does this break any principle of SOLID principle or Whats the best practice to deal with such situation? Help, Collaboration and Discussion are welcome.

TIA Ariful

0 likes
6 replies
pobble's avatar

If you ever need to add a new type of user, your controller will violate the open/closed principle. I'd Consider creating a general repository interface that reflects the most common CRUD operations or at least a user interface and pass an implementation to a function that does the saving.

arifulhb's avatar

Hi pobble, Thank for replay.. However I still have some confusion or I get it wrong. Considering your quote " or at least a user interface and pass an implementation to a function that does the saving."

User Inteface

interface IUser
{   
    public function save(array $data);
}

User class that implement the interface

class RegularUser implements IUser
{   
    public function(array $data)
{
    // save normal user
}
}

class AdminUser implements IUser
{   
    public function(array $data)
    {
    // save Admin user
    }
}

User Repository

class UserRepository 
{
    public function save(array $data, IUser $user)
    {
    $user->save($data);
    }
}

** UserController **

public function store(Resource $resource)
{

    $inputs = $resource->all();

            /**
            *  HOW TO DECIDE WHICH IMPLEMENTATION TO SENT TO AVOID OPEN/CLOSE PRINCIPLE 
            */
    $admin = new AdminUser;

    $this->repo->save($inputs, $admin);
}
gratiafide's avatar

Everything is fine in your original post, except instead of putting this in your controller:

if($inputs['type']=='user'){
   $repo = new UserRepository;
   $repo->save($inputs);
} elseif($inputs['type']=='admin'){
   $repo = new AdminRepository;
   $repo->save($inputs); 
}

Create a new class instead in a different file:

class Registration{
    // Notice the 2nd parameter below is referring to the interface, not an implementation
    public function register($inputs, UserRepositoryInterface $myuser){
        $myuser->save($inputs);
    }
}

Now you can call that class from a method in your controller for new regular users:

$repo = new RegisterUser;
// Here is the reference a specific implementation of the interface in the 2nd parameter.
$repo->save($inputs, new UserRepository);

And you can have a different method in the controller for new admins:

$repo = new RegisterUser;
// Now  use the other implementation of the interface as the 2nd parameter.
$repo->save($inputs, new AdminRepository);

You also might want to consider not using the word "Repository" for these classes if all they do is save the information to the database. The reason for this is because I think the idea of a repository is that it is supposed to provide data from the database into your classes. If you are just using it to save information to the database, then maybe it would be more fitting to call it a "AdminStore" class instead of an "AdminRepository" class. Then you could change "UserRepository" to "UserStore" as well, and "UserRepositoryInterface" to "UserInterface", but the above code will function fine if you leave your classes named as they are.

If you haven't seen it, I think this laracast might be equally valuable and maybe more clear for what I think you are trying to do: https://laracasts.com/series/solid-principles-in-php/episodes/1

3 likes
jcmargentina's avatar

I think that this part of your code can be handled using a Factory (check the factory Design Pattern) in order to create the proper Repository to be used in your controller.

I refear to this part:

if($inputs['type']=='user'){
   $repo = new UserRepository;
   $repo->save($inputs);
} elseif($inputs['type']=='admin'){
   $repo = new AdminRepository;
   $repo->save($inputs); 
}

If you use a Factory then in your controller you could have something like this:


public function store(Request $request) {

    $repo = new UserRepositoryFactory($request->type)->create();

    $repo->save();

}
´´´

pretty clean a? I know I know ... I not giving you the code of the Factory ... because you will have to find it out by yourself, in the laracasts videos you will find the answer.

The good thing is ... that piece of code ... will be as it is even if you need another type of user in the future, because teh Factory will be in charge of creating the right one for the controller. 

In fact, the only piece of code you will have to modify, is the factory, and thats it.
jcmargentina's avatar

LOL, yes I know my friend. BUT .... Is never too late to add some light to the tunnel

1 like

Please or to participate in this conversation.