Qu'est-ce qu'un view model ?

Les view models sont des classes qui permettent d'éviter d'avoir à récupérer toute la DI du parent d'un block lorsque l'on veut ajouter une dépendance à une classe.

Imagineons par exemple que nous ayons un block qui étende Magento\Catalog\Block\Product\ProductList\Toolbar, si nous vous ajouter une dépendance à notre block, nous allons devoir reprendre tous les paramètres de la méthode __construct :

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\Catalog\Model\Session $catalogSession,
    \Magento\Catalog\Model\Config $catalogConfig,
    ToolbarModel $toolbarModel,
    \Magento\Framework\Url\EncoderInterface $urlEncoder,
    ProductList $productListHelper,
    \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
    array $data = [],
    ToolbarMemorizer $toolbarMemorizer = null,
    Context $httpContext = null,
    FormKey $formKey = null
) {
    $this->_catalogSession = $catalogSession;
    $this->_catalogConfig = $catalogConfig;
    $this->_toolbarModel = $toolbarModel;
    $this->urlEncoder = $urlEncoder;
    $this->_productListHelper = $productListHelper;
    $this->_postDataHelper = $postDataHelper;
    $this->toolbarMemorizer = $toolbarMemorizer ?: ObjectManager::getInstance()->get(
        ToolbarMemorizer::class
    );
    $this->httpContext = $httpContext ?: ObjectManager::getInstance()->get(
        Context::class
    );
    $this->formKey = $formKey ?: ObjectManager::getInstance()->get(
        FormKey::class
    );
    parent::__construct($context, $data);
}

Cela va compliquer notre block "pour rien". Nous pouvons donc ici ajouter un view model, qui sera une classe à part :

<referenceBlock name="mon.block">
    <arguments>
        <argument name="view_model" xsi:type="object">Vendor\Module\ViewModel\Monviewmodel</argument>
    </arguments>
</referenceBlock>

La classe du view model sera disponible via $block->getViewModel(). Nous pourrons donc ajouter une méthode à notre view model et faire en sorte qu'un template existant l'appelle sans avoir à surcharger le block parent.

Par exemple dans le template, nous pourrions faire :

<?php echo $block->getViewModel()->getHelloText() ?>

Et dans le view model :

<?php
namespace Vendor\Module\ViewModel;

class Monviewmodel implements \Magento\Framework\View\Element\Block\ArgumentInterface
{
    public function getHelloText()
    {
        // ...
    }
}

TP - Utiliser un view model pour ajouter une donnée au formulaire de contact