Przejdź do głównej zawartości

Wewnętrzności przepływu zastępowania

Ta strona dokumentuje zachowanie runtime dla czytelników, którzy chcą zrozumieć lub rozszerzyć plugin. Nic z tego nie jest potrzebne do konfiguracji.

Plugin słucha trzech eventów page-loaded storefront i dwóch eventów entity-loaded:

EventHandlerRodzaj strony
ProductPageLoadedEventonProductPageLoadedSzczegóły produktu
NavigationPageLoadedEventonNavigationPageLoadedKategoria / listing
LandingPageLoadedEventonLandingPageLoadedStrona docelowa
CategoryEvents::CATEGORY_LOADED_EVENTonCategoryEntityLoadedWidget nawigacji CMS (XHR)
LandingPageEvents::LANDING_PAGE_LOADED_EVENTonLandingPageEntityLoadedWczytanie encji strony docelowej

Wszystkie pięć żyją w Subscriber\PageLoadedSubscriber.

Handlery page-loaded pokrywają normalną nawigację storefront. Dwa handlery entity-loaded pokrywają XHR widgetu nawigacji CMS (call, którym twój storefront lazy-loaduje treść kategorii) oraz bezpośrednie wczytania encji strony docelowej, by zastępowanie zachowywało się spójnie zarówno gdy layout jest renderowany jako część głównej strony, jak i jako część widget XHR.

Dla każdego istotnego requesta handler wykonuje mniej więcej:

salesChannelId = rozwiąż z requesta
1. Czy bazowy layout przeszedł bramkę trybu zastępowania?
- Product page → ProductPageReplaceModeEnum (4 wartości)
- Category page → NavigationPageReplaceModeEnum (3 wartości)
- Landing page → LandingPageReplaceModeEnum (3 wartości)
Jeśli nie → return.
2. alternativeTypes = SettingsService::getAlternativeReplaceTypes(baseType, salesChannelId)
Jeśli puste → return.
3. Przejdź każdy p2lab_cms_assigner_cms_page_to_rule, którego cmsPage.type IN alternativeTypes:
- Posortowane po rule.priority ASC (sortowanie standardowe Shopware).
- W stronach po 100 (LIMIT_PER_REQUEST), do 500 łącznie (LIMIT_TOTAL).
- Grupuj wiersze po cmsPageId — pojedynczy layout może mieć wiele reguł przypiętych.
4. Dla każdego cmsPageId zawołaj RuleConditionService::match(rules, page, salesChannelContext):
- Wszystkie przypięte reguły muszą pasować (semantyka AND).
- Reguła jest budowana ze swoich warunków, filtrowane do ConditionNameEnum::CONDITIONS i CONTAINERS.
- Matcher dispatchuje po typie strony → ProductRuleScope / CategoryRuleScope / LandingRuleScope.
5. Pierwsze trafienie wygrywa. Plugin ładuje CmsPage przez SalesChannelCmsPageLoaderInterface
z EntityResolverContext zbudowanym wokół product / category / landingPage,
następnie przypisuje go z powrotem do obiektu page.

Plugin przechowuje przypisania reguła ↔ layout w pojedynczej tabeli junction. Każdy wiersz trzyma:

  • id — klucz główny.
  • cms_page_id + cms_page_version_id — alternatywny layout.
  • rule_id — reguła, od której zależy.

Layout z N przypiętymi regułami ma N wierszy; reguła przypięta do M layoutów ma M wierszy. Czytane w obie strony.

Plugin definiuje trzy własne rule scopes (w Rule\Scope\), by jego własne warunki (i te standardowe Shopware) mogły introspektować to, co jest oglądane:

  • ProductRuleScope — trzyma SalesChannelProductEntity plus kontekst kanału sprzedaży. Używany przez handlery stron produktu i dzielony przez InCategoryRule / InCategoryWithChildrenRule gdy ewaluują względem categoryIds produktu.
  • CategoryRuleScope — trzyma categoryId plus kontekst kanału sprzedaży. Wystawia isHomepage() (używane przez IsHomepageRule).
  • LandingRuleScope — trzyma LandingPage plus kontekst kanału sprzedaży.

Wszystkie trzy dziedziczą po AbstractRuleScope, który trzyma SalesChannelContext i repozytorium kategorii (by reguły, które przechodzą drzewo, mogły szukać).

Plugin dostarcza trzy własne klasy Rule (w Rule\):

  • IsHomepageRule — boolean check względem CategoryRuleScope::isHomepage(). Zwraca false dla scope’ów nie-kategorii.
  • InCategoryRule — porównanie UUID względem categoryIds produktu lub własnego id kategorii.
  • InCategoryWithChildrenRule rozszerza InCategoryRule — dodatkowo przechodzi path kategorii (Shopware przechowuje łańcuch przodków jako |id1|id2|id3|), by matchować potomków.

Jest też Rule\Container\MatchAllRule — stand-in dla “All line items container” Shopware, którego semantyka produkt-only nie ma sensu w kontekście wyboru layoutu CMS. Plugin podstawia własną implementację, która zwraca true tylko gdy każda reguła-dziecko pasuje względem bieżącego scope’u.

ConditionNameEnum definiuje dwa array’e: CONTAINERS i CONDITIONS. Cokolwiek nie jest w tych array’ach jest po cichu ignorowane gdy reguła jest budowana. Lista wykluczeń jest celowo szeroka — wiele standardowych warunków Shopware (sumy koszyka, atrybuty pozycji, metoda dostawy) celuje w flow checkout i nie mają sensu przy wyborze layoutu dla strony, która jeszcze nie została zbudowana.

By dowiedzieć się dokładnie co jest wspierane, zobacz Własne warunki reguł.

onCategoryEntityLoaded jest najbardziej subtelny. Uruchamia się na eventach category.loaded i działa tylko gdy request wygląda jak XHR widgetu nawigacji CMS — ścieżka pasuje do ^/widgets/cms/navigation/<32-hex>$ a query string niesie navigationId + cms-page-id. W ten sposób plugin utrzymuje spójne zastępowanie gdy storefront pobiera treść kategorii przez widget XHR (dodatkowo do początkowego renderu strony).

Wykonuje to samo sprawdzenie trybu co główny handler onNavigationPageLoaded, zanim nadpisze cmsPageId encji.

onLandingPageEntityLoaded uruchamia się na eventach landing_page.loaded i aplikuje domyślny layout strony docelowej jeśli strona docelowa nie ma własnego layoutu. To jest punkt wejścia dla ustawienia default-layout w karcie Landing page.

  • Nie modyfikuje samej strony CMS — tylko to, która CmsPageEntity jest renderowana.
  • Nie dotyka encji kategorii / produktu / strony docelowej w bazie danych — nadpisanie dzieje się w pamięci, per request.
  • Nie cache’uje swoich decyzji; każdy request od nowa ewaluuje reguły. Wyszukiwanie repozytorium trafia w standardowe cache’e Shopware, ale ewaluacja reguł jest per-request.