SlideShare una empresa de Scribd logo
1 de 29
Descargar para leer sin conexión
Come Drupal
costruisce le tue
pagine?
28/09/2022
Luca Lusso
Drupal / PHP / Go developer @ SparkFabrik
Drupal contributor (WebProfiler, Monolog, XHProf, …) and speaker
Drupal.org: https://www.drupal.org/u/lussoluca
Twitter: https://www.twitter.com/lussoluca
LinkedIn: www.linkedin.com/in/lussoluca
Slack (drupal.slack.com): lussoluca
Drupal costruisce tutte le pagine alla stessa maniera:
● Nodi
● Viste
● Pagine di amministrazione
● Form
● …
Tutte seguono lo stesso ciclo di vita: una Richiesta viene processata per generare
una Risposta.
In questa sessione analizzeremo nel dettaglio quello che succede sotto il cofano,
quali componenti e sottosistemi di Drupal sono coinvolti per trasformare una
Richiesta in una Risposta.
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}
Drupal 10 è ottimizzato per la produzione. Per analizzare nel dettaglio quello che
succede, conviene spegnere queste ottimizzazioni e disabilitare tutte le cache.
Per fare questo basta aggiungere 3 righe in fondo al file sites/default/settings.php
Nel file sites/development.services.yml invece alteriamo la configurazione di Twig
per abilitare il debug e disabilitare la cache dei template.
parameters:
http.response.debug_cacheability_headers: true
twig.config:
debug: true
auto_reload: null
cache: false
services:
cache.backend.null:
class: DrupalCoreCacheNullBackendFactory
Per analizzare il funzionamento di Drupal abbiamo bisogno di un tool che ci faccia vedere come
i diversi sottosistemi del CMS interagiscono tra di loro.
● WebProfiler è un modulo per Drupal 8/9/10 (prima era dentro Devel, ora è un progetto a se)
● Basato sul profiler di Symfony
● Colleziona dati su ogni risposta che il sistema genera
● Instrumenta il codice del Core per estrarre informazioni utili
https://blog.sparkfabrik.com/en/webprofiler-updates
Una volta installato ed abilitato, il modulo WebProfiler inizia a collezionare e salvare
informazioni per ogni pagina visitata.
I profili vengono salvati all’interno del filesystem di Drupal.
Viene iniettata una toolbar in fondo ad ogni pagina HTML, con un overview dei dati
raccolti. L’insieme di tutti i dati è accessibile su una dashboard che li mostra per
esteso
<?php
use DrupalCoreDrupalKernel;
use SymfonyComponentHttpFoundationRequest;
$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
index.php AKA The Front Controller
https://www.richardbagshaw.co.uk/stack-php-middleware/
Prima di essere processata, ogni richiesta attraversa un insieme di strati, nei quali
può essere modificata, anche radicalmente.
Dopo essere stata generata, ogni risposta ri-attraversa gli stessi strati, ma alla
rovescia, dall’ultimo al primo. Ogni strato può modificare la risposta, prima di
passare a quello dopo.
drupalcon.example:
path: '/example'
defaults:
_controller: 'DrupaldrupalconControllerExampleController::view'
_title: 'Example'
requirements:
_access: 'TRUE'
Dopo aver attraversato tutti i middleware, la richiesta è pronta per essere instradata
verso il pezzo di codice che dovrà gestirla.
Questo processo è chiamato routing e consente a Drupal di decidere quale controller
invocare.
In questo caso il controller che viene invocato non fa altro che ritornare la più
semplice delle risposte: Hello, world!
<?php
namespace DrupaldrupalconController;
use DrupalCoreControllerControllerBase;
class ExampleController extends ControllerBase {
public function view() {
return [
'#type' => 'markup',
'#markup' => 'Hello, world!',
];
}
}
Vediamo qualcosa di più complesso, un controller che chiama un endpoint
esterno, in HTTP, per recuperare un dato e lo ritorna in una risposta.
Per fare una chiamata HTTP mi serve un client HTTP. Il Core di Drupal ne
fornisce uno e lo mette a disposizione come servizio.
I servizi sono oggetti PHP il cui solo scopo è mettere a disposizione una
qualche funzionalità a chi li utilizza.
Il Core di Drupal ne definisce a centinaia.
Le caratteristiche principali di un servizio sono:
● Non mantengono uno stato
● Meglio se implementano un’interfaccia
● Devono fare una cosa soltanto (la S di SOLID)
Un controller Drupal non è un servizio, quindi usare la Dependency Injection
non è un opzione. Dobbiamo usare il metodo create() di ControllerBase.
<?php
namespace DrupaldrupalconController;
use DrupalCoreControllerControllerBase;
use GuzzleHttpClient;
use SymfonyComponentDependencyInjectionContainerInterface;
class MicroserviceController extends ControllerBase {
private Client $httpClient;
public static function create(ContainerInterface $container) {
return new static(
$container->get('http_client')
);
}
final public function __construct(Client $httpClient) {
$this->httpClient = $httpClient;
}
}
Il controller delega tutta la Business Logic ai servizi. Il suo unico compito è di
coordinarli per trasformare una richiesta in una risposta.
public function view() {
$response = $this
->httpClient
->get('http://ddev-drupal10-microservice:8080/hello-instrumented');
$json = json_decode($response->getBody()->getContents());
return [
'#type' => 'markup',
'#markup' => $json->message,
];
}
Se la rotta richiesta è quella di un nodo (/node/42 ad esempio), il flusso seguito da
Drupal è esattamente lo stesso.
Con solo qualche passaggio in più:
● La rotta è parametrica, 42 identifica l’id del nodo da caricare
● Drupal usa un servizio per fare l’upcast del parametro all’oggetto Node che lo rappresenta
● Il nodo è caricato dal database usando un servizio apposito
Un controller però contribuisce solo ad una parte della risposta, quello che ritorna è
stampato all’interno della regione main del template.
Tutto il resto della pagina è contribuito dal sistema dei Blocchi.
I blocchi sono plugin, ma ne parleremo un’altra volta :-)
Un po’ di informazioni qua:
https://drupalize.me/blog/201409/unravelling-drupal-8-plugin-system
Fin qua abbiamo visto come il controller contribuisca a costruire il render array della
regione main e quali sono i blocchi che contribuiscono al resto della pagina.
Arrivati a questo punto però, anche se si segue il codice passo passo con un
debugger è difficile capire cosa succede dopo l’invocazione del controller.
Chi carica i blocchi? Chi assembla la pagina?
Molti dei sistemi che compongono Drupal sono debolmente accoppiati e la
comunicazione tra loro avviene attraverso gli eventi.
In questo caso il Kernel di Drupal prende il render array ritornato dal controller e lo
“spedisce” a tutti i servizi in ascolto per l’evento kernel.view.
Uno o più ascoltatori (listener) si registrano per ricevere eventi di un determinato
tipo. Se qualcuno solleva un evento di quello specifico tipo, tutti gli ascoltatori
vengono invocati, in ordine di priorità, e ciascuno di essi può interagire con l’evento
(per compiere azioni o modificare l’evento stesso).
Ci deve essere quindi un ascoltatore dell’evento kernel.view capace di trasformare il
render array ritornato dal controller in quello di una pagina completa e poi di renderlo
in HTML.
public function onViewRenderArray(ViewEvent $event) {
$request = $event->getRequest();
$result = $event->getControllerResult();
// Render the controller result into a response if it's a render array.
if (is_array($result)) {
$wrapper = $request->query->get(static::WRAPPER_FORMAT, 'html');
$renderer = $this->classResolver->getInstanceFromDefinition($this->mainContentRenderers[$wrapper]);
$response = $renderer->renderResponse($result, $request, $this->routeMatch);
$event->setResponse($response);
}
}
core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php
public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) {
[$page, $title] = $this->prepare($main_content, $request, $route_match);
[...]
return $response;
}
protected function prepare(array $main_content, Request $request, RouteMatchInterface $route_match) {
[...]
$event = new PageDisplayVariantSelectionEvent('simple_page', $route_match);
$this->eventDispatcher->dispatch($event, RenderEvents::SELECT_PAGE_DISPLAY_VARIANT);
[...]
}
core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php
public function onSelectPageDisplayVariant(PageDisplayVariantSelectionEvent $event) {
$event->setPluginId('block_page');
}
core/modules/block/src/EventSubscriber/BlockPageDisplayVariantSubscriber.php
Dopo aver costruito il render array con tutte le informazioni necessarie a costruire
tutta la pagina di risposta, HtmlRenderer usa il servizio renderer per convertire il
tutto in HTML.
Il processo di rendering di un render array coinvolge il tema di Drupal, che a sua volta
usa un’insieme di funzioni di preprocess e di file di Twig.
Durante il processo di rendering tutti gli asset CSS e Javascript vengono aggiunti al
markup finale.
Come ultima cosa la risposta passa attraverso tutti gli strati di middleware,
dall’ultimo al primo e viene inviata al client.
Il viaggio dentro Drupal finisce qua, la risposta HTML verrà renderizzata dal browser.
Il nostro lavoro è concluso.
Oppure no…
Restano (almeno) altre due cose che possiamo analizzare:
● BigPipe
● Performance del frontend
GRAZIE!

Más contenido relacionado

Similar a Come Drupal costruisce le tue pagine

Similar a Come Drupal costruisce le tue pagine (20)

Html5 e PHP
Html5 e PHPHtml5 e PHP
Html5 e PHP
 
SaaS con Symfony2 un caso *molto* concreto di applicazione multitenant
SaaS con Symfony2 un caso *molto* concreto di applicazione multitenantSaaS con Symfony2 un caso *molto* concreto di applicazione multitenant
SaaS con Symfony2 un caso *molto* concreto di applicazione multitenant
 
react-it.pdf
react-it.pdfreact-it.pdf
react-it.pdf
 
Drupal 8: dal download del Core alla pubblicazione in produzione. Cos'è cambi...
Drupal 8: dal download del Core alla pubblicazione in produzione. Cos'è cambi...Drupal 8: dal download del Core alla pubblicazione in produzione. Cos'è cambi...
Drupal 8: dal download del Core alla pubblicazione in produzione. Cos'è cambi...
 
Drupal 8 - dal download del core alla pubblicazione in produzione
Drupal 8 - dal download del core alla pubblicazione in produzioneDrupal 8 - dal download del core alla pubblicazione in produzione
Drupal 8 - dal download del core alla pubblicazione in produzione
 
SaaS con Symfony2
SaaS con Symfony2SaaS con Symfony2
SaaS con Symfony2
 
Introduzione a Struts
Introduzione a StrutsIntroduzione a Struts
Introduzione a Struts
 
Laravel Framework PHP
Laravel Framework PHPLaravel Framework PHP
Laravel Framework PHP
 
Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il fram...
Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il fram...Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il fram...
Tech Webinar: Advanced AngularJS, tecniche avanzate per padroneggiare il fram...
 
Write less do more...with jQuery
Write less do more...with jQueryWrite less do more...with jQuery
Write less do more...with jQuery
 
DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8DDAY2014 - Performance in Drupal 8
DDAY2014 - Performance in Drupal 8
 
#dd12 grillo daniele_xpages_tips_tricks_rev2
#dd12 grillo daniele_xpages_tips_tricks_rev2#dd12 grillo daniele_xpages_tips_tricks_rev2
#dd12 grillo daniele_xpages_tips_tricks_rev2
 
Sviluppo web con Ruby on Rails
Sviluppo web con Ruby on RailsSviluppo web con Ruby on Rails
Sviluppo web con Ruby on Rails
 
Drupal come framework di sviluppo
Drupal come framework di sviluppoDrupal come framework di sviluppo
Drupal come framework di sviluppo
 
Laravel 7 REST API
Laravel 7 REST APILaravel 7 REST API
Laravel 7 REST API
 
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
Drupal diventa un CMF e WordPress che fa? Slide WordCamp Milano 2019
 
Applicazioni distribuite con Symfony2
Applicazioni distribuite con Symfony2Applicazioni distribuite con Symfony2
Applicazioni distribuite con Symfony2
 
Perl Template Toolkit
Perl Template ToolkitPerl Template Toolkit
Perl Template Toolkit
 
Java lezione 18
Java lezione 18Java lezione 18
Java lezione 18
 
Introduzione a node.js
Introduzione a node.jsIntroduzione a node.js
Introduzione a node.js
 

Más de sparkfabrik

Más de sparkfabrik (20)

KCD Italy 2023 - Secure Software Supply chain for OCI Artifact on Kubernetes
KCD Italy 2023 - Secure Software Supply chain for OCI Artifact on KubernetesKCD Italy 2023 - Secure Software Supply chain for OCI Artifact on Kubernetes
KCD Italy 2023 - Secure Software Supply chain for OCI Artifact on Kubernetes
 
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
 
IAD 2023 - 22 Years of Agile and all I got is this lousy t-shirt
IAD 2023 - 22 Years of Agile and all I got is this lousy t-shirtIAD 2023 - 22 Years of Agile and all I got is this lousy t-shirt
IAD 2023 - 22 Years of Agile and all I got is this lousy t-shirt
 
2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pages2023 - Drupalcon - How Drupal builds your pages
2023 - Drupalcon - How Drupal builds your pages
 
2023 - TAC23 - Agile HR - Racconti dal fronte
2023 - TAC23 - Agile HR - Racconti dal fronte2023 - TAC23 - Agile HR - Racconti dal fronte
2023 - TAC23 - Agile HR - Racconti dal fronte
 
CodeMotion 2023 - Deep dive nella supply chain della nostra infrastruttura cl...
CodeMotion 2023 - Deep dive nella supply chain della nostra infrastruttura cl...CodeMotion 2023 - Deep dive nella supply chain della nostra infrastruttura cl...
CodeMotion 2023 - Deep dive nella supply chain della nostra infrastruttura cl...
 
What is the Secure Supply Chain and the Current State of the PHP Ecosystem
What is the Secure Supply Chain and the Current State of the PHP EcosystemWhat is the Secure Supply Chain and the Current State of the PHP Ecosystem
What is the Secure Supply Chain and the Current State of the PHP Ecosystem
 
UX e Web sostenibile (UXday 2023).pdf
UX e Web sostenibile (UXday 2023).pdfUX e Web sostenibile (UXday 2023).pdf
UX e Web sostenibile (UXday 2023).pdf
 
Drupal Dev Days Vienna 2023 - What is the secure software supply chain and th...
Drupal Dev Days Vienna 2023 - What is the secure software supply chain and th...Drupal Dev Days Vienna 2023 - What is the secure software supply chain and th...
Drupal Dev Days Vienna 2023 - What is the secure software supply chain and th...
 
Deep dive nella supply chain della nostra infrastruttura cloud
Deep dive nella supply chain della nostra infrastruttura cloudDeep dive nella supply chain della nostra infrastruttura cloud
Deep dive nella supply chain della nostra infrastruttura cloud
 
KCD Italy 2022 - Application driven infrastructure with Crossplane
KCD Italy 2022 - Application driven infrastructure with CrossplaneKCD Italy 2022 - Application driven infrastructure with Crossplane
KCD Italy 2022 - Application driven infrastructure with Crossplane
 
Drupal 10: un framework PHP di sviluppo Cloud Native moderno
Drupal 10: un framework PHP di sviluppo Cloud Native modernoDrupal 10: un framework PHP di sviluppo Cloud Native moderno
Drupal 10: un framework PHP di sviluppo Cloud Native moderno
 
Do you know what your Drupal is doing Observe it! (DrupalCon Prague 2022)
Do you know what your Drupal is doing Observe it! (DrupalCon Prague 2022)Do you know what your Drupal is doing Observe it! (DrupalCon Prague 2022)
Do you know what your Drupal is doing Observe it! (DrupalCon Prague 2022)
 
Do you know what your Drupal is doing_ Observe it!
Do you know what your Drupal is doing_ Observe it!Do you know what your Drupal is doing_ Observe it!
Do you know what your Drupal is doing_ Observe it!
 
Progettare e sviluppare soluzioni serverless con AWS
Progettare e sviluppare soluzioni serverless con AWSProgettare e sviluppare soluzioni serverless con AWS
Progettare e sviluppare soluzioni serverless con AWS
 
From React to React Native - Things I wish I knew when I started
From React to React Native - Things I wish I knew when I startedFrom React to React Native - Things I wish I knew when I started
From React to React Native - Things I wish I knew when I started
 
Headless Drupal: A modern approach to (micro)services and APIs
Headless Drupal: A modern approach to (micro)services and APIsHeadless Drupal: A modern approach to (micro)services and APIs
Headless Drupal: A modern approach to (micro)services and APIs
 
Cloud-Native Drupal: a survival guide
Cloud-Native Drupal: a survival guideCloud-Native Drupal: a survival guide
Cloud-Native Drupal: a survival guide
 
Mobile Development: una introduzione per Web Developers
Mobile Development: una introduzione per Web DevelopersMobile Development: una introduzione per Web Developers
Mobile Development: una introduzione per Web Developers
 
Retro gaming machine made with Javascript and Kubernetes
Retro gaming machine made with Javascript and Kubernetes Retro gaming machine made with Javascript and Kubernetes
Retro gaming machine made with Javascript and Kubernetes
 

Come Drupal costruisce le tue pagine

  • 1. Come Drupal costruisce le tue pagine? 28/09/2022
  • 2. Luca Lusso Drupal / PHP / Go developer @ SparkFabrik Drupal contributor (WebProfiler, Monolog, XHProf, …) and speaker Drupal.org: https://www.drupal.org/u/lussoluca Twitter: https://www.twitter.com/lussoluca LinkedIn: www.linkedin.com/in/lussoluca Slack (drupal.slack.com): lussoluca
  • 3. Drupal costruisce tutte le pagine alla stessa maniera: ● Nodi ● Viste ● Pagine di amministrazione ● Form ● … Tutte seguono lo stesso ciclo di vita: una Richiesta viene processata per generare una Risposta. In questa sessione analizzeremo nel dettaglio quello che succede sotto il cofano, quali componenti e sottosistemi di Drupal sono coinvolti per trasformare una Richiesta in una Risposta.
  • 4. if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) { include $app_root . '/' . $site_path . '/settings.local.php'; } Drupal 10 è ottimizzato per la produzione. Per analizzare nel dettaglio quello che succede, conviene spegnere queste ottimizzazioni e disabilitare tutte le cache. Per fare questo basta aggiungere 3 righe in fondo al file sites/default/settings.php
  • 5. Nel file sites/development.services.yml invece alteriamo la configurazione di Twig per abilitare il debug e disabilitare la cache dei template. parameters: http.response.debug_cacheability_headers: true twig.config: debug: true auto_reload: null cache: false services: cache.backend.null: class: DrupalCoreCacheNullBackendFactory
  • 6. Per analizzare il funzionamento di Drupal abbiamo bisogno di un tool che ci faccia vedere come i diversi sottosistemi del CMS interagiscono tra di loro. ● WebProfiler è un modulo per Drupal 8/9/10 (prima era dentro Devel, ora è un progetto a se) ● Basato sul profiler di Symfony ● Colleziona dati su ogni risposta che il sistema genera ● Instrumenta il codice del Core per estrarre informazioni utili https://blog.sparkfabrik.com/en/webprofiler-updates
  • 7. Una volta installato ed abilitato, il modulo WebProfiler inizia a collezionare e salvare informazioni per ogni pagina visitata. I profili vengono salvati all’interno del filesystem di Drupal. Viene iniettata una toolbar in fondo ad ogni pagina HTML, con un overview dei dati raccolti. L’insieme di tutti i dati è accessibile su una dashboard che li mostra per esteso
  • 8.
  • 9. <?php use DrupalCoreDrupalKernel; use SymfonyComponentHttpFoundationRequest; $autoloader = require_once 'autoload.php'; $kernel = new DrupalKernel('prod', $autoloader); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response); index.php AKA The Front Controller
  • 10. https://www.richardbagshaw.co.uk/stack-php-middleware/ Prima di essere processata, ogni richiesta attraversa un insieme di strati, nei quali può essere modificata, anche radicalmente. Dopo essere stata generata, ogni risposta ri-attraversa gli stessi strati, ma alla rovescia, dall’ultimo al primo. Ogni strato può modificare la risposta, prima di passare a quello dopo.
  • 11. drupalcon.example: path: '/example' defaults: _controller: 'DrupaldrupalconControllerExampleController::view' _title: 'Example' requirements: _access: 'TRUE' Dopo aver attraversato tutti i middleware, la richiesta è pronta per essere instradata verso il pezzo di codice che dovrà gestirla. Questo processo è chiamato routing e consente a Drupal di decidere quale controller invocare.
  • 12. In questo caso il controller che viene invocato non fa altro che ritornare la più semplice delle risposte: Hello, world! <?php namespace DrupaldrupalconController; use DrupalCoreControllerControllerBase; class ExampleController extends ControllerBase { public function view() { return [ '#type' => 'markup', '#markup' => 'Hello, world!', ]; } }
  • 13. Vediamo qualcosa di più complesso, un controller che chiama un endpoint esterno, in HTTP, per recuperare un dato e lo ritorna in una risposta.
  • 14. Per fare una chiamata HTTP mi serve un client HTTP. Il Core di Drupal ne fornisce uno e lo mette a disposizione come servizio.
  • 15. I servizi sono oggetti PHP il cui solo scopo è mettere a disposizione una qualche funzionalità a chi li utilizza. Il Core di Drupal ne definisce a centinaia. Le caratteristiche principali di un servizio sono: ● Non mantengono uno stato ● Meglio se implementano un’interfaccia ● Devono fare una cosa soltanto (la S di SOLID)
  • 16. Un controller Drupal non è un servizio, quindi usare la Dependency Injection non è un opzione. Dobbiamo usare il metodo create() di ControllerBase. <?php namespace DrupaldrupalconController; use DrupalCoreControllerControllerBase; use GuzzleHttpClient; use SymfonyComponentDependencyInjectionContainerInterface; class MicroserviceController extends ControllerBase { private Client $httpClient; public static function create(ContainerInterface $container) { return new static( $container->get('http_client') ); } final public function __construct(Client $httpClient) { $this->httpClient = $httpClient; } }
  • 17. Il controller delega tutta la Business Logic ai servizi. Il suo unico compito è di coordinarli per trasformare una richiesta in una risposta. public function view() { $response = $this ->httpClient ->get('http://ddev-drupal10-microservice:8080/hello-instrumented'); $json = json_decode($response->getBody()->getContents()); return [ '#type' => 'markup', '#markup' => $json->message, ]; }
  • 18. Se la rotta richiesta è quella di un nodo (/node/42 ad esempio), il flusso seguito da Drupal è esattamente lo stesso. Con solo qualche passaggio in più: ● La rotta è parametrica, 42 identifica l’id del nodo da caricare ● Drupal usa un servizio per fare l’upcast del parametro all’oggetto Node che lo rappresenta ● Il nodo è caricato dal database usando un servizio apposito
  • 19. Un controller però contribuisce solo ad una parte della risposta, quello che ritorna è stampato all’interno della regione main del template. Tutto il resto della pagina è contribuito dal sistema dei Blocchi. I blocchi sono plugin, ma ne parleremo un’altra volta :-) Un po’ di informazioni qua: https://drupalize.me/blog/201409/unravelling-drupal-8-plugin-system
  • 20. Fin qua abbiamo visto come il controller contribuisca a costruire il render array della regione main e quali sono i blocchi che contribuiscono al resto della pagina. Arrivati a questo punto però, anche se si segue il codice passo passo con un debugger è difficile capire cosa succede dopo l’invocazione del controller. Chi carica i blocchi? Chi assembla la pagina?
  • 21. Molti dei sistemi che compongono Drupal sono debolmente accoppiati e la comunicazione tra loro avviene attraverso gli eventi. In questo caso il Kernel di Drupal prende il render array ritornato dal controller e lo “spedisce” a tutti i servizi in ascolto per l’evento kernel.view.
  • 22. Uno o più ascoltatori (listener) si registrano per ricevere eventi di un determinato tipo. Se qualcuno solleva un evento di quello specifico tipo, tutti gli ascoltatori vengono invocati, in ordine di priorità, e ciascuno di essi può interagire con l’evento (per compiere azioni o modificare l’evento stesso). Ci deve essere quindi un ascoltatore dell’evento kernel.view capace di trasformare il render array ritornato dal controller in quello di una pagina completa e poi di renderlo in HTML.
  • 23. public function onViewRenderArray(ViewEvent $event) { $request = $event->getRequest(); $result = $event->getControllerResult(); // Render the controller result into a response if it's a render array. if (is_array($result)) { $wrapper = $request->query->get(static::WRAPPER_FORMAT, 'html'); $renderer = $this->classResolver->getInstanceFromDefinition($this->mainContentRenderers[$wrapper]); $response = $renderer->renderResponse($result, $request, $this->routeMatch); $event->setResponse($response); } } core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php
  • 24. public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { [$page, $title] = $this->prepare($main_content, $request, $route_match); [...] return $response; } protected function prepare(array $main_content, Request $request, RouteMatchInterface $route_match) { [...] $event = new PageDisplayVariantSelectionEvent('simple_page', $route_match); $this->eventDispatcher->dispatch($event, RenderEvents::SELECT_PAGE_DISPLAY_VARIANT); [...] } core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php public function onSelectPageDisplayVariant(PageDisplayVariantSelectionEvent $event) { $event->setPluginId('block_page'); } core/modules/block/src/EventSubscriber/BlockPageDisplayVariantSubscriber.php
  • 25. Dopo aver costruito il render array con tutte le informazioni necessarie a costruire tutta la pagina di risposta, HtmlRenderer usa il servizio renderer per convertire il tutto in HTML. Il processo di rendering di un render array coinvolge il tema di Drupal, che a sua volta usa un’insieme di funzioni di preprocess e di file di Twig.
  • 26. Durante il processo di rendering tutti gli asset CSS e Javascript vengono aggiunti al markup finale.
  • 27. Come ultima cosa la risposta passa attraverso tutti gli strati di middleware, dall’ultimo al primo e viene inviata al client. Il viaggio dentro Drupal finisce qua, la risposta HTML verrà renderizzata dal browser. Il nostro lavoro è concluso. Oppure no…
  • 28. Restano (almeno) altre due cose che possiamo analizzare: ● BigPipe ● Performance del frontend