PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Wzorce GoF w Magento 2 – gdzie je znaleźć i jak działają

by Henryk Tews / wtorek, 21 czerwca 2022 / Opublikowano w Magento 2, Wzorce projektowe

Magento 2 to jeden z najbardziej wzorcowych (dosłownie) frameworków PHP. Jego architektura jest niemal podręcznikowym przykładem zastosowania wzorców GoF. Jeśli rozumiesz wzorce omówione w tej serii, czytanie kodu Magento staje się znacznie łatwiejsze – zamiast „skąd się to bierze” masz „aha, to Factory” albo „to Observer przez di.xml”. Pokazuję gdzie konkretnie każdy wzorzec żyje w platformie.

Wzorce kreacyjne w Magento 2

Factory Method i Abstract Factory

Magento 2 generuje klasy Factory automatycznie dla każdego modelu. Gdy w konstruktorze zadeklarujesz ProductFactory, Magento generuje plik generated/code/Magento/Catalog/Model/ProductFactory.php z metodą create(). To klasyczny Factory Method – fabryka wie jak stworzyć produkt, Ty tylko prosisz ją o nowy egzemplarz.

<?php

// Factory Method - automatycznie generowane przez Magento
use Magento\Catalog\Model\ProductFactory;

class MyService
{
    public function __construct(
        private ProductFactory $productFactory
    ) {}

    public function createProduct(array $data): \Magento\Catalog\Model\Product
    {
        // create() to factory method - zawsze nowa instancja
        return $this->productFactory->create(['data' => $data]);
    }
}

// Abstract Factory - rodziny powiązanych obiektów
// Magento\Framework\DB\Adapter\AdapterInterface tworzy spójną rodzinę:
// - zapytania SELECT, INSERT, UPDATE, DELETE
// - obsługę transakcji
// - budowanie warunków WHERE
// Podmiana adaptera (MySQL -> PostgreSQL) zmienia całą rodzinę operacji

Singleton

ObjectManager Magento działa domyślnie jako singleton w obrębie requestu – każda klasa zarejestrowana bez shared="false" jest tworzona raz i zwracana przy kolejnych żądaniach. To „managed singleton” zarządzany przez kontener DI, a nie klasyczny getInstance().

<?php

// Singleton przez DI - Magento tworzy instancję raz i reużywa
// (shared="true" to domyślne zachowanie)
$serviceA = $objectManager->get(MyService::class);
$serviceB = $objectManager->get(MyService::class);
// $serviceA === $serviceB - ten sam obiekt

// Non-singleton - shared="false" w di.xml lub przez Factory
// Każde create() zwraca nową instancję
$product1 = $productFactory->create();
$product2 = $productFactory->create();
// $product1 !== $product2

Builder

Magento\Framework\Api\SearchCriteriaBuilder to podręcznikowy przykład wzorca Builder. Budujesz złożone kryterium wyszukiwania krok po kroku przez fluent interface, a create() zwraca gotowy, zwalidowany obiekt:

<?php

// Builder - SearchCriteriaBuilder
$searchCriteria = $this->searchCriteriaBuilder
    ->addFilter('status', 1)
    ->addFilter('visibility', [2, 3, 4], 'in')
    ->addSortOrder(
        $this->sortOrderBuilder
            ->setField('name')
            ->setAscendingDirection()
            ->create()
    )
    ->setPageSize(20)
    ->setCurrentPage(1)
    ->create(); // build() - zwraca gotowy SearchCriteria

// Inne Buildery w Magento:
// - Magento\Framework\Api\SortOrderBuilder
// - Magento\Ui\Component\Form\Field\Builder (UI Components)

Wzorce strukturalne w Magento 2

Decorator

System pluginów Magento 2 (Interceptors) to implementacja wzorca Decorator przez AOP. Magento generuje klasy Interceptor które owijają oryginalne klasy warstwami pluginów:

<?php

// Plugin "after" - Decorator dodający funkcjonalność po wywołaniu metody
class ProductNamePlugin
{
    public function afterGetName(
        \Magento\Catalog\Model\Product $subject,
        string $result
    ): string {
        // Dekorujemy wynik - dodajemy sufiks
        return $result . ' [Promocja]';
    }
}

// Magento generuje:
// Magento\Catalog\Model\Product\Interceptor extends Product
// który opakowuje oryginalne metody pluginami
// - to jest wzorzec Decorator wygenerowany automatycznie

Proxy

Magento automatycznie generuje klasy Proxy dla klas z ciężkimi konstruktorami. Plik generated/code/Magento/Catalog/Model/ResourceModel/Product/Proxy.php implementuje lazy loading – prawdziwy obiekt tworzony jest dopiero przy pierwszym wywołaniu metody:

<?xml version="1.0"?>
<config>
    <!-- Wstrzyknięcie Proxy zamiast ciężkiej klasy -->
    <type name="Vendor\Module\Model\MyService">
        <arguments>
            <argument name="heavyDependency" xsi:type="object">
                Magento\Catalog\Model\ResourceModel\Product\Proxy
            </argument>
        </arguments>
    </type>
</config>

Adapter

Magento\Framework\DB\Adapter\AdapterInterface i jego implementacje to Adapter – ujednolicają dostęp do różnych baz danych za jednym interfejsem. Magento\Framework\Filesystem\DriverInterface adaptuje operacje na plikach niezależnie od systemu plików (lokalny, remote, stream).

Facade

Magento\Framework\App\Helper\AbstractHelper oraz helpery modułów jak Magento\Catalog\Helper\Data to Facade – upraszczają dostęp do złożonych podsystemów przez jeden obiekt. Podobnie Magento\Framework\View\Result\PageFactory ukrywa złożoność budowania strony wynikowej.

Wzorce behawioralne w Magento 2

Observer

System zdarzeń Magento 2 to pełna implementacja Observer. Magento\Framework\Event\Manager pełni rolę Subject, a każdy observer zarejestrowany w events.xml to Concrete Observer:

<?xml version="1.0"?>
<config>
    <event name="sales_order_place_after">
        <observer name="vendor_module_notify"
                  instance="Vendor\Module\Observer\NotifyErp"/>
    </event>
</config>
<?php

// Concrete Observer
class NotifyErp implements \Magento\Framework\Event\ObserverInterface
{
    public function execute(\Magento\Framework\Event\Observer $observer): void
    {
        $order = $observer->getData('order');
        // reaguj na zdarzenie - Subject (EventManager) nie zna tej klasy
    }
}

Strategy

System obliczania cen w Magento to wielowarstwowy Strategy. Magento\Framework\Pricing\Price\Collection trzyma zbiór strategii cenowych (RegularPrice, SpecialPrice, TierPrice), każda implementuje PriceInterface. Podobnie metody wysyłki i płatności to Strategy – każda implementuje MethodInterface i może być podmieniona przez konfigurację.

<?php

// Strategy - ceny produktu
use Magento\Catalog\Pricing\Price\RegularPrice;
use Magento\Catalog\Pricing\Price\SpecialPrice;
use Magento\CatalogRule\Pricing\Price\CatalogRulePrice;

// Każda implementuje PriceInterface - wymienne strategie obliczania ceny
$regularPrice = $product->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE);
$specialPrice = $product->getPriceInfo()->getPrice(SpecialPrice::PRICE_CODE);
$rulePrice    = $product->getPriceInfo()->getPrice(CatalogRulePrice::PRICE_CODE);

Command

Magento Command w dwóch miejscach: system komend CLI (bin/magento) oparty na Symfony Console, oraz Message Queue Framework gdzie każda wiadomość w kolejce to Command – serializowany obiekt z danymi do wykonania przez Consumer.

<?php

// Command - komenda CLI
class ReindexCommand extends \Symfony\Component\Console\Command\Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // execute() to factory method z Command GoF
        return Command::SUCCESS;
    }
}

// Command - wiadomość w Message Queue
// Publisher wysyła komendę, Consumer wykonuje - klasyczny Command pattern

Chain of Responsibility

Pipeline przetwarzania płatności w Magento to Chain of Responsibility. Każdy krok (walidacja, autoryzacja, capture, settlement) to handler który może przerwać łańcuch lub przekazać dalej. Podobnie Magento\Framework\App\Router\Base i system routerów – każdy router próbuje dopasować URL, przy sukcesie zatrzymuje łańcuch.

<?php

// Chain of Responsibility - router Magento
// FrontController::dispatch() przechodzi przez listę routerów:
// 1. Magento\Framework\App\Router\Base (standardowe akcje)
// 2. Magento\Cms\App\Router (strony CMS)
// 3. Magento\UrlRewrite\App\Router (przepisania URL)
// 4. Magento\Framework\App\Router\DefaultRouter (404)
// Pierwszy który dopasuje - zatrzymuje łańcuch

Mapa wzorców GoF w Magento 2

Wzorzec Gdzie w Magento 2
Factory Method Generowane klasy *Factory, ObjectManager
Abstract Factory DB Adapter, Filesystem Driver
Singleton Shared instances w ObjectManager (domyślne)
Builder SearchCriteriaBuilder, SortOrderBuilder
Decorator System pluginów – generowane Interceptory
Proxy Generowane klasy *Proxy (lazy loading)
Adapter DB Adapter, Filesystem Driver, Cache Backend
Facade Helper klasy, PageFactory, Context
Observer System zdarzeń – events.xml + ObserverInterface
Strategy PriceInterface, MethodInterface (shipping/payment)
Command CLI commands, Message Queue messages
Chain of Responsibility Router pipeline, payment processing pipeline

Podsumowanie serii

Wzorce GoF to język którym możesz opisywać architekturę systemu – szybciej i precyzyjniej niż długimi opisami. Gdy mówisz „to jest Observer przez di.xml” albo „użyjmy tu Buildera bo konstruktor rośnie” – każdy developer w zespole od razu wie o czym mówisz.

Magento 2 jest zbudowane na tych wzorcach konsekwentnie i celowo. Architekci platformy przez lata dopracowywali sposób w jaki DI, pluginy, eventy i fabryki współpracują ze sobą. Rozumienie wzorców GoF sprawia że ta architektura przestaje być chaosem XML-i i klas, a staje się spójnym systemem z jasną logiką decyzji projektowych.

About Henryk Tews

Co możesz przeczytać następne

Factory Method + Abstract Factory – implementacje od zera, tabela różnic, Simple Factory jako alternatywa
CQRS – Command Bus, Query Bus, read models, integracja z Magento 2
Checkout customization – własne pola, mixin JS, krok do procesu, zapis do Order
  • Publikacje
  • O autorze
  • Kontakt

© 2026 Created by

GÓRA
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Zawsze aktywne
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Zarządzaj opcjami
  • Zarządzaj serwisami
  • Zarządzaj {vendor_count} dostawcami
  • Przeczytaj więcej o tych celach
Zobacz preferencje
  • {title}
  • {title}
  • {title}