„Adott egy paragraph, ami további paragraphokra hivatkozik. Szeretnék a hivatkozó elemre egy plusz classt tenni, ami a hivatkozott elem típusától függ. Ha egy képre hivatkozik, akkor »aside-image«, ha szövegre, »aside-text«.” Ezzel a kéréssel fordultam nemrégiben a többiekhez.
A segítségemre Vince sietett, aki néhány tisztázó kérdés után szállította a működő kódot. Én meg – amellett, hogy örültem nagyon – csak néztem, hogy miként oldotta meg ezt így, pikk-pakk!
Pár nappal ezelőtt ezt is elmesélte.
Jó, jó de minek ez az egész?
A látványterven, amit kaptam, kéthasábos elrendezés szerepel. A fő hasáb mindig szöveg, mellette azonban kép vagy szöveg is megjelenhet. És attól függően, hogy mi van oldalt, más-más a két hasáb közötti távolság illetve a kiegészítő mérete is.
Nem szerettem volna emiatt két külön hivatkozó paragraph típust létrehozni. És a leendő tartalomszerkesztőket sem akartam azzal terhelni, hogy külön be kelljen jelölniük, milyen típusú kiegészítőt választottak. Az tűnt az elegáns megoldásnak, hogy automatizáltan jelenítünk meg egy classt, amivel a doboz layoutot tudom befolyásolni. Hiszen a szükséges típus adat elérhető a rendszerben!
No igen. Elérhető. Hogyan is?
Első lépés: theme suggestions és preprocess
A paragraphs modul háromféle theme hook suggestion-t ad meg.
-
paragraph__[view_mode](pl.paragraph--default.html.twig) -
paragraph__[type](pl.paragraph--image.html.twig) -
paragraph__[type]__[view_mode](pl.paragraph--image--default.html.twig)
Ez az információ még megtalálható a dokumentációban is, Vince azonban – az egyszerűség kedvéért – a modul forráskódjában kereste meg.
Fontos tudni, hogy a theme hook suggestion-ök, nem csak a használandó template-re adnak javaslatot, hanem az elem renderelése során meghívandó preprocess függvények listáját is bővítik.
Így a következő logikus lépés a paragraphs alapértelmezett preprocess funkciójának a megvizsgálása volt.
Eredet, avagy: mélyebbre kell menni
„Szerencsére” a hivatkozás szabványos módon, mezőn keresztül történik. A mezőkhöz mindig tartozik adatbázis tábla, aminek a felépítése meghatározott struktúrát követ.

A field táblák első 3 mezője az értéket tartalmazó entitást írja le (bundle, entity_id, revision_id). A következő 3 (deleted, langcode, delta) a konkrét értékre vonatkozik: Törölt érték? Milyen nyelvű az érték, hányadik elem a több elemű listában?
Minden további oszlopot a mező típusa határoz meg. Egyszerű típusoknál egy plusz oszlop lesz, aminek a neve általában a [field neve]_value mintát követi.
Az összetett esetben a mező típusa határozza meg, hogy milyen nevű és típusú oszlopok lesznek a táblában.
Sorról-sorra
Íme a kész megoldás:
/**
* Implements hook_preprocess_paragraph().
*
* Paragraph preprocess for ‘Text and Aside’ typed paragraphs.
*/
function THEMENAME_preprocess_paragraph__text_and_aside(&$variables) {
/** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
$paragraph = $variables['elements']['#paragraph'];
foreach ($paragraph->get('field_paph_aside')->getValue() as $item) {
/** @var Drupal\paragraphs\Entity\Paragraph $sub_item */
$sub_item = \Drupal\paragraphs\Entity\Paragraph::load($item['target_id']);
$variables['attributes']['class'][] = 'aside-' . $sub_item->bundle();
}
}
Nézzük meg, mi micsoda a fenti kódban:
function THEMENAME_preprocess_paragraph__text_and_aside(&$variables)
Ez a függvény a sminkben egy preprocess hook-ot valósít meg, ami a Text and aside típusú paragraph-ok megjelenítésére lesz hatással.
/** @var Drupal\paragraphs\Entity\Paragraph $paragraph */
A @var komment sorokat a fejlesztő környezet (ld: IDE, PHPStorm) számára ad információt, hogy a $paragraph változó milyen típusú értéket tartalmaz. Erre az információra építve tudja a kódkiegészítést építeni.

A $variables-ben megkaptuk az éppen megjelenített paragraph entitást is.
$paragraph = $variables['elements']['#paragraph'];
Az éppen megjelenített $paragraph-tól elkérjük az általa hivatkozott paragraphokat és végignézzük mindegyiket.
foreach ($paragraph->get('field_paph_aside')->getValue() as $item) {
A hivatkozott paragraph-ot az azonosítója alapján betöltjük...
$sub_item = \Drupal\paragraphs\Entity\Paragraph::load($item['target_id']);
... majd elkérjük, hogy milyen típusú (bundle). Ezt az értéket használva a hivatkozó paragraph class listájához adunk egy új elemet.
$variables['attributes']['class'][] = 'aside-' . $sub_item->bundle();
Az eredmény

Epilógus: Preprocess nélkül
A preprocess nem az egyetlen módja, hogy a szükséges class-t hozzáadjuk a hivatkozó paragraph-hoz. Létrehozhatunk egy saját twig sablont (paragraph--text-and-aside.html.twig) a számára. Ebben a következőképp hozhatjuk létre a hivatkozott elem típusát tartalmazó változót (amit aztán class-ként hozzáadhatunk az attribútumokhoz):
{% set aside_bundle = paragraph.field_paph_aside.entity.type.0.target_id %}
Ez a megoldás Mark Conroy-tól származik, a DrupalTwig Slack csatornából.

…
Köszönet Vincének a fenti bejegyzés elkészítésében nyújtott segítségéért is!
Oszd meg ismerőseiddel!