Magento how to make a helper (and use it)

Creating a helper is quite easy, go on your /etc module directory and edit your config.xml file
ex : app/code/local/Adin/Epub/etc/config.xml
Add a block inside the <global> and after </blocks>

<?xml version="1.0"?>
<config>
	<modules>
		<Adin_Epub>
			<version>1.0.0</version>
		</Adin_Epub>
	</modules>
	
	<global>
		<helpers>
			<epub>
				<class>Adin_Epub_Helper</class>
			</epub>
		</helpers>
	</global>
	
</config>

Then creates the Helper folder on your module directory and create a data class :
app/code/local/Adin/Epub/Helper/Data.php

<?php
class Adin_Epub_Helper_Data extends Mage_Core_Helper_Abstract
{
    //fonction de test
    public function getTest()
    {
        return "Ceci est un test de helper";
    }	
}

If you create a new module, don’t forget to activate it, for that, in app/etc/modules directory, create or append a xml file and add your new module, for example :

<?xml version="1.0"?>
<config>
    <modules>
        <Adin_Epub>
            <active>true</active>
            <codePool>local</codePool>
        </Adin_Epub>
    </modules>
</config>

Now, for using your new helper, just instanciate it and call the function :

$helper = Mage::helper('epub');
echo $helper->getTest();

Magento : list all values of an attribute

You want to see all values of an attribute, for debug purpose or something else ?

$attr_model = Mage::getModel('catalog/resource_eav_attribute');
$attr_model->load(959); // you can find the attribute_id on the eav_attribute table
$options = $attr_model->getSource()->getAllOptions(false);
foreach($options as $value)
{
     print_r($value);
     echo "<br />";
}

You will get something like that :

Array
(
    [value] => 154
    [label] => 2008
)
Array
(
    [value] => 155
    [label] => 2009
)
Array
(
    [value] => 156
    [label] => 2010
)

Gestion des droits d’accès dans le backend de Magento

Imaginons qu’on ait une entrée de menu qui ressemble à ceci :

...
        <menu>
            <mon_module translate="title" module="adminhtml">
                <children>
                    <mon_entree>
                        <title>Le titre de mon menu</title>
                        <action>maroute/adminhtml_index</action>
                    </mon_entree>
                </children>
            </mon_module>
        </menu>
...

alors si on veut pouvoir gérer les droits d’accès via le menu permission alors il suffit d’ajouter

...
        <menu>
            <mon_menu translate="title" module="adminhtml">
                <children>
                    <mon_entree>
                        <title>Le titre de mon entrée dans le menu mon_menu</title>
                        <action>maroute/adminhtml_index</action>
                    </mon_entree>
                </children>
            </mon_menu>
        </menu>
        <acl>
            <resources>
                <admin>
                    <children>
                        <mon_menu translate="title" module="mon_module">
                            <title>Le titre du menu qui va apparaître dans les permissions</title>
                            <sort_order>100</sort_order>
                            <children>
                                <mon_entree translate="title" module="mon_module">
                                    <title>Le titre de mon entrée de menu qui va apparaître dans les permissions</title>
                                    <sort_order>10</sort_order>
                                </mon_entree>
                            </children>
                        </mon_menu>
                    </children>
                </admin>
            </resources>
        </acl>...

voilà c tout…

Left join on addAttributeToFilter with EAV tables

When you want to filter a collection with custom attribute value it works but when you want to retrieve the non-corresponding entries (like with the neq, null, not null, …. statements) it doesn’t work.

Default join on collection is an inner join so if you are doing that :

$myCollection()->addAttributeToFilter('my_attribute', array('null' => true));

.. you will find no entries

If you want to change the default inner join to a left join you just have to add ‘left’ as the third parameter of the addAttributeToFilter method :

$myCollection()->addAttributeToFilter('my_attribute', array('null' => true), 'left');

and now it works…

Here is the prototype of the corresponding method in Mage_Catalog_Model_Resource_Product_Collection :

public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')

We can see that inner parameter is used by default

Increment ID identiques sur plusieurs commandes dans Magento 1.3

Découverte de la journée … un bug dans la version 1.3 de Magento lors de forte charge de mysql…. des commandes apparaissent avec des increment id identiques

La méthode fetchNewIncrementId de la classe Furet_Eav_Model_Entity_Type qui au final permet de récupérer le nouvel increment id, génère un SELECT et un UPDATE

SELECT `eav_entity_store`.* FROM `eav_entity_store` WHERE (entity_type_id='11') AND (store_id='1')
START TRANSACTION
UPDATE `eav_entity_store` SET `entity_store_id` = '2', `entity_type_id` = '11', `store_id` = '1', `increment_prefix` = '1', `increment_last_id` = '100132298' WHERE (entity_store_id='2')
commit

On s’imagine facilement ce qu’il peut se passer si beaucoup de clients tapent à la porte du site…

Client 1 => SELECT `eav_entity_store`.* FROM `eav_entity_store` WHERE (entity_type_id='11') AND (store_id='1')

Client 2 => SELECT `eav_entity_store`.* FROM `eav_entity_store` WHERE (entity_type_id='11') AND (store_id='1')

Client 1 => START TRANSACTION
Client 1 => UPDATE `eav_entity_store` SET `entity_store_id` = '2', `entity_type_id` = '11', `store_id` = '1', `increment_prefix` = '1', `increment_last_id` = '100132298' WHERE (entity_store_id='2')
Client 1 => commit

Client 2 => START TRANSACTION
Client 2 => UPDATE `eav_entity_store` SET `entity_store_id` = '2', `entity_type_id` = '11', `store_id` = '1', `increment_prefix` = '1', `increment_last_id` = '100132298' WHERE (entity_store_id='2')
Client 2 => commit

et voilà .. 2 commandes avec le même increment id

Ce bug est corrigé dans la version 1.7 en intégrant le SELECT dans la transaction et surtout en lui ajoutant le verrou de lecture “for update”

La méthode en question (Mage_Eav_Model_Mysql4_Entity_Store)

public function loadByEntityStore(Mage_Core_Model_Abstract $object, $entityTypeId, $storeId)
{
$read = $this->_getWriteAdapter();

$select = $read->select()-&gt;from($this-&gt;getMainTable())
->forUpdate(true)
->where('entity_type_id=?', $entityTypeId)
->where('store_id=?', $storeId);
$data = $read-&gt;fetchRow($select);

if (!$data) {
return false;
}

$object->setData($data);

$this->_afterLoad($object);

return true;
}

La solution pour corriger la 1.3 (même si il vaudrait mieux penser à passer à une version supérieure) :

  • Nouveau Module
  • Surchage de Mage_Eav_Model_Entity_Type->fetchNewIncrementId() pour ajouter le select dans la transaction
  • Surcharge de Mage_Eav_Model_Mysql4_Entity_Store->loadByEntityStore() pour ajouter le lock “for update”

Et voilà le rsultat

START TRANSACTION
SELECT `eav_entity_store`.* FROM `eav_entity_store` WHERE (entity_type_id='11') AND (store_id='1') FOR UPDATE
UPDATE `eav_entity_store` SET `entity_store_id` = '2', `entity_type_id` = '11', `store_id` = '1', `increment_prefix` = '1', `increment_last_id` = '100132304' WHERE (entity_store_id='2')
commit

Magento – display more than one image on page list

If you need to pull out more than one image per product in page list (list.phtml), the code below will help you.

<?php
  //get more images for product
  $product = Mage::getModel('catalog/product')->load($_product->getId());
  foreach ($product->getMediaGalleryImages() as $image) {
     echo "<img src='" . $this->helper('catalog/image')->init($this->getProduct(), 'thumbnail', $image->getFile())->resize(50) . "' />";
  }
?>