IDCT Bartosz Pachołek

Uwaga: Ciasteczka!

Ta witryna korzysta z cookies: Informujemy, że ta witryna korzysta z własnych, technicznych oraz należących do podmiotów zewnętrznych ciasteczek ("cookies") celem śledzenia aktywności oraz zapewnienia pełnej funkcjonalności. Kontynuując akceptujesz użycie cookies. Aby korzystać z pewnych części witryny konieczna jest akceptacja.

Sylius, szablony: nadpisz szablon lepiej korzystając z wykrzyknika

Opublikowano 2020-07-08

Problem

Oficjalna dokumentacja Syliusa mówi nam, że chcąc nadpisać template mamy kilka opcji: sylius theme events i drugą, bardzo związaną z samym działaniem Symfony, czyli poprzez nadpisanie plików z template w identycznej strukturze folderów - w jakiej występują w swoim bundle - pod naszym projektem. Znaczy to mniej więcej tyle, że chcąc zmienić @SyliusShopBundle/login.html.twig powinieneś zrobić kopię tego pliku do: templates/bundles/SyliusShopBundle/login.html.twig i tam nadpisać zawartość.

Zrzut ekranu dowodzący, że ktoś faktycznie poleca takie rozwiązanie: Sylius 1

Sam tekst znajduje się pod adresem: https://docs.sylius.com/en/latest/customization/template.html

Teraz wyobraź sobie sytuację, w której musisz zmienić wiele plików, a same zmiany to najczęściej drobne, wręcz kosmetyczne modyfikacje i nagle następuje istotna aktualizacja Syliusa, która nie zmienia bloków, ale zmienia np. nazwy czy identyfikatory w polach w wielu plikach. Jesli trudno Ci wyobrazić sobie taką sytuację to wiedz, że co prawda na małą skalę, ale przynajmniej raz wystąpiła: https://github.com/Sylius/Sylius/commit/080c7d6eef9f5e788a745b0da706cf55f197d646#diff-04120f8acd7aa621c497ab95171502cf

W sytuacji gdy masz plik Sylius/Bundle/UiBundle/Resources/views/Form/imagesTheme.html.twig nadpisany w swojej aplikacji, jak polecają autorzy Syliusa, ze względu na jakieś własne modyfikacje w blokach to po tej aktualizacji wyżej nagle przestanie Tobie działać JavaScript obsługujący dodawnie nowej grafiki, gdyż zaczyna polegać na nieistniejącym wcześniej i którego przez to nie masz w swoim oryginalnym pliku atrybucie data-prototype-name.

Brzmi źle, prawda? Jak więc przynajmniej obniżyć ryzyko płynące z aktualizacji?

Potencjalne rozwiąznaie

Najlepszym a przynajmniej lepszym rozwiązaniem jest nadpisanie tylko części, które faktycznie potrzebujemy nadpisać. Jako przykład weźmy plik wspomniany w dokumentacji Syliusa.

Napisali, aby skopiować plik @SyliusShopBundle/views/login.html.twig do templates/SyliusShopBundle/views/login.html.twig więc tak zróbmy.

Jeśli przejdziemy do http://localhost:8000/pl_PL/login (zakładając, że korzystamy z lokalnego serwera devowego) ujrzymy standardowy ekran logowania: Sylius 2

Teraz wyobraź sobie, że chcemy dodać tekst You are awesome! pod formularzem. Zgodnie z dokumentacją Syliusa musimy skopiować całą treść, dodać nową zawartość i zapisać w nadpisującym pliku:

{% extends '@SyliusShop/layout.html.twig' %}

{% form_theme form '@SyliusShop/Form/theme.html.twig' %}

{% block content %}
    {% include '@SyliusShop/Login/_header.html.twig' %}

    {{ sylius_template_event('sylius.shop.login.after_content_header') }}

    <div class="ui padded segment">
        <div class="ui two column very relaxed stackable grid">
            <div class="column">
                {{ sylius_template_event('sylius.shop.login.main_column', _context) }}
            </div>
            <div class="ui hidden vertical divider">
            </div>
            <div class="column">
                {{ sylius_template_event('sylius.shop.login.register_column', _context) }}
            </div>
        </div>
    </div>
    <h1>You are awesome!</h1> 
{% endblock %}

Proste, prawda? Teraz wyobraź sobie, że zmienia się nazwa funkcji sylius_template_event alob zmeinia się identyfikator, któregoś z eventów (np. sylius.shop.login.main_column na sylius.shop.most_important_column): musisz w takim wypadku ręcznie zapoznać się, ze wszystkimi wymaganymi danymi i je wprowadzić w swoich plikach template, które nadpisują te oryginalne.

Czy jest lepsze rozwiązanie?

Najbardziej naturalnym wydaje się rozszerzenie (extend) oryginalnego pliku i dodanie tylko tego co potrzebujemy:

{% extends '@SyliusShop/login.html.twig' %}

{% block content %}
    {{ parent() }}
    <h1>You are awesome!</h1> 
{% endblock %}

(Zwróć uwagę na zmiane namespace)

Jeśli tego spróbujesz, po wyczyszczeniu cache i przeładowaniu to najprawdopodobniej doświadczysz nieskończonego ładowania (wiecznej pętli) lub błędu informującego o przekroczeniu czasu wykonywania. Dlaczego? Ponieważ nasz plik nadpisujący faktycznie nadpisuje @SyliusShop/login.html.twig, więc Symfony na prośbę o jego rozszerzenie cały czas odnosi się do tego samego pliku i zagłębia coraz dalej w rozszerzenia tego samego template, nigdy nie sięga do tego oryginalnego. Wynika to z samej specyfikacji Twiga.

Rozwiązanie

Jest jeden wihajster, trick, który rozwiązuje problem: wystarczy dodać ! po @ a przed nazwą bundle - w naszym wypadku:

{% extends '@!SyliusShop/login.html.twig' %}

{% block content %}
    {{ parent() }}
    <h1>You are awesome!</h1> 
{% endblock %}

Informuje to Symfony, że ma szukać dalej pliku spełniającego ścieżkę niż pierwszego z brzegu, w naszym projekcie.

Wyczyść cache i sprawdź.

Proste i ładne, czyż nie? Takie rozwiąznaie ma jednak swoje minusy: np. nie możesz dodać dodatkowego kodu html pomiędzy blokami, ale możesz dodać nowe albo ukryć istniejące w nadrzędnym template, z którego rozszerzamy.

Rozwiązanie jest idealne gdy plik nadrzędny ma więcej bloków i chcemy zmodyfikować tylko jeden lub kilka, gdy np. chcemy coś dodać na początku lub końcu bloku. Korzystając głównie z bloku nadrzędnego, a rozszerzająć tylko potrzebne elementy zmniejszamy ryzyko utraty spójności.

Mam nadzieję, że komuś to pomogło! Jak zawsze: w przypadku problemów lub pytań: dajcie mi znać.