Étiquette : namespace

[Magento 2] Surcharger un Block ou un Model natif

Testé fonctionnel Magento 2.3

Sources: www.magestore.com – Overriding Block, Model In Magento 2 – Magento 2.3, Surcharger une classe native magento2 (Model, Block, Helper, Action…).

(si ce n’est pas fait) Créer un nouveau Module

En ligne de commande:

…puis:

Surcharger un Block natif dans Magento 2

Convention: dans l’exemple ci-dessous, nous surchargeons le Block Magento\Catalog\Block\Product\ListProduct.php.

Créer le fichier di.xml dans app/code/[Name_Space]/[Your_Module]/etc:

Dans le fichier ci-dessus:

  • l’attribut for de la balise preference déclare le namespace + \ + le nom de la classe du Block initial avec, en dernier, le libellé du fichier sans l’extension *.php. Dans notre exemple, le chemin vers le fichier natif est vendor/magento/module-catalog/Block/Product/ListProduct.php.
  • l’attribut type de la balise preference déclare le chemin, à partir de la racine de votre projet et sans les deux premiers dossiers app/code/, vers le Block qui surcharge avec, en dernier, le libellé du fichier sans l’extension *.php

Créer le fichier Block ListProduct.php dans app/code/[Name_Space]/[Your_Module]/Block/Rewrite/Product:

Dans le fichier ci-dessus:

  • le namespace déclare le chemin vers le Block qui surcharge, cette fois-ci sans le nom du fichier. Ici, on peut reprendre une partie de la valeur déclarée pour l’attribut type de la balise preference du fichier di.xml (sans le nom du fichier à la fin, donc…)
  • le libellé de la class déclarée reprend celui du fichier qui surcharge (le libellé du fichier qu’on est justement en-train de créer ou d’éditer) sans l’extension *.php
  • le chemin déclaré après extends est celui vers le Block initial avec, en dernier, le libellé du fichier sans l’extension *.php. Ici, on peut reprendre l’intégralité de la valeur déclarée pour l’attribut for de la balise preference du fichier di.xml, mais ATTENTION: il faut impérativement rajouter un anti-slash \ devant ce dernier!

Commandes Magerun à exécuter impérativement:

A la création de votre module (la première fois):

Puis à chaque modification dans le fichier di.xml:

Surcharger un Model natif dans Magento 2

Convention: dans l’exemple ci-dessous, nous surchargeons le Model Magento\Catalog\Model\Product.php.

Créer le fichier di.xml dans app/code/[Name_Space]/[Your_Module]/etc:

Dans le fichier ci-dessus:

  • l’attribut for de la balise preference déclare le namespace + \ + le nom de la classe du Model initial avec, en dernier, le libellé du fichier sans l’extension *.php. Dans notre exemple, le chemin vers le fichier natif est vendor/magento/module-catalog/Model/Product.php.
  • l’attribut type de la balise preference déclare le chemin, à partir de la racine de votre projet et sans les deux premiers dossiers app/code/, vers le Model qui surcharge avec, en dernier, le libellé du fichier sans l’extension *.php

Créer le fichier Model Product.php dans app/code/[Name_Space]/[Your_Module]/Model/Rewrite/Catalog:

Dans le fichier ci-dessus:

  • le namespace déclare le chemin vers le Model qui surcharge, cette fois-ci sans le nom du fichier. Ici, on peut reprendre une partie de la valeur déclarée pour l’attribut type de la balise preference du fichier di.xml (sans le nom du fichier à la fin, donc…)
  • le libellé de la class déclarée reprend celui du fichier qui surcharge (le libellé du fichier qu’on est justement en-train de créer ou d’éditer) sans l’extension *.php
  • le chemin déclaré après extends est celui vers le Model initial avec, en dernier, le libellé du fichier sans l’extension *.php. Ici, on peut reprendre l’intégralité de la valeur déclarée pour l’attribut for de la balise preference du fichier di.xml, mais ATTENTION: il faut impérativement rajouter un anti-slash \ devant ce dernier!

Commandes Magerun à exécuter impérativement:

A la création de votre module (la première fois):

Puis à chaque modification dans le fichier di.xml:

[Magento 2] Surcharge d’une classe PHP située dans app/code/Vendor/Module/Model/Config/Source via un namespace spécifique

La classe Width que nous souhaitons surcharger dans notre exemple définie dans le fichier app/code/MGS/ThemeSettings/Model/Config/Source/Width.php du thème payant Supro. Mais l’exemple est tout-à-fait adaptable à des classes du core code de Magento 2 ou d’autres thèmes open-source.

1. Création d’un nouveau module qui contiendra notre surcharge de classe:

2. Modification du fichier app/code/Sodifrance/Pdv/etc/module.xml comme ci-dessous.

Note: le tag sequence déclare que notre nouveau module dépend du module Supro_ThemeSettings.

3. Petit upgrade de setup en ligne de commande:

4. Modification du fichier app/code/Sodifrance/Pdv/etc/di.xml comme ci-dessous.

Ici, nous procédons à une injection de dépendances: on veut utiliser, à la place de la classe MGS\ThemeSettings\Model\Config\Source\Width, une nouvelle classe Sodifrance\Pdv\Model\Config\Source\Width.

5. Créer le dossier Model/Config/Source dans app/code/Sodifrance/Pdv.

6. Créer le fichier app/code/Sodifrance/Pdv/Model/Config/Source/Width.php sur les bases du parent app/code/MGS/ThemeSettings/Model/Config/Source/Width.php.

On va se contenter de ne rendre disponible que la valeur 1200px pour les choix de largeur de page depuis l’interface d’admin.

7. On vérifie que le nouveau module Sodifrance_Pdv est bien activé:

7b. On l’active si il est présent dans la liste des modules désactivés:

8. On compile le setup:

Résultat: depuis l’interface d’admin, dans MGS > [MGS Theme] Theme Setting v1.1.0, accodéron « Général », champ « Largeur ». Le seul choix disponible reste « 1200px ».

Il faut tout-de-même enregistrer la configuration pour que les changements soient pris en compte.

[javascript] L’exécution des ressources JS d’un projet via une fonction _autoload et l’encapsulation de code dans des namespaces

A étudier également: Lazy Loading JavaScript Modules With ConditionerJS sur Smashing Magazine.

ATTENTION: Note that this only works in browsers that support Dynamic import(). At the time of this writing that would be Chrome 63 and Safari 11.

Comme d’hab on pourra pas s’en servir parce qu’on doit tjrs avoir une compatibilité avec un vieux navigateur à la noix.


Télécharger une démo
(zip 35ko).

Article de Jean-Luc BOES sur le blog Netapsys: Introduction aux développements sur la suite SAP Hybris (section Le javascript).

Le javascript dans Hybris est du javascript standard mais il est intéressant de remarquer la fonction d’autoload et l’utilisation des espaces de noms. Chaque fichier javascript doit définir une variable _autoload et chaque fonction remplissant les conditions seront appelé une fois le DOM de la page web chargée.

[à traduire] to avoid collisions and improve code organization when working with components under another namespace

Remarque

Attention: je ne suis (pour l’instant) pas parvenu à faire fonctionner l'autoload lorsqu’une condition doit être remplie (dans notre exemple ci-dessous ["bindCarousel", $(".js-owl-carousel").length != 0]) et que les sources JS sont chargées au sein de l’élément HEAD d’un document. Il faut obligatoirement charger les sources Js (au moins l’autoload et les fichiers qui y font référence) tout en bas du DOM, juste avant la fermeture de la balise BODY, et ce même si le code JS est encapsulé dans un $(document).ready(function(){}); ou équivalent.

Cela ne devrait pas être un problème en soi car faire appel aux sources JS en bas de page est une bonne pratique, mais d’expérience ce n’est pas toujours possible…

Source de la fonction _autoload

Assurez vous que ACC soit disponible

Exemple d’utilisation

Cette méthodologie consiste à limiter le nombre d’initialisation d’un même plugin (ici Owl Carousel). On l’initialise une seule fois via la classe .js-owl-carousel affectée à tous les carousels utilisés dans le site. On passe ensuite les paramètres pour différentes configs (default, rotating-image, lazy-reference) en fonction d’une classe (.js-owl-default, .js-owl-rotating-image, .js-owl-lazy-reference) présente dans la vue.

Vue HTML pour un carousel avec config « lazy-reference » (voir au-dessus)

Notez ligne 8 la présence de la classe .js-owl-lazy-reference (qui déclenche la config) sur le même élément que la classe .js-owl-carousel (qui initialise le plug-in).

Modifier à la volée les paramètres d’un objet

Conclusion

Je n’ai pas un niveau de ninja en javaScript (je pratique pas mal jQuery pour répondre à des contraintes liées au front). Cette organisation du code JS autour d’une fonction _autoload (la méthodologie adoptée par les concepteurs d’Hybris) m’a permis de rentrer facilement dans le code sans lire aucune documentation et de greffer rapidement mes propres fonctions à l’existant sans pour autant le dénaturer, tant j’ai trouvé cette ossature facile à comprendre. C’est là l’intérêt de l’utilisation d’un pattern.

Pour aller plus loin

et ses patterns (et notamment le namespaced pattern dont la philosophie se rapproche de la méthodologie JS Hybris.

[Hybris] Ajouter une référence JS proprement

Cas d’école : j’écris du code JS spécifique pour un bloc (un tag) donné, par exemple la pagination, et je souhaite l’inclure proprement afin :

  • qu’il ne soit pas présent directement dans le template *.jsp du bloc (chemin : /webroot/WEB-INF/tags/responsive/nav/pagination/pageSelectionPagination.tag)
  • qu’il soit plutôt déclaré dans un fichier séparé qui contient uniquement des directives JS propres à ce bloc (chemin : /webroot/_ui/responsive/common/js/)
  • qu’il soit exécuté uniquement si une pagination est présente dans la page qui s’affiche dans le navigateur

Ajouter, dans le template de bloc, une classe qui servira à l’exécution des directives JS

Dans /webroot/WEB-INF/tags/responsive/nav/pagination/pageSelectionPagination.tag :

Ici, on ajoute une classe js-spe-pagination.

Créer le fichier qui contiendra notre code JS spécifique

Dans /webroot/_ui/responsive/common/js/, créer un fichier acc.spe.pagination.js qui contient le code ci dessous :

  • ligne 3: l'_autoload va définir qu’on exécute le code présent dans la fonction spePagination à la condition que la classe .js-spe-pagination soit présente dans le DOM
  • ligne 1: l’ensemble du code JS spécifique relatif à notre pagination est encapsulé dans un namespace ACC.spePagination qu’on retrouve ensuite à chaque fois qu’on cherche à exécuter une fonction (spePagination: function (){ACC.spePagination.buildDropupPagination();})
  • Attention: noter la présence de virgules lignes 3, 4 et 8 pour bien assurer la transition entre les différentes parties du code

Déclarer la nouvelle référence JS

Dans /webroot/WEB-INF/tags/responsive/template/javaScript.tag, ajouter :

mais aussi dans web/webroot/WEB-INF/wro.xml.

Déclarer des variables (hors fonctions)

Starter kit :

Sample de code pour démarrer récupéré ici : /_ui/responsive/common/js/_autoload.js.

Activer le mode « wro » (la concaténation des fichiers JS et CSS) :

Le mode « wro » permet de concaténer l’ensemble des fichiers JS du projet. Il faut déclarer les scripts dans deux fichiers distincts :

  • /webroot/WEB-INF/tags/responsive/template/javaScript.tag (pour le JS)
  • \webroot\WEB-INF\tags\responsive\template\styleSheets.tag (pour le CSS)
  • /webroot/WEB-INF/wro.xml

Pour le second, le chemin vers chaque ressource Js se déclare comme suit :

Pour tester sans passer par une modification de conf’ plus lourde :

Ne pas versionner de code avec l’exemple ci-dessous!

Dans le fichier /webroot/WEB-INF/tags/responsive/template/javaScript.tag ajouter le caractère ! dans <c:when test="${!wro4jEnabled}"> :

où: