Développer un module pour Magento 2 : première approche

  • De le 23 août 2012
  • Difficulté : 2/4

Développer un module pour Magento 2 : première approche Magento 2 est annoncé pour fin 2012 / début 2013. Mis à disposition sur Git, il est déjà possible de se familiariser avec la nouvelle structure. Afin d'anticiper la sortie de la première version stable, voici un petit aperçu de ce qui devrait changer dans nos habitudes de développement.

Introduction

Dans quelques mois Magento 2 sera disponible. Et la liste des nouveautés apportées par cette nouvelle version est longue (voir le très bon article de la e-commerce Academy : Magento 2 : ce qui va changer !).

Magento 2 demandera aux développeurs quelques adaptations, et la bonne nouvelle c'est qu'il sera bien plus rapide de développer un module sur la version 2 !

Par anticipation et pour commencer à se familiariser avec cette futur version, rien de mieux que de développer un module complet. J'ai choisi de développer un module pour l'ajout d'un nouveau formulaire. Pas beaucoup de mérite, il ressemble comme 2 goûtes d'eau au module contacts de base, mais cela constitue une première approche avec la nouvelle façon de concevoir une extension.

Parallèlement à la lecture de cet article je vous invite à télécharger le module de test sur lequel je me suis basé pour rédiger l'article : Module Magento 2

Notez que cet article est rédigé à partir d'une version de développement, récupérée depuis Git le 23 août 2012. Il est possible que certains points abordés soient amenés à changer ou évoluer.

Organisation des dossiers et fichiers

Première révolution, la totalité des fichiers que composent un module sont regroupés au sein d'un même dossier. Il n'est plus nécessaire de voyager entre les dossiers code, design, locale et skin pour développer.

Pour notre module, voici un petit comparatif entre l'ancienne organisation et celle proposée par Magento 2.

Magento 1.X Magento 2
  • app
  • code
  • community
  • Magentix
  • Callback
  • controllers
  • IndexController.php
  • Helper
  • Data.php
  • etc
  • adminhtml.xml
  • config.xml
  • system.xml
  • etc
  • modules
  • Magentix_Callback.xml
  • design
  • frontend
  • base
  • default
  • layout
  • callback.xml
  • template
  • callback
  • form.phtml
  • locale
  • fr_FR
  • Magentix_Callback.csv
  • template
  • email
  • callback_form.html
  • en_US
  • Magentix_Callback.csv
  • template
  • email
  • callback_form.html
  • skin
  • frontend
  • base
  • default
  • css
  • callback.css
  • app
  • code
  • community
  • Magentix
  • Callback
  • controllers
  • IndexController.php
  • Helper
  • Data.php
  • etc
  • config.xml
  • system.xml
  • adminhtml
  • acl.xml
  • locale
  • en_US
  • Magentix_Callback.csv
  • fr_FR
  • Magentix_Callback.csv
  • view
  • email
  • callback_form.html
  • frontend
  • form.phtml
  • layout.xml
  • css
  • callback.css

Plus de perte de temps à naviguer dans l'arborescence, maintenance du module aisée et beaucoup plus simple de packager les extensions !

Fichier de configuration

Le fichier de configuration du module (config.xml) est quasiment identique à celui que nous connaissons. Quelques différences tout de même.

Si vous regardez l'arborescence des fichiers ci-dessus, vous constatez la disparition du ficher d'activation du module, placé auparavant dans le dossier app/etc/modules. L'activation s'opère désormais directement dans le fichier de configuration :

app/code/community/Magentix/Callback/etc/config.xml

<config>
    <modules>
        <Magentix_Callback>
            <version>0.1.0</version>
            <active>true</active>
            <codePool>community</codePool>
            <depends>
                <Mage_Core/>
                <Mage_Customer/>
            </depends>
        </Magentix_Callback>
    </modules>
</config>

Petite parenthèse sur le noeud codePool. Celui-ci indique toujours l'origine du module (core, community ou local), mais une petite erreur que j'ai commise m'a permis de découvrir un nouveau système de cache utilisé pour les fichiers du thème et du template. J'ai placé mon module dans le pool community mais en oubliant de modifier la valeur du noeud codePool suite à un copier/coller.

Malgré la rectification de la valeur et une réinitialisation du cache, Magento cherchait désespérément à charger le fichier layout.xml de mon module dans le mauvais dossier (core et non community).

Mon enquête m'a conduit au dossier var/maps/fallback, dans lequel j'ai découvert de nouveaux fichiers de cache spécifiques aux thèmes, par exemple frontend_default_default_default_fr_FR.ser.

Ce système de cache évite l'analyse systématique des layouts et détermine l'ensemble des fichiers du thème et du template à charger. Une simple suppression des fichiers du répertoire a permis de rectifier mon erreur.

2ème grande nouveauté, il n'est plus nécessaire de déclarer les alias pour les blocks, models et helpers. Concrètement, nous avions l'habitude d'indiquer dans le fichier de configuration :

app/code/community/Magentix/Callback/etc/config.xml

<!-- Magento 1.X -->
<config>
    <global>
        <models>
            <callback>
                <class>Magentix_Callback_Model</class>
            </callback>
        </models>
        <helpers>
            <callback>
                <class>Magentix_Callback_Helper</class>
            </callback>
        </helpers>
        <blocks>
            <callback>
                <class>Magentix_Callback_Block</class>
            </callback>
        </blocks>
    </global>
</config>

Nous pouvions ainsi instancier nos classes de la façon suivante :

Factory Methods

/* Magento 1.X */
$model = Mage::getModel('callback/mymodel');
$block = Mage::getModel('callback/myblock');
$helper = Mage::helper('callback/myhelper');

Il nous faut maintenant indiquer le nom complet de la classe :

Factory Methods

/* Magento 2 */
$model = Mage::getModel('Magentix_Callback_Model_Mymodel');
$block = Mage::getModel('Magentix_Callback_Block_Myblock');
$helper = Mage::helper('Magentix_Callback_Helper_Myhelper');

L'abandon des alias permet une simplification du système de surcharges (d'après l'analyse rapide que j'ai pu faire). Et certainement un gain de temps non négligeable dans les traitements.

Edit : la nouvelle instanciation des classes permet également les tests unitaires sur l'ensemble du code (merci à Christophe).

Surcharges

Directement lié à l'abandon des alias, déclarer le rewrite d'une classe devient plus facile :

app/code/community/Magentix/Callback/etc/config.xml

<config>
    <!-- ... -->
    <global>
        <!-- Magento 1.X -->
        <!-- 
        <blocks>
            <cms>
                <rewrite>
                    <page>Magentix_Callback_Block_Page</page>
                </rewrite>
            </cms>
        </blocks>
         -->

        <!-- Magento 2 -->
        <rewrites>
            <Mage_Cms_Block_Page>Magentix_Callback_Block_Page</Mage_Cms_Block_Page>
            <Mage_Cms_Model_Page>Magentix_Callback_Model_Page</Mage_Cms_Model_Page>
            <Mage_Cms_Helper_Page>Magentix_Callback_Helper_Page</Mage_Cms_Helper_Page>
        </rewrites>
    </global>
    <!-- ... -->
</config>

Petit test pour vérifier :

test.phtml

echo get_class(Mage::helper('Mage_Cms_Helper_Page'));

// Magentix_Callback_Helper_Page

Access Control Lists permissions

La déclaration des acl est déportée dans le fichier adminhtml/acl.xml. La syntaxe est beaucoup plus lisible qu'elle ne l'était auparavant : disparition du noeud children et les ressources sont désignées par un identifiant :

app/code/community/Magentix/Callback/etc/adminhtml/acl.xml

<config>
    <acl>
        <resources>
            <resource id="Mage_Adminhtml::admin">
                <resource id="Mage_Adminhtml::system">
                    <resource id="Mage_Adminhtml::config">
                        <resource id="Magentix_Callback::callback" module="Magentix_Callback" title="Callback" />
                    </resource>
                </resource>
            </resource>
        </resources>
    </acl>
</config>

Pour les ressources accessibles depuis le menu système > configuration, il est nécessaire de préciser l'identifiant dans le fichier system.xml :

app/code/community/Magentix/Callback/etc/system.xml

<config>
    <sections>
        <callback translate="label" module="Magentix_Callback">
            <label>Callback</label>
            <tab>general</tab>
            <frontend_type>text</frontend_type>
            <sort_order>100</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <!-- Identifiant de la ressource -->
            <resource>Magentix_Callback::callback</resource>
            <!-- ... -->
        </callback>
    </sections>
</config>

Pour les menus principaux, un nouveau fichier nommé menu.xml est placé dans le dossier etc/adminhtml :

app/code/community/Mage/Catalog/etc/adminhtml/menu.xml

<config>
    <menu>
        <add id="Mage_Catalog::catalog" title="Catalog"
             module="Mage_Catalog" sortOrder="30"
             dependsOnModule="Mage_Catalog" resource="Mage_Catalog::catalog"
        />
    </menu>
</config>

Ajouter un menu et gérer les acl devient plus simple et beaucoup plus lisible.

Layouts

L'abandon des alias nous oblige à indiquer le nom complet de la classe pour le type de bloc. Il faudra également préciser depuis quel module les fichiers du thème sont accessibles (Js, CSS et phtml). Magento ira automatiquement chercher ces fichiers dans le dossier view de l'extension. Pour le reste, rien de très différent de ce que nous connaissions :

app/code/community/Magentix/Callback/view/frontend/layout.xml

<layout version="0.1.0">
    <callback_index_index translate="label" type="page" parent="cms_page_view">
        <label>Callback Form</label>
        <reference name="head">
            <action method="setTitle" translate="title" module="Magentix_Callback"><title>Instant call back</title></action>
            <action method="addCss"><file>Magentix_Callback::css/callback.css</file></action>
        </reference>
        <reference name="root">
            <action method="setTemplate"><template>2columns-right.phtml</template></action>
            <action method="setHeaderTitle" translate="title" module="Magentix_Callback"><title>Instant call back</title></action>
        </reference>
        <reference name="content">
            <block type="Mage_Core_Block_Template" name="callbackForm" template="Magentix_Callback::form.phtml"/>
        </reference>
    </callback_index_index>
</layout>

Notez que les fichiers CSS et Javascript des modules sont copiés dans un autre répertoire :

  • app/code/community/Magentix/Callback/view/frontend/css/callback.css
  • pub/media/skin/frontend/default/default/default/fr_FR/Magentix_Callback/css/callback.css

Dans l'en-tête de la page nous trouvons donc :

Page

<link rel="stylesheet"
      type="text/css"
      media="all"
      href="http://www.domaine.com/pub/media/skin/frontend/default/default/default/fr_FR/Magentix_Callback/css/callback.css"
/>

Conclusion

Ce petit aperçu du développement d'un module simple avec Magento 2 montre qu'il sera beaucoup plus rapide de réaliser une extension. Il s'agit évidemment d'une première approche, reste de nombreux points que je n'ai pas abordé dans cet article mais dont je parlerai au fur à mesure de mes développements. L'objectif est de réaliser une transition en douceur ;)

commentaires

Commentez cet article : Développer un module pour Magento 2 : première approche