Este artículo explica cómo utilizar JLayouts para evitar ensuciar el código HTML, JS y CSS en campos (fields) complejos.

Para ilustrar el problema utilizaremos el campo del core ya existente para seleccionar usuarios:

libraries/cms/form/field/user.php

Este es el contenido de la función getInput() dentro de ese field:

/**
 * Method to get the user field input markup.
 *
 * @return  string  The field input markup.
 *
 * @since   1.6.0
 */
protected function getInput()
{
    $html = array();
    $groups = $this->getGroups();
    $excluded = $this->getExcluded();
    $link = 'index.php?option=com_users&view=users&layout=modal&tmpl=component&field=' . $this->id
        . (isset($groups) ? ('&groups=' . base64_encode(json_encode($groups))) : '')
        . (isset($excluded) ? ('&excluded=' . base64_encode(json_encode($excluded))) : '');
    // Initialize some field attributes.
    $attr = $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : '';
    $attr .= $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : '';
    // Initialize JavaScript field attributes.
    $onchange = (string) $this->element['onchange'];
    // Load the modal behavior script.
    JHtml::_('behavior.modal', 'a.modal_' . $this->id);
    // Build the script.
    $script = array();
    $script[] = '   function jSelectUser_' . $this->id . '(id, title) {';
    $script[] = '       var old_id = document.getElementById("' . $this->id . '_id").value;';
    $script[] = '       if (old_id != id) {';
    $script[] = '           document.getElementById("' . $this->id . '_id").value = id;';
    $script[] = '           document.getElementById("' . $this->id . '_name").value = title;';
    $script[] = '           ' . $onchange;
    $script[] = '       }';
    $script[] = '       SqueezeBox.close();';
    $script[] = '   }';
    // Add the script to the document head.
    JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
    // Load the current username if available.
    $table = JTable::getInstance('user');
    if ($this->value)
    {
        $table->load($this->value);
    }
    else
    {
        $table->username = JText::_('JLIB_FORM_SELECT_USER');
    }
    // Create a dummy text field with the user name.
    $html[] = '<div class="input-append">';
    $html[] = ' <input class="input-medium" type="text" id="' . $this->id . '_name" value="' . htmlspecialchars($table->name, ENT_COMPAT, 'UTF-8') . '"'
        . ' disabled="disabled"' . $attr . ' />';
    // Create the user select button.
    if ($this->element['readonly'] != 'true')
    {
        $html[] = '     <a class="btn btn-primary modal_' . $this->id . '" title="' . JText::_('JLIB_FORM_CHANGE_USER') . '" href="' . $link . '"'
            . ' rel="{handler: \'iframe\', size: {x: 800, y: 500}}">';
        $html[] = '<i class="icon-user"></i></a>';
    }
    $html[] = '</div>';
    // Create the real field, hidden, that stored the user id.
    $html[] = '<input type="hidden" id="' . $this->id . '_id" name="' . $this->name . '" value="' . (int) $this->value . '" />';
    return implode("\n", $html);
}

Como podrás observar, hay algo de código HTML y JS embedido y desordenado con el PHP. La primera razón para evitarlo o reemplazarlo es por cuestiones de legibilidad. Además imagina que tienes una plantilla que no utiliza resaltado Bootstrap como Hathor o quieres cargar un modal diferente que no usa Mootools.

Puede JLayouts ayudarnos en esta tarea? Si. De hecho es probablemente la mejor solución. Manos a la obra.

Primero moveremos casi todo el código al layout. Nuestra nueva función getInput() quedará así:

/**
     * Method to get the user field input markup.
     *
     * @return  string  The field input markup.
     *
     * @since   1.6.0
     */
    protected function getInput()
    {
        $this->groups   = $this->getGroups();
        $this->excluded = $this->getExcluded();
        return JLayoutHelper::render("libraries.cms.forms.fields.user", $this);
    }

Solo lo básico para obtener la información requerida y pasarsela al layout. Ahora tenemos que crear el layout. Probablemente has notado por la llamada a la función render que vamos a crearla en:

layouts/libraries/cms/forms/fields/user.php

El contenido del archivo es el siguiente:

<?php
/**
 * @package     Joomla.Site
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('JPATH_BASE') or die;
$data = $displayData;
$html = array();
$link = 'index.php?option=com_users&amp;view=users&amp;layout=modal&amp;tmpl=component&amp;field=' . $data->id
    . (isset($data->groups) ? ('&amp;groups=' . base64_encode(json_encode($data->groups))) : '')
    . (isset($data->excluded) ? ('&amp;excluded=' . base64_encode(json_encode($data->excluded))) : '');
// Initialize some field attributes.
$attr = $data->element['class'] ? ' class="' . (string) $data->element['class'] . '"' : '';
$attr .= $data->element['size'] ? ' size="' . (int) $data->element['size'] . '"' : '';
// Initialize JavaScript field attributes.
$onchange = (string) $data->element['onchange'];
// Load the modal behavior script.
JHtml::_('behavior.modal', 'a.modal_' . $data->id);
// Build the script.
$script = "
    function jSelectUser_" . $data->id . "(id, title) {
        var old_id = document.getElementById('" . $data->id . "_id').value;
        if (old_id != id) {
            document.getElementById('" . $data->id . "_id').value = id;
            document.getElementById('" . $data->id . "_name').value = title;
            " . $onchange . "
        }
        SqueezeBox.close();
    }
";
// Add the script to the document head.
JFactory::getDocument()->addScriptDeclaration($script);
// Load the current username if available.
$table = JTable::getInstance('user');
if ($data->value)
{
    $table->load($data->value);
}
else
{
    $table->username = JText::_('JLIB_FORM_SELECT_USER');
}
?>
<?php // Create a dummy text field with the user name. ?>
<div class="input-append">
    <input class="input-medium" type="text" id="<?php echo $data->id; ?>_name" value="<?php echo  htmlspecialchars($table->name, ENT_COMPAT, 'UTF-8'); ?>" disabled="disabled" <?php echo $attr; ?> />
    <?php
    // Create the user select button.
    if ($data->element['readonly'] != 'true') : ?>
        <a class="btn btn-primary modal_<?php echo $data->id; ?>" title="<?php echo JText::_('JLIB_FORM_CHANGE_USER'); ?>" href="/<?php echo $link; ?>" rel="{handler: 'iframe', size: {x: 800, y: 500}}">
            <i class="icon-user"></i>
        </a>
    <?php endif; ?>
</div>
<?php // Create the real field, hidden, that stored the user id. ?>
<input type="hidden" id="<?php echo $data->id; ?>_id" name="<?php echo $data->name; ?>" value="<?php echo (int) $data->value; ?>" />

Ahora el código HTML está separado del PHP. También los usuarios pueden sobresribirla facilmente creando un fichero en la plantilla activa como:

templates/TEMPLATE_NAME/html/layouts/libraries/cms/forms/fields/user.php

Todo puede cambiarse dentro de la plantilla excepto la información de entrada..