Come creare un modulo in Magento 2 – Guida allo sviluppo – Parte III

guida-modulo-magento2

Alla fine dello scorso articolo (Come creare un modulo in Magento 2 – Parte II) siamo arrivati al risultato parziale di una pagina bianca contenete la scritta “Hello World!”. Ovviamente il nostro obiettivo è tutt’altro: “Hello World!” deve essere stampato all’interno di una pagina dello store che comprende la grafica generale del sito.

Per raggiungere il nostro scopo occorrono due passaggi fondamentali:

  1. caricare il sistema di layout di Magento;
  2. spostare l’attività di stampa di una frase nel posto corretto.

Il primo punto dei compiti da svolgere può ulteriormente essere suddiviso in due ulteriori momenti. Durante il primo avviene la chiamata alla classe che si occupa dell’avvio del sistema di theming di Magento 2 all’interno del controller tramite l’inizializzazione dell’istanza di resultPageFactory.

Per questo motivo occorre iniettare nel costruttore del nostro file controller <base_dir>/app/code/WaPoNe/HelloWorld/Controller/Index/Index.php il factory method PageFactory:

<?php
namespace WaPoNe\HelloWorld\Controller\Index;

class Index extends \Magento\Framework\App\Action\Action
{
    /** @var \Magento\Framework\View\Result\PageFactory */
    protected $_resultPageFactory;

    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    )
    {
        $this->_resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }

    public function execute()
    {
        echo "Hello World!";

        $resultPage = $this->_resultPageFactory->create();
        return $resultPage;
    }
}

Per il secondo passaggio l’attività da compiere è un po’ più complessa e consiste nella generazione dei file di layout e di template, oltre al blocco, che, come in Magento 1, sono i componenti della parte ‘view’ di Magento 2.

Cominciamo con la dichiarazione del file helloworld_index_index.xml da inserire nella cartella <base_dir>/app/code/WaPoNe/HelloWorld/view/frontend/layout/

Ed ecco un’altra delle più importanti migliorie introdotte con la nuova versione della piattaforma. Tutto lo sviluppo del modulo è contenuto all’interno di un’unica e sola directory.

Notiamo quindi l’introduzione della cartella view/ che sostituisce, per l’implementazione di un plugin, quello che era lo scopo della dir design/ in M1. E’ nella dir view/ quindi che vengono posti tutti i file relativi alla parte “visiva” dell’estensione. All’interno di questa cartella ci sono le sotto cartelle (a seconda delle necessità) frontend/, adminhtml/ e base/ che a loro volta possono contenere, tra le altre, le cartelle layout/, templates/ e web/.

Vediamo nel dettaglio la nomenclatura utilizzata per il file di layout analizzando nuovamente come è stato dichiarato il file di routing (<base_dir>/app/code/WaPoNe/HelloWorld/etc/frontend/routes.xml) nell’articolo precedente:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="helloworld" frontName="helloworld">
            <module name="WaPoNe_HelloWorld" />
        </route>
    </router>
</config>

E’ proprio l’id di route a definire la prima parte del nome del file (“helloworld”), successivamente viene preso il nome del controller (“index”), ed infine il nome della action (“index”): helloworld_index_index.xml

Mi permetto di consigliarvi, come esercizio, di provare a cambiare nome del file di layout, il valore degli attributi id e frontName di route e abilitare/disabilitare la chiamata dell’istanza di resultPageFactory per capire meglio lo scopo di ognuno di loro.

Ma torniamo al file di layout (<base_dir>/app/code/WaPoNe/HelloWorld/view/frontend/layout/helloworld_index_index.xml) che ha questo formato:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>Helloworld Landing</title>
    </head>
    <body>
        <referenceContainer name="content">
              <block class="WaPoNe\HelloWorld\Block\Landingpage"
                     name="landingblock"
                     template="WaPoNe_HelloWorld::landingpage.phtml" />
       </referenceContainer>
   </body>
</page>

L’obiettivo di questo file non si discosta da quello assegnatogli già in Magento 1: costruire lo schema dalla pagina html finale. Nell’esempio mostrato si definisce il layout della pagina (layout=”1column”), le si assegna un titolo nella head (<title>Helloworld Landing</title>) e infine si definisce un ‘blocco’ con il suo template per il riempimento della parte centrale (<referenceContainer name=”content”>) della pagina stessa.

Occupiamoci quindi dell’implementazione del blocco e del template.

Creiamo il file <base_dir>/app/code/WaPoNe/HelloWorld/Block/Landingpage.php

<?php
namespace WaPoNe\HelloWorld\Block;

class Landingpage extends \Magento\Framework\View\Element\Template
{
}

ed il file <base_dir>/app/code/WaPoNe/HelloWorld/view/frontend/templates/landingpage.phtml per ora completamente vuoto.

Puliamo la cache (dalla dir del nostro progetto php bin/magento cache:clean come visto negli scorsi articoli) e ricarichiamo la nostra pagina web: http://nomesito.estensione/helloworld/index/index o più semplicemente http://nomesito.estensione/helloworld

hello_world_errato

Bene. Siamo giunti al passaggio conclusivo.

Come M1 anche M2 adotta il design pattern MVC (Model-View-Controller) e, quindi, la parte che si occupa di ‘View’, come spiegato, resta sempre l’insieme di layout, blocchi e template.

Per questo motivo, spostiamo dal controller l’istruzione

echo “Hello World!”

nel posto corretto, nel template (<base_dir>/app/code/WaPoNe/HelloWorld/view/frontend/templates/landingpage.phtml):

<?php
echo "Hello World!";

Nuovamente, pulizia della cache e reloading della pagina web. Finalmente il risultato prefissato all’inizio:

hello_world_corretto

Evviva! Siamo riusciti nel nostro intento iniziale.

Vediamo ora un esempio più complesso. Supponiamo di voler pubblicare gli ultimi cinque prodotti caricati sul nostro store al posto della semplice scritta “Hello World!”.

Avvalendoci dei file giù usati in precedenza, modifichiamo il file del blocco, Landingpage.php:

<?php
namespace WaPoNe\HelloWorld\Block;

class Landingpage extends \Magento\Framework\View\Element\Template
{
   private $_productCollectionFactory;

   public function __construct
   (
       \Magento\Framework\View\Element\Template\Context $context,
       \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
       array $data
   )
   {
       parent::__construct($context, $data);

       $this->_productCollectionFactory = $productCollectionFactory;
   }

   public function getProducts()
   {
       $collection = $this->_productCollectionFactory->create();

       $collection
            ->addAttributeToSelect('*')
            ->setOrder('created_at')
            ->setPageSize(5);

       return $collection;
    }
}

Anche in questo caso, grazie alla tecnica del Dependency Injection (DI) riusciamo ad “iniettare” la collection dei prodotti, dalla quale filtriamo gli attributi da estrarre (addAttributeToSelect()), impostiamo l’ordinamento (setOrder()) e limitiamo il numero di righe estrapolate (setPageSize()).

Il metodo public getProducts() restituisce la collection dei prodotti estratti che verranno stampati nel template landingpage.phtml, così modificato:

<h2>New Products</h2>

<ul>
    <?php foreach ($block->getProducts() as $product): ?>
        <li><?php echo $product->getName() ?></li>
    <?php endforeach; ?>
</ul>

L’unica nota da evidenziare in questo pezzo di codice è la differente modalità di chiamata al metodo getProducts() (e a tutte le altre eventuali proprietà) del blocco; se in Magento 1 viene utilizzata la parola riservata $this in Magento 2 è stata sostituita con $block.

Il risultato finale del nostro plugin:

new_products

Conclusioni

Con questa mini serie di articoli  abbiamo imparato le basi per lo sviluppo delle estensioni in Magento 2, mettendo in evidenza le differenze o le tecniche rimaste intatte con il suo predecessore e sottolineando le migliorie apportate che possiamo riassumere:

  • tutti i componenti di un modulo sono racchiusi in un’unica cartella nel file system;
  • etc/config.xml scompattato in più file xml di configurazione (module.xml, routes.xml ecc.), ognuno con uno scopo ben preciso;
  • un file per ogni action evitando file ‘pesanti’ e complessi, pieni di funzionalità;
  • eliminazione dei ‘code pool’;
  • utilizzo di XML Style Definition (XSD) all’interno dei file xml;
  • lo script bin/magento;
  • sostituzione della cartella controllers/ con Controller/

Insomma, la nuova piattaforma porta con sé tante nuove tecnologie e differenti scelte implementative che migliorano lo sviluppo e che, per forza di cose, rendo la curva di apprendimento ancora più ripida di M1 ma i benefici che ne derivano nell’ immediato futuro giustificano gli sforzi e rendo l’intera fase di sviluppo più semplice.

Ti è piaciuto questo articolo? Votalo!

Torna in alto