2017-10-03 79 views
6

Chcę (w tym momencie) przestrzegać zasad SOLID, ale mój umysł się rozwali.Laravel SOLID przy użyciu wzorca repozytorium

Przeczytałem wiele postów o Wzorze repozytorium w Laravel, aby przestrzegać zasad SOLID. Moje pytanie jest bardzo podobne do this question. Ale ja nie rozumiem jak można nie naruszają otwarte/zamknięte Principal w Wzorca Fabryki

Zajmuję system Two Factor Authentication i mam wiele metod do wykorzystania jako TFA.

Teraz:

  • Authenticator App
  • SMS

skok Let do kodu:

Kontroler: (bez fabrycznie)

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); 
} 

klasa TwoFactorMethod:

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

Każda metoda ma swoje własne klasy. W porządku. Ale jeśli chcę dodać nową metodę, taką jak: E-mail, zepsuję OCP w klasie za pomocą przełącznika.

Jak mogę "naprawić"? Czy to po prostu nieporozumienie z mojej strony?

Dziękujemy!

+0

Możesz użyć kontenera usługowego Laravel. Utwórz powiązanie, np. 'app() -> bind (" tfa.authenticator ", Authenticator :: class)' i 'app() -> bind (" tfa.sms ", SMS :: class)', a następnie możesz uzyskać poprawny z 'app() -> make (" tfa. ". $ request-> method)' bez potrzeby przełączania, po prostu dodawaj wiązania, gdy obsługujesz więcej metod (i nie powiodło się, jeśli otrzymasz null z kontenera). Czy nie rozumiem cię? – apokryfos

Odpowiedz

5

można użyć TfaMethodRegisty, może coś takiego:

class TfaMethodRegistry 
{ 
    protected $methods = []; 


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


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

Następnie należy wypełnić go na przykład w 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; 
    }); 
} 

I wtedy można po prostu pozwolić laravel IoC-Container wstrzyknąć do kontrolera lub gdziekolwiek go potrzebujesz:

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

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

Zasadniczo traktujesz dostępne metody jako konfigurację, ale możesz także dodać więcej w czasie wykonywania bez edytowania czegokolwiek.

Po prostu mała wskazówka: nie popadaj w szaleństwo i nie traktuj zbyt SOLIDNIE zbyt religijnie. Częściej niż nie, KISS jest o wiele lepszy niż SOLID :)

+0

WOW! Wspaniale, koleś. Dziękuję bardzo! I o końcówce, rozumiem. Czasami naprawdę byłem za bardzo szalony. – webmasterdro

1

Jeśli nie piszesz biblioteki przeznaczonej do użytku przez innych klientów, moja rada jest taka, że ​​pozwoliłeś fabryce na taką wiedzę, szczególnie jeśli lista klas konstrukcja jest dość krótka i statyczna. Otrzymasz główne korzyści: nie musisz rozwiązywać reszty kodu za pomocą instrukcji switch/case i scentralizowanej wiedzy, ale bez wielu bólów głowy.

Przykładem jak to może wyglądać:

class TwoFactorAuthenticatorFactory { 
    public static function createFromMethod(string $method): TwoFactorAuthenticator 
    { 
     switch ($method) { 
      case 'authenticator': 
       return new Authenticator(); 
      case 'sms': 
       return new SMS(); 
     } 

     throw new RuntimeException(sprintf('Method %s could not be resolved to an authenticator.', $method)); 
    } 
} 

Zastosowanie:

TwoFactorAuthenticatorFactory::createFromMethod($request->method); 

I planuje dać szybki przegląd w jaki sposób rozwiązać ten problem „dogmatycznie” ale @Quasdunk pobili mnie do punch z doskonałą odpowiedzią :) Zauważ, że oprócz robienia rzeczy (prawdopodobnie niepotrzebnie) bardziej abstrakcyjnych, to rozwiązanie ma również dużą wadę w przenoszeniu wiedzy z domeny do warstwy infrastruktury szkieletowej. W ten sposób powiążesz się z frameworkiem, którego zazwyczaj chcesz uniknąć.

+0

Rzeczywiście, idealnie nadaje się do tej sytuacji. – pbond

+0

Dobre rozwiązanie. Widzę, że Taylor Otwell używa czegoś podobnego do tego, tutaj: https://medium.com/@taylorotwell/expressive-code-real-time-facades-41c442914291 – webmasterdro