Dependency Injection w laravel - bindowanie

0

Hej,

poniżej z dokumentacji Laravela

$this->app->bind(
    'App\Contracts\EventPusher',
    'App\Services\RedisEventPusher'
);

This statement tells the container that it should inject the RedisEventPusher when a class needs an implementation of EventPusher. Now we can type-hint the EventPusher interface in a constructor, or any other location where dependencies are injected by the service container.

W klasie, w której chce wstrzyknąć zależność przekazuję interfejs a nie jego konkretną implementację.
Dalej aby to "skonfigurować" należy w klasie dziedziczącej po ServiceProvider w metodzie register() ..... zbindować jak powyżej
Nie rozumiem co w przypadku gdy napiszę inną implementację tego interfejsu ? po prostu dodać kolejny bind? Nie rozumiem skąd Laravel wybierze implementację, której chce?

$this->app->bind(
    'App\Contracts\EventPusher',
    'App\Services\ZupelnieJakisTamHiperTorpedaEventPusher'
);

Moje pytanie

0

Nie rozumiem co w przypadku gdy napiszę inną implementację tego interfejsu ? po prostu dodać kolejny bind?

Gdy napiszesz inną implementację i to ją będziesz chciał wykorzystać, będziesz musiał podmienić już istniejący bind na ten nowy.
Nie możesz mieć jednego interfejsu wskazującego na dwie implementacje.

0

rozumiem.
Jeszcze jedno pytanie.
Kiedy tworzę sobię warstwę repozytoriów, serwisów czy do metod przekazywać np. UserRequest tak wprost czy próbować wrzucać np. kolekcje

0

Dlaczego chciałbyś do repozytorium przekazywać request?

0

Chciałbym sprowadzić Laravela do tego co robię np. w Spring Boot.

W Laravel próbuje to zrobić tak

  1. Mam RepozytoriumInterface
  2. Piszę do niego implementację np.

metoda update(Request) -
metoda save(Requestobject)

  1. Binduję w ServiceProvider

  2. Wstrzykuję do kontrolera

w Spring Boot bardziej piszę servisy, które robią cała robotę a do nich wstrzykuję repozytoria

0

No tak - i w Laraverze nikt nie broni Ci przecież też tworzyć serwisów i to do nich wstrzykiwać repozytoria (mało tego - nawet jest to lepsze, ponieważ serwisy możesz potem przetestować jednostkowo).

0

Patryk27, moglbys zarzucić przykładowe kody jak to realizujesz albo bys zrealizowal doslownie w konwencji tez z Laravel, realizujace dowolna operacje?
Ja chce utworzyc katalog repositories i tam katalogi dla kazdej domeny. W nich interface + implementacja + serwis jesli trzeba.

0

Tak jak zalinkował @Desu, możesz rzucić okiem tu - jest to jeden z moich starszych projektów (całe pół roku! :-P), lecz ogólnie prezentuje ogólne podejście do tego tematu.

W skrócie - w moim przypadku podział wygląda tak: kontroler przyjmuje żądanie (request), które jest wysyłane do odpowiedniego serwisu, który dopiero operuje na repozytorium. Sprawdza się to póki co i w mniejszych, i większych przypadkach ;-)

0

O taki link mi chodzilo DZIEKUJE
Czy nazewnictwo ...Contract jest Laravelowe czy Twoje?

1

Słowo kontrakt pochodzi od tego, że interfejs to swojego rodzaju kontrakt. Można powiedzieć, że klasa implementując dany interfejs podpisuje kontrakt, na mocy którego zobowiązuje się do posiadania pewnej funkcjonalności.

Są różne konwencje:

  • .NET: IUserRepository i konkretna implementacja UserRepository
  • Spring: UserRepository i konkretna implementacja UserRepositoryImpl (impl od implementacja :P).

Laravel przyjął nazwę Contract. Jak popatrzysz po źródłach to zobaczysz, że wszelakiej maści interfejsy siedzą w podkatalogu Contract (doc).

0

Contract jest Laravelowe czy Twoje?

Tak jak napisał @Desu - Contract jest wykorzystywane w samym frameworku, dlatego naturalnym było wykorzystanie tej konwencji również w projekcie.

0

@Patryk27: czy mógłbyś wytłumaczyć mi implementacje getCacheConfiguration()
np to

    public static function getCacheConfiguration(): array {
        return [
            'tags' => [
                'Finances',
                'Finances.Budget',
            ],

            'flush-tags' => [
                'Finances.Budget',
            ],
        ];
    }

co się tutaj dzieje? To są katalogi?

0

To są tagi - każdy wpis w pamięci podręcznej może być otagowany.

Klucz 'tags' oznacza tagi, którymi ten wpis będzie oznaczony podczas tworzenia go w pamięci podręcznej (czyli w tym przypadku wpis będzie otagowany Finances oraz Finances.Budget), a klucz 'flush-tags' oznacza te tagi, które należy wyczyścić, gdy będziemy czyścić daną sekcję pamięci podręcznej.

Idea stojąca za tym pomysłem była taka, aby można było usunąć zarówno ogólne części pamięci podręcznej (czyli np. cały cache modułu Finances), jak i te konkretne (czyli np. cały cache budżetów).

Innymi słowy: jeśli masz jakieś encje A oraz B, chodziło o to, aby aktualizacja encji A nie wywalała kesza encji B, chyba że są one powiązane (a powiązania między encjami są widoczne właśnie przez to getCacheConfiguration).

W gruncie rzeczy jednak podsystem keszowania wyszedł IMHO overdesigned, jak na tę aplikację (kiedyś to zrefaktoryzuję :-P).

0

@Patryk27: jeszcze jedno pytanie. Każde repozytorium rozszerza CrudRepositoryContract. Dlaczego w interfejsie, który go rozszerza powielasz metody get(), getOrFail(), getBy(), getAll()

0

Aby działało podpowiadanie składni w PhpStormie (w sensie: aby poprawnie podpowiadało, o które modele chodzi).

0

@Patryk27: nie wiem czy o to chodzi, bo pisze z telefonu, ale zamiast redefiniować metody, dla samego podpowiadani składni, to wystarczy zrobić:

/**
  * @method Model get()
  * @method Model[] getAll()
  */
class Foo extends Bar {}

Nie wiem czy PHPStorm przypadkiem nie nauczył się już rozpoznawać typów jeżeli w klasie bazowej/interfejsie użyjemy @return static - trzeba by to przetestować.

0

u mnie działa tak, że wystarczy jedną metodę powielić i wszystko podpowiada się ok.
Musi jakoś pójść aby tego nie robić :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1