Krypton Solid

Cómo crear una entidad de Magento administrable por el administrador para marcas – Smashing Magazine

Cómo crear una entidad de Magento administrable por el administrador para marcas – Smashing Magazine

En este tutorial, crearemos una nueva entidad de «marca» en Magento que se puede administrar a través del panel de administración. Una vez que hayamos terminado, podrá crear, actualizar y eliminar marcas que se pueden ver en el front-end de forma independiente, de la misma manera que puede interactuar con entidades existentes como «productos» y «categorías».

En este tutorial, crearemos una nueva entidad de «marca» en Magento que se puede administrar a través del panel de administración. Una vez que hayamos terminado, podrá crear, actualizar y eliminar marcas que se pueden ver en el front-end de forma independiente, de la misma manera que puede interactuar con entidades existentes como «productos» y «categorías».

Además, asociaremos nuestra nueva entidad de marca con otras entidades de Magento, como productos. El proceso en sí es bastante largo porque explicaré cada paso en detalle, pero realmente es fácil una vez que sabes cómo hacerlo, y es un gran ejemplo de lo poderosa que puede ser la plataforma Magento con un mínimo esfuerzo.

Cubriremos los siguientes temas:

  • Cree una nueva entidad de marca en Magento.
  • Busque, filtre y clasifique las marcas en el panel de administración de Magento.
  • Cree, actualice y elimine marcas en el panel de administración.
  • Cree una lista de marcas y visualice las páginas en la interfaz.
  • Asociar marcas con productos.
  • Muestre una asociación de producto-marca en el front-end.
  • Incluya imágenes en todas partes.

Este tutorial se refiere a Magento Community Edition 1.8.0.0, la última versión disponible en el momento de escribir este artículo. Pero el código y los principios se aplican a todas las versiones recientes de Magento, tanto Community como Enterprise.

Cuadrícula de administración de marca de Magento

Aunque he tratado de ser lo más completo posible en mis explicaciones, documentar el código es a veces la mejor manera de explicar ciertas cosas, por lo que encontrará muchos comentarios en los fragmentos de código. El fragmento de código vinculado al final contiene más usos y elementos de los que se tratan en este tutorial, para mostrarle cómo ampliar las cosas que aprenderá aquí.

Otras lecturas en SmashingMag:

Creando Nuestro Módulo

Empiece por crear la siguiente estructura de carpetas y archivos. Por el momento, todos los archivos estarán vacíos. Normalmente, estos archivos y carpetas se crearían uno a la vez según sea necesario, pero por el bien de este tutorial, pondremos todo en su lugar desde el principio.

Como de costumbre, supongo que ya conoce los conceptos básicos de la creación de un módulo de Magento y se siente cómodo con este paso, sin necesidad de explicación.

app
  - code
      - community
          - SmashingMagazine
              - BrandDirectory
                  - Block
                      - Adminhtml
                          - Brand
                              - Edit
                                  - Form.php
                              - Edit.php
                              - Grid.php
                          - Brand.php
                  - Helper
                      - Data.php
                  - Model
                      - Resource
                          - Brand
                              - Collection.php
                          - Brand.php
                      - Brand.php
                  - controllers
                      - Adminhtml
                          - BrandController.php
                  - etc
                      - adminhtml.xml
                      - config.xml
                  - sql
                      - smashingmagazine_branddirectory_setup
                          - install-0.0.1.php
  - etc
      - modules
          - SmashingMagazine_BrandDirectory.xml

Secuencias de comandos de configuración del módulo

Para que nuestro módulo sea de alguna utilidad, necesitamos un lugar para almacenar nuestros datos. Por lo tanto, necesitamos escribir un script de configuración del módulo para crear una tabla de base de datos para contener información sobre nuestra entidad de marca. Los scripts de configuración se almacenan en dos lugares dentro del módulo, /sql y /data. El primero es para cambios físicos en su instancia de Magento, como actualizaciones del esquema de la base de datos, y el segundo es para completar o eliminar entradas del esquema existente.

En nuestro caso, estamos agregando una nueva tabla. Entonces, edite el archivo en sql/smashingmagazine_branddirectory_setup/install-0.0.1.php con el siguiente código:

<?php
$this->startSetup();

/**
 * Note: there are many ways in Magento to achieve the same result of
 * creating a database table. For this tutorial, we have gone with the
 * Varien_Db_Ddl_Table method, but feel free to explore what Magento
 * does in CE 1.8.0.0 and earlier versions.
 */
$table = new Varien_Db_Ddl_Table();

/**
 * This is an alias of the real name of our database table, which is
 * configured in config.xml. By using an alias, we can refer to the same
 * table throughout our code if we wish, and if the table name ever has
 * to change, we can simply update a single location, config.xml
 * - smashingmagazine_branddirectory is the model alias
 * - brand is the table reference
 */
$table->setName($this->getTable('smashingmagazine_branddirectory/brand'));

/**
 * Add the columns we need for now. If you need more later, you can
 * always create a new setup script as an upgrade. We will introduce
 * that later in this tutorial.
 */
$table->addColumn(
    'entity_id',
    Varien_Db_Ddl_Table::TYPE_INTEGER,
    10,
    array(
        'auto_increment' => true,
        'unsigned' => true,
        'nullable'=> false,
        'primary' => true
    )
);
$table->addColumn(
    'created_at',
    Varien_Db_Ddl_Table::TYPE_DATETIME,
    null,
    array(
        'nullable' => false,
    )
);
$table->addColumn(
    'updated_at',
    Varien_Db_Ddl_Table::TYPE_DATETIME,
    null,
    array(
        'nullable' => false,
    )
);
$table->addColumn(
    'name',
    Varien_Db_Ddl_Table::TYPE_VARCHAR,
    255,
    array(
        'nullable' => false,
    )
);
$table->addColumn(
    'url_key',
    Varien_Db_Ddl_Table::TYPE_VARCHAR,
    255,
    array(
        'nullable' => false,
    )
);
$table->addColumn(
    'description',
    Varien_Db_Ddl_Table::TYPE_TEXT,
    null,
    array(
        'nullable' => false,
    )
);
$table->addColumn(
    'visibility',
    Varien_Db_Ddl_Table::TYPE_BOOLEAN,
    null,
    array(
        'nullable' => false,
    )
);

/**
 * These two important lines are often missed.
 */
$table->setOption('type', 'InnoDB');
$table->setOption('charset', 'utf8');

/**
 * Create the table!
 */
$this->getConnection()->createTable($table);

$this->endSetup();

Inicializando nuestro módulo

En este punto, todavía no tenemos un módulo Magento activo; solo tenemos una serie de carpetas y archivos vacíos y un script de configuración de instalación que aún no hace nada. Esto es a propósito. En los siguientes pasos, completaremos el app/etc/modules Archivo XML y configurar config.xml para que Magento sepa dónde buscar nuestro script de configuración, después de lo cual la próxima visita al sitio web activará el contenido de nuestro script de configuración para que se ejecute.

Si hubiéramos realizado estas tareas al revés (es decir, configuramos el módulo primero y luego completamos el script de configuración), entonces existe la posibilidad de que Magento piense que nuestro módulo estaba en la versión 0.0.1 y que nuestro script de configuración todavía estaba vacío y, como resultado, que la secuencia de comandos efectivamente tendría que ser omitida. Entonces, para limitar los momentos de la palma de la mano para ustedes, he tratado de mantener el orden de los pasos lo más seguro posible.

Configurando nuestro módulo

Edite el archivo en app/etc/modules/SmashingMagazine_BrandDirectory.xmly agregue lo siguiente para habilitar nuestro módulo:

<?xml version="1.0"?>
<config>
    <modules>
        <SmashingMagazine_BrandDirectory>
            <active>true</active>
            <codePool>community</codePool>
        </SmashingMagazine_BrandDirectory>
    </modules>
</config>

Notarás que estamos usando el codepool de la comunidad. Este módulo BrandDirectory no contendrá ningún código o personalización específicos del cliente. En cambio, contendrá los bloques de construcción para nuestra nueva entidad, que se pueden usar en otros módulos, según el caso de uso. Por lo tanto, este módulo de comunidad puede colocarse en cualquier instancia de Magento y usarse como está, sin necesidad de cambiar ningún código. Si se requirieran cambios de código para cada uso, entonces esto sería más adecuado para el grupo de códigos local.

Ahora, le decimos a Magento que tenemos un módulo con un número de versión, que de hecho determinará qué scripts de configuración se ejecutarán y dónde encontrar los scripts de configuración. Editar etc/config.xml con lo siguiente:

<?xml version="1.0"?>
<config>
    <modules>
        <SmashingMagazine_BrandDirectory>
            <!--
            This is the version number that our module is currently at. In
            order for setup scripts to run, their version number must be less
            than or equal to this value.

            As we add upgrade scripts, we increment this value. The next time
            your Magento instance is accessed, Magento will compare values in
            the DB table 'core_resource' against this value. If the DB is
            lower, it will attempt to run any setup scripts for the module
            and then update the database table to match this value.
            -->
            <version>0.0.1</version>
        </SmashingMagazine_BrandDirectory>
    </modules>
    <global>
        <models>

            <!--
            This is the Model alias referred to in install-0.0.1.php.
            -->
            <smashingmagazine_branddirectory>

                <!--
                This tells Magento where to find
                resource materials for this module.
                -->
      <resourceModel>smashingmagazine_branddirectory_resource</resourceModel>

            </smashingmagazine_branddirectory>

            <!--
            This alias must match the above <resourceModel/> value.
            -->
            <smashingmagazine_branddirectory_resource>

                <entities>

                    <!--
                    This is the table alias referred to in install-0.0.1.php.
                    -->
                    <brand>

                        <!--
                        This is the actual name of the database table.
                        -->
                        <table>smashingmagazine_branddirectory_brand</table>

                    </brand>

                </entities>

            </smashingmagazine_branddirectory_resource>

        </models>

        <resources>

            <!--
            This must match our folder name in the module sql folder.
            -->
            <smashingmagazine_branddirectory_setup>

                <setup>

                    <!--
                    This defines which module the setup
                    scripts in this location belong to.
                    -->
                    <module>SmashingMagazine_BrandDirectory</module>

                    <!--
                    In each setup script, this
                    value determines the class of $this.
                    -->
                    <class>Mage_Core_Model_Resource_Setup</class>

                </setup>

                <!--
                This is only relevant if you have
        multiple database connections.
                -->
                <connection>
                    <use>core_setup</use>
                </connection>

            </smashingmagazine_branddirectory_setup>

        </resources>

    </global>
</config>

¿Está todo funcionando hasta ahora?

Continúe y acceda a cualquier página de su sitio web; la página de inicio servirá. Magento encontrará que tiene un nuevo módulo en la versión 0.0.1, pero no tiene registro de este módulo en el core_resource tabla de base de datos. Esta entrada faltante hará que Magento busque un script de configuración de instalación y ejecute su contenido.

Si todo va bien…

Si todo va bien, parecerá que no ha pasado nada. La página de Magento puede tardar unos minutos más en cargarse mientras se ejecuta el contenido de nuestro script de configuración (es decir, mientras se crea la nueva tabla de la base de datos), y luego la página continuará cargándose normalmente. Ahora tienes dos tareas que realizar para comprobar que todo ha ido como se esperaba:

  1. Asegúrese de que Magento conozca su módulo y que el módulo esté habilitado yendo a System → Configuration → Advanced → Advanced.
  2. Acceda a su base de datos a través de la terminal o algo como PHPMyAdmin para ver si Magento ha creado una nueva tabla, smashingmagazine_branddirectory_brand.

Si no todo va bien …

Si no todo va bien, también puede parecer que no ha pasado nada, ¡solo que esta vez no ha pasado nada! La razón de esto podría ser errores tipográficos en config.xml, carpetas o archivos mal nombrados (tenga cuidado con la distinción entre mayúsculas y minúsculas) o algo más. Siga los pasos anteriores y verifique que todo esté como debería ser.

Por otro lado, es posible que vea un mensaje de error, tal vez un «Error fatal de PHP» o una página de informe, según la gravedad del error. Use sus habilidades de depuración para identificar el problema y corregirlo, nuevamente revisando todos los pasos anteriores en este tutorial.

“Salió mal. ¿Cómo lo intento de nuevo? «

Para volver a intentarlo desde cero, puede realizar las siguientes acciones; es posible que no todas sean necesarias, dependiendo de qué tan lejos llegó Magento antes de que las cosas salieran mal. Deberá acceder a su base de datos directamente porque esto no se puede realizar a través de Magento:

  1. En el core_resource tabla, elimine la fila única smashingmagazine_branddirectory_setup.
  2. Borrar el smashingmagazine_branddirectory_brand mesa.

Creando nuestro ayudante

En realidad, no necesitamos definir ninguna funcionalidad personalizada en un asistente para este tutorial. Pero agregaremos elementos de menú al panel de administración que usan un ayudante para fines de traducción, por lo que simplemente podemos crear uno en Helper/Data.php y olvídalo.

<?php
class SmashingMagazine_BrandDirectory_Helper_Data
    extends Mage_Core_Helper_Abstract
{

}

Creando Nuestros Modelos

A continuación, necesitamos crear modelos y modelos de recursos para que podamos conservar los datos de la marca en la base de datos al crear y guardar, mostrar información sobre nuestras marcas en las cuadrículas del panel de administración de Magento y mostrar nuestras marcas al cliente en el front-end.

Modelo de marca

Necesitamos definir un modelo que permita a los desarrolladores interactuar con nuestras entidades de marca. No entraré en más detalles porque las personas más inteligentes que yo sin duda ya han explicado lo que hace un modelo, así que siéntete libre de buscar algunos artículos. Por ahora, me limitaré a hacer que nuestro modelo haga el trabajo que necesitamos para continuar con nuestro tutorial. Entonces, editar Model/Brand.php con este:

<?php
class SmashingMagazine_BrandDirectory_Model_Brand
    extends Mage_Core_Model_Abstract
{
    const VISIBILITY_HIDDEN = '0';
    const VISIBILITY_DIRECTORY = '1';

    protected function _construct()
    {
        /**
         * This tells Magento where the related resource model can be found.
         *
         * For a resource model, Magento will use the standard model alias -
         * in this case 'smashingmagazine_branddirectory' - and look in
         * config.xml for a child node <resourceModel/>. This will be the
         * location that Magento will look for a model when
         * Mage::getResourceModel() is called - in our case,
         * SmashingMagazine_BrandDirectory_Model_Resource.
         */
        $this->_init('smashingmagazine_branddirectory/brand');
    }

    /**
     * This method is used in the grid and form for populating the dropdown.
     */
    public function getAvailableVisibilies()
    {
        return array(
            self::VISIBILITY_HIDDEN
                => Mage::helper('smashingmagazine_branddirectory')
                       ->__('Hidden'),
            self::VISIBILITY_DIRECTORY
                => Mage::helper('smashingmagazine_branddirectory')
                       ->__('Visible in Directory'),
        );
    }

    protected function _beforeSave()
    {
        parent::_beforeSave();

        /**
         * Perform some actions just before a brand is saved.
         */
        $this->_updateTimestamps();
        $this->_prepareUrlKey();

        return $this;
    }

    protected function _updateTimestamps()
    {
        $timestamp = now();

        /**
         * Set the last updated timestamp.
         */
        $this->setUpdatedAt($timestamp);

        /**
         * If we have a brand new object, set the created timestamp.
         */
        if ($this->isObjectNew()) {
            $this->setCreatedAt($timestamp);
        }

        return $this;
    }

    protected function _prepareUrlKey()
    {
        /**
         * In this method, you might consider ensuring
         * that the URL Key entered is unique and
         * contains only alphanumeric characters.
         */

        return $this;
    }
}

Modelo de recursos de marca

Como en mi introducción al modelo anterior, no entraré en más detalles que decir que el trabajo del modelo de recursos es persistir y recuperar datos de la base de datos. Así que edita Model/Resource/Brand.php con este:

<?php
class SmashingMagazine_BrandDirectory_Model_Resource_Brand
    extends Mage_Core_Model_Resource_Db_Abstract
{
    protected function _construct()
    {
        /**
         * Tell Magento the database name and primary key field to persist
         * data to. Similar to the _construct() of our model, Magento finds
         * this data from config.xml by finding the <resourceModel/> node
         * and locating children of <entities/>.
         *
         * In this example:
         * - smashingmagazine_branddirectory is the model alias
         * - brand is the entity referenced in config.xml
         * - entity_id is the name of the primary key column
         *
         * As a result, Magento will write data to the table
         * 'smashingmagazine_branddirectory_brand' and any calls
         * to $model->getId() will retrieve the data from the
         * column named 'entity_id'.
         */
        $this->_init('smashingmagazine_branddirectory/brand', 'entity_id');
    }
}

Colección de recursos de marca

Finalmente, necesitamos una colección de recursos para permitir la iteración a través de nuestras marcas para cosas como las cuadrículas del panel de administración y las páginas de listas frontales. Editar Model/Resource/Brand/Collection.php con este:

<?php
class SmashingMagazine_BrandDirectory_Model_Resource_Brand_Collection
    extends Mage_Core_Model_Resource_Db_Collection_Abstract
{
    protected function _construct()
    {
        parent::_construct();

        /**
         * Tell Magento the model and resource model to use for
         * this collection. Because both aliases are the same,
         * we can omit the second paramater if we wish.
         */
        $this->_init(
            'smashingmagazine_branddirectory/brand',
            'smashingmagazine_branddirectory/brand'
        );
    }
}

Creación de nuestros bloques de administración

La mayor parte del trabajo pesado ya está hecho. Una base de datos está lista para ser poblada y los modelos y modelos de recursos están listos para poblarlos. Solo necesitamos crear la interfaz para hacerlo. Comenzaremos creando y configurando bloques de administración para mostrar nuestras marcas como cuadrículas en el panel de administración y permitir que se creen y actualicen.

Bloque contenedor de rejilla

El trabajo del contenedor de cuadrícula es albergar las filas individuales de entradas de marca que se mostrarán en el panel de administración de Magento. El contenedor de la cuadrícula es como un contenedor e incluye los botones en la parte superior derecha (por ejemplo, «Agregar»). Editar Block/Adminhtml/Brand.php con este:

<?php
class SmashingMagazine_BrandDirectory_Block_Adminhtml_Brand
    extends Mage_Adminhtml_Block_Widget_Grid_Container
{
    protected function _construct()
    {
        parent::_construct();

        /**
         * The $_blockGroup property tells Magento which alias to use to
         * locate the blocks to be displayed in this grid container.
         * In our example, this corresponds to BrandDirectory/Block/Adminhtml.
         */
        $this->_blockGroup = 'smashingmagazine_branddirectory_adminhtml';

        /**
         * $_controller is a slightly confusing name for this property.
         * This value, in fact, refers to the folder containing our
         * Grid.php and Edit.php - in our example,
         * BrandDirectory/Block/Adminhtml/Brand. So, we'll use 'brand'.
         */
        $this->_controller="brand";

        /**
         * The title of the page in the admin panel.
         */
        $this->_headerText = Mage::helper('smashingmagazine_branddirectory')
            ->__('Brand Directory');
    }

    public function getCreateUrl()
    {
        /**
         * When the "Add" button is clicked, this is where the user should
         * be redirected to - in our example, the method editAction of
         * BrandController.php in BrandDirectory module.
         */
        return $this->getUrl(
            'smashingmagazine_branddirectory_admin/brand/edit'
        );
    }
}

Bloque de cuadrícula

Al renderizar la cuadrícula, Magento esperará encontrar un bloque de cuadrícula en el _controller ubicación definida en el contenedor de la cuadrícula anterior, por lo que crearemos esto ahora. Aquí, podemos definir qué campos recuperar de la base de datos y mostrar en la cuadrícula del panel de administración, y Magento permitirá automáticamente buscar y filtrar estas columnas. Editar Block/Adminhtml/Brand/Grid.php con este:

<?php
class SmashingMagazine_BrandDirectory_Block_Adminhtml_Brand_Grid
    extends Mage_Adminhtml_Block_Widget_Grid
{
    protected function _prepareCollection()
    {
        /**
         * Tell Magento which collection to use to display in the grid.
         */
        $collection = Mage::getResourceModel(
            'smashingmagazine_branddirectory/brand_collection'
        );
        $this->setCollection($collection);

        return parent::_prepareCollection();
    }

    public function getRowUrl($row)
    {
        /**
         * When a grid row is clicked, this is where the user should
         * be redirected to - in our example, the method editAction of
         * BrandController.php in BrandDirectory module.
         */
        return $this->getUrl(
            'smashingmagazine_branddirectory_admin/brand/edit',
            array(
                'id' => $row->getId()
            )
        );
    }

    protected function _prepareColumns()
    {
        /**
         * Here, we'll define which columns to display in the grid.
         */
        $this->addColumn('entity_id', array(
            'header' => $this->_getHelper()->__('ID'),
            'type' => 'number',
            'index' => 'entity_id',
        ));

        $this->addColumn('created_at', array(
            'header' => $this->_getHelper()->__('Created'),
            'type' => 'datetime',
            'index' => 'created_at',
        ));

        $this->addColumn('updated_at', array(
            'header' => $this->_getHelper()->__('Updated'),
            'type' => 'datetime',
            'index' => 'updated_at',
        ));

        $this->addColumn('name', array(
            'header' => $this->_getHelper()->__('Name'),
            'type' => 'text',
            'index' => 'name',
        ));

        $this->addColumn('lastname', array(
            'header' => $this->_getHelper()->__('Url Key'),
            'type' => 'text',
            'index' => 'url_key',
        ));

        $brandSingleton = Mage::getSingleton(
            'smashingmagazine_branddirectory/brand'
        );
        $this->addColumn('visibility', array(
            'header' => $this->_getHelper()->__('Visibility'),
            'type' => 'options',
            'index' => 'visibility',
            'options' => $brandSingleton->getAvailableVisibilies()
        ));

        /**
         * Finally, we'll add an action column with an edit link.
         */
        $this->addColumn('action', array(
            'header' => $this->_getHelper()->__('Action'),
            'width' => '50px',
            'type' => 'action',
            'actions' => array(
                array(
                    'caption' => $this->_getHelper()->__('Edit'),
                    'url' => array(
                        'base' => 'smashingmagazine_branddirectory_admin'
                                  . '/brand/edit',
                    ),
                    'field' => 'id'
                ),
            ),
            'filter' => false,
            'sortable' => false,
            'index' => 'entity_id',
        ));

        return parent::_prepareColumns();
    }

    protected function _getHelper()
    {
        return Mage::helper('smashingmagazine_branddirectory');
    }
}

Bloque contenedor de formulario

El bloque de contenedor de formulario tiene una función similar a la del contenedor de cuadrícula, pero se usa para crear o editar una entidad. Editar Block/Adminhtml/Brand/Edit.php con este:

<?php
class SmashingMagazine_BrandDirectory_Block_Adminhtml_Brand_Edit
    extends Mage_Adminhtml_Block_Widget_Form_Container
{
    protected function _construct()
    {
        $this->_blockGroup = 'smashingmagazine_branddirectory_adminhtml';
        $this->_controller="brand";

        /**
         * The $_mode property tells Magento which folder to use
         * to locate the related form blocks to be displayed in
         * this form container. In our example, this corresponds
         * to BrandDirectory/Block/Adminhtml/Brand/Edit/.
         */
        $this->_mode="edit";

        $newOrEdit = $this->getRequest()->getParam('id')
            ? $this->__('Edit')
            : $this->__('New');
        $this->_headerText =  $newOrEdit . ' ' . $this->__('Brand');
    }
}

Bloque de formulario

En el bloque de formulario, definimos qué campos se pueden administrar al crear o editar una entidad. Editar Block/Adminhtml/Brand/Edit/Form.php con este:

<?php
class SmashingMagazine_BrandDirectory_Block_Adminhtml_Brand_Edit_Form
    extends Mage_Adminhtml_Block_Widget_Form
{
    protected function _prepareForm()
    {
        // Instantiate a new form to display our brand for editing.
        $form = new Varien_Data_Form(array(
            'id' => 'edit_form',
            'action' => $this->getUrl(
                'smashingmagazine_branddirectory_admin/brand/edit',
                array(
                    '_current' => true,
                    'continue' => 0,
                )
            ),
            'method' => 'post',
        ));
        $form->setUseContainer(true);
        $this->setForm($form);

        // Define a new fieldset. We need only one for our simple entity.
        $fieldset = $form->addFieldset(
            'general',
            array(
                'legend' => $this->__('Brand Details')
            )
        );

        $brandSingleton = Mage::getSingleton(
            'smashingmagazine_branddirectory/brand'
        );

        // Add the fields that we want to be editable.
        $this->_addFieldsToFieldset($fieldset, array(
            'name' => array(
                'label' => $this->__('Name'),
                'input' => 'text',
                'required' => true,
            ),
            'url_key' => array(
                'label' => $this->__('URL Key'),
                'input' => 'text',
                'required' => true,
            ),
            'description' => array(
                'label' => $this->__('Description'),
                'input' => 'textarea',
                'required' => true,
            ),
            'visibility' => array(
                'label' => $this->__('Visibility'),
                'input' => 'select',
                'required' => true,
                'options' => $brandSingleton->getAvailableVisibilies(),
            ),

            /**
             * Note: we have not included created_at or updated_at.
             * We will handle those fields ourself in the model
       * before saving.
             */
        ));

        return $this;
    }

    /**
     * This method makes life a little easier for us by pre-populating
     * fields with $_POST data where applicable and wrapping our post data
     * in 'brandData' so that we can easily separate all relevant information
     * in the controller. You could of course omit this method entirely
     * and call the $fieldset->addField() method directly.
     */
    protected function _addFieldsToFieldset(
        Varien_Data_Form_Element_Fieldset $fieldset, $fields)
    {
        $requestData = new Varien_Object($this->getRequest()
            ->getPost('brandData'));

        foreach ($fields as $name => $_data) {
            if ($requestValue = $requestData->getData($name)) {
                $_data['value'] = $requestValue;
            }

            // Wrap all fields with brandData group.
            $_data['name'] = "brandData[$name]";

            // Generally, label and title are always the same.
            $_data['title'] = $_data['label'];

            // If no new value exists, use the existing brand data.
            if (!array_key_exists('value', $_data)) {
                $_data['value'] = $this->_getBrand()->getData($name);
            }

            // Finally, call vanilla functionality to add field.
            $fieldset->addField($name, $_data['input'], $_data);
        }

        return $this;
    }

    /**
     * Retrieve the existing brand for pre-populating the form fields.
     * For a new brand entry, this will return an empty brand object.
     */
    protected function _getBrand()
    {
        if (!$this->hasData('brand')) {
            // This will have been set in the controller.
            $brand = Mage::registry('current_brand');

            // Just in case the controller does not register the brand.
            if (!$brand instanceof
                    SmashingMagazine_BrandDirectory_Model_Brand) {
                $brand = Mage::getModel(
                    'smashingmagazine_branddirectory/brand'
                );
            }

            $this->setData('brand', $brand);
        }

        return $this->getData('brand');
    }
}

Formulario de administrador de marca de Magento

Creación de nuestro controlador de administración

Ahora, necesitamos un controlador para aceptar solicitudes y renderizar los bloques contenedores desde arriba. El controlador también manejará POST solicitudes para crear, actualizar y eliminar marcas según sea necesario. Editar controllers/Adminhtml/BrandController.php con este:

<?php
class SmashingMagazine_BrandDirectory_Adminhtml_BrandController
    extends Mage_Adminhtml_Controller_Action
{
    /**
     * Instantiate our grid container block and add to the page content.
     * When accessing this admin index page, we will see a grid of all
     * brands currently available in our Magento instance, along with
     * a button to add a new one if we wish.
     */
    public function indexAction()
    {
        // instantiate the grid container
        $brandBlock = $this->getLayout()
            ->createBlock('smashingmagazine_branddirectory_adminhtml/brand');

        // Add the grid container as the only item on this page
        $this->loadLayout()
            ->_addContent($brandBlock)
            ->renderLayout();
    }

    /**
     * This action handles both viewing and editing existing brands.
     */
    public function editAction()
    {
        /**
         * Retrieve existing brand data if an ID was specified.
         * If not, we will have an empty brand entity ready to be populated.
         */
        $brand = Mage::getModel('smashingmagazine_branddirectory/brand');
        if ($brandId = $this->getRequest()->getParam('id', false)) {
            $brand->load($brandId);

            if ($brand->getId() _getSession()->addError(
                    $this->__('This brand no longer exists.')
                );
                return $this->_redirect(
                    'smashingmagazine_branddirectory_admin/brand/index'
                );
            }
        }

        // process $_POST data if the form was submitted
        if ($postData = $this->getRequest()->getPost('brandData')) {
            try {
                $brand->addData($postData);
                $brand->save();

                $this->_getSession()->addSuccess(
                    $this->__('The brand has been saved.')
                );

                // redirect to remove $_POST data from the request
                return $this->_redirect(
                    'smashingmagazine_branddirectory_admin/brand/edit',
                    array('id' => $brand->getId())
                );
            } catch (Exception $e) {
                Mage::logException($e);
                $this->_getSession()->addError($e->getMessage());
            }

            /**
             * If we get to here, then something went wrong. Continue to
             * render the page as before, the difference this time being
             * that the submitted $_POST data is available.
             */
        }

        // Make the current brand object available to blocks.
        Mage::register('current_brand', $brand);

        // Instantiate the form container.
        $brandEditBlock = $this->getLayout()->createBlock(
            'smashingmagazine_branddirectory_adminhtml/brand_edit'
        );

        // Add the form container as the only item on this page.
        $this->loadLayout()
            ->_addContent($brandEditBlock)
            ->renderLayout();
    }

    public function deleteAction()
    {
        $brand = Mage::getModel('smashingmagazine_branddirectory/brand');

        if ($brandId = $this->getRequest()->getParam('id', false)) {
            $brand->load($brandId);
        }

        if ($brand->getId() _getSession()->addError(
                $this->__('This brand no longer exists.')
            );
            return $this->_redirect(
                'smashingmagazine_branddirectory_admin/brand/index'
            );
        }

        try {
            $brand->delete();

            $this->_getSession()->addSuccess(
                $this->__('The brand has been deleted.')
            );
        } catch (Exception $e) {
            Mage::logException($e);
            $this->_getSession()->addError($e->getMessage());
        }

        return $this->_redirect(
            'smashingmagazine_branddirectory_admin/brand/index'
        );
    }

    /**
     * Thanks to Ben for pointing out this method was missing. Without
     * this method the ACL rules configured in adminhtml.xml are ignored.
     */
    protected function _isAllowed()
    {
        /**
         * we include this switch to demonstrate that you can add action
         * level restrictions in your ACL rules. The isAllowed() method will
         * use the ACL rule we have configured in our adminhtml.xml file:
         * - acl
         * - - resources
         * - - - admin
         * - - - - children
         * - - - - - smashingmagazine_branddirectory
         * - - - - - - children
         * - - - - - - - brand
         *
         * eg. you could add more rules inside brand for edit and delete.
         */
        $actionName = $this->getRequest()->getActionName();
        switch ($actionName) {
            case 'index':
            case 'edit':
            case 'delete':
                // intentionally no break
            default:
                $adminSession = Mage::getSingleton('admin/session');
                $isAllowed = $adminSession
                    ->isAllowed('smashingmagazine_branddirectory/brand');
                break;
        }

        return $isAllowed;
    }
}

Completando la configuración

Ese es todo el código que necesitamos para el back-end. Solo necesitamos hacer algunos cambios en config.xml para decirle a Magento dónde encontrar nuestro controlador, bloques, modelos y ayudante. También tenemos que agregar un elemento de menú al panel de administración para facilitar el acceso a la gestión de nuestra entidad de marca.

config.xml

Necesitamos agregar definiciones de bloque, ayudante y modelo a la configuración de nuestro módulo para que Magento sepa dónde ubicar estos archivos, así como un enrutador de administración para que Magento sepa dónde ubicar nuestro controlador para los elementos del menú que estamos a punto de agregar. el siguiente paso. La versión final de nuestro etc/config.xml El archivo se verá de la siguiente manera:

<?xml version="1.0"?>
<config>
    <modules>
        <SmashingMagazine_BrandDirectory>
            <!--
            This is the version number that our module is currently at.
            In order for setup scripts to run, their version number must
            be less than or equal to this value.

            As we add upgrade scripts, we increment this value. The next time
            your Magento instance is accessed, Magento will compare values in
            the database table 'core_resource' against this value. If the
            database is lower, it will attempt to run any setup scripts for
            the module and then update the database table to match this value.
            -->
            <version>0.0.1</version>
        </SmashingMagazine_BrandDirectory>
    </modules>
    <global>

        <!--
        add an adminhtml block definition
        -->
        <blocks>
            <smashingmagazine_branddirectory_adminhtml>
               <class>SmashingMagazine_BrandDirectory_Block_Adminhtml</class>
            </smashingmagazine_branddirectory_adminhtml>
        </blocks>

        <!--
        Add a helper definition for use in adminhtml.xml menu translation.
        -->
        <helpers>
            <smashingmagazine_branddirectory>
                <class>SmashingMagazine_BrandDirectory_Helper</class>
            </smashingmagazine_branddirectory>
        </helpers>

        <models>

            <!--
            This is the model alias referred to in install-0.0.1.php.
            -->
            <smashingmagazine_branddirectory>
                <!--
                This tells Magento where to find models for this module.
                -->
                <class>SmashingMagazine_BrandDirectory_Model</class>

                <!--
                This tells Magento where to find resource
                materials for this module.
                -->
      <resourceModel>smashingmagazine_branddirectory_resource</resourceModel>

            </smashingmagazine_branddirectory>

            <!--
            This alias must match the <resourceModel/> value above.
            -->
            <smashingmagazine_branddirectory_resource>
                <!--
                This tells Magento where to find resource
                models for this module.
                -->
                <class>SmashingMagazine_BrandDirectory_Model_Resource</class>

                <entities>

                    <!--
                    This is the table alias referred to in install-0.0.1.php.
                    -->
                    <brand>

                        <!--
                            This is the name of the database table itself.
                        -->
                        <table>smashingmagazine_branddirectory_brand</table>

                    </brand>

                </entities>

            </smashingmagazine_branddirectory_resource>

        </models>

        <resources>

            <!--
            This must match our folder name in the module sql folder.
            -->
            <smashingmagazine_branddirectory_setup>

                <setup>

                    <!--
                    This defines which module the setup
                    scripts in this location belong to.
                    -->
                    <module>SmashingMagazine_BrandDirectory</module>

                    <!--
                    In each setup script, this
                    value determines the class of $this.
                    -->
                    <class>Mage_Core_Model_Resource_Setup</class>

                </setup>

                <!--
                This is relevant only if you have multiple database connections.
                -->
                <connection>
                    <use>core_setup</use>
                </connection>

            </smashingmagazine_branddirectory_setup>

        </resources>

    </global>

    <!-- Add a router for access to our admin panel controller. -->
    <admin>
        <routers>

            <!-- This is the alias for this router. -->
            <smashingmagazine_branddirectory_admin>

                <!--
                This basically informs Magento to use the
                admin scope for requests to this router.
                -->
                <use>admin</use>

                <args>
                    <!--
                    This tells Magento where to find
                    adminhtml controllers for this module.
                    -->
                   <module>SmashingMagazine_BrandDirectory_Adminhtml</module>

                    <!-- This is the term used in the actual URL. -->
                    <frontName>brand-directory-admin</frontName>
                </args>

            </smashingmagazine_branddirectory_admin>

        </routers>
    </admin>

</config>

adminhtml.xml

Agregar elementos de menú al panel de administración de Magento es sencillo. Simplemente tenemos que crear un adminhtml.xml archivo, defina qué elementos deben aparecer y adónde deben conducir cuando se hace clic en ellos. Editar etc/adminhtml.xml con este:

<?xml version="1.0"?>
<config>
    <!-- We are defining a new menu item for the admin panel. -->
    <menu>

        <!--
        First, create a top-level menu item, which will appear alongside CMS
        -->
        <smashingmagazine_branddirectory translate="title"
                module="smashingmagazine_branddirectory">
            <title>Brand Directory</title>
            <sort_order>75</sort_order>
            <depends>
                <module>SmashingMagazine_BrandDirectory</module>
            </depends>

            <!-- Under this top-level menu, create a child menu item. -->
            <children>
                <brand translate="title"
                        module="smashingmagazine_branddirectory">
                    <title>Manage Brands</title>
                    <sort_order>10</sort_order>

                    <!--
                    When the menu is clicked, take the user here.
                    -->
                 <action>smashingmagazine_branddirectory_admin/brand</action>

                </brand>
            </children>
        </smashingmagazine_branddirectory>
    </menu>

    <!-- Define ACL for access to these menu items. -->
    <acl>
        <resources>
            <admin>
                <children>
                    <smashingmagazine_branddirectory translate="title"
                            module="smashingmagazine_branddirectory">
                        <title>Brand Directory</title>
                        <sort_order>75</sort_order>
                        <children>
                            <brand translate="title"
                                    module="smashingmagazine_branddirectory">
                                <title>Manage Brands</title>
                            </brand>
                        </children>
                    </smashingmagazine_branddirectory>
                </children>
            </admin>
        </resources>
    </acl>
</config>

Visualización de marcas en el front-end

Hemos llegado al final de este tutorial sobre cómo crear una entidad que se pueda administrar desde el panel de administración. A estas alturas, debería poder crear, actualizar y eliminar marcas y tener esos cambios reflejados en la base de datos. Tienes una entidad de marca en pleno funcionamiento, pero en realidad no hace nada. El siguiente paso es integrar esta nueva entidad en el resto de su código de Magento.

Vista del producto de la marca Magento

En lugar de seguir divagando sobre cómo hacer esto, he incluido en el código fuente adjunto un módulo local adicional, llamado “BrandExample”, que contiene ejemplos de cómo lograrlo.

Al inspeccionar el archivo adjunto, notará que he mantenido este ejemplo de front-end complementario como un módulo local separado, para que no se confunda con las secciones de administración del panel de administración mencionadas anteriormente. Una vez que esté más familiarizado, entonces, por supuesto, agrupe ambos módulos en uno si lo desea.

No entraré en muchos detalles con los usos de ejemplo, pero no dude en hacer cualquier pregunta en la sección de comentarios a continuación.

Lista de marcas de Magento

Vista de marca de Magento

No dude en ver o descargar el código fuente (Github), que incluye el siguiente contenido adicional:

  • el tutorial completo de arriba;
  • un nuevo atributo de producto para asociar productos con marcas;
  • inclusión de marcas en la página de visualización del producto, una vez asociadas;
  • una lista de marcas y una página de inicio de marcas, incluidos productos relacionados;
  • scripts de configuración de datos para crear marcas y productos ficticios.

Deja un comentario