Prestashop 1.7 : Ajouter des champs dans le listing produit admin

A la suite de mon précédent article sur comment ajouter des champs produits dans l’administration de prestashop 1.7 : https://www.h-hennes.fr/blog/2017/10/19/prestashop-1-7-ajouter-des-champs-produit/ , nous allons à présent voir comment ajouter des champs dans le listing des produits de l’administration.

Cette page est gérée via les nouveaux controllers symfony et leur fonctionnement est donc différents des autres listing de l’administration.

Je précise tout de suite, à date d’aujourd’hui et avec la version 1.7.2.x et inférieur il n’est pas possible de réaliser cette modification sans toucher à des fichiers « coeur » puisque la surcharge des templates symfony n’est pas encore gérée via les modules ( c’est en cours d’implémentation pour les versions suivantes, je mettrais à jour mon article en conséquence )

Pour autant la solution que je propose reste assez propre les seules lignes qui seront ajoutées le seront pour ajouter un appel de hook.

Je ne détaille pas la base de la création du module qui pourra reprendre celle de l’article sur la création des champs produits.

Le module devra implémenter les hooks suivants :

  • actionAdminProductsListingFieldsModifier (hook natif )
  • displayAdminCatalogTwigListingProductFields ( hook custom)
  • displayAdminCatalogTwigProductFilter ( hook custom )
  • displayAdminCatalogTwigProductHeader ( hook custom )

Pour l’exemple nous allons ajouter un filtre sur les marques des produits, mais la logique s’applique à n’importe quel champ.

Modification des fichiers twigs pour la création des nouveaux hooks

Les templates utilisés pour le listing des produits sont les suivants :

  • src\PrestaShopBundle\Resources\views\Admin\Product\catalog.html.twig
  • src\PrestaShopBundle\Resources\views\Admin\Product\list.html.twig

Dans catalog.html.twig :

Rajouter le code suivant :

 {# Hhennes Hook Custom pour afficher des colonnes supplémentaires #}
 {{ renderhook('displayAdminCatalogTwigProductHeader') }}

Après le code :

 <th>
 {{ "Category"|trans({}, 'Admin.Catalog.Feature') }}
 {% include 'PrestaShopBundle:Admin/Product/Include:catalog_order_carrets.html.twig' with {
 'column': 'name_category'
 } %}
 </th>

Rajouter le code suivant :

 {# Hhennes Hook Custom pour afficher des filtres supplémentaires #}
 {{ renderhook('displayAdminCatalogTwigProductFilter') }}

Après le code :

 <th>
 <input
 type="text"
 class="form-control"
 placeholder="{{ "Search category"|trans({}, 'Admin.Catalog.Help') }}"
 name="filter_column_name_category"
 value="{{ filter_column_name_category }}"
 />
 </th>

Dans list.html.twig :
Rajouter le code suivant :

 {# Hhennes Hook Custom pour afficher les nouveaux champs dans le listing #}
 {{ renderhook('displayAdminCatalogTwigListingProductFields', { 'product': product }) }}

Après le code :

 <td>
 {{ product.name_category|default('') }} 
 </td>

Affichage des nouveaux champs via les hooks du fichier twig

Nos nouveaux hooks étant maintenant créé il est temps d’ajouter nos champs via les hooks du module :

hook displayAdminCatalogTwigProductHeader : Affichage de l’entête de la colonne

 /**
 * Hook personnalisé ( non core ) pour afficher le header product
 * cf. src\PrestaShopBundle\Resources\views\Admin\Product\catalog.html.twig
 * @param type $params
 */
 public function hookDisplayAdminCatalogTwigProductHeader($params)
 {
 return $this->display(__FILE__,'views/templates/hook/displayAdminCatalogTwigProductHeader.tpl'); 
 }

Contenu du fichier displayAdminCatalogTwigProductHeader.tpl :

 <th>{l s='Manufacturer' mod='hhproduct'}</th>

 

hook displayAdminCatalogTwigProductFilter : Affichage du champ html du filtre

 /**
 * Hook personnalisé ( non core ) pour afficher le filter product
 * cf. src\PrestaShopBundle\Resources\views\Admin\Product\catalog.html.twig
 * @param type $param
 */
 public function hookDisplayAdminCatalogTwigProductFilter($params)
 {
 $manufacturers = Manufacturer::getManufacturers();
 $this->context->smarty->assign(
 [
 'filter_column_name_manufacturer' => Tools::getValue('filter_column_name_manufacturer',''),
 'manufacturers' => $manufacturers,
 ]
 );
 return $this->display(__FILE__,'views/templates/hook/displayAdminCatalogTwigProductFilter.tpl');
 }

Contenu du fichier displayAdminCatalogTwigProductFilter.tpl :

 <th>
 <select name="filter_column_name_manufacturer" data-toggle="select2">
 <option value="">{l s='Manufacturer' mod='hhproduct'}</option>
 {foreach from=$manufacturers item=manufacturer}
 <option value="{$manufacturer.id_manufacturer}" 
 {if $filter_column_name_manufacturer == $manufacturer.id_manufacturer} selected="selected"{/if}>
 {$manufacturer.name}
 </option>
 {/foreach}
 </select>
</th>

 

hook displayAdminCatalogTwigListingProductFields : Affichage de la valeur du champ pour chaque produit

 /**
 * Hook personnalisé (non core) pour afficher les informations additionnelles produits )
 * cf. src\PrestaShopBundle\Resources\views\Admin\Product\list.html.twig
 * @param type $params
 */
 public function hookDisplayAdminCatalogTwigListingProductFields($params)
 {
 $this->context->smarty->assign('product',$params['product']);
 return $this->display(__FILE__,'views/templates/hook/displayAdminCatalogTwigListingProductFields.tpl');
 }

Contenu du fichier displayAdminCatalogTwigListingProductFields.tpl :

 <td>{$product.manufacturer}</td>

 

Avec ces codes nous devrions à présent obtenir l’affichage suivant :

Prestashop produt fields

C’est bien joli mais il n’y a pas de données 😉

 

Affichage et filtrage des résultats

Pour remonter ces données la bonne nouvelle c’est que le hooks natif de prestashop 1.6 fonctionne encore !
Dans le fichier \src\Adapter\Product\AdminProductDataProvider.php, le hook actionAdminProductsListingFieldsModifier est toujours appellé.
Comme vous pouvez le voir ligne 280

 // exec legacy hook but with different parameters (retro-compat < 1.7 is broken here)
 \HookCore::exec('actionAdminProductsListingFieldsModifier', array(
 '_ps_version' => _PS_VERSION_,
 'sql_select' => &$sqlSelect,
 'sql_table' => &$sqlTable,
 'sql_where' => &$sqlWhere,
 'sql_order' => &$sqlOrder,
 'sql_limit' => &$sqlLimit,
 ));

Voici donc l’implémentation du hook dans notre module :

/**
* Modification de la requête de la liste
* @param type $params
*/
public function hookActionAdminProductsListingFieldsModifier($params)
{
/**
* Rajout du fabricant
*/
//Champ sql
$params['sql_select']['manufacturer'] = [
'table' => 'm',
'field' => 'name',
'filtering' => \PrestaShop\PrestaShop\Adapter\Admin\AbstractAdminQueryBuilder::FILTERING_LIKE_BOTH
];
//Table sql
$params['sql_table']['m'] = [
'table' => 'manufacturer',
'join' => 'LEFT JOIN',
'on' => 'p.`id_manufacturer` = m.`id_manufacturer`',
];
 
//Gestion du filtre, si un paramètre post est défini ( c'est le nom du champ dans le fichier displayAdminCatalogTwigProductFilter.tpl )
$manufacturer_filter = Tools::getValue('filter_column_name_manufacturer',false);
if ( $manufacturer_filter && $manufacturer_filter != '') {
$params['sql_where'][] .= "p.id_manufacturer =".$manufacturer_filter;
}
}

Voici donc comment rajouter et filtrer les résultats de l’attribut manufacturer 🙂

Et voici le rendu final, avec le filtre qui fonctionne :

Colonne manufacturer OK

 

 

Pas de commentaires

Magento 2 : Commande console pour supprimer les fichiers de logs et les reports

Lors de la phase de développement sous magento 2, les dossiers contenants les fichiers de logs et de reports ont tendance à augmenter rapidement et il devient difficile de s’y retrouver.
Il est possible de supprimer facilement le contenu des ces dossiers via l’explorateur de fichier ou via des commandes shell, mais cela peut être rébarbatif ou source d’erreurs ( rm -rf sur un mauvais dossier entre autre … )

Pour simplifier ces actions nous allons donc créer 2 nouvelles commandes dans la console Magento.
Ceci nous permets de constater qu’ajouter des commandes consoles sur magento 2 c’est très simple 🙂

Le module s’appellera Hhennes_Tools et sera situé dans app/code/Hhennes/Tools/

Pour initialiser le module créer le fichier etc/module.xml avec le contenu suivant

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Hhennes_Tools" setup_version="0.1.0">
    </module>
</config>

Et le fichier de registration registration.php avec le contenu suivant :

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Hhennes_Tools',
    __DIR__
);

Dans le fichier Hhennes/Tools/etc/di.xml ajoutez le contenu suivant :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandList">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="hhennes_tools_cleanreports" xsi:type="object">Hhennes\Tools\Console\Command\CleanReportsCommand</item>
                <item name="hhennes_tools_cleanlogs" xsi:type="object">Hhennes\Tools\Console\Command\CleanLogsCommand</item>
            </argument>
        </arguments>
    </type>
</config>

La logique d’ajout des commandes est situé dans ce fichier, nous ajoutons nos commandes à la liste des commandes disponible lors de l’initialisation de la classe Magento\Framework\Console\CommandList

Il ne reste plus qu’a créer les fichiers php des commandes :
Hhennes/Tools/Console/Command/CleanLogsCommand.php

<?php
 
namespace Hhennes\Tools\Console\Command;
 
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
 
class CleanLogsCommand extends Command
{
 
    /** @var DirectoryList  */
    protected $_directoryList;
 
    /**
     * CleanLogsCommand constructor.
     * @param DirectoryList $directoryList
     */
    public function __construct(DirectoryList $directoryList)
    {
        $this->_directoryList = $directoryList;
        parent::__construct();
    }
 
    public function configure()
    {
        $this->setName('dev:clean:logs')
            ->setDescription('clean logs directory');
    }
 
    /**
     * @param InputInterface $inputInterface
     * @param OutputInterface $outputInterface
     * @return bool
     */
    public function execute(InputInterface $inputInterface, OutputInterface $outputInterface)
    {
 
        if (!function_exists('exec')) {
            $outputInterface->writeln('<error>exec command should be available in order to clean log directory</error>');
        } else {
            $reportDir = $this->_directoryList->getPath(DirectoryList::VAR_DIR) . DIRECTORY_SEPARATOR . 'log';
            if (is_dir($reportDir)) {
                //Suppression du contenu du dossier des logs
                exec('rm -rf ' . $reportDir . '/*');
                $outputInterface->writeln('<info>log directory clean with success</info>');
            } else {
                $outputInterface->writeln('<error>log directory does not exists</error>');
            }
        }
        return true;
    }
 
}

Hhennes/Tools/Console/Command/CleanReportsCommand.php

<?php
 
namespace Hhennes\Tools\Console\Command;
 
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
 
class CleanReportsCommand extends Command
{
 
    /** @var DirectoryList  */
    protected $_directoryList;
 
    /**
     * CleanReportsCommand constructor.
     * @param DirectoryList $directoryList
     */
    public function __construct(DirectoryList $directoryList)
    {
        $this->_directoryList = $directoryList;
        parent::__construct();
    }
 
    public function configure()
    {
        $this->setName('dev:clean:reports')
            ->setDescription('clean reports directory');
    }
 
    /**
     * @param InputInterface $inputInterface
     * @param OutputInterface $outputInterface
     * @return bool
     */
    public function execute(InputInterface $inputInterface, OutputInterface $outputInterface)
    {
 
        if (!function_exists('exec')) {
            $outputInterface->writeln('<error>exec command should be available in order to clean report directory</error>');
        } else {
            $reportDir = $this->_directoryList->getPath(DirectoryList::VAR_DIR) . DIRECTORY_SEPARATOR . 'report';
            if (is_dir($reportDir)) {
                //Suppression du contenu des reports
                exec('rm -rf ' . $reportDir . '/*');
                $outputInterface->writeln('<info>report directory clean with success</info>');
            } else {
                $outputInterface->writeln('<error>report directory does not exists</error>');
            }
        }
        return true;
    }
 
}

Puis d’ installer le module via la commande :

php bin/magento module:enable Hhennes_Tools

Puis de lancer les updates :

php bin/magento setup:upgrade

 

Relancer la console et les nouvelles commandes sont disponibles 🙂

Magento 2 commands
Pour toutes les syntaxes n’hésitez pas à consulter la documentation de la console symfony, car c’est elle que Magento utilise 😉

Pas de commentaires

Prestashop 1.7 : Ajouter des champs produit

La nouvelle version 1.7 de Prestashop introduit de gros changements dans la gestion backoffice des fiches produits.
Cette page utilise les nouvelles méthodes symfony et tout les modules souhaitant ajouter des informations produits doivent se mettre à jour pour utiliser les nouvelles méthodes.
Comme d’habitude la documentation prestashop n’est pas exhaustive et je n’ai à date trouvé aucune information ni tutoriel sur le sujet.

Nous allons donc voir ensemble comment rajouter des nouveaux champs produits et les gérer dans l’administration avec Prestashop 1.7
Pour cela nous allons créer un module hhproduct.

Celui-ci ajoutera des nouveaux champs à notre entité produit.

  • custom_field
  • custom_field_lang
  • custom_field_lang_wysiwyg

Nous allons donc de surcharger l’objet Product afin de lui ajouter ces nouveaux champs.
Pour cela créer un fichier Product.php avec le contenu suivant dans le dossier override/classes du module.

<?php
class Product extends ProductCore {
 
    public $custom_field;
    public $custom_field_lang;
    public $custom_field_lang_wysiwyg;
 
    public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, \Context $context = null) {
        //Définition des nouveaux champs
        self::$definition['fields']['custom_field'] = [
            'type' => self::TYPE_STRING,
            'required' => false, 'size' => 255
        ];
        self::$definition['fields']['custom_field_lang']     = [
            'type' => self::TYPE_STRING,
            'lang' => true,
            'required' => false, 'size' => 255
        ];
        self::$definition['fields']['custom_field_lang_wysiwyg']     = [
            'type' => self::TYPE_HTML,
            'lang' => true,
            'required' => false,
            'validate' => 'isCleanHtml'
        ];
        parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
    }
}

lors de l’installation du module ce fichier sera automatiquement placé dans le dossier des overrides par Prestashop.

Contrairement aux autres formulaires Prestashop les hooks spécifiques d’ajout produit sont situés dans un fichier twig,s situé sur le chemin suivant :
src/PrestaShopBundle/Resources/views/Admin/Product/form.html.twig

Les hooks disponibles sont les suivants :

  • displayAdminProductsExtra
  • displayAdminProductsMainStepLeftColumnMiddle
  • displayAdminProductsMainStepLeftColumnBottom
  • displayAdminProductsMainStepRightColumnBottom
  • displayAdminProductsQuantitiesStepBottom
  • displayAdminProductsPriceStepBottom
  • displayAdminProductsOptionsStepTop
  • displayAdminProductsOptionsStepBottom

Vous pouvez voir leurs emplacements sur les captures ci-dessous.


prestashop-product-field-1

prestashop-product-field-2


prestashop-product-field-3


prestashop-product-field-4

Nous pouvons donc greffer notre module sur l’ensemble de ces hooks ou uniquement sur celui sur lequel vous souhaitez afficher vos champs.

Pour l’exemple nous utiliserons le hook AdminProductsMainStepLeftColumnMiddle
Dans cette fonction nous allons récupérer et afficher les nouvelles informations produit.

Comme vous pouvez le voir dans le fichier twig , la fonction récupère en paramètre l’identifiant du produit édité.

{{ renderhook('displayAdminProductsMainStepLeftColumnMiddle', { 'id_product': id_product }) }}

Voici le contenu de la fonction

/**
* Affichage des informations supplémentaires sur la fiche produit
* @param type $params
* @return type
*/
public function hookDisplayAdminProductsMainStepLeftColumnMiddle($params) {
$product = new Product($params['id_product']);
$languages = Language::getLanguages($active);
$this->context->smarty->assign(array(
'custom_field' => $product->custom_field,
'custom_field_lang' => $product->custom_field_lang,
'customer_field_lang_wysiwyg' => $product->custom_field_lang_wysiwyg,
'languages' => $languages,
'default_language' => $this->context->employee->id_lang,
)
);
 
return $this->display(__FILE__, 'views/templates/hook/extrafields.tpl');
}

Note : Pour l’instant je n’ai pas trouvé de helper spécifique pour générer le contenu du formulaire, nous allons donc devoir le réaliser à la main dans le fichier extrafields.tpl qui sera situé dans le dossier views/templates/hook/ du module

Voici son contenu :

<div class="m-b-1 m-t-1">
<h2>{l s='Custom Attribute from module' mod='hhproduct'}</h2>
 
<fieldset class="form-group">
<div class="col-lg-12 col-xl-4">
 
{*Champ Standard *}
<label class="form-control-label">{l s='my custom field' mod='hhproduct'}</label>
<input type="text" name="custom_field" class="form-control" {if $custom_field && $custom_field != ''}value="{$custom_field}"{/if}/>
 
{* Champ langue avec une structure particulière *}
<label class="form-control-label">{l s='my custom lang field' mod='hhproduct'}</label>
<div class="translations tabbable">
<div class="translationsFields tab-content">
{foreach from=$languages item=language }
<div class="tab-pane translation-label-{$language.iso_code} {if $default_language == $language.id_lang}active{/if}">
<input type="text" name="custom_field_lang_{$language.id_lang}" class="form-control" {if isset({$custom_field_lang[$language.id_lang]}) && {$custom_field_lang[$language.id_lang]} != ''}value="{$custom_field_lang[$language.id_lang]}"{/if}/>
</div>
{/foreach}
</div>
</div>
</div>
 
{* Champ wysiwyg avec TinyMce *}
<div class="col-lg-12 col-xl-12">
<label class="form-control-label">{l s='my custom lang field wysiwyg' mod='hhproduct'}</label>
<div class="translations tabbable">
<div class="translationsFields tab-content bordered">
{foreach from=$languages item=language }
<div class="tab-pane translation-label-{$language.iso_code} {if $default_language == $language.id_lang}active{/if}">
<textarea name="custom_field_lang_wysiwyg_{$language.id_lang}" class="autoload_rte">{if isset({$custom_field_lang_wysiwyg[$language.id_lang]}) && {$custom_field_lang_wysiwyg[$language.id_lang]} != ''}{$custom_field_lang_wysiwyg[$language.id_lang]}{/if}</textarea>
</div>
{/foreach}
</div>
</div>
</div>
 
</fieldset>
 
<div class="clearfix"></div>
</div>

Pour la gestion des langues,nous pouvons voir dans le fichier admin-dir/themes/default/js/bundle/product/form.js qu’il faut respecter une certaine structure d’affichage pour que le changement de langue soit géré.

function switchLanguage(iso_code) {
$('div.translations.tabbable > div > div.tab-pane:not(.translation-label-' + iso_code + ')').removeClass('active');
$('div.translations.tabbable > div > div.tab-pane.translation-label-' + iso_code).addClass('active');
}

Une fois notre module installé le résultat obtenu sera le suivant :

Champs produits supplémentaire prestashop 1.7

Pour finir voici le contenu complet du fichier hhproduct.php

<?php
class HhProduct extends Module {
 
     public function __construct() {
 
        $this->name = 'hhproduct';
        $this->tab = 'others';
        $this->author = 'hhennes';
        $this->version = '0.1.0';
        $this->need_instance = 0;
        $this->bootstrap = true;
 
        parent::__construct();
 
        $this->displayName = $this->l('hhproduct');
        $this->description = $this->l('add new fields to product');
        $this->ps_versions_compliancy = array('min' => '1.7.1', 'max' => _PS_VERSION_);
    }
 
   public function install() {
        if (!parent::install() || !$this->_installSql()
                //Pour les hooks suivants regarder le fichier src\PrestaShopBundle\Resources\views\Admin\Product\form.html.twig
                || ! $this->registerHook('displayAdminProductsExtra')
                || ! $this->registerHook('displayAdminProductsMainStepLeftColumnMiddle')       
        ) {
            return false;
        }
 
        return true;
    }
 
     public function uninstall() {
        return parent::uninstall() && $this->_unInstallSql();
    }
 
    /**
     * Modifications sql du module
     * @return boolean
     */
    protected function _installSql() {
        $sqlInstall = "ALTER TABLE " . _DB_PREFIX_ . "product "
                . "ADD custom_field VARCHAR(255) NULL";
        $sqlInstallLang = "ALTER TABLE " . _DB_PREFIX_ . "product_lang "
                . "ADD custom_field_lang VARCHAR(255) NULL,"
                . "ADD custom_field_lang_wysiwyg TEXT NULL";
 
        $returnSql = Db::getInstance()->execute($sqlInstall);
        $returnSqlLang = Db::getInstance()->execute($sqlInstallLang);
 
        return $returnSql && $returnSqlLang;
    }
 
    /**
     * Suppression des modification sql du module
     * @return boolean
     */
    protected function _unInstallSql() {
       $sqlInstall = "ALTER TABLE " . _DB_PREFIX_ . "product "
                . "DROP custom_field";
        $sqlInstallLang = "ALTER TABLE " . _DB_PREFIX_ . "product_lang "
                . "DROP custom_field_lang,DROP custom_field_lang_wysiwyg";
 
        $returnSql = Db::getInstance()->execute($sqlInstall);
        $returnSqlLang = Db::getInstance()->execute($sqlInstallLang);
 
        return $returnSql && $returnSqlLang;
    }
 
    public function hookDisplayAdminProductsExtra($params)
    {
 
    }
 
    /**
     * Affichage des informations supplémentaires sur la fiche produit
     * @param type $params
     * @return type
     */
    public function hookDisplayAdminProductsMainStepLeftColumnMiddle($params) {
        $product = new Product($params['id_product']);
        $languages = Language::getLanguages($active);
        $this->context->smarty->assign(array(
            'custom_field' => $product->custom_field,
            'custom_field_lang' => $product->custom_field_lang,
            'customer_field_lang_wysiwyg' => $product->custom_field_lang_wysiwyg,
            'languages' => $languages,
            'default_language' => $this->context->employee->id_lang,
            )
           );
        /** 
         * @Todo Faire marcher le champ langue
         */
        return $this->display(__FILE__, 'views/templates/hook/extrafields.tpl');
    }
}

Le processus pourra surement être amélioré lors des prochaines mise à jour de prestashop, n’hésitez pas à remonter vos astuces.

Pas de commentaires

Prestashop 1.7 : Ajouter des champs clients

La version 1.7 de prestashop apporte des changements dans la gestion des champs clients.
Cet article est une mise à jour avec  des articles suivants  qui ne fonctionnent donc plus sur prestashop 1.7

Le but de ce tutoriel va d’être d’ajouter 2 nouveaux champs à l’entité client :

  • professionnal_id => champ standard qui sera un input text
  • justificatif => champ de type file

Vous trouverez l’ensemble du code en fin d’article.

Nous allons voir la base du module qui s’appellera hhcustomer et son fonctionnement global.

Pour commencer voici le code d’initialisation, d’installation / désinstallation du module.

class HhCustomer extends Module {
 
    public function __construct() {
 
        $this->name = 'hhcustomer';
        $this->tab = 'others';
        $this->author = 'hhennes';
        $this->version = '0.1.0';
        $this->need_instance = 0;
        $this->bootstrap = true;
 
        parent::__construct();
 
        $this->displayName = $this->l('hhcustomer');
        $this->description = $this->l('add new fields to customer');
        $this->ps_versions_compliancy = array('min' => '1.7.1', 'max' => _PS_VERSION_);
    }
 
    /**
     * Installation du module
     * @return boolean
     */
    public function install() {
        if (!parent::install() 
               // Install Sql du module
                || !$this->_installSql() 
                //Hooks Admin
                || !$this->registerHook('actionAdminCustomersControllerSaveAfter') 
                || !$this->registerHook('actionAdminCustomersFormModifier')
                //Hooks Front        
                || !$this->registerHook('additionalCustomerFormFields')
                //Hooks objects 
                || !$this->registerHook('actionObjectCustomerAddAfter') 
                || !$this->registerHook('actionObjectCustomerUpdateAfter')
        ) {
            return false;
        }
 
        return true;
    }
 
    /**
     * Désinstallation du module
     * @return boolean
     */
    public function uninstall() {
        return parent::uninstall() && $this->_unInstallSql();
    }
 
    /**
     * Modifications sql du module
     * @return boolean
     */
    protected function _installSql() {
        $sqlInstall = "ALTER TABLE " . _DB_PREFIX_ . "customer "
                . "ADD professionnal_id VARCHAR(255) NULL, "
                . "ADD justificatif VARCHAR(255) NULL";
 
        return Db::getInstance()->execute($sqlInstall);
    }
 
    /**
     * Suppression des modification sql du module
     * @return boolean
     */
    protected function _unInstallSql() {
        $sqlUnInstall = "ALTER TABLE " . _DB_PREFIX_ . "customer "
                . "DROP professionnal_id,"
                . " DROP justificatif";
 
        return Db::getInstance()->execute($sqlUnInstall);
    }
}

Ce module ajoute donc 2 colonnes correspondants à nos 2 champs supplémentaires dans la table customer.
Il se greffe également sur les hooks suivants :

  • actionAdminCustomersControllerSaveAfter : Exécuté après la sauvegarde d’un client en back office
  • actionAdminCustomersFormModifier : Exécuté avant l’affichage du formulaire d’édition en back office
  • additionalCustomerFormFields : Ajout de champs supplémentaires dans le formulaire d’édition client
  • actionObjectCustomerAddAfter : Exécuté après l’ajout d’un nouveau client
  • actionObjectCustomerUpdateAfter : Exécuté après la mise à jour d’un client

Nous verrons plus loin le détails des différentes fonctions.

Il est également nécessaire de surcharger l’objet Customer et de lui ajouter ces nouveaux champs.
Pour cela créér un fichier Customer.php avec le contenu suivant dans le dossier override/classes du module.

<?php 
class Customer extends CustomerCore { 
//Nouveaux paramètres de classe 
public $professionnal_id; 
public $justificatif;
 
public function __construct($id = null) { 
//Définition du nouveau champ professionnal_id 
       self::$definition['fields']['professionnal_id'] = [ 'type' => self::TYPE_STRING,
            'required' => false, 'size' => 255
        ];
        //Définition du nouveau champ justificatif
        self::$definition['fields']['justificatif']     = [
            'type' => self::TYPE_STRING,
            'required' => false, 'size' => 255
        ];
        parent::__construct($id);
    }
}

lors de l’installation du module ce fichier sera automatiquement placé dans le dossier des override par prestashop.

 

Ajout d’un nouveau champ standard (pour le client) :

 

Le fonctionnement est très simple, ( après l’exécution des étapes précédentes ), nous utiliserons le hook AdditionalCustomerFormFields dans la fonction hookAdditionalCustomerFormFields du module.

il faut déclarer les nouveaux champs de la manière suivante :

   /**
     * Ajout d'un champ client supplémentaire en FO
     * @param type $params
     */
    public function hookAdditionalCustomerFormFields($params) {
 
        return [
                    (new FormField)
                    ->setName('professionnal_id')
                    ->setType('text')
                    ->setLabel($this->l('Professionnal id')),
                    (new FormField)
                    ->setName('justificatif_upload')
                    ->setType('file')
                    ->setLabel($this->l('document ID'))
        ];
    }

Et puis c’est tout … :), tout fonctionne très bien ensuite tant que l’attribut « name » de votre FormField correspond bien au nom du champ dans la classe et dans la base de donnée, prestashop enregistera automatiquement les nouvelles informations

 

Ajout d’un nouveau champ standard (dans l’administration ) :

 

Pour l’ajout des champs dans l’administration je ne détaille pas, vous pouvez voir le fonctionnement général dans cet article : Prestashop : Ajouter des champs dans un formulaire d’administration

Nous utlisons le hook actionAdminCustomersFormModifier pour ajouter les nouveaux champs et définir leur valeur.

/**
 * Modification du formulaire d'édition d'un client en BO
 * @param type $params
 */
public function hookActionAdminCustomersFormModifier($params) {
 
	$params['fields'][0]['form']['input'][] = [
		'type' => 'text',
		'label' => $this->l('Professionnal id'),
		'name' => 'professionnal_id',
		'class' => 'input fixed-width-xxl',
		'hint' => $this->l('Professionnal id')
	];
 
	//Définition de la valeur du champ supplémentaire
	$params['fields_value']['professionnal_id'] = $params['object']->professionnal_id;
}

Et voila l’enregistrement du nouveau champ fonctionne également dans le backoffice.
Vous vous dites sans-doute que nous n’avons pas utilisé l’ensemble des hooks énoncés plus hauts…, c’est pourquoi nous allons voir un cas particulier, l’ajout d’un champ de type file

 

Cas particulier : ajout d’un nouveau champ de type file

 

Pour les champs de type file 2 contraintes s’ajoutent par rapport aux champs standards :

  • Upload de la pièce jointe
  • Mise à jour du champ ( et aucune action si celui-ci est vide )

J’ai eut un peu de mal à trouver une solution propre pour gérer la mise à jour de cette données, mais finalement je suis passé par le contournement suivant :

Dans les formulaires , le nom du champ ajouté n’est pas celui-correspondant à la propriété de la classe.

Par exemple pour le champ « justificatif » j’ai rajouté dans les formulaires un champ « justificatif_upload »
L’assignation de la valeur au client est ensuite gérée via des hooks prestashop.

Dans l’administration :

Affichage du champ + ajout d’un champ pour gérer sa suppression

/**
* Modification du formulaire d'édition d'un client en BO
* @param type $params
*/
public function hookActionAdminCustomersFormModifier($params) {
 
$params['fields'][0]['form']['input'][] = [
'type' => 'file',
'label' => $this->l('File upload'),
'name' => 'justificatif_upload',
'hint' => $this->l('File upload field add with a module')
];
 
//Si la pièce jointe est déjà assignée on donne la possibilité de la supprimer
if ($params['object']->justificatif && $params['object']->justificatif != '') {
$fileUrl = $this->context->link->getBaseLink() . 'modules/' . $this->name . '/files/' . $params['object']->justificatif;
$params['fields'][0]['form']['input'][] = [
'type' => 'html',
'label' => $this->l('Delete justificatif'),
'name' => 'delete_justificatif',
'html_content' => '<div class="checkbox">
<p>' . $this->l('Current File') . ': <a href="' . $fileUrl . '" target="_blank">' . $params['object']->justificatif . '</a></p>
<label for="delete_justificatif">
<input type="checkbox" name="delete_justificatif" value="' . $params['object']->justificatif . '"/>
' . $this->l('Delete File ?') . '
</label>
</div>',
'hint' => $this->l('Check this to delete current justificatif')
];
}
 
}

Gestion de la suppression via le hook adminCustomersControllerSaveAfter

/**
     * Evénement après la sauvegarde du client dans le back-office
     * @param type $params
     */
    public function hookActionAdminCustomersControllerSaveAfter($params) {
 
        //Suppression du fichier actuel si défini
        if ($deletejustificatif = Tools::getValue('delete_justificatif')) {
 
            $currentFile = dirname(__FILE__) . '/files/' . $justificatif;
            if (is_file($currentFile)) {
                unlink($currentFile);
            }
 
            try {
                $params['return']->justificatif = '';
                $params['return']->save();
            } catch (Exception $ex) {
                PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
            }
        }
    }

Sur le front office :

Attention pour permettre l’envoi de fichiers via la formulaire d’inscription il faut ajouter la propriété suivante : enctype= »multipart/form-data » au formulaire de création de compte de compte dans le fichier :
themes/votre-theme/customer/__partials/customer-form.tpl

Lors de la création d’un compte client ( en front office ou via l’administration ) nous allons utiliser le hook actionObjectCustomerAddAfter via le code suivant :

/**
     * Ajout de la pièce jointe à la création du compte
     * @param type $params
     */
    public function hookActionObjectCustomerAddAfter($params) {
        //Gestion de l'upload du fichier lors de la création de compte en Front office et en BO
        if (
                $this->context->controller->php_self == 'authentication'
                || $this->context->controller instanceof AdminCustomersController
            ) {
 
            if (isset($_FILES['justificatif_upload']) && $_FILES['justificatif_upload']['name'] != "") {
                $fileUpload = $this->_uploadFile('justificatif_upload');
                //En cas d'erreur on supprime la valeur
                if ($fileUpload[0]['error'] == '0') {
                    $params['object']->justificatif = $fileUpload[0]['name'];
                    try {
                        $params['object']->save();
                    } catch (Exception $ex) {
                        PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
                    }
                }
            }
        }
    }

Celui-ci permet de n’effectuer ce traitement uniquement dans les pages de création de compte client.

Pour finir pour gérer la mise à jour du client nous utiliserons le hook : actionObjectCustomerUpdateAfter

/**
     * Action effectuée APRES la mise à jour d'un client
     * Gestion de l'upload de la pièce jointe si il y'a an une
     * @param type $params
     */
    public function hookActionObjectCustomerUpdateAfter($params) {
 
        if (
                $this->context->controller->php_self == 'identity'
                || $this->context->controller instanceof AdminCustomersController
            ) {
 
            if (isset($_FILES['justificatif_upload']) && $_FILES['justificatif_upload']['name'] != "" && !$this->context->cookie->__isset('customer_justificatif_updated')) {
 
                $fileUpload = $this->_uploadFile('justificatif_upload');
 
                //En cas d'erreur on supprime la valeur
                if ($fileUpload[0]['error'] != '0') {
                    $params['object']->justificatif = '';
                } else {
                    $params['object']->justificatif = $fileUpload[0]['name'];
                }
 
                try {
                    //Mise en place d'un flag pour éviter une boucle de redirection
                    $this->context->cookie->__set('customer_justificatif_updated', 1);
                    $params['object']->save();
                } catch (Exception $ex) {
                    PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
                }
            } else {
                $this->context->cookie->__unset('customer_justificatif_updated');
            }
        }
    }

La principale difficulté dans ce hook étant qu’il est effectué lors de la mise à jour d’un client, et que ce code génère la mise à jour d’un client…
Pour éviter les boucles infinies il est donc nécessaire de mettre en place un cookie définissant que le client a déjà été mis à jour.

Nous en avons fini avec cette problèmatique d’ajout des nouveau champs, vous pouvez voir le code complet du module ci-dessous :

<?php class HhCustomer extends Module { public function __construct() { $this->name = 'hhcustomer';
        $this->tab = 'others';
        $this->author = 'hhennes';
        $this->version = '0.1.0';
        $this->need_instance = 0;
        $this->bootstrap = true;
 
        parent::__construct();
 
        $this->displayName = $this->l('hhcustomer');
        $this->description = $this->l('add new fields to customer');
        $this->ps_versions_compliancy = array('min' => '1.7.1', 'max' => _PS_VERSION_);
    }
 
    /**
     * @return boolean
     */
    public function install() {
        if (!parent::install() || !$this->_installSql()
                //Hooks Admin
                || !$this->registerHook('actionAdminCustomersControllerSaveAfter') 
                || !$this->registerHook('actionAdminCustomersFormModifier')
                //Hooks Front        
                || !$this->registerHook('additionalCustomerFormFields')
                //Hooks objects 
                || !$this->registerHook('actionObjectCustomerAddAfter') 
                || !$this->registerHook('actionObjectCustomerUpdateAfter')
        ) {
            return false;
        }
 
        return true;
    }
 
    public function uninstall() {
        return parent::uninstall() && $this->_unInstallSql();
    }
 
    /**
     * Modifications sql du module
     * @return boolean
     */
    protected function _installSql() {
        $sqlInstall = "ALTER TABLE " . _DB_PREFIX_ . "customer "
                . "ADD professionnal_id VARCHAR(255) NULL, "
                . "ADD justificatif VARCHAR(255) NULL";
 
        return Db::getInstance()->execute($sqlInstall);
    }
 
    /**
     * Suppression des modification sql du module
     * @return boolean
     */
    protected function _unInstallSql() {
        $sqlUnInstall = "ALTER TABLE " . _DB_PREFIX_ . "customer "
                . "DROP professionnal_id,"
                . " DROP justificatif";
 
        return Db::getInstance()->execute($sqlUnInstall);
    }
 
    /**
     * Evénement après la sauvegarde du client dans le back-office
     * @param type $params
     */
    public function hookActionAdminCustomersControllerSaveAfter($params) {
 
        //Suppression du fichier actuel si défini
        if ($deletejustificatif = Tools::getValue('delete_justificatif')) {
 
            $currentFile = dirname(__FILE__) . '/files/' . $justificatif;
            if (is_file($currentFile)) {
                unlink($currentFile);
            }
 
            try {
                $params['return']->justificatif = '';
                $params['return']->save();
            } catch (Exception $ex) {
                PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
            }
        }
    }
 
    /**
     * Modification du formulaire d'édition d'un client en BO
     * @param type $params
     */
    public function hookActionAdminCustomersFormModifier($params) {
 
        $params['fields'][0]['form']['input'][] = [
            'type' => 'text',
            'label' => $this->l('Professionnal id'),
            'name' => 'professionnal_id',
            'class' => 'input fixed-width-xxl',
            'hint' => $this->l('Professionnal id')
        ];
 
        $params['fields'][0]['form']['input'][] = [
            'type' => 'file',
            'label' => $this->l('File upload'),
            'name' => 'justificatif_upload',
            'hint' => $this->l('File upload field add with a module')
        ];
 
       //Si la pièce jointe est déjà assignée on donne la possibilité de la supprimer
         if ($params['object']->justificatif && $params['object']->justificatif != '') {
           $fileUrl = $this->context->link->getBaseLink() . 'modules/' . $this->name . '/files/' . $params['object']->justificatif;
           $params['fields'][0]['form']['input'][] = [
           'type' => 'html',
           'label' => $this->l('Delete justificatif'),
           'name' => 'delete_justificatif',
           'html_content' => '<div class="checkbox">
           <p>' . $this->l('Current File') . ': <a href="' . $fileUrl . '" target="_blank">' . $params['object']->justificatif . '</a></p>
           <label for="delete_justificatif">
           <input type="checkbox" name="delete_justificatif" value="' . $params['object']->justificatif . '"/>
           ' . $this->l('Delete File ?') . '
           </label>
           </div>',
           'hint' => $this->l('Check this to delete current justificatif')
          ];
         }
 
        //Définition de la valeur du champ supplémentaire
        $params['fields_value']['professionnal_id'] = $params['object']->professionnal_id;
    }
 
    /**
     * Ajout d'un champ client supplémentaire en FO
     * @param type $params
     */
    public function hookAdditionalCustomerFormFields($params) {
 
        return [
                    (new FormField)
                    ->setName('professionnal_id')
                    ->setType('text')
                    ->setLabel($this->l('Professionnal id')),
                    (new FormField)
                    ->setName('justificatif_upload')
                    ->setType('file')
                    ->setLabel($this->l('document ID'))
        ];
    }
 
    /**
     * Ajout de la pièce jointe à la création du compte
     * @param type $params
     */
    public function hookActionObjectCustomerAddAfter($params) {
        //Gestion de l'upload du fichier lors de la création de compte en Front office et en BO
        if (
                $this->context->controller->php_self == 'authentication'
                || $this->context->controller instanceof AdminCustomersController
            ) {
 
            if (isset($_FILES['justificatif_upload']) && $_FILES['justificatif_upload']['name'] != "") {
                $fileUpload = $this->_uploadFile('justificatif_upload');
                //En cas d'erreur on supprime la valeur
                if ($fileUpload[0]['error'] == '0') {
                    $params['object']->justificatif = $fileUpload[0]['name'];
                    try {
                        $params['object']->save();
                    } catch (Exception $ex) {
                        PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
                    }
                }
            }
        }
    }
 
    /**
     * Action effectuée APRES la mise à jour d'un client
     * Gestion de l'upload de la pièce jointe si il y'a an une
     * @param type $params
     */
    public function hookActionObjectCustomerUpdateAfter($params) {
 
        if (
                $this->context->controller->php_self == 'identity'
                || $this->context->controller instanceof AdminCustomersController
            ) {
 
            if (isset($_FILES['justificatif_upload']) && $_FILES['justificatif_upload']['name'] != "" && !$this->context->cookie->__isset('customer_justificatif_updated')) {
 
                $fileUpload = $this->_uploadFile('justificatif_upload');
 
                //En cas d'erreur on supprime la valeur
                if ($fileUpload[0]['error'] != '0') {
                    $params['object']->justificatif = '';
                } else {
                    $params['object']->justificatif = $fileUpload[0]['name'];
                }
 
                try {
                    //Mise en place d'un flag pour éviter une boucle de redirection
                    $this->context->cookie->__set('customer_justificatif_updated', 1);
                    $params['object']->save();
                } catch (Exception $ex) {
                    PrestaShopLogger::addLog($this->l('Error in customer in module ' . $this->name));
                }
            } else {
                $this->context->cookie->__unset('customer_justificatif_updated');
            }
        }
    }
 
    /**
     * Envoi du fichier en Front et en back
     */
    protected function _uploadFile($index) {
        $_registration_allowed_extensions = array('txt', 'rtf', 'doc', 'docx', 'pdf', 'png', 'jpeg', 'gif', 'jpg');
        $uploader = new Uploader($index); //Renseigner ici le nom du champ input
        return $uploader->setAcceptTypes($_registration_allowed_extensions) // Définition des extensions autorisées
                        ->setCheckFileSize(Uploader::DEFAULT_MAX_SIZE) //Taille maximum des fichiers à envoyer
                        ->setSavePath(dirname(__FILE__) . '/files/') // Répertoire de destination
                        ->process(); // Traitement de l'envoi
    }
 
}
6 commentaires

Prestashop 1.7 : Créer un module de paiement

La version 1.7 de prestashop introduit des changements dans la création des modules de paiement.
De mon point de vue cela simplifie vraiment la création de modules de paiement qui deviennent faciles et rapides à coder 🙂

C’est parti pour voir cela en détails et en exemple  via la création d’un module de paiement hhPayment.

use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
 
if (!defined('_PS_VERSION_')) {
    exit;
}
 
class HhPayment extends PaymentModule
{
 
    public function __construct()
    {
        $this->author    = 'hhennes';
        $this->name      = 'hhpayment';
        $this->tab       = 'payment_gateways';
        $this->version   = '0.1.0';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('HH Payment');
        $this->description = $this->l('HH sample Payment for PS 1.7');
    }
 
    public function install()
    {
        if (!parent::install() 
            || !$this->registerHook('paymentOptions')
            || !$this->registerHook('paymentReturn')
            ) {
            return false;
        }
        return true;
    }
}

Comme vous pouvez le voir ci-dessus, le module doit toujours étendre la classe PaymentModule mais vous noterez également l’utilisation de la classe PaymentOption.
Ansi que du nouveau hook paymentOptions.
C’est dans celui-ci que se situe toute la nouveauté !

La classe PaymentOption vous permets de gérer facilement l’affichage et les actions de votre module en quelques lignes.
Le tunnel de commande a été entièrement revu dans cette version 1.7 de prestashop ( inpiré de magento 1 au passage ^^ ) , c’est plus cadré et plus propre

Voici un aperçu de l’affichage d’une méthode, ainsi que des différentes zones dans le template par défaut.
Le template utilisé étant situé dans /themes/classic/checkout/_partials/steps/payment.tpl

Prestashop paiement

 

Voici la liste des méthodes utiles sur cette classe et leur utilisation

  • setCallToActionText : Défini le texte de la méthode de paiement (1) / Obligatoire
  • setAdditionalInformation : Défini les informations additionnelles de la méthode (3) / Optionnel
  • setLogo : Défini le logo de la méthode (2) / Optionnel
  • setAction : Défini le controller à appeler pour valider le paiement (Non visible ) / Obligatoire sauf si utilisation de setForm
  • setInputs : Permets d’ajouter des champs de formulaires, idéalement de type hidden (4)  / Optionnel
  • setForm : Permets d’utiliser un formulaire spécifique au module, si utilisé , les fonctions setInputs et setAction n’ont aucun effet ( ) / Optionnel
  • setModuleName : Nom  du module ( Non visible ) / Obligatoire
  • setBinary : Défini si le module utilise un binaire pour générer le formulaire, c’est le cas pour atos par exemple, dans ce cas il faut également greffer votre module sur le hook displayPaymentByBinaries / Optionnel

 

Exemples :

voici comment créer une option de paiement de type « Chèque »

  $standardPayment = new PaymentOption();
  //Inputs supplémentaires (utilisé idéalement pour des champs cachés )
        $inputs = [
            [
                'name' => 'custom_hidden_value',
                'type' => 'hidden',
                'value' => '30'
            ],
            [
                'name' => 'id_customer',
                'type' => 'hidden',
                'value' => $this->context->customer->id,
            ],
        ];
        $standardPayment->setModuleName($this->name)
                //Logo de paiement
                ->setLogo($this->context->link->getBaseLink().'/modules/hhpayment/views/img/logo.png')
                ->setInputs($inputs)
                //->setBinary() Utilisé si une éxécution de binaire est nécessaires ( module atos par ex )
                //Texte de description
                ->setCallToActionText($this->l('Payment in x days'))
                ->setAction($this->context->link->getModuleLink($this->name, 'validation', array(), true))
                //Texte informatif supplémentaire
                ->setAdditionalInformation($this->fetch('module:hhpayment/views/templates/hook/displayPayment.tpl'));

Avec le contenu suivant dans  le tpl par exemple

  <div class="row">
 <div class="col-xs-12 col-md-12">
 <p class="payment-module-description">
 {l s='Your order will be automaticaly payed with your account.' mod='hhpayment'}
 </p>
 </div>
</div>

Un autre exemple de type « CB » qui renvoie l’utilisateur vers une api externe.

 //Variables pour paiement API
        //Variables pour paiement API
        $this->smarty->assign(
            [
                'payment_url' => Configuration::get('PAYMENT_API_URL'),
                'success_url' => Configuration::get('PAYMENT_API_URL_SUCESS'),
                'error_url' => Configuration::get('PAYMENT_API_URL_ERROR'),
                'id_cart' => $this->context->cart->id,
                'cart_total' => $this->context->cart->getOrderTotal(true,
                    Cart::BOTH),
                'id_customer' => $this->context->cart->id_customer,
            ]
        );
 
        $apiPayement = new PaymentOption();
        $apiPayement->setModuleName($this->name)
                ->setCallToActionText($this->l('HH Sample payement module (like CB )'))
                //Définition d'un formulaire personnalisé
                ->setForm($this->fetch('module:hhpayment/views/templates/hook/payment_api_form.tpl'))
                ->setAdditionalInformation($this->fetch('module:hhpayment/views/templates/hook/displayPayment.tpl'));

Avec le contenu suivant pour le formulaire :

<form method="post" action="{$payment_url}">
<div class="form-group">
{* choix du mode de carte *}
{l s='please choose your card type' mod='hhpayment'}
<div class="radio">
<label>
<input type="radio" name="cb_type" value="mastercard" id="cb_type1" checked="checked" /> Mastercard
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="cb_type" id="cb_type2" value="visa"/> Visa
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="cb_type" id="cb_type3" value="cb"/> CB
</label>
</div>
</div>
{* Informations pour l'api *}
<input type="hidden" name="success_url" value="{$success_url}" />
<input type="hidden" name="error_url" value="{$error_url}" />
<input type="hidden" name="id_cart" value="{$id_cart}" />
<input type="hidden" name="cart_total" value="{$cart_total}" />
<input type="hidden" name="id_customer" value="{$id_customer}" />
</form>

 

L’affichage du message de retour reste toujours géré via le hook paymentReturn.

/**
     * Affichage du message de confirmation de la commande
     * @param type $params
     * @return type
     */
    public function hookDisplayPaymentReturn($params) 
    {
        if (!$this->active) {
            return;
        }
 
        $this->smarty->assign(
            $this->getTemplateVars()
            );
        return $this->fetch('module:hhpayment/views/templates/hook/payment_return.tpl');
    }

Pour voir le code de démo complet vous pouvez télécharger mon module de démo, qui inclue les différents tps ainsi qu’une configuration basique dans l’administration.

hhpayment

Nous avons à présent fait le tour du fonctionnement des modules de paiement sur Prestashop 1.7 🙂

1 commentaire

Mise en place d’une réplication mysql

Dans le cadre de site à forts traffics, de la préparation d’une migration ou d’une politique de sauvegarde, il est possible de mettre en place une réplication mysql.

Nous allons voir ensemble comment mettre en place une réplication de type master / slave sur des distribution de type debian / ubuntu.

Il est possible de jouer la réplication sur autant de serveur slaves que souhaités.

Cette procédure nécessitera des redémarages de mysql

 

Préparation du serveur master.

Pour commencer il est nécessaire de créer un utilisateur mysql :

Pour plus de sécurité nous restreindrons l’accès à une ip particulière via la commande suivante a éxécuter avec un utilisateur ayant tous les droits.

CREATE USER 'my-replication-user'@'hostname-de-votre-serveur' IDENTIFIED BY 'some_pass';

Il faut ensuite ajouter à cet utilisateur les droits de réplication :

GRANT REPLICATION SLAVE ON *.* TO 'my-replication-user'@'hostname-de-votre-serveur';

Il faudra ensuite activer la conservation des fichiers de logs sur le serveur.
Pour cela il faut rajouter la configuration suivante dans le fichier /etc/mysql/my.cnf

[mysqld]
log-bin=mysql-bin
server-id=1
expire_logs_days=2

Nous conserverons les logs binaires uniquement 2 jours

Il faut également autoriser les connexion à mysql depuis l’extérieur si ce n’est pas encore le cas
Vous pouvez le visualiser via la commande suivante :

netstat -lpn | grep mysql

Il faut bien s’assurer que le serveur écoute sur 0.0.0.0

NetStat mysql

Si ce n’est pas le cas, il faut changer la valeur du paramètre bind-address dans le fichier /etc/mysql/my.cnf

bind-address = 0.0.0.0

Redémarer ensuite mysql pour prendre en compte le changement de configuration

sudo service mysql restart

Il faut ensuite faire un dump de la base de données à répliquer via la commande suivante :

mysqldump -u root -p dbname --single-transaction --master-data=1 | gzip &gt; dump-replication.sql.gz

 

Préparation du serveur slave :

Dans le fichier /etc/mysql/my.cnf rajouter un serveur id différente de celui de prod

server-id=2

Il faut ensuite créer votre base de données sur le serveur slave.
Et importer le dump précédent.

zcat dump-replication.sql.gz | mysql -u root -p dbname

Connectez vous ensuite à mysql
Exécuter ensuite la commande suivante pour configurer les information de la réplication

CHANGE MASTER TO MASTER_HOST='master-host-name-or-ip', MASTER_USER='replication-user', MASTER_PASSWORD='mypassword';

Puis de démarrer la réplication via la commande :

Start slave;

Vous pouvez ensuite voir si la réplication à démarré via la commande mysql suivante :

SHOW PROCESSLIST;

mysql show slave status

Vous pouvez voir le statut de la synchronisation via la commande

SHOW SLAVE STATUS;

Le statut de la colonne Slave_IO_State doit être à « Waiting for master to send event »
Vous pouvez également voir la colonne « Seconds_behind_master » qui devra être à 0 une fois que tout sera synchronisé.

Et voila la réplication est en place 🙂

Pas de commentaires

Prestashop : Module Dashboard

Nous allons voir en détails comment réaliser un module dashboard sur prestashop ( Ce tuto a été testé sur les dernières versions à date de PS 1.6 et PS 1.7)

La documentation officielle présente de nombreuses informations mais elle n’est pas super détaillée sur les différents type de données possibles nativement, ni sur comment traiter les graphiques.

C’est parti pour voir en détails comment les modules dashboard fonctionnent :
Le nom du module sera hh_dashmodule

Pour commencer notre module sera greffé sur les hooks suivants :

dashboardZoneTwo ( Bloc central du dashboard ) OU dashboardZoneOne ( Colonne de gauche du dashboard )
dashboardData ( Récupérations des données du dashboard)
actionAdminControllerSetMedia ( Pour ajouter le js spécifique du module.)

Le code est volontairement simplifié pour comprendre l’essentiel.

Je passe rapidement sur les hooks
actionAdminControllerSetMedia dont le code sera le suivant :

    /**
     * Ajout du js spécifique du module dans le dashboard
     */
    public function hookActionAdminControllerSetMedia()
    {
        if (get_class($this->context->controller) == 'AdminDashboardController') {
            $this->context->controller->addJs($this->_path.'views/js/'.$this->name.'.js');
        }
    }

ansi que sur le hook hookDashboardZoneTwo qui affiche uniquement un template smarty.

     /**
     * Hook Dasboard Principale
     * @return type
     */
    public function hookDashboardZoneTwo()
    {
        return $this->display(__FILE__, 'views/templates/hook/hookDashboardZoneTwo.tpl');
    }

La particularité des modules de type dashboard et que les données sont mises à jour via des scripts ajax, qui appellent le hook DashboardData des modules.

C’est donc dans cette fonction qu’il va falloir renvoyer les informations à afficher.

    /**
     * Hook de récupération des données
     * @param type $params
     */
    public function hookDashboardData($params)
    {
        /**
         * Paramètres envoyés par leur dashboard pour actualiser les stats
         */
        $from = $params['date_from'];
        $to = $params['date_to'];
 
        //Exemple de requête qui utilise les pramètres
        $customers = Db::getInstance()->executeS("SELECT DATE(date_add) AS date, COUNT(*) AS nbre "
                . "FROM " . _DB_PREFIX_ . "customer "
                . "WHERE DATE(date_add) >= '" . pSQL($from) . "' AND DATE(date_add) <= '" . pSQL($to) . "' " . "GROUP BY DATE(date_add)"); //Renvoi de tous les types de données possibles return [ 'data_value' =>
            [
                'current_time' => time(),
                'customers' => $customers,
                'sample_data' => '<strong>Test de données fixe</strong>',
            ],
            'data_table' => $this->_getSampleDataTable(),
            'data_trends' => $this->_getSampleDataTrends(),
            'data_list_small' => $this->_getSampleDataListSmall(),
            'data_chart' => $this->_getSampleDataChart(),
        ];
    }

Les plages de dates sélectionnées via le tableau de bord sont disponibles lors de l’appel comme vous pouvez le voir dans le code, et ce sont ces paramètres qui vont nous permettre de renvoyer les données adéquates

Les types de données natifs sont les suivants :

  • data_value
  • data_table
  • data_trends
  • data_list_small
  • data_chart

Nous allons voir type par type comment gérer leur affichage, qui nécessitera à la fois du code dans le fichier tpl « views/templates/hook/hookDashboardZoneTwo.tpl » et dans le fichier php

– Type data_value

Le type data_value est le plus simple, il suffit de renvoyer une valeur ( int / string ) dans le tableau
‘data_value’ du hook comme dans l’exemple ci-dessous.

return [
            'data_value' =>
            [
                'current_time' => time(),
                'sample_data' => '<strong>Test de données fixe</strong>',
            ],
];

Dans le tpl il est nécessaire de mettre le code suivant :

<div class="data_value">
{* Information remplie automatiquement par le script l'id correspond à la clé du tableau renvoyé dans data-value *}
<span id="current_time"></span>
<span id="sample_data"></span>
</div>

Le rendu sera le suivant :

Prestashop dashoard value

– Type data_table

Pour le type data_table il est nécessaire de renvoyer un tableau formaté sous la forme suivante :

return [
            'table_hh_sample_table' => [
                //Header de la table
                'header' => [
                    //Champ(s) wrapper(s) optionnel(s)
                    ['title' => 'sample_column_1','class' => 'text-left' , 'wrapper_start' => '<strong>','wrapper_stop' => '</strong>'],
                    ['title' => 'sample_column_2','class' => 'text-left'],
                    ['title' => 'sample_column_2','class' => 'text-left'],
                ],
                //Corps de la table
                'body' => [
                   [
                       //Champ wrapper optionnel
                       ['id' => 'sample_column_1','value' => 'test value', 'class' => 'text-left'],
                       ['id' => 'sample_column_2','value' => 'test value column2', 'class' => 'text-left','wrapper_start' => '<strong>','wrapper_stop' => '</strong>'],
                       ['id' => 'sample_column_3','value' => 'test value column3', 'class' => 'text-left'],
                   ],
                   [
                       ['id' => 'sample_column_1','value' => 'test value row 2', 'class' => 'text-left'],
                       ['id' => 'sample_column_2','value' => 'test value row 2 column2', 'class' => 'text-left'],
                       ['id' => 'sample_column_3','value' => 'test value row 2 column3', 'class' => 'text-left'],
                   ],
                   [
                       ['id' => 'sample_column_1','value' => 'test value row 3', 'class' => 'text-left'],
                       ['id' => 'sample_column_2','value' => 'test value row 3 column2', 'class' => 'text-left'],
                       ['id' => 'sample_column_3','value' => 'test value row 3 column3', 'class' => 'text-left'],
                   ]
                ]
            ],
        ];

Dans le tpl il est nécessaire de mettre le code suivant :

<table class="table data_table" id="table_hh_sample_table">
<thead></thead>
<tbody></tbody>
</table>

Le rendu sera le suivant :

Prestashop dashoard table

– Type data_trends

Pour le type data_trends il est nécessaire de renvoyer un tableau formatté sous la forme suivante :

 return [
            'dash_trend_sample_1' => [
                'way' => 'up',
                'value' => 3,
            ],
            'dash_trend_sample_2' => [
                'way' => 'down',
                'value' => 3,
            ]
        ];

 

Dans le tpl il est nécessaire de mettre le code suivant :

{l s='trend up' mod='hh_dashmodule'}<dd class="dash_trend"><span id="dash_trend_sample_1"></span></dd>
{l s='trend down' mod='hh_dashmodule'}<dd class="dash_trend"><span id="dash_trend_sample_2"></span></dd>

Le rendu sera le suivant :

Prestashop dashoard trends

– Type data_list_small

Pour le type data_list_small il est nécessaire de renvoyer un tableau formaté sous la forme suivante :

return [
            'dash_list_small_sample' => [
                   'key1 : ' => ' value1',
                   'key2 : ' => ' value2',
                   'key3 : ' => [ 'value1', 'value2'],
            ],
        ];

Dans le tpl il est nécessaire de mettre le code suivant :

<div class="dash_list_small">
<ul id="dash_list_small_sample1">
</ul>
</div>

Le rendu sera le suivant :

Prestashop dashoard list

– Type data_chart

Le type chart est lui plus complexe et nécessite l’ajout d’un fichier javascript spécifique au module.
Les graphiques sont générés via la librairie javascript nv3d http://nvd3.org/examples/index.html

Il est donc possible de générer l’ensemble des types de graphiques présentés par la librairie, le format de données attendu étant spécifique à chaque type de graphique, voici le principe général et comment faire à travers 2 exemples de type « line » et « bar ».
Pour tous les autres types, je vous invites à voir directement sur le site de la libairie nv3d.

Les données exportées via le php seront les suivantes :

return [
            //Graphique de type ligne
            'data_chart_sample_1' => [
                'chart_type' => 'sample_chart_line_model', //Nom de la fonction d'initialisation dans le fichier hh_dashmodule.js
                'chart_xaxis_label' => 'X axis Label',
                'chart_yaxis_label' => 'Y axis Label',
                'data' => [
                    [
                        'color' => '#7777ff',
                        'area' => true,
                        'values' => [
                            ['x' => '1', 'y' => 10],
                            ['x' => '2', 'y' => 20],
                            ['x' => '3', 'y' => 30],
                            ['x' => '4', 'y' => 60],
                        ]
                    ],
                ]
            ],
            'data_chart_sample_2' => [
                'chart_type' => 'sample_chart_bar_model', //Nom de la fonction d'initialisation dans le fichier hh_dashmodule.js
                'chart_xaxis_label' => 'X axis Label',
                'chart_yaxis_label' => 'Y axis Label',
                'data' => [
                    [
                        'values' => [
                            ['label' => '2017-09-20', 'value' => 10],
                            ['label' => '2017-09-21', 'value' => 20],
                            ['label' => '2017-09-22', 'value' => 15],
                            ['label' => '2017-09-23', 'value' => 7],
                            ['label' => '2017-09-24', 'value' => 35],
                        ]
                    ],
                ]
            ],
        ];

Dans le tpl il est nécessaire de mettre le code suivant :

  <div id="data_chart_sample_1" class="chart with-transitions">
 <svg></svg>
 </div>
 
 <p>{l s='Bar Chart' mod='hh_dashmodule'}</p>
 <div id="data_chart_sample_2" class="chart with-transitions">
 <svg></svg>
 </div>

En supplément il faut également rajouter le contenu suivant dans le fichier views/js/hh_dashmodule.js
Le point essentiel à retenir étant que les données de notre tableau sont envoyées dans la variable chart_details

/**
 * La librairie utilisée est nvd3 : pour plus d'informations => http://nvd3.org/examples/index.html
 *  documentation : https://nvd3-community.github.io/nvd3/examples/documentation.html
 */
 
/**
 * Modèle d'exemple de graphique en ligne
 * @param string widget_name
 * @param array chart_details
 * @returns chart
 */
function sample_chart_line_model(widget_name, chart_details) {
 
    nv.addGraph(function () {
        var chart = nv.models.lineChart()
                .margin({left: 100})  //Adjust chart margins to give the x-axis some breathing room.
                .useInteractiveGuideline(true)  //We want nice looking tooltips and a guideline!
                .transitionDuration(350)  //how fast do you want the lines to transition?
                .showLegend(true)       //Show the legend, allowing users to turn on/off line series.
                .showYAxis(true)        //Show the y-axis
                .showXAxis(true)        //Show the x-axis
                ;
 
        //Chart x-axis settings        
        chart.xAxis
                .axisLabel(chart_details.chart_xaxis_label)
                .tickFormat(d3.format('d'));
 
        //Chart y-axis settings        
        chart.yAxis
                .axisLabel(chart_details.chart_yaxis_label)
                .tickFormat(d3.format('d'));
 
        d3.select('#data_chart_sample_1 svg')    //Select the  element you want to render the chart in.   
                .datum(chart_details.data)         //Populate the  element with chart data...
                .call(chart);          //Finally, render the chart!
 
        //Update the chart when window resizes.
        nv.utils.windowResize(function () {
            chart.update()
        });
        return chart;
    });
}
/**
 * Modèle d'exemple de graphique en barre
 * @param string widget_name
 * @param array chart_details
 * @returns chart
 */
function sample_chart_bar_model(widget_name, chart_details) {
 
    nv.addGraph(function () {
        var chart = nv.models.discreteBarChart()
                .x(function (d) {
                    return d.label
                })    //Specify the data accessors.
                .y(function (d) {
                    return parseInt(d.value)
                })
                .staggerLabels(true)    //Too many bars and not enough room? Try staggering labels.
                .tooltips(false)        //Don't show tooltips
                .showValues(true)       //...instead, show the bar value right on top of each bar.
                .transitionDuration(350)
                .valueFormat(d3.format('d'))
                ;
 
        //Chart x-axis settings        
        chart.xAxis.axisLabel(chart_details.chart_xaxis_label);
 
        //Chart y-axis settings        
        chart.yAxis
                .axisLabel(chart_details.chart_yaxis_label)
                .tickFormat(d3.format('d'));
 
        d3.select('#data_chart_sample_2 svg')
                .datum(chart_details.data)
                .call(chart);
 
        nv.utils.windowResize(chart.update);
 
        return chart;
    });
}

Le rendu sera le suivant :

Prestashop dashoard chart

 

Et voila nous avons fait le tour du fonctionnement des modules de type dashboard sous Prestashop.
N’hésitez pas à remonter vos questions 😉

 

Vous pouvez récupérer le module complet d’exemple ici

Pas de commentaires

Prestashop : Récupérer une configuration directement depuis un template

J’ai récemment rencontré la problématique de devoir utiliser des variables de configuration dans plusieurs templates non liés d’un site prestashop.
Plutôt que de surcharger l’ensemble des controllers impacté , je suis passé par la solution d’ajouter une nouvelle fonctionnalité directement dans Smarty.
Tout ça sans surcharge et via un module qui fonctionne sur PS 1.6 et 1.7

Le code est relativement simple :

class HhConfigTemplate extends Module
{
    public function __construct()
    {
        $this->author    = 'hhennes';
        $this->name      = 'hhconfigtemplate';
        $this->tab       = 'front_office_features';
        $this->version   = '0.1.0';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('HH Config Template');
        $this->description = $this->l('HH Config Template');
    }
 
    public function install()
    {
        if (!parent::install()
            || ! $this->registerHook('displayHeader')
           ) {
            return false;
        }
 
        return true;
    }
 
    public function uninstall()
    {
        return parent::uninstall();
    }
 
    /**
     * Hook Header Ajout d'une fonction dans smarty
     * @param $params
     */
    public function hookDisplayHeader($params)
    {
        //Enregistrement de la fonction "Configuration" dans Smarty qui appelle la fonction "getConfiguration" de cette classe
        smartyRegisterFunction($this->context->smarty, 'function', 'Configuration', array($this, 'getConfiguration'));
    }
 
    /**
     * Récupération d'une configuration
     * @param array $params
     * @return string
     */
    public static function getConfiguration($params)
    {
        if ( isset($params['key'])) {
            return Configuration::get($params['key'],
                isset($params['id_lang']) ? $params['id_lang'] : null,
                isset($params['id_shop_group']) ? $params['id_shop_group'] : null,
                isset($params['id_shop']) ? $params['id_shop'] : null
            );
        } else {
            return '';
        }
    }
}

Dans le template il suffit ensuite de mettre le code suivant par exemple pour récupérer la valeur :

{Configuration key="PS_PRODUCT_PICTURE_WIDTH"}

Vous pouvez également définir l’identifiant de la langue, du groupe de boutique, ou de la boutique, comme vous pouvez le voir dans la fonction getConfiguration() 😉

Pas de commentaires

Magento 2 : Ajouter des nouveaux attributs aux formulaires de création de compte

Cet article est une mise à jour d’un article précédent sur Magento 1 : Magento 1 : Ajouter des nouveaux attributs aux formulaires de création de compte

Nous allons voir comment rajouter un attribut client aux formulaire de création de compte et d’édition du compte client.
Celui-ci sera nommé « Sample »
(La partie checkout a été totalement réécrite dans magento 2 et fera l’objet d’un article ultérieur)

Pour cela nous allons créer un module Hhennes_Customer qui sera situé dans le dossier app/code/Hhennes/Customer.
La structure de notre module sera la suivante :

Structure module magento 2

Pour commencer comme pour tout module magento 2, il faut déclarer notre module en créant le fichier module.xml avec le contenu suivant dans le dossier /etc/ de notre module :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
 <module name="Hhennes_Customer" setup_version="0.1.0">
 <sequence>
 <module name="Mage_Customer"/> <!-- Dépendance au module Mage Customer -->
 </sequence>
 </module>
</config>

Ansi que le fichier registration.php à la racine avec le contenu suivant :

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Hhennes_Customer',
__DIR__
);

Pour installer notre module il faut le fichier « InstallData.php » dans un dossier « Setup » avec le contenu suivant

<!--?php namespace Hhennes\Customer\Setup; use Magento\Eav\Setup\EavSetup; use Magento\Eav\Setup\EavSetupFactory; use Magento\Eav\Model\Config; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\ModuleContextInterface; class InstallData implements InstallDataInterface { protected $eavSetupFactory; protected $eavConfig; /** * Injection des dépendances à la création des * InstallData constructor * @param EavSetupFactory $eavSetupFactory * @param Config $eavConfig */ public function __construct( EavSetupFactory $eavSetupFactory , Config $eavConfig ) { $this->eavSetupFactory = $eavSetupFactory;
        $this->eavConfig = $eavConfig;
 
    }
 
	 /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
 
		//Création de l'attribut
        $eavSetup->addAttribute(
            \Magento\Customer\Model\Customer::ENTITY,
            'sample',
            [
                'type' => 'text',
                'label' => 'Sample attribute',
                'input' => 'text',
                'required'=> false,
                'default' => '',
                'sort_order' => 100,
                'system' => false,
                'position' => 100,
            ]
        );
 
		//Ajout de l'attribut aux formulaires clients
        $autoLoginAttribute = $this->eavConfig->getAttribute(\Magento\Customer\Model\Customer::ENTITY,'sample');
        $autoLoginAttribute->setData('used_in_forms',
            ['adminhtml_customer','customer_account_create','customer_account_edit']
        );
        $autoLoginAttribute->save();
    }
}
</pre>
<p>La partie back-office du module est à présent complète.<br ?-->
Il faut gérer l'affichage via la création de layouts et de templates et l'ensemble fonctionne quasiment comme dans Magento 1
Les pages de création et d'édition de compte comportent le code suivant :
<?php echo $block->getChildHtml('form_additional_info'); ?>

qui permet de rajouter des éléments supplémentaires.

Les controller concernés sont donc les suivants : customer_account_create customer_account_edit, nous allons donc créer les fichiers de layouts associés dans le dossier view/frontend/layout/

customer_account_create.xml avec le contenu suivant :

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="form.additional.info">
<block class="Magento\Framework\View\Element\Template" name="form_additional_sample" template="Hhennes_Customer::form/sample_attribute.phtml"/>
</referenceContainer>
</body>
</page>

customer_account_edit.xml avec le contenu suivant :

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="form.additional.info">
<block class="Magento\Customer\Block\Form\Edit" name="form_additional_sample" template="Hhennes_Customer::form/sample_attribute_edit.phtml"/>
</referenceContainer>
</body>
</page>

Notez bien la différence dans le premier cas le bloc est de type Magento\Framework\View\Element\Template alors que dans le second il est de type Magento\Customer\Block\Form\Edit

Pour finir il faut créer les fichier phtml dans le dossier view/frontend/template/form/sample_attribute.phtml

<?php
<div class="field">
<label class="label" for="sample"><span><?php /* @escapeNotVerified */ echo __('Sample Data') ?></span></label>
<input type="text" name="sample" title="<?php /* @escapeNotVerified */ echo __('Sample Data') ?>" class="input-text" autocomplete="off" value=""/>
</div>

et sample_attribute_edit.phtml

<?php
<div class="field">
<label class="label" for="sample"><span><?php /* @escapeNotVerified */ echo __('Sample Data') ?></span></label>
<input type="text" name="sample" title="<?php /* @escapeNotVerified */ echo __('Sample Data') ?>" class="input-text" autocomplete="off"
value="<?php echo $block->getCustomer()->getCustomAttribute('sample')->getValue() ?>"/>
</div>

Si tout va bien votre champ devrait être visible sur les pages de création et d’édition de compte.

Nouveau champs account

Note : Attention à date d’aujourd’hui dans le thème luma, les champs additionnels sont affichés à la suite du mot de passe, et il est nécessaire d’afficher celui-ci pour les voir.

Pas de commentaires

Module Catpcha pour prestashop 1.7

Je viens enfin de rendre compatible mon module de captcha eicaptcha avec la version 1.7 de prestashop 🙂
En raison des nombreux changements sur l’infrastructure j’ai quasiment procédé à une réécriture complète du module.

Celui-ci permets d’ajouter un captcha sur le formulaire de contact, et sur le formulaire de création de compte.
( La possibilité de le rajouter sur le formulaire de commentaire produit, et envoyer à un ami est supprimée pour l’instant )

Aperçu :

Formulaire de contact

Formulaire de création de compte

 

Récupération du module :

Via ssh : (recommandée )

git clone https://github.com/nenes25/eicaptcha.git -b 17
cd eicaptcha
composer install

Télécharger directement l’archive et l’envoyer en ftp : eicaptcha-17-beta

 

Changements techniques :

La gestion du formulaire de contact est géré dans prestashop 1.7 via un widget du module contactform.
Ce module surcharge donc le module contactform pour vérifier la complétion du captcha via un nouveau hook actionContactFormSubmitBefore.

context->controller->errors)) {
           parent::sendMessage();
       }
    }

Lors de la création de compte la gestion du hook natif actionSubmitAccountBefore a été changée.
De ce fait je n’ai pas pu l’utiliser et j’ai du surcharger également le fichier AuthController pour rajouter un nouveau hook personnalisé pour gérer la vérification du captcha.

 

Le module est fonctionnel, mais étant encore en beta, des changements et des optimisations sont encore possibles dans les prochains jours / semaines, n’hésitez pas donc pas à remonter des issues sur github.
https://github.com/nenes25/eicaptcha

Le code est disponible sur la branche 17 du dépôt.

4 commentaires
Magento certified developper
Modules Prestashop
Compte Github