Powiedzmy, że ilekroć wykonuję operację CRUD lub modyfikuję relację w określony sposób, chcę też zrobić coś innego. Np. Za każdym razem, gdy ktoś publikuje post, chcę również zapisać coś w tabeli do celów analitycznych. Może nie jest to najlepszy przykład, ale generalnie istnieje wiele funkcji „pogrupowanych”.
Zwykle widzę tego typu logikę umieszczoną w kontrolerach. To wszystko w porządku, dopóki nie zechcesz odtworzyć tej funkcji w wielu miejscach. Kiedy zaczynasz wchodzić w częściowe, tworzenie API i generowanie fikcyjnej zawartości, staje się problemem z utrzymaniem rzeczy SUCHYCH.
Sposoby radzenia sobie z tym to zdarzenia, repozytoria, biblioteki i dodawanie do modeli. Oto moje rozumienie każdego z nich:
Usługi: tutaj większość ludzi prawdopodobnie umieściłaby ten kod. Moim głównym problemem związanym z usługami jest to, że czasami trudno jest znaleźć w nich określoną funkcjonalność i czuję, że zapomina się o nich, gdy ludzie koncentrują się na używaniu Eloquent. Skąd mam wiedzieć, że muszę wywołać metodę publishPost()
w bibliotece, skoro mogę to zrobić $post->is_published = 1
?
Jedynym warunkiem, w jakim to działa dobrze, jest to, że używasz TYLKO usług (i idealnie sprawisz, że Eloquent będzie w jakiś sposób niedostępny dla wszystkich kontrolerów).
Ostatecznie wygląda na to, że utworzyłoby to kilka dodatkowych niepotrzebnych plików, jeśli Twoje żądania generalnie są zgodne ze strukturą modelu.
Repozytoria: z tego, co rozumiem, jest to w zasadzie jak usługa, ale istnieje interfejs, dzięki czemu można przełączać się między ORMami, których nie potrzebuję.
Zdarzenia: uważam to za najbardziej elegancki system w pewnym sensie, ponieważ wiesz, że zdarzenia modelowe zawsze będą wywoływane metodami elokwentnymi, więc możesz pisać kontrolery tak, jak zwykle. Widzę jednak, że robi się bałagan i jeśli ktoś ma przykłady dużych projektów wykorzystujących zdarzenia do krytycznego sprzężenia, chciałbym to zobaczyć.
Modele: Tradycyjnie miałbym klasy, które wykonywały CRUD, a także obsługiwały krytyczne sprzężenia. To faktycznie ułatwiło sprawę, ponieważ znałeś wszystkie funkcje związane z CRUD +, cokolwiek trzeba było z tym zrobić, było tam.
Proste, ale w architekturze MVC zwykle nie jest to to, co widzę. W pewnym sensie wolę to od usług, ponieważ jest trochę łatwiejsze do znalezienia i jest mniej plików do śledzenia. Może się jednak trochę zdezorganizować. Chciałbym usłyszeć wady tej metody i dlaczego większość ludzi tego nie robi.
Jakie są zalety / wady każdej metody? Czy coś mi brakuje?
źródło
Odpowiedzi:
Myślę, że wszystkie wzorce / architektury, które prezentujesz, są bardzo przydatne, o ile przestrzegasz zasad SOLID .
Albowiem gdzie dodać logikę myślę, że ważne jest, aby zapoznać się z jednolitej odpowiedzialności Zasada . Moja odpowiedź dotyczy również tego, że pracujesz nad średnim / dużym projektem. Jeśli jest to projekt, który rzuca coś na stronę , zapomnij o tej odpowiedzi i dodaj to wszystko do kontrolerów lub modeli.
Krótka odpowiedź brzmi: gdzie ma to dla Ciebie sens (w przypadku usług) .
Długa odpowiedź:
Administratorzy : Jaka jest odpowiedzialność administratorów? Jasne, możesz umieścić całą swoją logikę w kontrolerze, ale czy to odpowiedzialność kontrolera? Nie sądzę.
U mnie kontroler musi otrzymać żądanie i zwrócić dane, a to nie jest miejsce na walidacje, wywoływanie metod db itp.
Modele : Czy jest to dobre miejsce na dodanie logiki, takiej jak wysyłanie powitalnego e-maila, gdy użytkownik rejestruje się lub aktualizuje liczbę głosów w poście? Co jeśli chcesz wysłać ten sam e-mail z innego miejsca w kodzie? Tworzysz metodę statyczną? A jeśli te e-maile wymagają informacji z innego modelu?
Myślę, że model powinien reprezentować byt. Z laravel, używam tylko klasę modelu, aby dodać takie rzeczy jak
fillable
,guarded
,table
a stosunki (to dlatego używam Repository Pattern, inaczej model będzie również posiadaćsave
,update
,find
itp metod).Repozytoria (wzorzec repozytorium) : Na początku byłem tym bardzo zdezorientowany. I tak jak ty pomyślałem „cóż, używam MySQL i to wszystko”.
Jednak zrównoważyłem zalety i wady korzystania ze wzorca repozytorium i teraz go używam. Myślę, że teraz , w tej chwili, będę musiał używać tylko MySQL. Ale jeśli za trzy lata będę musiał przejść na coś takiego jak MongoDB, większość pracy zostanie wykonana. Wszystko kosztem jednego dodatkowego interfejsu i pliku
$app->bind(«interface», «repository»)
.Zdarzenia ( wzorzec obserwatora ): Zdarzenia są przydatne w przypadku rzeczy, które mogą być rzucane w dowolnej klasie w dowolnym momencie. Pomyśl na przykład o wysyłaniu powiadomień do użytkownika. W razie potrzeby uruchamiasz zdarzenie, aby wysłać powiadomienie w dowolnej klasie aplikacji. Następnie możesz mieć taką klasę,
UserNotificationEvents
która obsługuje wszystkie uruchomione zdarzenia dla powiadomień użytkowników.Usługi : do tej pory możesz dodać logikę do kontrolerów lub modeli. Dla mnie sensowne jest dodanie logiki w ramach usług . Spójrzmy prawdzie w oczy, usługi to fantazyjna nazwa dla zajęć. Możesz mieć tyle zajęć, ile ma to sens w twojej aplikacji.
Weźmy ten przykład: Niedawno opracowałem coś takiego jak Formularze Google. I zaczęło się
CustomFormService
i skończyło sięCustomFormService
,CustomFormRender
,CustomFieldService
,CustomFieldRender
,CustomAnswerService
iCustomAnswerRender
. Czemu? Ponieważ to miało dla mnie sens. Jeśli pracujesz z zespołem, powinieneś umieścić swoją logikę tam, gdzie ma to sens dla zespołu.Zaletą korzystania z usług w porównaniu z kontrolerami / modelami jest to, że nie jesteś ograniczony przez pojedynczy kontroler lub pojedynczy model. Możesz utworzyć dowolną liczbę usług w oparciu o projekt i potrzeby aplikacji. Dodaj do tego zaletę wywoływania usługi w dowolnej klasie aplikacji.
To trwa długo, ale chciałbym pokazać, jak zbudowałem moją aplikację:
Używam każdego folderu do określonej funkcji. Na przykład
Validators
katalog zawieraBaseValidator
klasę odpowiedzialną za przetwarzanie walidacji na podstawie$rules
i$messages
określonych walidatorach (zwykle po jednym dla każdego modelu). Mógłbym równie łatwo umieścić ten kod w usłudze, ale sensowne jest, aby mieć do tego określony folder, nawet jeśli jest on używany tylko w usłudze (na razie).Zalecam przeczytanie następujących artykułów, ponieważ mogą one trochę lepiej wyjaśnić:
Breaking the Mould, Dayle Rees (autor CodeBright): Tutaj złożyłem to wszystko razem, mimo że zmieniłem kilka rzeczy, aby pasowały do moich potrzeb.
Oddzielenie kodu w Laravel przy użyciu repozytoriów i usług autorstwa Chrisa Gooseya: Ten post wyjaśnia dobrze, czym jest usługa i wzorzec repozytorium oraz jak do siebie pasują.
Laracasts ma również uproszczoną repozytoria i pojedynczą odpowiedzialność, które są dobrymi zasobami z praktycznymi przykładami (nawet jeśli musisz zapłacić).
źródło
Chciałem zamieścić odpowiedź na moje własne pytanie. Mógłbym o tym mówić całymi dniami, ale spróbuję szybko to opublikować, aby mieć pewność, że to zrobię.
Skończyło się na tym, że wykorzystałem istniejącą strukturę, którą zapewnia Laravel, co oznacza, że zachowałem moje pliki głównie jako Model, Widok i Kontroler. Mam również folder Biblioteki dla komponentów wielokrotnego użytku, które tak naprawdę nie są modelami.
NIE OPAKOWAŁEM MOICH MODELI W USŁUGI / BIBLIOTEKI . Wszystkie podane powody nie przekonały mnie w 100% do korzyści płynących z korzystania z usług. Chociaż mogę się mylić, o ile widzę, po prostu skutkują tonami dodatkowych, prawie pustych plików, które muszę tworzyć i przełączać się między nimi podczas pracy z modelami, a także naprawdę zmniejszają korzyści z używania elokwentnego (szczególnie jeśli chodzi o ODZYSKIWANIE modeli , np. przy użyciu paginacji, zakresów itp.).
Umieszczam logikę biznesową W MODELACH i uzyskuję dostęp elokwentny bezpośrednio z moich kontrolerów. Używam kilku podejść, aby upewnić się, że logika biznesowa nie zostanie ominięta:
Rozwiązywanie problemów ludzi związanych z używaniem modeli:
Dodatkowa uwaga: Czuję, że pakowanie modeli w usługi jest jak posiadanie szwajcarskiego scyzoryka z dużą ilością narzędzi i budowanie wokół niego innego noża, który w zasadzie robi to samo? Tak, czasami możesz chcieć odklejać ostrze lub upewnić się, że dwa ostrza są używane razem ... ale zazwyczaj są na to inne sposoby ...
KIEDY KORZYSTAĆ Z USŁUG : W tym artykule bardzo dobrze przedstawiono WSPANIAŁE przykłady korzystania z usług ( wskazówka: niezbyt często ). Mówi po prostu, że kiedy twój obiekt używa wielu modeli lub modeli w dziwnych częściach ich cyklu życia , ma to sens. http://www.justinweiss.com/articles/where-do-you-put-your-code/
źródło
To, czego używam do stworzenia logiki między kontrolerami i modelami, to utworzenie warstwy usług . Zasadniczo jest to mój przepływ dla każdej akcji w mojej aplikacji:
Oto jak to robię:
Oto metoda kontrolera do tworzenia czegoś:
To jest klasa usług, która wykonuje logikę związaną z operacją:
A to jest mój model:
Aby uzyskać więcej informacji o tym, jak organizuję swój kod dla aplikacji Laravel: https://github.com/rmariuzzo/Pitimi
źródło
$congregation->save();
może nie potrzebujesz repozytoriów. Możesz jednak zauważyć, że z czasem Twoje potrzeby w zakresie dostępu do danych wzrosną. Może zacząć mieć zapotrzebowanie na$congregation->destroyByUser()
lub$congregationUsers->findByName($arrayOfSelectedFields);
i tak dalej. Dlaczego nie odłączyć usług od potrzeb dostępu do danych. Pozwól, aby reszta Twojej aplikacji działała z obiektami / tablicami zwróconymi z repozytoriów, i po prostu zajmij się manipulowaniem / formatowaniem / itp ... Twoje repozytorium będzie rosło (ale podzieli je na różne pliki, ostatecznie złożoność projektu musi gdzieś znajdować się).Moim zdaniem Laravel ma już wiele opcji przechowywania logiki biznesowej.
Krótka odpowiedź:
Request
obiektów laravel, aby automatycznie sprawdzić poprawność danych wejściowych, a następnie utrwalić dane w żądaniu (utwórz model). Ponieważ wszystkie dane wprowadzane przez użytkowników są bezpośrednio dostępne w żądaniu, uważam, że ma to sens tutaj.Job
obiektów laravel do wykonywania zadań wymagających pojedynczych komponentów, a następnie po prostu je wysyłaj . Myślę, żeJob
obejmują klasy usług. Wykonują zadanie, takie jak logika biznesowa.Długa odpowiedź:
Użyj repozytoriów, gdy jest to wymagane: repozytoria są na pewno nadmiernie rozbudowane i przez większość czasu są po prostu używane jako
accessor
model. Wydaje mi się, że na pewno mają jakieś zastosowanie, ale chyba że tworzysz ogromną aplikację, która tego wymaga takiej elastyczności, abyś mógł całkowicie porzucić laravel, trzymaj się z dala od repozytoriów. Podziękujesz sobie później, a Twój kod będzie znacznie prostszy.Zadaj sobie pytanie, czy istnieje możliwość, że będziesz zmieniać frameworki PHP pytanie, lub typ bazy danych, którego laravel nie obsługuje.
Jeśli Twoja odpowiedź brzmi „Prawdopodobnie nie”, nie implementuj wzorca repozytorium.
Oprócz powyższego, nie kładź wzoru na wspaniałym ORM, takim jak Eloquent. Po prostu dodajesz złożoność, która nie jest wymagana i nie przyniesie Ci to żadnych korzyści.
Oszczędnie korzystaj z usług: dla mnie klasy usług są po prostu miejscem do przechowywania logiki biznesowej w celu wykonania określonego zadania z określonymi zależnościami. Laravel ma je po wyjęciu z pudełka, zwane „Jobs”, i mają znacznie większą elastyczność niż niestandardowa klasa usług.
Wydaje mi się, że Laravel ma dobrze zaokrąglone rozwiązanie
MVC
problemu logiki. To tylko sprawa lub organizacja.Przykład:
Żądanie :
Kontroler :
W powyższym przykładzie dane wejściowe żądania są automatycznie sprawdzane, a wszystko, co musimy zrobić, to wywołać metodę utrwalania i przekazać nowy post. Uważam, że czytelność i łatwość konserwacji powinny zawsze przewyższać złożone i niepotrzebne wzorce projektowe.
Następnie możesz użyć dokładnie tej samej metody utrwalania, aby aktualizować posty, ponieważ możemy sprawdzić, czy post już istnieje i wykonać logikę naprzemienną w razie potrzeby.
źródło
ShouldQueue
które zapewnia Laravel. Jeśli chcesz napisać logikę biznesową w poleceniu lub zdarzeniu, po prostu uruchom zadanie w tych zdarzeniach / poleceniach. Praca w Laravels jest niezwykle elastyczna, ale ostatecznie są to zwykłe klasy usług.