Magento 5 avril 2024 15 min de lecture

Comment créer un module Magento 2 : Guide complet avec exemples

Gabriel Janez

Gabriel Janez

Développeur Full-Stack PHP

Créer un module Magento 2 peut sembler complexe au premier abord, mais en suivant une méthodologie structurée, vous verrez que c'est accessible. Dans ce guide complet, je vous accompagne étape par étape dans la création d'un module fonctionnel.

1. Structure de base d'un module

Tout module Magento 2 doit respecter une structure de fichiers précise. Voici l'arborescence minimale :

app/code/Vendor/ModuleName/
├── etc/
│   └── module.xml
├── registration.php
└── composer.json (optionnel mais recommandé)

Remplacez Vendor par votre nom d'entreprise et ModuleName par le nom de votre module.

2. Fichiers obligatoires

registration.php

Ce fichier enregistre votre module auprès de Magento :

<?php
/**
 * @category  Vendor
 * @package   Vendor_ModuleName
 */

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Vendor_ModuleName',
    __DIR__
);

etc/module.xml

Ce fichier déclare le module et ses dépendances :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_ModuleName" setup_version="1.0.0">
        <sequence>
            <!-- Dépendances (modules qui doivent être chargés avant) -->
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

3. Créer un Controller

Les controllers gèrent les requêtes HTTP. Voici comment créer une page frontend accessible via /modulename/index/index :

etc/frontend/routes.xml

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

Controller/Index/Index.php

<?php
declare(strict_types=1);

namespace Vendor\ModuleName\Controller\Index;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\View\Result\Page;

class Index implements HttpGetActionInterface
{
    /**
     * @var PageFactory
     */
    private PageFactory $pageFactory;

    /**
     * @param PageFactory $pageFactory
     */
    public function __construct(PageFactory $pageFactory)
    {
        $this->pageFactory = $pageFactory;
    }

    /**
     * Execute action
     *
     * @return Page
     */
    public function execute(): Page
    {
        $page = $this->pageFactory->create();
        $page->getConfig()->getTitle()->set(__('Ma Page Custom'));

        return $page;
    }
}

4. Injection de dépendances (DI)

Magento 2 utilise l'injection de dépendances via le constructeur. Le fichier etc/di.xml permet de configurer les dépendances :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <!-- Préférence : remplacer une interface par une implémentation -->
    <preference for="Vendor\ModuleName\Api\ServiceInterface"
                type="Vendor\ModuleName\Model\Service"/>

    <!-- Type : configurer les arguments d'un constructeur -->
    <type name="Vendor\ModuleName\Model\MyClass">
        <arguments>
            <argument name="config" xsi:type="array">
                <item name="key" xsi:type="string">value</item>
            </argument>
        </arguments>
    </type>

</config>

5. Créer un Model avec ResourceModel

Pour stocker des données en base, vous avez besoin de trois classes :

Model/Item.php (Model)

<?php
declare(strict_types=1);

namespace Vendor\ModuleName\Model;

use Magento\Framework\Model\AbstractModel;
use Vendor\ModuleName\Model\ResourceModel\Item as ResourceModel;

class Item extends AbstractModel
{
    /**
     * @var string
     */
    protected $_eventPrefix = 'vendor_modulename_item';

    /**
     * Initialize resource model
     *
     * @return void
     */
    protected function _construct(): void
    {
        $this->_init(ResourceModel::class);
    }
}

Model/ResourceModel/Item.php (ResourceModel)

<?php
declare(strict_types=1);

namespace Vendor\ModuleName\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Item extends AbstractDb
{
    /**
     * @var string
     */
    protected $_eventPrefix = 'vendor_modulename_item_resource';

    /**
     * Initialize resource model
     *
     * @return void
     */
    protected function _construct(): void
    {
        $this->_init('vendor_modulename_item', 'entity_id');
    }
}

Model/ResourceModel/Item/Collection.php (Collection)

<?php
declare(strict_types=1);

namespace Vendor\ModuleName\Model\ResourceModel\Item;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Vendor\ModuleName\Model\Item as Model;
use Vendor\ModuleName\Model\ResourceModel\Item as ResourceModel;

class Collection extends AbstractCollection
{
    /**
     * @var string
     */
    protected $_eventPrefix = 'vendor_modulename_item_collection';

    /**
     * Initialize collection
     *
     * @return void
     */
    protected function _construct(): void
    {
        $this->_init(Model::class, ResourceModel::class);
    }
}

6. Script d'installation de la base de données

Créez la table via un script de schema :

etc/db_schema.xml

<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">

    <table name="vendor_modulename_item" resource="default" engine="innodb"
           comment="Module Items Table">

        <column xsi:type="int" name="entity_id" unsigned="true" nullable="false"
                identity="true" comment="Entity ID"/>

        <column xsi:type="varchar" name="name" nullable="false" length="255"
                comment="Item Name"/>

        <column xsi:type="text" name="description" nullable="true"
                comment="Description"/>

        <column xsi:type="smallint" name="is_active" unsigned="true"
                nullable="false" default="1" comment="Is Active"/>

        <column xsi:type="timestamp" name="created_at" nullable="false"
                default="CURRENT_TIMESTAMP" comment="Created At"/>

        <column xsi:type="timestamp" name="updated_at" nullable="false"
                default="CURRENT_TIMESTAMP" on_update="true" comment="Updated At"/>

        <constraint xsi:type="primary" referenceId="PRIMARY">
            <column name="entity_id"/>
        </constraint>

    </table>

</schema>

7. Créer un Block et un Template

Block/ItemList.php

<?php
declare(strict_types=1);

namespace Vendor\ModuleName\Block;

use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Vendor\ModuleName\Model\ResourceModel\Item\CollectionFactory;

class ItemList extends Template
{
    /**
     * @var CollectionFactory
     */
    private CollectionFactory $collectionFactory;

    /**
     * @param Context $context
     * @param CollectionFactory $collectionFactory
     * @param array $data
     */
    public function __construct(
        Context $context,
        CollectionFactory $collectionFactory,
        array $data = []
    ) {
        parent::__construct($context, $data);
        $this->collectionFactory = $collectionFactory;
    }

    /**
     * Get active items
     *
     * @return \Vendor\ModuleName\Model\ResourceModel\Item\Collection
     */
    public function getItems()
    {
        return $this->collectionFactory->create()
            ->addFieldToFilter('is_active', 1);
    }
}

view/frontend/layout/modulename_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">

    <body>
        <referenceContainer name="content">
            <block class="Vendor\ModuleName\Block\ItemList"
                   name="modulename.item.list"
                   template="Vendor_ModuleName::item/list.phtml"/>
        </referenceContainer>
    </body>

</page>

view/frontend/templates/item/list.phtml

<?php
/**
 * @var \Vendor\ModuleName\Block\ItemList $block
 */
$items = $block->getItems();
?>

<div class="modulename-items">
    <?php if ($items->getSize()): ?>
        <ul class="items-list">
            <?php foreach ($items as $item): ?>
                <li class="item">
                    <h3><?= $block->escapeHtml($item->getName()) ?></h3>
                    <p><?= $block->escapeHtml($item->getDescription()) ?></p>
                </li>
            <?php endforeach; ?>
        </ul>
    <?php else: ?>
        <p><?= __('No items found.') ?></p>
    <?php endif; ?>
</div>

8. Activer et tester le module

Une fois tous les fichiers créés, activez le module :

# Activer le module
bin/magento module:enable Vendor_ModuleName

# Mettre à jour la base de données
bin/magento setup:upgrade

# Compiler le code (mode production)
bin/magento setup:di:compile

# Nettoyer le cache
bin/magento cache:clean

9. Structure complète du module

Voici l'arborescence finale de notre module :

app/code/Vendor/ModuleName/
├── Block/
│   └── ItemList.php
├── Controller/
│   └── Index/
│       └── Index.php
├── etc/
│   ├── db_schema.xml
│   ├── di.xml
│   ├── module.xml
│   └── frontend/
│       └── routes.xml
├── Model/
│   ├── Item.php
│   └── ResourceModel/
│       ├── Item.php
│       └── Item/
│           └── Collection.php
├── view/
│   └── frontend/
│       ├── layout/
│       │   └── modulename_index_index.xml
│       └── templates/
│           └── item/
│               └── list.phtml
├── composer.json
└── registration.php

Conclusion

Vous avez maintenant les bases pour créer un module Magento 2 complet. Les points clés à retenir :

  • Respectez toujours la structure de fichiers imposée par Magento
  • Utilisez l'injection de dépendances via le constructeur
  • Préférez les interfaces aux classes concrètes
  • Utilisez db_schema.xml pour les modifications de base de données
  • N'oubliez pas de vider le cache après chaque modification

Pour aller plus loin, explorez les concepts avancés comme les Plugins, les Observers, les API REST et GraphQL. N'hésitez pas à me contacter pour un accompagnement sur vos projets Magento 2 !

Tags

E-commerce Magento 2 Module PHP Tutoriel

Partager

Articles similaires

Besoin d'aide sur votre projet ?

Discutons de vos besoins et trouvons ensemble la meilleure solution technique.

Me contacter