Magento modules

Les modules et extensions Magento

Extension Magento : Baobaz Automatic Orders Cancel

Baobaz - Automatic Orders CancelNous sommes fiers de vous annoncer la publication de Baobaz Automatic Orders Cancel sur Magento Connect. Il s'agit de la première extension Baobaz publiée sur Magento Connect.

Le but de cette extension est d'annuler automatiquement les vieilles commandes non payées. Il est possible de paramétrer dans le back office les statuts d'annulation ainsi que le délai avant l'annulation d'une commande.

Pour plus de détails rendez vous sur la page de l'extension : http://www.magentocommerce.com/extension/3156

Liste des bestsellers VS flat catalog dans Magento

Magento utilise par défaut le modèle EAV dans sa base de données mais il est également possible d'utiliser le flat catalog dans votre magasin. L'activation de cette option améliorera vos performances, mais peut aussi s'accompagner de problèmes lors de l'affichage de produits. L'affichage d'une liste de produits bestsellers est un bon exemple de problème que peut engendrer l'activation du flat catalog.

Une liste de bestsellers peut être construite en utilisant une collection :

$collection = Mage::getResourceModel('reports/product_collection');

$collection->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());

$collection = $this->_addProductAttributesAndPrices($collection)
    ->addOrderedQty()
    ->addStoreFilter()
    ->setOrder('ordered_qty', 'desc')
    ->setPageSize(5)
    ->setCurPage(1);

$this->setProductCollection($collection);

De cette façon, nous créons une collection de produits ordonnés selon le nombre de fois qu'un produit a été commandé. Cependant, lors de l'affichage des produits de cette collection dans une template vous verrez que certaines données (telles que le nom ou l'image) ne s'afficheront pas si le flat catalog est activé. Cela provient de la méthode addOrderedQty qui effectue une mauvaise requête. Voici la solution :

La méthode addOrderedQty appartient au module Mage/Reports. Vous trouverez son code dans le fichier Magento app/code/core/Mage/Reports/Model/Mysql4/Product/Collection.php. La partie nous intéressant se trouve à la fin de cette méthode :

$this->getSelect()
    ->joinInner(
        array('e' => $this->getProductEntityTableName()),
        "e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}"
    )
    ->group('e.entity_id')
    ->having('ordered_qty > 0');

Pour résoudre le problème de l'utilisation du flat catalog vous devez simplement réécrire la méthode en utilisant un rewrite et remplacer le code défaillant par le code suivant:

if ($this->isEnabledFlat()) {
    $this->getSelect()->joinInner(
        array('e' => $this->getResource()->getFlatTableName()),
        "e.entity_id = order_items.{$productIdFieldName}{$productTypes}"
    );
}
else {
    $this->getSelect()
        ->joinInner(
            array('e' => $this->getProductEntityTableName()),
            "e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}"
        );
}

$this->getSelect()
    ->group('e.entity_id')
    ->having('ordered_qty > 0');

De cette manière, la requête interroge la bonne table en fonction de l'activation ou non du flat catalog. Le problème est alors résolu.

Traduction par Laurent Clouet

Magento Dataflow - parsers standard et valeurs de mapping [partie 4]

Comme promis dans le post Magento Dataflow - les Adapters par défaut [Partie 2], aujourd'hui je vais écrire à propos des parsers standards et des mappers disponibles dans le module Magento DataFlow.

  1. Définition des parsers

    Les parsers servent à transformer les données provenant des adapters. L'interface du parser Mage_Dataflow_Model_Convert_Parser_Interface définie 2 méthodes obligatoires pour chaque parser : parse() et unparse(). Définir un parser dans le XML d'actions du profil est aussi simple que ça :

    <action type="dataflow/convert_parser_serialize" method="parse" />

    Comme pour les adapters, nous définissons un tag d'action avec deux attributs: type qui indique quelle classe nous voulons utiliser et method qui indique la méthode à appeler. Nous pouvons également définir le parser en lui fournissant des variables à l'intérieur de l'action tag comme vous allez le voir dans la suite de ce post.

  2. Les parsers standards

    Magento Dataflow inclus quelques parsers standards que vous pouvez trouver dans le dossier app/code/core/Dataflow/Model/Convert/Parser.

    Le plus simple des parsers standards est le parser dataflow/convert_parser_serialize (Mage_Dataflow_Model_Convert_Parser_Serialize) qui n'a besoin d'aucune variable. Il a néanmoins besoin que l'une des actions précédentes du profil d'actions initialise les données. La méthode parse() délinéarise (avec la fonction unserialize) les données contenues dans le container du profile et les remplace avec le résultat. La méthode unparse() fait le contraire, elle linéarise (avec la fonction serialize) les données contenues dans le container du remplace et les remplace avec le résultat.

    Un des parsers standards le plus utilisé est le parser dataflow/convert_parser qui permet des transformations depuis (avec la méthode parse()) ou vers (avec la méthode unparse()) un fichier CSV. Exemple de définition :

    <action type="dataflow/convert_parser_csv" method="parse">
        <var name="delimiter"><![CDATA[,]]></var>
        <var name="enclose"><![CDATA["]]></var>
        <var name="fieldnames">true</var>
        <var name="store"><![CDATA[0]]></var>
        <var name="decimal_separator"><![CDATA[.]]></var>
        <var name="adapter">catalog/convert_adapter_product</var>
        <var name="method">parse</var>
    </action>

    Ce parser nécessite que vous appeliez au préalable un adapter io (par exemple, l'adapter dataflow/convert_adapter_io afin de lire un fichier csv) afin de pouvoir utiliser la méthod parse(). Si vous désirez enregistrer des données dans un fichier CSV, vous devez faire les deux : appeler une méthode qui va définir les données dans le container du profile avant l'exécution du parser et appeler un adapter io après l'exécution du parser afin d'enregistrer les données dans un fichier.

    Les variables suivantes vont vous permettre de personnaliser le parsing du fichier csv :

    • delimiter - définit le délimiteur utilisé dans le fichier csv ; le caractère virgule (,) est utilisé par défaut
    • enclose - définit le caractère utilisé pour encapsulées les données ; valeur vide par défaut.
    • escape - définit le caractère échappatoire pour le fichier csv ; caratère \\ par défaut
    • decimal_separator - définit le caractère pour séparer les décimales
    • fieldnames - si a la valeur true, il considère que la première ligne du fichier csv contient le nom de champs ; si a la valeur false, la variable map est utilisé
    • map - définit le nom des champs pour les fichier dont la première ligne ne contient pas le nom des champs ; pour voir comment définir une map regarder la section de cet article traitant des valeurs de mapping
    • adapter - indique quel adapter doit être appelé pour chaque ligne
    • method - indique quelle méthode de l'adapter doit être appelée pour chaque ligne ; par défaut saveRow

    Toutes les variables définies dans le parser sont transmises à l'adapter. Donc, si vous avez besoin de lui transmettre quelque chose, vous pouvez tout simplement définir les variables obligatoires dans le parser.

    Le dernier des parsers standards inclus dans le module Dataflow est le parser dataflow/convert_parser_xml_excel (Mage_Dataflow_Model_Convert_Parser_Xml_Excel), qui convertit les données depuis et vers un fichier Excel xml. Exemple de définition :

    <action type="dataflow/convert_parser_xml_excel" method="unparse">
        <var name="single_sheet"><![CDATA[products]]></var>
        <var name="fieldnames">true</var>
    </action>

    Les conditions d'utilisation de ce parser sont les mêmes que pour le parser dataflow/convert_parser_csv.

    Les variables suivantes vont vous permettre de personnaliser le parsing de votre fichier Excel :

    • fieldnames - si a la valeur true, il considère que la première ligne du fichier Excel contient le nom de champs ; si a la valeur false, la variable map est utilisé
    • map - définit le nom des champs pour les fichier dont la première ligne ne contient pas le nom des champs
    • single_sheet - indique si les données analysées proviennent d'une seule feuille ou de toutes ; doit contenir le nom de la feuiller à analyser
    • adapter - indique quel adapter doit être appelé pour chaque ligne
    • method - indique quelle méthode de l'adapter doit être appelée pour chaque ligne ; par défaut saveRow
  3. Les parsers standards pour les clients et les produits

    Pour échanger les entités les plus courantes - les clients et les produits - Magento fournit aussi des parsers standards : customer/convert_parser_customer (Mage_Customer_Model_Convert_Parser_Customer) et catalog/convert_parser_product (Mage_Catalog_Model_Convert_Parser_Product). Tous deux héritent de la classe Mage_Eav_Model_Convert_Adapter_Entity.

    Étant donné que les méthodes load() des adapters retournent uniquement un tableau contenant les identifiants des entités, il est nécessaire d'utiliser les méthodes unparse() des parsers afin d'obtenir plus de données. Les deux parsers prennent ce tableau d'identifiants et pour chaque entité retrouvent les données de ces entités tout en ignorant les champs du système, les objets et les champs qui ne sont pas des attributs. Ils créent finalement un tableau associatif avec les données récoltées. Le parser de produits ajoute également les données provenant de l'objet stock associé au produit. Le parser de clients ajoute quant à lui les données provenant des adresses de livraison et de facturation et les données provenant de l'inscription à la newsletter.

    Les deux parsers d'entités ont des méthodes parse() dépréciées depuis que leur fonctionnement est maintenant principalement réalisée par les actions de parser dans les méthodes des adapters standards appelées dans le contexte du parser. Exemple d'une définition d'un parser de produits, parsant uniquement les produits depuis le magasin sélectionné :

    <action type="catalog/convert_parser_product" method="unparse">
        <var name="store"><![CDATA[1]]></var>
    </action>

  4. Les valeurs de mapping

    Le module Dataflow apporte aussi un concept de mapper - une classe avec une méthode map() responsable de lier (mapper) les champs traités les uns avec les autres. La définition d'un mapper ressemble à ça par exemple :

    <action type="dataflow/convert_mapper_column" method="map">
        <var name="map">
            <map name="category_ids"><![CDATA[categorie]]></map>
            <map name="sku"><![CDATA[reference]]></map>
            <map name="name"><![CDATA[titre]]></map>
            <map name="description"><![CDATA[description]]></map>
            <map name="price"><![CDATA[prix]]></map>
            <map name="special_price"><![CDATA[special_price]]></map>
            <map name="manufacturer"><![CDATA[marque]]></map>
        </var>
        <var name="_only_specified">true</var>
    </action>

    Nous avons encore un tag d'action avec deux attributs : type pour définir la classe du mapper et method pour définir la méthode à appeler pour faire le mapping. Le mapper dataflow/convert_mapper_column est un mapper standard que vous pouvez trouver dans le module Magento Dataflow dans le dossier app/code/core/Dataflow/Model/Mapper/. Son but est de lier un tableau vers un autre en changeant le nom et en limitant les champs dans le résultat. L'attribut name du tag map indique le nom du champ qui doit être remplacé dans le nouveau tableau. Il est remplacé par le nom se trouvant dans le contenu du tag map. Si le nom du champ n'existe pas dans le tableau d'origine, la valeur du champ dans le tableau résultat est alors nulle. La variable _only_specified indique si uniquement les champs spécifiés dans la définition de map doivent être présents dans le tableau résultat.

Cet article devrait être l'article cloturant la présentation des spécifications standards du module Dataflow et les exemples basiques de son utilisation.

Traduction par Laurent Clouet

Les commandes Magento : états et statuts

Les commandes sous Magento possèdent différents états afin de suivre leur processus (facturée, expédiée, remboursée...) au sein du Workflow de commandes. Ces états sont invisibles dans le back office de Magento. En effet ce que l'on peut voir sont les statuts des commandes et non pas leurs états.

Chaque état peut avoir un ou plusieurs statuts alors qu'un statut ne peut avoir qu'un seul état. Par défaut, le statut porte généralement le même nom que l'état, ce qui peut porter à confusion. Voici la liste des états et statuts disponibles par défaut.

Code état Nom état Code statut Nom statut
new New pending Pending
pending_payment Pending Payment pending_paypal
pending_amazon_asp
Pending PayPal
Pending Amazon Simple Pay
processing Processing processing Processing
complete Complete complete Complete
closed Closed closed Closed
canceled Canceled canceled Canceled
holded On Hold holded On Hold

Pour ajouter un nouveau statut à un état, il suffit de le déclarer dans un fichier config.xml

<config>
  ...
  <global>
    <sales>
      <order>
        <!-- Statuses declaration -->
        <statuses>
          <my_processing_status translate="label"><label>My Processing Status</label></my_status>
        </statuses>
        <!-- Linking Status to a state -->
        <states>
          <processing>
            <statuses>
              <my_processing_status/>
            </statuses>
          </processing>
        </states>
      </order>
    </sales>  
  </global>
</config>

Lorsque l'on modifie le statut d'une commande dans le code, on doit être sûr que l'état actuel accepte ce statut. Pour celà, on peut modifier en même temps l'état et le statut avec la méthode setState

$order = Mage::getModel('sales/order')->loadByIncrementId('100000001');
$state = 'processing';
$status = 'my_processing_status';
$comment = 'Changing state to Processing and status to My Processing Status';
$isCustomerNotified = false;
$order->setState($state, $status, $comment, $isCustomerNotified);
$order->save();

$statut peut aussi prendre la valeur false, afin de modifier uniquement l'état de la commande, ou true afin de modifier le statut en prenant le premier statut associé à l'état.

Vous pouvez donc désormais ajuster votre processus de gestion des commandes dans Magento.

Edit du 03/12/09 : Un post intéressant concernant le workflow des statuts de commandes a été publié sur Le blog des équipes... : Workflow des statuts de commande sur Magento.

Magento Dataflow - Optimisation des imports de produits [Partie 3]

Le module Magento Dataflow fournit en standard un adapter produits (voir Magento Dataflow - les Adapters par défaut [Partie 2]). Cependant, la solution par défaut ne suffit parfois pas et vous pouvez être amené à créer votre propre adapter pour traiter les produits de votre site Magento.

Créer son adapter n'est pas compliqué, mais si vous omettez deux lignes de code vous pourriez être désagréablement surpris des performances. Ces deux lignes devraient être insérées avant d'appeler $product->save() :

$product->setIsMassupdate(true);
$product->setExcludeUrlRewrite(true);

La première ligne définit la variable 'is_massupdate' qui peut être vérifiée par la suite afin de gagner du temps dans les actions post-traitements.
Certains observers qui scrutent l'événement catalog_product_save_after vérifient cette valeur (c'est à dire l'observer du module CatalogRule, qui saute les actions de règles de catalogue sur les produits si  $product->getIsMassupdate() renvoie  true ).

La deuxième ligne définit la variable 'exclude_url_rewrite' qui est utilisée par la méthode afterSave de Mage_Catalog_Model_Product_Attribute_Backend_Urlkey afin de vérifier si le cache de l'url réécrite du catalogue doit être rafraichi.

Ces deux lignes peuvent vous permettre de gagner quelques secondes pour chacune des lignes traitées, gardez les dans un coin de votre tête et ne les oubliez pas !

Traduction par Benjamin Bellamy

Magento Dataflow - les Adapters par défaut [Partie 2]

Le billet "Magento DataFlow - L'échange de données rendu flexible [Partie 1]" a permis d'introduire le concept global du framework d'échange de données implémenté dans Magento. Aujourd'hui nous allons voir les adapters par défaut implémentés dans le module Dataflow.

  1. Définition d'un Adapter

    Les adapters sont responsables de se connecter dans une ressource de données externe et de récupérer les données ou de sauver les données transmises dans la ressource. Pour ce faire tous les adapters implémentent l'interface Mage_Dataflow_Model_Convert_Adapter_Interface qui contient deux méthodes : load() et save(). Le concept d'échange de données introduit dans le module Dataflow utilise les adapters dans trois contextes :

    • pour lire des données depuis une ressource - en utilisant la méthode load()
    • pour sauver des données vers une ressource - en utilisant la méthode save()
    • pour traiter une ligne analysée - comme défini par les variables du parser

    Pour les deux premiers contextes d'utilisation, la définition XML ressemblera à cela :

    <action type="dataflow/convert_adapter_io" method="load">
        ...
    </action>

    L'élément "action" a deux attributs : "type" et "method". Le "type" définit quelle classe d'apdapter doit être utilisée par cette action. Il est défini par son alias. L'élément "method" définit quelle méthode de la classe de l'adapter doit être appelée. Comme précisé plus tôt, il existe deux méthodes par défaut : load et save. Les éléments fils de l'élément "action" définissent les paramètres utilisés lors de l'exécution de la méthode de l'adapter. Les paramètres sont définis comme dans l'exemple qui suit :

    <action type="dataflow/convert_adapter_io" method="load">
        <var name="type">file</var>
        <var name="path">var/import</var>
        <var name="filename"><![CDATA[products.csv]]></var>
        <var name="format"><![CDATA[csv]]></var>
    </action>

  2. Les adapter par défaut de Magento DataFlow

    Le module Magento DataFlow contient quelques classes par défaut que vous pouvez trouver dans le répertoire app/code/core/Dataflow/Model/Convert/Adapter. Toutes n'implémentent pas encore les méthodes load() et save().

    Pour une utilisation classique de lecture ou d'écriture depuis un fichier local ou distant vous utiliserez dataflow/convert_adapter_io (Mage_Dataflow_Model_Convert_Adapter_Io).

    Les variables suivantes vous permettrons de définir les fichiers locaux/distants comme sources de données :

    • type - définit le type de source à traiter. Valeurs acceptées : file, ftp
    • path - définit le chemin relatif du fichier
    • filename - définit le nom du fichier
    • host - pour le type ftp, définit l'hôte
    • port - pour le type ftp, définit le port IP, 21 par défaut
    • user - pour le type ftp, le om de l'utisateur. Par défaut 'anonymous' et le mot de passe associé est alors 'anonymous@noserver.com'
    • password - pour le type ftp, définit le mot de passe
    • timeout - pour le type ftp, le délai maximum de connexion, 90 par défaut
    • file_mode - pour le type ftp, définit le mode de transfert, FTP_BINARY par défaut
    • ssl - pour le type ftp, utilise ssl si non vide
    • passive - pour le type ftp, définit le type de connexion, false par défaut
  3. Les adapters clients et produits catalogue

    Pour la plupart des entités échangées - client et produits - Magento fournit des adapters par défaut : customer/convert_adapter_customer (Mage_Customer_Model_Convert_Adapter_Customer) et catalog/convert_adapter_product (Mage_Catalog_Model_Convert_Adapter_Product). Les deux héritent de Mage_Eav_Model_Convert_Adapter_Entity.

    Pour charger toutes les données clients d'un magasin sélectionné, vous pouvez utiliser le code XML suivant :

    <action type="customer/convert_adapter_customer" method="load">
        <var name="store">default</var>
    </action>

    Vous aurez parfois besoin de ne pas charger tous les clients dans la base. Les variables suivantes sont disponibles à cet effet :

    • filter/firstname - charge uniquement les clients dont le prénom commence par la valeur précisée
    • filter/lastname - charge uniquement les clients dont le nom commence par la valeur précisée
    • filter/email - tcharge uniquement les clients dont l'adresse électronique commence par la valeur précisée
    • filter/group - charge uniquement les clients dont l'ID de groupe est égal à la valeur précisée
    • filter/adressType - exporte uniquement les addressType précisés; les valeurs possibles sont : both, default_billing, default_shipping
    • filter/telephone - charge uniquement les clients dont le téléphone commence par la valeur précisée
    • filter/postcode - charge uniquement les clients dont le code postal commence par la valeur précisée
    • filter/country - tcharge uniquement les clients dont le code ISO du pays est égal à la valeur précisée
    • filter/region - charge uniquement les clients dont la région est égale à la valeur précisée (2 caractères pour les états américains)
    • filter/created_at/from - charge uniquement les clients dont la date de création est postérieure à la valeur précisée
    • filter/created_at/to - charge uniquement les clients dont la date de création est antérieure à la valeur précisée

    Par exemple:

    <action type="customer/convert_adapter_customer" method="load">
        <var name="store"><![CDATA[0]]></var>
        <var name="filter/firstname"><![CDATA[a]]></var>
        <var name="filter/lastname"><![CDATA[a]]></var>
        <var name="filter/email"><![CDATA[a]]></var>
        <var name="filter/group"><![CDATA[1]]></var>
        <var name="filter/adressType"><![CDATA[default_billing]]></var>
        <var name="filter/telephone"><![CDATA[1]]></var>
        <var name="filter/postcode"><![CDATA[7]]></var>
        <var name="filter/country"><![CDATA[BS]]></var>
        <var name="filter/region"><![CDATA[WA]]></var>
        <var name="filter/created_at/from"><![CDATA[09/22/09]]></var>
        <var name="filter/created_at/to"><![CDATA[09/24/09]]></var>
    </action>

    De la même manière vous pouvez charger et filtrer les produits catalogue dans la base avec les variables suivantes :

    • filter/name - charge les produits dont le nom commence par la valeur précisée
    • filter/sku - charge les produits dont le SKU commence par la valeur précisée
    • filter/type - charge les produits dont le type est la valeur précisée; Les valeurs possible sont : simple, configurable, grouped, bundle, virtual, downloadable
    • filter/attribute_set - charge les produits dont l'ID de jeu d'attribut est la valeur précisée
    • filter/price/from - charge les produits dont le prix est supérieur à la valeur précisée
    • filter/price/to - charge les produits dont le prix est inférieur à la valeur précisée
    • filter/qty/from - charge les produits dont le stock est supérieur à la valeur précisée
    • filter/qty/to - charge les produits dont le stock est inférieur à la valeur précisée
    • filter/visibility - charge les produits dont l'ID de visibilité est égal à la valeur précisée
    • filter/status - charge les produits dont le statut est égal à la valeur précisée

    Par exemple :

    <action type="catalog/convert_adapter_product" method="load">
        <var name="store"><![CDATA[0]]></var>
        <var name="filter/name"><![CDATA[a]]></var>
        <var name="filter/sku"><![CDATA[1]]></var>
        <var name="filter/type"><![CDATA[simple]]></var>
        <var name="filter/attribute_set"><![CDATA[29]]></var>
        <var name="filter/price/from"><![CDATA[1]]></var>
        <var name="filter/price/to"><![CDATA[2]]></var>
        <var name="filter/qty/from"><![CDATA[1]]></var>
        <var name="filter/qty/to"><![CDATA[2]]></var>
        <var name="filter/visibility"><![CDATA[2]]></var>
        <var name="filter/status"><![CDATA[1]]></var>
    </action>

Il peut sembler rébarbatif de voir tous ces ID de valeurs que vous avez à fournir pour les filtres. Heureusement pour ces deux entités - clients et produits - il existe un assistant qui vous permet de générer ces filtres avec de simples boites de sélection.

Dans une prochaine partie, nous verrons comment utiliser parsers et adapters dans la contexte de parsers.

Traduction par Benjamin Bellamy

eZ Gento, une alternative au module CMS de Magento : traduction de contenu [Partie 2]

La gestion de contenu sous forme d'arborescence avec eZ-Gento est une avancée majeure, mais ce n'est qu'une infime partie des nouveautés devenues possibles...

Connaissez-vous la notion de "vue magasin" (store view) de Magento qui permet, entre autres, l'ajout de plusieurs langues à un même site e-commerce ?
En effet, des clients étrangés peuvent être amenés à visiter votre site Magento et les perdre sous prétexte qu'il ne comprennent pas la langue du site serait dommage... C'est pourquoi il est possible de créer plusieurs vues magasin et attribuer une langue différente à chacune.

Magento permet également de dupliquer des pages ou des blocs de contenus CMS et d'avoir ainsi une copie pour chaque vue magasin (et donc pour chaque langue).
Mais dans le cas d'un multilingue conséquent, avoir tant de pages avec un même identifiant peut devenir complexe et peu pratique pour les mises à jour.

Maintenant, tout est plus facile avec ez Gento et son mapping automatique entre la vue magasin Magento et les siteaccesses eZ Publish. En pratique, lorsque l'on accède à la vue magasin française, le siteaccess français eZ Publish sera appelé pour afficher son contenu. Ainsi, si la page demandée possède une traduction française, elle sera affichée.

Pour rappel, il existe deux manières principales de définir des traductions de contenus dans eZ Publish :

  • La première est l'ajout d'une traduction à une page existante. Ainsi, une arborescence unique contient des pages avec deux (ou plus) traductions.
  • La seconde est de définir autant d'arbre que de langues. (Ce qui est pratique lorsqu'on ne souhaite pas se donner de limite ou lorsqu'on veut étendre le site par rapport au contenu du site initial.)

Bien sur, il est possible de mélanger les deux méthodes et d'ajouter seulement quelques pages à la nouvelle langue, ou de simplement ne pas traduire certaines d'entre elles.

Quant à l'accessibilité des URLs, eZ Publish est muni d'un outil complet de réécriture : à chaque langue sa propre URL. Par défault, elle est créée à partir du titre de la page, mais il est également possible de la rendre paramétrable et de la définir manuellement pour chaque page.

Pour en savoir plus sur les fonctionnalités multilingue, n'hésitez pas à consulter la page de documentation d'eZ Publish.

Tout ce qu'il est possible de faire avec eZ Publish est maintenant disponible dans Magento grace à eZ Gento !

eZ Gento

Magento DataFlow - L'échange de données rendu flexible [Partie 1]

Une des fonctionnalités principales des solutions e-Commerce est la possibilité de partager des données avec les systèmes de gestion de ventes offline. Magento rend les échanges de données flexibles et relativement simples grâce au module DataFlow (flux de données).

Le module DataFlow est un framework d'échange de données qui recourt à quatre types de composants :

  • l'adapter (adaptateur),
  • le parser (analyseur),
  • le mapper (mise en relation)
  • et le validator (validateur).

Dans l'état actuel des développement, les validators ne sont pas implémentés, mais réservés pour une utilisation future.

Le process du module DataFlow est défini dans un fichier XML appelé profile. Magento fournit un assistant pour générer des profiles d'import/export basiques opérant sur les données produits (catalogue) ou les données clients. Un outil de gestion avancé de profiles est également mis à disposition des utilisateurs confirmés qui souhaitent créer le fichier XML du profile

  • sans passer par l'assistant,
  • et/ou pour créer des opérations de flux de données (DataFlow) plus personnalisées qui requièrent des relations avec d'autres entités.

Les Adapters sont responsables de la connexion à une ressource externe de données, de récupérer les données demandées et filtrées.
Cela peut être utilisé par exemple pour récupérer des données depuis :

  • un fichier local ou distant,
  • un web service,
  • une base de données,
  • et caetera.

Par exemple, pour lire des données depuis un fichier CSV vous pouvez mettre le code suivant dans votre fichier XML :

<action type="dataflow/convert_adapter_io" method="load">
    <var name="type">file</var>
    <var name="path">var/import</var>
    <var name="filename"><![CDATA[products.csv]]></var>
    <var name="format"><![CDATA[csv]]></var>
</action>

Pour lire des données depuis un serveur FTP distant vous pouvez utiliser le meme adapter, mais avec les paramètres suivants :

<action type="dataflow/convert_adapter_io" method="load">
    <var name="type">ftp</var>
    <var name="host"><![CDATA[ftp.server.com]]></var>
    <var name="passive">true</var>
    <var name="user"><![CDATA[user]]></var>
    <var name="password"><![CDATA[password]]></var>
    <var name="path">var/import</var>
    <var name="filename"><![CDATA[products.csv]]></var>
    <var name="format"><![CDATA[csv]]></var>
</action>

Les parsers sont responsables de transformer un format de données en un autre. Il peuvent par exemple être utilisés pour convertir le contenu d'un fichier CSV dans un tableau à deux dimensions, ou l'inverse.

Pour parser le contenu d'un fichier CSV dans l'entité produitde la base de données, vous pouvez utiliser le code suivant dans votre profile :

<action type="dataflow/convert_parser_csv" method="parse">
    <var name="delimiter"><![CDATA[,]]></var>
    <var name="enclose"><![CDATA["]]></var>
    <var name="fieldnames">true</var>
    <var name="store"><![CDATA[0]]></var>
    <var name="number_of_records">1</var>
    <var name="decimal_separator"><![CDATA[.]]></var>
    <var name="adapter">catalog/convert_adapter_product</var>
    <var name="method">parse</var>
</action>

L'adapter défini au sein des attributs du parser comme <var name="adapter"> et la méthode de l'adapter <var name="method"> sont responsables de l'analyse (parsing) des données lues. Dans ce cas de figure le parser convertit les données du fichier CSV vers un tableau à deux dimensions et appelle la méthode de l'adapter appelée "parse" pour les traiter.

Le moyen le plus simple de personnaliser l'import est de créer son propre adapter et de le préciser dans la déclaration du parser.
Dans la plupart des cas vous aurez besoin de partir d'un adapter existant et de modifier ou de créer votre méthode d'analyse (parsing).

Les Mappers sont responsables de transformer les valeurs des données. Ceci est utile pour faire correspondre un champ à un autre.

Dans l'exemple ci-dessous, la colonne source 'reference' est mappée dans la colonne 'sku' et la variable '_only_specified' est définie à 'true' :

<action type="dataflow/convert_mapper_column" method="map">
    <var name="map">
        <map name="sku"><![CDATA[reference]]></map>
        <map name="name"><![CDATA[name]]></map>
        <map name="price"><![CDATA[price]]></map>
        <map name="qty"><![CDATA[qty]]></map>
    </var>
    <var name="_only_specified">true</var>
</action>

Tout ceci n'est que la partie émergée de l'icerberg des possibilités que le module DataFlow de Magento permet.

Revenez plus tard pour en savoir plus !

Traduction par Benjamin Bellamy

Tutoriel - Développer un module pour Magento - Où commencer ? [Partie 1]

Avez-vous déjà lu la liste complète des fonctionnalités que Magento propose en standard ? Elle est énorme. Et cela devient encore plus impressionnant lorsque vous regardez sur Magento Connect et toutes les extensions qui s'y trouvent.
Cependant, si vous êtes en train de lire ce billet, vous êtes probablement à la recherche de quelque chose qui n'est pas encore disponible.
Ou alors vous êtes un développeur qui aime juste mettre les mains dans le cambouis.
Dans un cas comme dans l'autre, que cela soit pour des raisons de business ou par esprit hacker, developper un module Magento est fun.

Mettons en place quelque chose de vraiment vraiment simple. Le module.
Vous vous demandez ce que ce sacré module va faire. Et bien dans ce premier épisode il ne va absolument rien faire, rien d'autre que d'être déclaré dans votre site Magento !

Où commencer?

Jetez un œil aux répertoires de votre installation de Magento. Dans app > code > local,
créez un répertoire, qui sera un peu le conteneur de vos modules, dans Magento on l'appelle en général pool de code (code pool). Si vous ne savez pas comment le nommer, le nom de la société pour laquelle vous travaillez est en général une bonne option. Ça l'est dans mon cas. ;-)

Ainsi, créons le :

$ cd app/code/local/
$ mkdir Baobaz

Là, dans ce conteneur, nous devrions créer le module. Dans le cadre de ce blog appelons-le "Reader" (dans les épisodes suivants le choix de ce nom devrait se clarifier, si tel n'est pas le cas... eh bien... ça sonne toujours bien ! ;-) )

$ cd Baobaz
$ mkdir Reader

Jusque là, tout va bien. L'étape suivante est un peu plus complexe mais toujours relativement simple. Changeons de répertoire...

$ cd ../../../etc/modules/

Euh... où sommes-nous ?

$ pwd /Your/favorite/place/for/web/projects/magento/app/etc/modules/

Maintenant, vous devez avertir Magento de l'existence de votre module. Pour ce faire vous allez devoir créer un fichier XML. Lancez votre éditeur favori et créez un fichier nommé Baobaz_Reader.xml (comme vous avez sûrement deviné, le nom est formé sur le schéma <nom_du_conteneur>_<nom_du_module>.xml

$ vi Baobaz_Reader.xml

Maintenant collez ceci dans le fichier :

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

Sauvez le fichier. Et voilà ! That's one small step for a man, one giant leap for man...gento. :-)

Afin d'être sûr que Magento ait bien pris en compte votre module, rendez-vous sur le panneau d'administration. Allez sur System > Configuration, sélectionnez Advanced.

Vous devriez voir Baobaz_Reader en haut (ou quelque part par là) de la liste "Disable modules output".

OK, OK, OK... Je reconnais que notre module ne réalise rien pour le moment mais soyez patient, dans les épisodes suivants nous ajouterons des fonctionnalités plus utiles.

À suivre...

Traduction par Benjamin Bellamy

Magento : Le bloc "product_type_data"

Comme chacun le sait, Magento est extensible de façon modulaire, et il est possible de construire de nouvelle fonctionnalités assez aisément tout en se reposant sur de l'existant.

Ainsi, il est relativement simple de composer dans un nouveau module Magento une page réutilisant plusieurs block standards, par le biais, par exemple, d'un nouveau contrôleur. Prenons l'exemple d'une fonctionnalité de "Quicklook", c'est à dire un aperçu d'un produit permettant de l'intégrer au panier rapidement via des requêtes Ajax.

La logique est donc assez différente de la page produit standard, toutefois, certains éléments de celle-ci pourraient néanmoins figurer sur notre aperçu, afin de factoriser le plus de choses possibles, notament le block permettant la sélection des options.

Or, un site Magento peut être pourvu d'un catalogue comportant des produits de natures différentes : des produits simples, des produits configurables, des produits groupés, etc.. On s'attend donc à devoir contrôler le type du produit afin de pouvoir importer le block correspondant. Toutefois, si l'on jette un oeil au template de la vue produit standard ("catalog/product/view.phtml"), on peut remarquer qu'en lieu et place de tout celà, on trouve un simple :

$this->getChildHtml('product_type_data');

Intéressant ! Ce block ferait tout le travail à notre place ?

C'est effectivement le but, mais tout n'est pas si simple : ce block est introuvable dans le design par défaut, et son utilisation au sein d'un template executé via le contrôleur fourni dans un module autre que "catalog" ne fonctionne pas. Bon nombre de questions fusent à ce sujet dans les différents forums communautaires, et des solutions de contournement sont bien souvent utilisées, comme par exemple, inclure directement le block "configurable", ce qui est génant pour supporter les différents types de produits possibles.

La raison : le layout correspondant au module ne donne aucune indication sur le block "product_type_data". Si l'on observe le layout de catalog (catalog.xml), on trouve ceci :

<PRODUCT_TYPE_simple>
        <reference name="product.info">
                <block type="catalog/product_view_type_simple" name="product.info.simple" as="product_type_data" template="catalog/product/view/type/simple.phtml"/>
        </reference>
</PRODUCT_TYPE_simple>
<PRODUCT_TYPE_gift>
        <reference name="content.info">
                <block type="catalog/product_view" name="product.info" template="catalog/product/giftview.phtml" />
                <block type="catalog/product_view" name="product.info.preview" as="preview" template="catalog/product/view/preview.phtml"/>
        </reference>
</PRODUCT_TYPE_gift>
<PRODUCT_TYPE_configurable>
        <reference name="product.info">
                <block type="catalog/product_view_type_configurable" name="product.info.configurable" as="product_type_data" template="catalog/product/view/type/configurable.phtml"/>
        </reference>
</PRODUCT_TYPE_configurable>
<PRODUCT_TYPE_grouped>
        <reference name="product.info">
                <block type="catalog/product_view_type_grouped" name="product.info.grouped" as="product_type_data" template="catalog/product/view/type/grouped.phtml"/>
        </reference>
</PRODUCT_TYPE_grouped>

Ces quelques blocks XML définissent des "handles" customs, comparables à ceux qu'utilisent automatiquement les actions d'un contrôleur. On a donc un "handle" par type de produit, présentant chacun un block appelable via l'alias "product_type_data" mais fixant chacun un template adapté pour la mise en forme du contenu de ce block selon le type du produit.

Dernier problème : contrairement aux handles liés aux actions, qui sont automatiquements associés grace à une convention de nommage, ces handles supplémentaires ne seront pas interpretés. Comment donc se fait-il que cela fonctionne pour le module Catalog ?

Pour le comprendre, jettons un oeil au contrôleur principalement interessé, le ProductController ("/app/code/core/Mage/Catalog/controllers/ProductController.php"). Ce controller est généralement sollicité via l'action "view", c'est donc la méthode viewAction qui va nous interesser.

Dans celle ci, on va pouvoir trouver un appel à la méthode _initProductLayout, avec le produit passé en paramètre (ligne 125). Et dans l'implémentation de cette dernière, on trouve enfin ce qui nous interesse vers la ligne 94 :

$update->addHandle('PRODUCT_TYPE_'.$product->getTypeId());

Cette ligne déclare donc un handle supplémentaire dont le nom dépend du type du produit. Cela signifie que parmi tous les handles qui figurent dans le layout catalog.xml, on en interprètera qu'un : celui qui correspond au type du produit.

Voilà comment le block alias "product_type_data" est construit de façon à pointer vers un et un seul block adapté au type du produit à utiliser.

Vous pouvez donc reproduire ce principe dans vos modules spécifiques, et ainsi utiliser des inclusions génériques comme "product_type_data" dans vos templates. Pensez juste, notament, à changer le nom des handles si vous décidez d'utiliser des templates différents, ou si vous changez le block de réference, etc.. sinon vos changements risquent d'être pris en compte aussi par la fiche produit d'origine car les handlers de catalog auront été remplacés par les votres !