Comprendiendo el layout y el renderizado de los XML en Magento (parte 1)


Notice: Undefined variable: post in /furanet/sites/diegomestre.com/web/htdocs/wp-content/themes/docpress/functions.php on line 294

Notice: Trying to get property of non-object in /furanet/sites/diegomestre.com/web/htdocs/wp-content/themes/docpress/functions.php on line 294

Comprendiendo el layout y el renderizado de los XML en Magento (parte 1)

Antes de empezar, debo decir que este artículo es una traducción libre hecha de este otro magnífico artículo en inglés. Si queréis consultar la versión original aquí:

Artículo original en inglés

La visualización de la implementación del modelo MVC de Magento, es algo particular, se divide en dos partes, el template y el layout. El template contiene los bloques phtml mientras que define la localización del bloque en la página. Magento dispone de un flexible y reusable sistema de diseño por layouts definido en los XML

Layout XML

Los archivos XML del Layout se pueden encontrar en app/design/frontend/[package]/[theme]/layout, cada módulo de Magento puede, además, definir su propio archivo XML de Layout en su archivo config.xml

<frontend>
  <layout>
    <updates>
      <mymodule>
        <file>mymodule.xml</file>
      </mymodule>
    </updates>
  </layout>
</frontend>

Cada archivo XML del layout representa su propia actualización de diseño. Por ejemplo, la navegación del catálogo es parte del módulo Mage_Catalog y el módulo Mage_Catalog define su propia actualización del layout general en el archivo catalog.xml. De este modo, el bloque para la navegación del catálogo y su localización en la página web se definirán en este catalog.xml

Previamente al renderizado de la página, magento carga todos los archivos de actualización de layout configurados con sus actualizaciones de diseño para determinar qué bloque va a ser renderizado en cada localización

Aquí tenemos un ejemplo del archivo XML del layout contacts.xml del módulo Mage_Contacts, el elemento raíz de cada archivo XML de layout es <layout>

<layout version="0.1.0">
  <default>
    <reference name="footer_links">
      <action method="addLink" translate="label title" module="contacts" ifconfig="contacts/contacts/enabled"><label>Contact Us</label><url>contacts</url><title>Contact Us</title><prepare>true</prepare></action>
    </reference>
  </default>
 
  <contacts_index_index translate="label">
    <label>Contact Us Form</label>
    <reference name="root">
      <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
      <action method="setHeaderTitle" translate="title" module="contacts"><title>Contact Us</title></action>
    </reference>
    <reference name="content">
      <block type="core/template" name="contactForm" template="contacts/form.phtml"/>
    </reference>
  </contacts_index_index>
</layout>

Handles del Layout

Los elementos del primer nivel (child) del nodo <layout>, se llaman handles (manejadores, aunque mantendré su nomenclatura en inglés), en el ejemplo supperior serían <default> y <contacts_index_indes>, cada handle representa una actualización del layout de la página. Puede definir nuevos bloques para ser incluidos en la página en una posición determinada o retirar un bloque de la página. Puede también definir modificaciones en bloques ya incluidos en la página por otros archivos XML de layout.

Después de que Magento haya cargado todos los XML del layout, determinará qué handles han de ser procesados. Normalmente el handle es seleccionado basándose en la acción del controller que está siendo ejecutada. En la mayoría de casos Magento cargará el handle con el nombre: [nombre_modulo]_[nombre_controller]_[nombre_action]

Por ejemplo, cuando la página contáctanos es solicitada, entonces el action index del controller index del módulo Mage_Contacts es ejecutado. El nombre del módulo Mage_Contacts en el front es contacts. Así pues el handle que se procesará en la página contáctanos será <contacts_index_index>

Para cualquier página Magento siempre procesará el handle default, así que las actualizaciones definidas en el handle default del layout serán procesadas en cada página independientemente de en qué parte del site estemos navegando. Como ilustra el ejemplo de arriba, el módulo Mage_Contacts necesita un enlace a la página de contáctanos en el footer de cada página para los elementos específicos para él definidos en el handle default. Estos elementos van a ser definidos en la siguiente sección

Elementos del Layout

Un handle puede contener los siguientes elementos

  • label: Este elemento fue introducido en la versión 1.4 de Magento, define la etiqueta que se mostrará como referencia descriptiva en algunas áreas del panel de administración
  • reference: Este elemento se usa para referenciar un bloque que ya está definido en otro XML de layout. Para añadir otro bloque hijo a otro que ya existe, para modificar atributos de un bloque existente o para realizar cualquier acción en bloques existentes. el valor del elemento reference debe coincidir con el atributo name del bloque que ya existe
  • block: Se utiliza para definir un nuevo bloque, este elemento normalmente se define dentro de reference cuando queremos crear un bloque nuevo, debe tener obligatoriamente los atributos name, que define un identificador único del bloque en el layout y un atributo type, que define el nombre de del tipo de bloque. Si el bloque es del type o subtype de core/template, puede también tener el atributo template que define el archivo phtml para esr usado para renderizar el bloque
  • remove: Este elemento se usa para eliminar un bloque existente en el layout. El bloque a ser eliminado se especifica con su atributo name
  • action: Este elemento define una acción para ser realizada en el bloque definido como referencia o en el bloque nuevo. Un action es simplemente un método de una instancia de bloque en el cual será ejecutado. Este atributo define el nombre del método en la instancia del bloque y en todos sus elementos hijos son tratados como parámetros del método. Este elemento puede ser colocado dentro de elementos reference o block
  • update: Este elemento carga un handle dentro del handle actual, esto nos ofrece una especie de herencia en los handles del layout. Debe contener un attribute handle que define el handle del bloque que va a ser incluido

Por ejemplo, todas las páginas de cuentas de cliente tienen un layout similar y aplican a menudo los mismos updates de layout, así, en vez de definir todos los updates para páginas individuales un handle frecuente:customer_account se define así customer.xml como:

<customer_account translate="label">
  <label>Customer My Account (All Pages)</label>
  <!-- Mage_Customer -->
  <reference name="root">
    <action method="setTemplate"><template>page/2columns-left.phtml</template></action>
  </reference>
 
  <reference name="content">
    <block type="page/html_wrapper" name="my.account.wrapper">
      <action method="setElementClass"><value>my-account</value></action>
    </block>
  </reference>
 
  <reference name="left">
    <block type="customer/account_navigation" name="customer_account_navigation" before="-" template="customer/account/navigation.phtml">
      <action method="addLink" translate="label" module="customer"><name>account</name><path>customer/account/</path><label>Account Dashboard</label></action>
      <action method="addLink" translate="label" module="customer"><name>account_edit</name><path>customer/account/edit/</path><label>Account Information</label></action>
      <action method="addLink" translate="label" module="customer"><name>address_book</name><path>customer/address/</path><label>Address Book</label></action>
    </block>
    <block type="catalog/product_compare_sidebar" name="catalog.compare.sidebar" template="catalog/product/compare/sidebar.phtml"/>
    <block type="sales/reorder_sidebar" name="sale.reorder.sidebar" as="reorder" template="sales/reorder/sidebar.phtml"/>
    <remove name="tags_popular"/>
  </reference>
</customer_account>

Este es el handle que se carga en todas las páginas de cuenta de cliente. Aquí hay un ejemplo del handle de la página de dirección del cliente en el mismo archivo customer.xml

<customer_address_index translate="label">
  <label>Customer My Account Address Book</label>
  <!-- Mage_Customer -->
  <update handle="customer_account"/>
  <reference name="my.account.wrapper">
    <block type="customer/address_book" name="address_book" before="-" template="customer/address/book.phtml"/>
  </reference>
</customer_address_index>

De este modo, cuando la página de dirección del cliente se renderiza los bloques del layout definidos en customer_account son también aplicados a la página

Proceso de renderizado

Antes de renderizar la página todos los elementos bloque definidos en el layout son instanciados. Los elementos bloque anidados definen bloques hijos. Si algún elemento bloque tiene un atributo output, entonces es considerado como un bloque de tipo output. Sólamente los bloques output son renderizados y añadidos al response. El resto de bloques hijos son renderizados sólo cuando son llamados por el bloque padre. Veamos como trabaja

El tema por defecto de Magento, el bloque raíz se define como un bloque output. Este bloque se define en el archivo page.xml. Con un valor concreto del atributo template, este bloque define el template a ser usado en el proceso de renderizado (por ej. 1 column, 2 columns with left sidebar, etc…). Por defecto el template de 3 columns es el asignado a la página. Hay otros bloques hijos definidos bajo el raíz como head, header, breadcrumbs, left, right, content, footer, etc… Estos bloques hijos serán renderizados en el archivo raíz del template (3columns.phtml) haciendo una llamada a algo como esto:

echo $this->getChildHtml('header');

En cualquier template, los bloques hijos pueden ser renderizados llamando al método getChildHtml(), como arriba, pasando el nombre del bloque como primer argumento. Si el método se llama sin argumentos, renderizará todos los bloques hijos del bloque actual que están definidos en el archivo XML del layout para ese bloque.

Por tanto, Magento procesa el layout siguiendo un proceso de renderizado recursivo. Primero el bloque raíz , después sus bloques hijos, después los hijos de sus hijos y así sucesivamente

Poniéndolo todo junto

Echemos un vistazo al ejemplo del archivo contacs.xml. El objetivo de este archivo de actualización de layout es añadir un enlace al footer en la página de contacto si el contacto está habilitado en Sistema-Configuración y definir la estructura de la página “Contactanos”.

Ya hay un bloque footer_links definido el archivo page.xml para mostrar enlaces en la página footer. El bloque footer_links tiene un método addLink para añadir nuevos enlaces dentro del bloque. Así que aquí, el bloque existente footer_links puede ser referenciado y la acción addLink puede ser llamada en él con ciertos parámetros para añadir un enlace a la página “Contáctanos” en él. Como el enlace necesita ser añadido en el footer en cada página, este deberia ser definido en el handle default.

<default>
  <reference name="footer_links">
    <action method="addLink" translate="label title" module="contacts" ifconfig="contacts/contacts/enabled"><label>Contact Us</label><url>contacts</url><title>Contact Us</title><prepare>true</prepare></action>
  </reference>
</default>

Aquí, el handle default contiene una referencia al bloque footer_links y realiza una acción addLink en él pasándole los parámetros label, url, title, etc… También en este caso, el atributo translate se utiliza para definir qué parámetros necesitan ser traducidos antes de ser pasados al método. En el ejemplo superior, label y title son traducidos utilizando el actual locale. La traducción será buscada en el scope definido en el módulo del atributo. El atributo ifconfig define la clave del sistema-configuración para ser chequeada antes de realizar la acción del método. Esta clave utilizada como valor de ifconfig, es normalmente definida como tipo Sí/No y devuelve un valor booleano. Si la configuración devuelve false, la acción no se realizará. En nuestro caso si valor de contacts/contacts/enabled es false (p.ej. contact us es deshabilitado en sistema-configuración) la acción de añadir el enlace no se realizará y el enlace al contactanos no aparecerá en el footer. ifconfig puede ser sólo utilizado en el elemento action y sólo cuando el action necesita para realizarse si una hay un valor concreto en la configuración puesto a “Sí”

<contacts_index_index translate="label">
  <label>Contact Us Form</label>
  <reference name="root">
    <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
    <action method="setHeaderTitle" translate="title" module="contacts"><title>Contact Us</title></action>
  </reference>
  <reference name="content">
    <block type="core/template" name="contactForm" template="contacts/form.phtml"/>
  </reference>
</contacts_index_index>

Como mencioné antes, Magento automáticamente determina el handle para ser cargado en la base de una acción que en estos momentos está siendo ejecutada. En el caso de la página de contáctanos, llamaría al módulo Mage_Contacts, su IndexController y su indexAction. El front name de Mage_Contacts es contacts. Así que el handle del layout debería ser contacts_index_index. La etiqueta dada es Contact Us Form para identificar la página en algunas áreas del panel de adminitración, por ejemplo el formulario para la creación de una instancia del widget.

layout-handles-admin

Después, la página de Contact Us debería tener dos columnas con columna derecha. Como expliqué en la sección anterior, el template es definido por el nodo root y por defecto utiliza el template 3 columnas. Así pues, para modificar éste para la página Contáctanos, el nodo root es refernciado aquí utilizando el elemento reference. Para asignar un template diferente a la página el método setTemplate debería ser llamado. De este modo un elemento action es definido para llamar al método setTemplate con la ruta del template deseado como parámetro.

<reference name="root">
  <action method="setTemplate"><template>page/2columns-right.phtml</template></action>
</reference>

Por último, en el área de contenido principal, un formulario de contacto debería mostrarse. Para añadir el bloque de formulario de contacto, el bloque de content es referenciado y un elemento nuevo bloque es definido para ser incluído en el formulario.

<reference name="content">
    <block type="core/template" name="contactForm" template="contacts/form.phtml"/>
  </reference>

Tipos de bloques

Magento define algunos tipos de bloques ya construidos que son generalmente los utilizados en el layout

  • core/template: Este bloque renderiza un template definido en el atributo template, la mayoría de bloques definidos en el layout son de este tipo
  • page/html: Este es un subtipo del anterior y define el archivo raíz
  • page/html_head: Define el HTML de la sección head de la página que lo contiene, donde llama a los archivos CSS, JS, etc…
  • page/html_header: Define la parte del header en la que van el logo, los toplinks, etc…
  • page/template_links: Este bloque se utiliza para definir listas de enlaces. Los enlaces visibles en el footer o en el header son de este tipo.
  • core/text_list: Algunos bloques como content, left, right, etc… son de este tipo. Cuando estos bloques son renderizados, todos sus bloques child son renderizados sin la necesidad de llamar al método getChildHtml()
  • page/html_wrapper: Este bloque se utiliza para crear un bloque “envoltorio” que renderiza todos sus childs dentro de la etiqueta HTML que hayamos definido en el action setHtmlTagName, del bloque. Si no se define ningún tag, utilizará por defecto <div>
  • page/html_breadcrumbs: Define el “rastro de migas” de la página
  • page/html_footerDefine el área del footer de la página que contiene normalmente los enlaces del footer, el mensaje del copyright, etc…
  • core/messages: Este bloque renderiza los mensajes de error, notas o success
  • page/switch: Este bloque puede ser usado para el selector de tienda, lenguaje o moneda

Esto es una lista solamente de los tipos de bloques usados más frecuentemente. Hay muchos otros tipos de bloques que son tuilizados en las implementaciones de themes más avanzados.

Anotaciones

Los archivos XML hacen el diseño de temas modular utilizando handles. Esto son sólo las bases de XML layouts en Magento. Utilizaciones más avanzadas pueden ser hechas utilizando handles y actions. Cubriremos el uso más avanzado de XML layouts en el próximo artículo de esta serie

Escribe tu comentario

comentarios