Jacques Bodin-Hullin Développeur d'applications Web

La perfection est atteinte non quand il ne reste rien à ajouter, mais quand il ne reste rien à enlever.

Antoine de Saint Exupéry

Le Layout sur Magento

Le Layout est une partie vraiment importante que tout développeur Magento doit connaître.

De premier abord il n'est pas simple de comprendre le fonctionnement du layout et c'est bien là le but de cet article.

Mais pas seulement ! Je vais aussi vous donner quelques trucs pour maîtriser encore mieux le layout !


Le Layout c'est du XML.

La balise principale est layout, quoi de mieux ?

Les handles

Le layout de Magento est vraiment très complet. On a des fichiers de plusieurs centaines de lignes parfois. Mais comment distinguer quelles parties du layout vont s'appliquer à notre page ?

Les handles sont des balises libres. Lors de son chargement Magento complète une liste de handles qui seront utilisés lors du rendu final.

Pour dire à notre action, dans notre contrôleur, d'utiliser les handles par défaut il faut utiliser la ligne de code suivante :

<?php
public function indexAction()
{
    // Ci-dessous la ligne qui charge les handles par défaut du Layout
    $this->loadLayout();
}

La méthode loadLayout() appelle deux méthodes qui sont les méthodes qui ajoutent réellement les handles par défaut :

<?php
$this->getLayout()->getUpdate()->addHandle('default');

et

<?php
addActionLayoutHandles();

Pour une action qui serait jbh_foo/bar/baz nous aurions les handles suivants :

  • default : handle principal par défaut
  • STORE_default : handle du store (par défaut)
  • THEME_frontend_default_default : handle du thème (par défaut)
  • jbh_foo_bar_baz : handle de notre action

On peut changer le handle default par autre chose si on le précise comme ceci :

<?php
$this->loadLayout('other');

Avant le chargement de ces layouts l'évènement controller_action_layout_load_before est lancé par Magento. Donc si vous souhaitez ajouter un handle il faut le faire avant cet évènement.

Magento peut gérer des handles à l'infinie.

Attention cependant : L'ordre de traitement de ces handle a son importance ! Car on peut faire de la surcharge de name et bien d'autres choses encore !

Dans le layout, on peut demander à charger un handle défini de la manière suivante :

<update handle="nom_du_handle" />

C'est très pratique ! Et ça permet surtout de ne pas dupliquer de code !

Comment trouver le handle d'une page ?

Prenons par exemple la page de connexion dont l'URL est : https://example.org/customer/account/login

Il nous suffit de remplacer les / par des _ :

customer_account_login

En règle générale :

  • En premier c'est le nom de la route (et pas du module !)
  • En deuxième c'est le nom du contrôleur
  • En troisième c'est le nom de l'action

Les blocks

Le layout c'est plein de block qui ont tous deux attributs principaux :

  • type ou class : indique la classe PHP du block (par exemple : jbh_foo/bar indique la classe Jbh_Foo_Block_Bar – à priori)
  • name : indique le nom du block dans le layout (doit être unique)

On peut ensuite trouver d'autres attributs tels que :

  • template : indique le path du fichier template .phtml utilisé par le block
  • as : indique le nom du block dans son parent
  • translate : indique les différentes balises qui peuvent être traduites (label est la valeur la plus utilisée)
  • output : indique la méthode du block à utiliser pour forcer l'affichage de celui-ci
  • parent : indique le nom du block parent (surcharge le parent réel dans le XML)
  • before : indique la place du block dans son parent (si la valeur est - alors le block sera ajouté tout au début de la liste des blocks enfants de son parent)
  • after : indique la place du block dans son parent (si la valeur est - alors le block sera ajouté tout à la fin de la liste des blocks enfants de son parent). Cet attribut n'est pas traité si before existe. Si la valeur est - et qu'un block est généré ensuite avec un after="-" alors ce dernier prendra la place en fin de liste.

Surcharger un block

On peut surcharger un block dans le layout, pour changer son type par exemple !

Deux solutions :

  1. Changer le type directement dans le fichier .xml qui déclare le block.
  2. Ajouter un nouveau block avec le même name.

La première solution a l'avantage de ne pas créer d'instance de block inutilisée. Cependant elle a le désavantage d'obliger (bien souvent) le développeur à copier le fichier .xml du core dans son nouveau thème et à en modifier le contenu.

La seconde solution permet en fait d'écraser un block existant. Le problème dans ce cas c'est que lorsqu'on écrase le block, celui-ci disparaît du layout mais il reste dans son parent (sauf si on ajoute l'attribut parent à notre nouveau block, auquel cas il y a aussi un écrasement). On perd également toutes les opérations effectuée sur le vieux block, ainsi que tous ces enfants (qui sont toujours dans le layout mais qui étaient dans le block qu'on tente de remplacer).

En conclusion il est plus simple d'utiliser la première méthode. Cependant la seconde méthode peut avoir un avantage si on souhaite surcharger un block simple (qui n'a pas d'enfants) et sur lequel il n'y a pas eu d'action (voir plus bas « Les actions »).

Les références

Dans un handle on peut récupérer un block en utilisant une référence.

Une référence c'est juste un rappel du block pour permettre l'appel à des actions ou l'ajout de blocks enfants.

Une référence peut être insérée à n'importe quel endroit dans le handle : dans un block ou même dans une autre référence.

Un seul attribut est nécessaire (et obligatoire) pour la balise reference : l'attribut name. Celui-ci indique le nom du block à utiliser en tant que parent pour tout ce qui est dans le noeud reference en cours de traitement.

Par exemple pour faire une référence au content, pour y ajouter un block par exemple, sur toutes les pages (handle default donc) :

<default>
    <reference name="content">
        <block type="core/text_list" name="sub_content" />
    </reference>
</default>

Les actions

Les actions sont très pratiques ! On utilise le XML du layout pour appeler des méthodes d'un block !

(La principale action utilisée est celle qui consiste à changer le template d'un block.)

Une action comprend 2 attributs :

  • method : il est obligatoire, il indique la méthode du block à appeler (peut être une méthode magique ! si si ;))
  • block : il est facultatif, il permet d'indiquer le block sur lequel l'action doit être appliquée.

Une action fait donc appel à une méthode de son block :

  • soit le block parent dans le Layout
  • soit le block précisé par l'attribut block

Dans les deux cas il faut préciser (sauf s'il n'y en a pas) les paramètres de la méthode.

Pour cela il suffit de suivre une logique simple :

  • Le premier paramètre sera le premier enfant de l'action
  • Le second paramètre sera le second enfant de l'action
  • etc.

Si bien que si nous avons par exemple la méthode suivante :

<?php
public function addLink($name, $path, $label, $urlParams = array());

Nous aurons l'action ci-dessous :

<action method="addLink">
    <param1>name</param1>
    <param2>path</param2>
    <param3>label</param3>
</action>

Nous ne mettons pas de 4ème balise car nous ne voulons pas préciser de 4ème paramètre lors de notre appel.

D'ailleurs... ce 4ème paramètre c'est un tableau !

Pour les tableaux c'est un peu plus compliqué...

Notez que bien souvent le nom d'une balise correspond au nom de la variable en paramètre de la méthode, pour plus de clareté (et uniquement pour cette raison, sauf pour les tableaux ;)).

Les tableaux en paramètre

Pour un tableau de valeurs (indexé) il faut faire :

<action ...>
    <tab>value_1</tab>
    <tab>value_2</tab>
    <tab>value_3</tab>
    <tab>value_4</tab>
</action>

Pour un tableau associatif il faut faire :

<action ...>
    <tab>
        <cle_1>value_1</cle_1>
        <cle_2>value_2</cle_2>
        <cle_3>value_3</cle_3>
    </tab>
</action>

Et bien sûr on peut aller loin...

<action ...>
    <tab>
        <cle_1>value_1</cle_1>
        <cle_2>value_2</cle_2>
        <cle_3>
            <cle_4>value_4</cle_4>
            <cle_5>value_5</cle_5>
            <cle_6>
                <cle_7>value_7</cle_7>
                <cle_8>value_8</cle_8>
            </cle_6>
        </cle_3>
    </tab>
</action>

Et ainsi de suite !

Par contre à partir du second niveau vous ne pourrez plus faire de tableaux indexés.

Changer le template d'un block

Nous voulons par exemple changer le template de la page de login (template global).

D'abord il nous faut déterminer le handle de cette page le plus approprié. Le plus simple quand il faut modifier le template d'un block qui n'est que sur une seule page c'est d'utiliser le handle de l'action. Ici nous avons donc le handle suivant :

customer_account_login

Ensuite nous devons trouver le block sur lequel nous devons changer le template. Comme nous voulons changer le template global, le block est root.

Nous avons maintenant deux possibilités :

Soit on passe par une référence :

<customer_account_login>
    <reference name="root">
        <action method="setTemplate">
            <template>customer/account/new_login.phtml</template>
        </action>
    </reference>
</customer_account_login>

Soit on utilise l'attribut block :

<customer_account_login>
    <action method="setTemplate" block="root">
        <template>customer/account/new_login.phtml</template>
    </action>
</customer_account_login>

Il s'avère qu'il est d'ailleurs préférable de changer le template d'un block en utilisant l'attribut block plutôt qu'en utilisant une référence car c'est moins coûteux en ressources : on fait une itération en moins dans la génération des blocks. (c'est peu certes, mais c'est par là que passe l'optimisation... aussi)

Ignorer un block

On voit de temps en temps une petite ligne qui ressemble à ceci :

<remove name="left" />

Cette balise permet d'ignorer un block. Ici on ignore le block left (la colonne de gauche).

Et il arrive assez fréquemment que le développeur se demande si le fait de mettre cette balise avant ou après la création d'un block aura un impact différent.

La réponse est non.

En effet, Magento utilise XPATH pour ignorer tous les noeuds et toutes les références aux noeuds dont le nom est indiqué dans l'attribut name de tous les tags remove du Layout.

Si vous ne voulez pas qu'un noeud soit finalement ignoré il faut réussir à supprimer le noeud remove qui le « supprime » ! (logique !)

(Sinon vous pouvez aller voir du côté du module Layout UnRemove de Alan Storm.)

La balise remove accepte l'attribut acl pour indiquer si on ignore ou non ce block dans le cas d'un layout admin. L'attribut prend la valeur du droit nécessaire pour afficher le block comme par exemple :

<remove name="foo" acl="jbh_foo/bar" />

Si l'administrateur connecté a le droit jbh_foo/bar alors le block ne sera pas ignoré.

A noter aussi qu'on peut inhiber l'action du remove sur un block en définissant l'attribut ignore de celui-ci !

<block name="foo" type="core/text_list" ignore="0" />

Ce block ne pourra donc pas être supprimé via remove. Attention par contre... vu qu'on ne peut pas ajouter un attribut à un block déjà existant (via une référence par exemple) cette manipulation implique que le block ne sera jamais ignoré.

Le fichier local.xml (dans design/../layout/)

Surprise ! Ce fichier est toujours parsé en dernier ! Donc si vous souhaitez faire de la mise à jour pour un thème sans rien en particulier vous pouvez utiliser ce fichier.

C'est bon à savoir non ?

Avec lui, plus besoin de faire un module pour « nettoyer » votre thème :)

Un recherché remplacé ?

Oui ! Magento effectue un str_replace sur tout votre XML comme ceci :

  • {{baseUrl}} devient l'URL non sécurisée de votre store
  • {{baseSecureUrl}} devient l'URL sécurisée de votre store

Les updates

Un update c'est simplement un bout de XML ajouté au layout qui sera traité de la même façon que tous les fichiers .xml de votre thème.

Le tag update

Il ne peut être qu'un enfant d'un handle, sinon il ne sera pas pris en compte.

Il doit comporter un seul attribut : handle.

Cet attribut indique le nom d'un autre handle qui doit être pris en compte dans le layout.

Vous pouvez par exemple vouloir appliquer le handle customer_account à votre nouvelle page pour qu'elle s'intègre parfaitement dans la partie "Mon Compte" du client :

<handle_de_ma_nouvelle_page>
    <update handle="customer_account" />
</handle_de_ma_nouvelle_page>

Vous pouvez également utiliser cette technique pour éviter de dupliquer un gros bout de layout que vous voudriez réutiliser !

Des updates en base de données

Les Widgets utilisent la base de données pour ajouter des updates sur le layout.

Il nous est possible de faire de même si on le souhaite en utilisant les deux tables core_layout_link et core_layout_update.

Désactiver le module des Widgets n'empêchera pas Magento de faire une requête SELECT par handle par page.

Donc si vous n'avez pas de cache, sachez que Magento fait au minimum 4 requêtes pour récupérer les possibles layout updates en base de données à chaque chargement.

A savoir que la sauvegarde d'un seul Widget invalidera les caches suivants :

  • Le cache « Blocks HTML output » (block_html)
  • Le cache « Layouts » (layout)

Merci les widgets ! (à utiliser avec parcimonie donc...)

Conclusion

Vous maîtrisez maintenant le layout sur Magento ! Au moins vous avez les connaissances... Vous savez comment créer, modifier, supprimer tout ou partie du Layout. Il ne vous manque plus que la pratique !

A présent n'hésitez surtout pas à laisser un commentaire sur vos astuces bien à vous ;) Ou simplement pour réagir à cet article !


Commentaires

blog comments powered by Disqus

Quelques infos

  • Par Jacques Bodin-Hullin
  • Publié le 15 September 2012
  • Les tags Magento, Layout

Contact

Mon QRcode

le QRcode