Béjean Développement

Utiliser la classe DataPatchInterface dans un module

Objectif

Mettre en place un module utilisant la classe DataPatchInterface

Introduction

Magento propose 2 classes permettant de définir des actions qui seront réalisées, une seule fois, lors de l'exécution de la commande bin/magento setup:upgrade. Les 2 classes qui nous intéressent sont \Magento\Framework\Setup\Patch\DataPatchInterface et \Magento\Framework\Setup\Patch\SchemaPatchInterface.

Tutoriel

Le projet Git de cet article est disponible sur Froggit, lien vers le dépôt.

Fonctionnement du patch

Le Data Patch, ou patch de données, ne sera appliqué qu'une seule fois. Une fois la commande bin/magento setup:upgrade exécutée, le patch sera ajouté à la liste des patchs appliqués par Magento. Cette liste est disponible dans la table patch_list.

Pour être appliqué, le patch doit avoir une version supérieure à celle spécifiée dans le fichier etc/module.xml. Pour notre exemple, le module aura la version 1.0.0 et le patch aura la version 1.0.1.

Création du patch

Le patch doit être créé dans le fichier Setup\Patch\Data. Le fichier peut comporter le nom que l'on souhaite. Pour le tutoriel, nous allons créer des pages CMS, nous allons nommer le patch CreateCmsPage. Voici le contenu du fichier :

<?php

namespace BejeanDeveloppement\SetupDataPatch\Setup\Patch\Data;

use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchVersionInterface;

/**
 * Class CreateCmsPage
 *
 * @package BejeanDeveloppement\SetupDataPatch\Setup\Patch\Data
 */
class CreateCmsPage implements DataPatchInterface, PatchVersionInterface
{
    /**
     * CreateCmsPage constructor.
     */
    public function __construct() {

    }

    /**
     * @return void
     */
    public function apply()
    {

    }

    /**
     * @return array
     */
    public static function getDependencies(): array
    {
        return [];
    }

    /**
     * @return array
     */
    public function getAliases(): array
    {
        return [];
    }

    /**
     * @return string
     */
    public static function getVersion(): string
    {
        return '1.0.1';
    }
}

Le patch implémente 2 interfaces Magento\Framework\Setup\Patch\DataPatchInterface et Magento\Framework\Setup\Patch\PatchVersionInterface.

La première interface étend une autre interface Magento\Framework\Setup\Patch\PatchInterface qui permet de gérer l'application et les alias du patch. Cette interface étend une dernière interface Magento\Framework\Setup\Patch\DependentPatchInterface qui permet de gérer les dépendances.

La seconde interface permet de gérer la version du patch. Comme indiqué ci-dessus, le patch aura la version 1.0.1.

A ce moment, le patch est prêt à être appliqué. Si la commande bin/magento setup:upgrade est exécutée, le patch sera appliqué et ajouté à la table patch_list.

Création d'une nouvelle page

Pour créer une nouvelle page, nous allons injecter 2 nouvelles classes : Magento\Cms\Api\Data\PageInterfaceFactory et Magento\Cms\Api\PageRepositoryInterface. La première classe permettra la création de la nouvelle page et la seconde réalisera l'enregistrement en base de données.

La création de la page se réalisée dans la méthode apply, de cette manière :

    /**
     * @return void
     * @throws LocalizedException
     */
    public function apply()
    {
        $pageData = array(
            'identifier' => 'ma-page',
            'title' => 'Mon titre',
            'content' => 'Mon Contenu',
            'is_active' => 1,
            'stores' => array(0),
            'page_layout' => '1column'
        );

        $page = $this->pageInterfaceFactory->create()
            ->setData($pageData);

        $this->pageRepository->save($page);
    }

La première étape consiste à créer un tableau qui sera injecté, via la méthode setData dans l'objet $page. La seconde est dernière étape enregistre, dans la base de données, l'objet, via la classe PageRepository.

Pensez à supprimer le patch dans la table patch_list si vous avez exécuté la commande setup:upgrade précédemment.

Lancez la commande bin/magento setup:upgrade puis vérifier, dans la base de données, la présence d'une nouvelle page dans les tables cms_page, cms_page_store et url_rewrite. Le patch doit également être présent dans la table patch_list.

Suppression de la page

Pour supprimer la page, nous allons utiliser la commande bin/magento module:uninstall --non-composer BejeanDeveloppement_SetupDataPatch. Cette dernière permet de désinstaller un module, l'argument --non-composer permet de supprimer un module qui a été installé dans le dossier app/code et dont qui n'a pas été installé par Composer.

La commande n'est pas magique, pour supprimer la page, il est nécessaire d'implémenter l'interface Magento\Framework\Setup\Patch\PatchRevertableInterface qui permet d'utiliser la méthode revert au sein du patch.

Une fois l'interface implémentée, il est nécessaire d'injecter 2 nouvelles classes au patch Magento\Framework\Api\SearchCriteriaInterface et Magento\Framework\Api\Search\FilterGroup qui permettront de rechercher la page à supprimer.

Au sein de la méthode revert, il faut créer la variable $searchCriteria qui sera un objet SearchCriteria qui comportera un ou plusieurs objets FilterGroup. La variable $searchCriteria sera passé en paramètre à la méthode getList de l'objet $this->pageRepository. Ce dernier retournera un tableau d'objets qui sera assigné à la variable $items.

Cette dernière sera parcourue par une boucle foreach qui contrôlera que l'identifiant de la page à supprimer correspond à ma-page. Puis la suppression sera réalisée par la méthode delete de l'objet $this->pageRepository.

Voici le contenu de la méthode revert :

    /**
     * @throws LocalizedException
     */
    public function revert()
    {
        $searchCriteria = $this->searchCriteria->setFilterGroups(
            array(
                $this->filterGroups->setData('identifier', 'ma-page')
            )
        );

        $items = $this->pageRepository->getList($searchCriteria)->getItems();

        foreach ($items as $page) {
            if ($page->getIdentifier() === 'ma-page') {
                $this->pageRepository->delete($page);
            }
        }
    }

En lançant la commande bin/magento module:uninstall --non-composer BejeanDeveloppement_SetupDataPatch pour supprimer la page et le module.

Pour supprimer complètement le module il est nécessaire de supprimer les fichiers sources situés dans le dossier app/code.