Instancja Magento 2 Helper

11

Kiedy myślę, że owinąłem głowę wokół systemu DI z Magento 2, coś pojawia się i rozpakowuje.
Widzę w kodzie podstawowym różne sposoby dostępu do pomocnika.
Na przykład Magento\Catalog\Controller\Category::_initCategoryjest tam:

if (!$this->_objectManager->get('Magento\Catalog\Helper\Category')->canShow($category)) {
    return false;
}

Ale w Magento\Catalog\Block\Category\Viewpomocnika wstrzykuje się konstruktor

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\Catalog\Model\Layer\Category $catalogLayer,
    \Magento\Framework\Registry $registry,
    \Magento\Catalog\Helper\Category $categoryHelper,
    array $data = array()
) {
    $this->_categoryHelper = $categoryHelper;
    $this->_catalogLayer = $catalogLayer;
    $this->_coreRegistry = $registry;
    parent::__construct($context, $data);
}

Doprowadziło mnie to do wniosku, że pomoce powinny być dostępne w różny sposób w kontrolerach i blokach (i modelach), ale potem znalazłem kontroler, w którym pomocnik jest wstrzykiwany do konstruktora Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

Proszę, wyczyść dla mnie mgłę.
Kiedy powinienem używać DI, a kiedy powinienem objectManager? i dlaczego?
Przeczytałem to pytanie: Tworzenie instancji Pomocników w Magento 2 . To tylko kolejne pytanie na ten temat.

Marius
źródło

Odpowiedzi:

10

Wolę DI tam, gdzie to możliwe, ponieważ używanie menedżera obiektów stanowi już naruszenie prawa demeter. Podczas korzystania z menedżera obiektów zależności te są po prostu ukryte w logice metody.

Tobiasz
źródło
Tak. Zgadzam się. Użyję DI, ale jestem ciekawy, dlaczego tak się dzieje w rdzeniu? Może ktoś jeszcze nie udało się refaktoryzować klas, o których wspomniałem?
Marius
Afaik, wciąż dużo refaktoryzują i mają nadzieję, że również dotkną tych miejsc. Ale także nie wiem o priorytetach, które muszą istnieć, jeśli chcą faktycznie wydać w pewnym momencie. Może więc najpierw zostaną naprawione niektóre nowe funkcje lub inne złe praktyki.
Tobias
Co jeśli masz klasę 10 funkcji i TYLKO 1 funkcja wymaga określonego modelu? Czy nie byłoby zbędne (z widoku wydajności) ładowanie modelu przez wstrzyknięcie konstruktora dla każdej z 10 funkcji, podczas gdy moglibyśmy go załadować za pomocą menedżera obiektów tylko w jednej funkcji?
JohnyFree
6

Nie wiem dużo o implementacji Magento, ale wygląda na ObjectManagerto, że jest lokalizatorem usług .

Zasadniczo używanie Lokalizatora usług do uzyskiwania dostępu do zależności w obiekcie jest dość złe, sprawdź ten artykuł .

Definiowanie własnych zależności za pomocą konstruktora jest znacznie lepszym podejściem. Pomaga w testowaniu jednostkowym i problemach z czasem działania, gdy usługi nie są zdefiniowane.

Wstrzyknięcie Menedżera obiektów do klasy jest po prostu wstrzyknięciem Rejestru do klasy, która ma dostęp do wszystkich usług aplikacji, co oczywiście nie jest właściwe.

Używam ZF2 dość często i ogólnie definiuję małe klasy fabryczne dla usług, kontrolerów i każdej klasy wymagającej zależności. Te klasy fabryczne mają dostęp do Lokalizatora usług i pobierają wszystkie usługi, od których zależy obiekt, i wstrzykują je przez konstruktor. Korzystanie z usługi lokalizatora w klasie Fabryka jest w porządku, jak to jest w większości wyrzucić kod, coś jak to na przykład.

Te fabryki są nadal łatwe do przetestowania .

IMO, Użyj iniekcji konstruktora tam, gdzie to możliwe. Znowu nie wiem zbyt wiele o implementacji Magento i jeśli ma ona koncepcję Fabryki, to od razu wygląda na to, że je obsługuje, ale wyraźne zdefiniowanie klas i użycie Lokalizatora usług do zbudowania ich w klasach Fabryki to znacznie czystsze podejście.

To jest od kogoś, kto ma ograniczone kontakt z wyżej wymienionymi wzorami, dlatego też chciałbym usłyszeć czyjeś myśli / doświadczenia w tej sprawie!

Więcej lektur

Aydin Hassan
źródło
Dzięki za miłe wyjaśnienie. Moje pytanie brzmiało: „Dlaczego istnieją 2 sposoby na uzyskanie dostępu do pomocnika w rdzeniu?” więc jest to trochę nie na temat, ale rozwiało inne wątpliwości, które miałem. :) Dzięki.
Marius
Prawdopodobnie powiedziałbym, że jest to coś, czego jeszcze nie zreformowano. Albo to, albo może być rzecz łatwą w użyciu. Wymaganie od konsumentów, aby zawsze wprowadzali wszystkie swoje zależności do kontrolera, może być postrzegane jako efekt przeciwny do zamierzonego, szczególnie podczas wykonywania RAD. Zapewnienie konsumentom obu sposobów dostępu do zależności pozwoliłoby na podejście RAD, ale nadal pozwalałoby innym na jawne zdefiniowanie swoich zależności, jeśli sobie tego życzą.
Aydin Hassan
5

Innym sposobem korzystania z pomocnika (w szablonach) jest:

$this->helper('[Vendor]\[Module]\Helper\[Helper Name]')->getMethodName();

Mam nadzieję, że jest to przydatne, jeśli jeszcze tego nie wiesz.

rbncha
źródło
jest to jakoś podobne do korzystania z menedżera obiektów. Nie jestem pewien, czy to najlepszy pomysł.
Marius
1
Powyższa metoda dotyczy wyłącznie szablonów, o ile mi wiadomo. Menedżer obiektów jest używany w kontrolerach, blokach, modelach itp.
rbncha
1
Nie ma go w tym samym polu co kod, ponieważ nie ma zależności kodu od szablonów. Szablony są tylko konsumentami i nie zanieczyszczają żadnych klientów z uszkodzoną enkapsulacją.
demonkoryu
Nie wiem, co próbuje powiedzieć demonkoryu. Ale najlepszym sposobem na wywołanie pomocnika dowolnego modułu jest to. To jest Magento. Jak mówią, każdy kod bloku / sekcji ma być wywoływalny / modyfikowalny bez dotykania rdzenia. Tak więc wszystko jest ze sobą powiązane lub ma zależności.
rbncha
2

Choć to stare pytanie, nie jestem pewien, czy Marius otrzymał odpowiedź. Wierzę, że Marius może lepiej odpowiedzieć. Chciałbym krótko odpowiedzieć na to pytanie. Dlaczego Magento 2 sugeruje użycie DI zamiast pomocnika?

  • Umożliwienie / łatwość izolacji w testach jednostkowych
  • Jawne definiowanie zależności klasy
  • Ułatwienie dobrego projektu (na przykład zasada pojedynczej odpowiedzialności)
  • Używanie DI w module zmniejsza ryzyko błędów niekompatybilności, gdy Magento zmienia podstawową implementację tych interfejsów. Jest to ważna koncepcja dla programistów rozszerzeń.

Dlaczego w niektórych przypadkach rdzeń M2 może nie używać DI?

  • Malejąca liczba klas
  • Nie tworzenie niepotrzebnych interfejsów
  • Brak ryzyka błędów niekompatybilności

Chociaż moduł katalogowy Core został użyty jako pomocnik, to w znacznym stopniu wykorzystał DI. W moich badaniach odkryłem, że Magento 2 używało kilku funkcji w plikach pomocniczych katalogu głównego, które nie są odpowiednie dla umów serwisowych.

Jeśli musisz jawnie użyć klasy zdefiniowanej przez Magento (takiej jak \ Magento \ Catalog \ Model \ Product), wyraź jawną zależność domyślną, zależnie od konkretnej implementacji zamiast interfejsu umowy serwisowej.

Niewątpliwie deweloper rozszerzeń powinien używać DI zamiast Magento1 jak Helper. Podczas wdrażania zgodnie z wytycznymi Magento 2 opadanie jest ograniczone. Podczas łamania zaleceń zdarzają się problemy.

Agilox
źródło
Tak, w międzyczasie otrzymałem odpowiedź. Ale dzięki za poświęcenie czasu na odpowiedź. To cenna informacja dla osób szukających tego online.
Marius