Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel SOLID using Repository Pattern

Tags:

php

laravel

I want (at this moment tyring) to follow the SOLID principles, but my mind is going to blows up.

I read a lot of posts about Repository Pattern in Laravel to follow the SOLID principles. My question is very similar to this question. But I don't understand how can I don't violate the Open/Closed Principal in the Factory Pattern

I'm developing a Two Factor Authentication system and I have multiple method to use as tfa.

Right now:

  • Authenticator App
  • SMS

Let's jump to the code:

Controller: (Without factory)

public function index(Request $request)
{   
    // Violate the OCP. I'm modyfing the class.
    switch ($request->method) {
        case 'authenticator':
            $tfaMethod = new Authenticator;
            break;
        case 'sms':
            $tfaMethod = new SMS;
            break;
    }

    return (new TwoFactorMethod)->process($this->currentUser, $tfaMethod);
}

TwoFactorMethod class:

public function process($user, MethodInterface $method)
{
    return $method->process($user);
}

Each method have their own class. It's ok. But if I want to add a new method, such as: E-mail i'll broken the OCP in the class using the switch case.

How can I "fix"? Or is just a misunderstanding from my side?

Thank you!

like image 435
webmasterdro Avatar asked Oct 03 '17 12:10

webmasterdro


1 Answers

You could use a TfaMethodRegisty, maybe something like this:

class TfaMethodRegistry
{
    protected $methods = [];


    public function register($name, $class)
    {
        $this->methods[$name] = $class;
    }


    public function get($name)
    {
        return $this->methods[$name];
    }
}

Then you populate it for instance in your AppServiceProvider:

public function register()
{
    $this->app->bind('App\TfaMethodRegistry', function ($app) {
        $registry new TfaMethodRegistry;

        $registry->register('sms', new Sms);
        $registry->register('authenticator', new Authenticator);

        return $registry;
    });
}

And then you can just let the Laravel IoC-Container inject into your controller or wherever you need it:

public function index(Request $request, TfaMethodRegistry $registry)
{   
    $tfaMethod = $registry->get($request->method);

    return (new TwoFactorMethod)->process($this->currentUser, $tfaMethod);
}

So basically you're treating the available methods as configuration but can also add more at runtime without editing anything.

Just a little tip: Don't go too crazy with this and don't take the whole SOLID-thing too religiously. More often than not, KISS is way better than SOLID :)

like image 148
Quasdunk Avatar answered Sep 19 '22 23:09

Quasdunk