Prestashop 1.7 : Ajouter des champs clients

Ce tutoriel est compatible avec les versions de Prestashop suivantes :
1.7 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 8.0 8.1 +
Cet article est assez ancien, malgré toute l'attention que j' apporte à mes contenus il est possible que celui-ci ne soit plus d'actualité.
N'hésitez pas à me le signaler si nécessaire via le formulaire de contact.

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.

La page des clients a été migrée vers symfony à partir de prestashop 1.7.6 , les informations liées à l’administration dans cet article ne sont donc plus valides à partir de cette version

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')
                //Hook validation des champs
                || !$this->registerHook('validateCustomerFormFields') 
        ) {
            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')
                    //->setRequired(true) Décommenter pour rendre obligatoire
                    ->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.

Edit 2018-03-13 :
Ajout d’une validation sur les champs personnalisés :

Il est également possible de rajouter une validation personnalisée sur ces champs pour empêcher la soumission du formulaire si ceux-ci contiennent une erreur.
Pour cela il faut que le module utilise le hook validateCustomerFormFields.

Le module obtiendra uniquement les instances des champs qui lui sont lié.
Voici un exemple pour vérifier si le champ professionnal_id comprends 6 caractères, mais vous pouvez appliquer ici toutes les règles de validation souhaitées.

/**
     * Validation des champs du formulaire client
     * @param type $params array : Tableau des champs du formulaire client lié au module
     * Instance de Field
     * cf. https://github.com/PrestaShop/PrestaShop/pull/6374
     */
    public function hookValidateCustomerFormFields($params)
    {
        foreach ( $params['fields'] as $field){
 
            /** @var FormField $field */          
            //Validation custom du champ professionnal id si celui-ci n'est pas vide
            if ( $field->getName() == 'professionnal_id' && $field->getValue() != "") {
 
                //Mise en place de notre vérification ( ex: 6 caractère pour le champ)
                if ( strlen($field->getValue()) != 6 ){
                   //Définition de l'erreur.
                    $field->setErrors(array($this->l('This code must have 6 characters')));
                }
            }
        }
 
        //Renvoi du tableau des paramètres
        return $params['fields'];
    }

Dans le cas ou le champ n’est pas valide le message d’erreur est affiché et le formulaire n’est pas pris en compte, comme vous pouvez le voir sur la capture ci-dessous.
Champs erreurs

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')
                //Hook validation des champs
                || !$this->registerHook('validateCustomerFormFields')
        ) {
            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
    }
 
   /**
     * Validation des champs du formulaire client
     * @param type $params array : Tableau des champs du formulaire client lié au module
     * Instance de Field
     * cf. https://github.com/PrestaShop/PrestaShop/pull/6374
     */
    public function hookValidateCustomerFormFields($params)
    {
        foreach ( $params['fields'] as $field){
 
            /** @var FormField $field */          
            //Validation custom du champ professionnal id si celui-ci n'est pas vide
            if ( $field->getName() == 'professionnal_id' && $field->getValue() != "") {
 
                //Mise en place de notre vérification ( ex: 6 caractère pour le champ)
                if ( strlen($field->getValue()) != 6 ){
                    $field->setErrors(array($this->l('This code must have 6 characters')));
                }
            }
        }
 
        //Renvoi du tableau des paramètres au validateur
        return $params['fields'];
    }
 
}

113 réflexions sur “Prestashop 1.7 : Ajouter des champs clients”

  1. Bonsoir,
    ce code me parait très intéressant car j’ai justement le prpblème créer un nouveau champ dans le formulaire de création de compte sur un site local qui utilise Prestashop 1.7.2.2..

    Mais mon ignorance me fait poser cette honteuse question…
    La première partie du code (class HhCustomer extends Module {…. )

    .. est à mettre dans quel type de fichier ?

    Merci d’avance.

    1. Bonjour,
      Ce code est à mettre en place dans un fichier php.
      Attention cependant car cet article est plutôt à destination d’un public technique, n’hésitez pas à consulter les modules disponibles sur addons si vous ne souhaitez pas mettre les mains dans le code.

      Cordialement,
      Hervé

  2. Bonjour, j’ai bien installer le module mais on Front l’upload dans le dossier ne se fait pas.

    Et quand je vais sur la fiche du client en BO et que je modifie le fichier upload, il apparait bien dans mon dossier image du serveur.

    J’ai bien changer le enctype= »multipartform-data » dans la balise form du front mais sans succès.

    Vous avez une autre idée?

    Merci d’avance

  3. C’est bon j’ai trouvé, en front il faut mettre multipart/form-data et non multipartform-data dans la balise form !!

    Merci pour votre module qui est vraiment bien fait !!

    A bientot !

    1. Bonjour,

      Effectivement, erreur de copier/coller dans mon article … :-/
      Le texte corrigé merci de la précision.
      C’est plus un module canevas pour développer selon ses propres besoins qu’un module tout fait à installer, mais c’est cool de savoir qu’il est utile 🙂

      Cordialement,
      Hervé

  4. Bonjour,

    Pour commencer merci pour ce tuto.
    Je suis en plein dedans.

    J’utilise cette méthode pour pouvoir ajouter un champ  » Numéro de téléphone  » pour les clients qui s’inscrive sur mon site.

    Je voulais juste savoir où placer le code du Hook AdditionalCustomerFormFields :

    setName(‘tel_client’)
    ->setType(‘text’)
    ->setLabel($this->l(‘tel_client’)),

    ];
    }

    Merci.

    1. Bonjour,

      Dans votre cas il suffit de suivre l’exemple du champ standard « professionnal_id » de l’article pour que tout fonctionne.
      Inutile d’appliquer tout ce qui concerne l’envoi des fichiers.

      Cordialement,
      Hervé

  5. Bonjour,
    J’ai suivis scrupuleusement votre tuto
    J’ai donc créé un module dans modules/monmodule :
    monmodule.php
    et un dossier
    override/classes/Customer.php

    Je ne trouve pas le module dans l’administration 1.7 ‘modules’
    quand je ne Zip et charge il me dit :
    Ce fichier ne semble pas être un fichier .zip de module valide

    pourriez vous m’aider svp ?

  6. Je me corrige j’ai réussi le retrouver 🙂
    quand je clique sur install :
    L’action install est impossible pour le module mailcustomer. Malheureusement, le module n’a pas fourni plus de détails.

    Comment puis je connaitre l’erreur ?

    1. Bonjour,
      Qu’il y’a t-il exactement dans votre fonction d’installation ?
      Si il y’a des fonctions spécifiques essayer dans un premier temps de les commenter pour trouver la source de l’erreur en débuguant pas à pas.

      Cordialement,
      Hervé

  7. Bonjour,
    Je veux lire les données de client qui se trouve dans $params
    public function hookActionObjectCustomerAddAfter($params)
    telque ID , nom , prenom email etc
    Comment je peux le faire ?!
    Cordialement,

    1. Bonjour,

      Cet événement est lancé par la fonction Hook::exec(‘actionObject’.$this->getFullyQualifiedName().’AddAfter’, array(‘object’ => $this)); dans la classe ObjectModel.
      L’instance de l’objet concerné ( c’est à dire le customer dans notre cas ) et disponible via $params[‘object’]

      Cordialement,

  8. merci Herve,
    alors pour récupère son id :
    $Customer = $params[‘object’];
    $Customer->id;

    et pour le panier ? :https://www.h-hennes.fr/blog/2017/10/02/prestashop-1-7-creer-un-module-de-paiement/

    $cart = $params[‘cart’];

    j’aime bien récupère des infos sur le client et les produits achetés.

    ___

    je veux ajouter un champ spécifique dans la commande coté admin seulement.
    Avec PS 1.7 il y a t il un changement aussi comme la fiche de produit ou non?
    Est ce que il est le même principe que le cas de fiche client?

    Cordialement,

    1. J’ai regroupé vos commentaires, essayez de centraliser vos questions 😉

      De manière générale faites un Tools::p($params) à l’intérieur des fonctions, cela vous permettre de voir l’ensemble des paramètres disponibles.

      Pour votre seconde demande les pages de commandes et de clients n’ont pas bougés entre la version 1.6 et 1.7 c’est toujours l’ancienne architecture qui est utilisée.

  9. Bonjour et merci beaucoup pour ce tuto très explicite et facile à mettre en place.
    J’ai 3 petites questions :

    – lorsque que j’affiche le formulaire de création du client en BO j’ai un message d’erreur :

    Notice à la ligne 429 du fichier /var/www/html/md-dev/app/cache/dev/classes.php
    [8] SessionHandler::gc(): ps_files_cleanup_dir: opendir(/var/lib/php/sessions) failed: Permission denied (13)

    Notice à la ligne 388 du fichier /var/www/html/md-dev/vendor/prestashop/smarty/sysplugins/smarty_internal_templatebase.php(157) : eval()'d code
    [8] Undefined index: code_activation

    Cela n’empeche pas que la création du client se fasse.
    En front tout est ok.

    – pour que le code soit actif j’ai dû ancrer le module sur les deux hooks en back office apparence->postion->ancrer module. Il serait peut etre intéressant de le rajouter sur le tuto ?

    – enfin comment faire pour positionner le nouveau champ non pas en fin de formulaire mais au début ?

    Merci encore pour cet article !
    Guilhem

    1. Bonjour Guilhem,

      Concernant votre premier problème je dirais qu’il spécifique à votre environnement et lié à un problème de droits.
      Pour le second effectivement en mode debug, si le nouveau champ n’est pas rempli , une erreur notice va être lancée, car il n’y aura pas de valeur dans l’array.

      Concernant les hooks que vous avez ancrez manuellement pouvez-vous me préciser de quels hooks vous parlez ?
      L’accroche sur l’ensemble des hooks nécessaires est normalement déjà gérée lors de l’installation du module.

      Cordialement,
      Hervé

  10. Merci Hervé pour cette réponse rapide.
    J’ai dû ancrer les hooks :

    additionalCustomerFormFields
    actionAdminCustomersFormModifier

    car je n’avais pas besoin de gérer l’upload de fichier.

    Le problème c’est que je n’ai pas réussi à ancrer les deux en même temps c’est soit l’un soit l’autre.
    Cela vient peut être dû fait que j’ai rajouté votre code sur un module préexistant.
    Je vais en faire un nouveau pour gérer cette inscription. Je pense que cela sera plus propre.
    Je reviendrai vers vous une fois cela fait.

    Merci encore, vos articles sont très bien et viennent compléter une documentation prestashop un peu légère à mon goût…

    Cordialement,

    Guilhem

  11. c’était bien ça j’ai créé un module à part entière et tout fonctionne bien.

    Une petite question :

    je dois traiter les informations du formulaire et faire notamment des enregistrement dans d’autres tables que customer, où dois je le faire ?

    j’imagine plusieurs possibilités :

    – directement dans la methode des hooks déjà présents ?

    – j’utilise le hook actionAuthenticationBefore ?

    – je créé un front controller qui override le AuthControllerCore ?

    Merci beaucoup pour votre aide !!!

    C’est la première fois que je développe des modules pour prestashop et j’avoue qu’au début cela ne me paraît pas des plus simple…

    Cordialement,

    Guilhem

    1. Bonjour,

      Tout dépends de votre problématique et du moment ou vos données doivent être modifiées.
      Est-ce uniquement à la création d’un client, lors de sa mise à jour , lors de sa connexion ?
      En fonction la méthodologie sera différente et le hook aussi.

      De manière générale je préconise toujours d’utiliser les hooks si c’est possible plutôt qu’un override.

      Cordialement,
      Hervé

  12. Bonjour,

    je dois modifier des données lors de la création du client :

    – avant la soumission du formulaire : afficher un nouveau champs en fonction de la valeur d’un autre

    – après la soumission :
    enregistrement des données

    – la même chose lors d’une mise à jour du client

    Je vais chercher les hooks correspondant en suivant votre conseil.

    Comment peut on choisir la position de ses nouveaux inputs dans le form de création ?

    Merci beaucoup pour vos précieux conseils.

    Cordialement.

    Guilhem

    1. Bonjour,

      Pour les champs liés, il faudra sans doute gérer ce point en javascript, je n’ai pas encore implémenté cela via le fonctionnement natif.
      Pour la positions des champs ce n’est pas gérable via un hook, tous les champs custom sont ajoutés à la fin du tableau $format ( cf. fichier classes/form/CustomerFormatter.php )
      Pour changer l’ordre il faudrait modifier la fonction getTemplateVariables() du fichier classes/form/CustomerForm pour rajouter un tri des champs.

  13. Merci pour ce tuto.

    Je l’ai suivi à la lettre, je souhaitais juste rajouter un champ « téléphone »; tout ce passe bien sauf l’ajout en BDD du champ saisie. La table est bien crée mais reste vide.

    J’ai de ce fait essayer en prenant tout votre code de base, mais idem : aucun enregistrement en BDD.

    Je suis en 1.7.3, savez-vous d’où pourrait venir mon problème ?

    Merci d’avance

    1. Bonjour,

      Il faut bien penser à vider votre fichier de cache « class_index.php » dans le dossier app/cache/prod ( ou app/cache/dev ) pour que la surcharge soit prise en compte.

      Cordialement,
      Hervé

  14. Bonjour,
    j’ai tenté de créer mon module en utilisant le code que vous proposez, mais je rencontre un problème dès son installation, lorsque j’essaie de transférer monmodule.zip : un message « Aïe : …  » (une erreur rencontrée).

    J’ai créé un dossier « monmodule » dans lequel j’insère mon fichier php ‘monmodule.php’ et le dossier ‘override/classes’ qui contient le fichier ‘Customer.php’.

    Pouvez-vous m’indiquer mes possibles erreurs ?

    Merci par avance.

  15. pardon… j’ai oublié de préciser que je suis sur la version 1.7.4.

    Pour le message d’erreur, aucune précision, juste qu’ « une erreur a été rencontrée ».

    1. Bonjour,

      Essayez d’activer le mode debug pour avoir le détails de l’erreur.
      Dans ce que vous me dites je ne vois pas vraiment de source d’erreur.

      Cordialement,

  16. J’ai refait un essai en mode debug, voici la réponse :

    in ModuleManager.php line 566
    at ModuleManager->checkIsInstalled(‘monmodule’) in ModuleManager.php line 331
    at ModuleManager->disable(‘monmodule’) in ModuleController.php line 642
    at ModuleController->importModuleAction(object(Request))
    at call_user_func_array(array(object(ModuleController), ‘importModuleAction’), array(object(Request))) in bootstrap.php.cache line 3246
    at HttpKernel->handleRaw(object(Request), ‘1’) in bootstrap.php.cache line 3205
    at HttpKernel->handle(object(Request), ‘1’, false) in bootstrap.php.cache line 3359
    at ContainerAwareHttpKernel->handle(object(Request), ‘1’, false) in bootstrap.php.cache line 2562
    at Kernel->handle(object(Request), ‘1’, false) in index.php line 86

    Je ne sais pas comment l’interpréter, sachant que la première ligne d’erreur (ligne 566 du fichier ModuleManager.php) mène simplement sur ce qui suit :

    private function checkIsInstalled($name)
    {
    if (!$this->moduleProvider->isInstalled($name)) {
    throw new Exception(
    $this->translator->trans(
    ‘The module %module% must be installed first’,
    array(‘%module%’ => $name),
    ‘Admin.Modules.Notification’));
    }
    }

  17. Je veux bien vous l’envoyer mais mon dernier essai est l’exacte copie de votre code.

    Voici l’architecture de mon module :
    – (dossier) monmodule
    |
    |__ (fichier) monmodule.php
    |
    |__ (dossier) override
    |___(dossier) classes
    |___(fichier) Customer.php

    1. Je copie-colle votre code (pour les 2 fichiers monmodule.php et Customer.php)

    2. Je zippe le tout (dossier monmodule.zip)

    3. Dans l’interface d’administration, lorsque je clique sur « installer un module », une fenêtre (modal) de prestashop s’ouvre et je fais glisser mon dossier zip dessus.

    4. Mon message d’erreur apparaît.

    Est-ce que vous notez une erreur dans mes manipulations ?
    Sinon, je vais éventuellement essayer de recommencer avec une nouvelle installation « propre » de prestashop pour voir un peu.

  18. OK…je suis vraiment un idiot… (ou trop de temps la tête dans le code, sans prendre l’air)

    Mes erreurs venaient tout simplement d’une différence entre le nom de mon module et celui de mon fichier/de ma classe/etc.

    Après avoir harmonisé le tout, tout marche très bien à présent.

    Merci pour votre aide et votre code précieux. 😉

  19. Bonjour,

    Tout d’abord merci pour ce tutoriel complet et surtout très bien expliqué. Je souhaiterai ajouter un champs de type à la place d’un input de type text. Est il possible de le faire avec un (new FormField) ?

    En vous remerciant

  20. Oups, le mot a disparu en effet. Je souhaiterai afficher une option pour l’utilisateur pour choisir le pays dans lequel il se trouve. Donc un formulaire de type .

    Egalement, etant donnée votre expertise sur prestashop et que le sujet de ma question est reliée, savez vous s’il est possible d’ajouter les champs de l’adresse lors du processus d’inscription ? (comme on pouvait le retrouver sur PS 1.6 avec l’option Type de processus d’enregistrement)

  21. Encore une fois le mot a disparu car je l’ai mis dans une balise (certainement enlevé ou inséré comme HTML dans le commentaire), un input de type SELECT 🙂

  22. Bonjour,
    (après un petit break, de retour sur prestashop…)

    Je travaille en version 1.7.2.4.

    Comment puis-je faire pour enregistrer mes nouveaux champs dans une table existante et créé par Prestashop ?

    (par exemple, pour mon input personnalisé adresse1, faire un INSERT INTO dans la table ps_address, colonne address1)

    Je souhaiterais pour cela modifier par exemple le comportement du bouton « submit » mais je ne trouve pas la page PHP à laquelle il fait référence pour traiter l’enregistrement.

    Merci par avance.

    1. Bonjour,
      Il me semble je n’ai pas encore creusé le sujet des formfield à fond mais j’ai prévu un article à ce sujet dans les prochains jours.

      Cordialement,

  23. Thanks for your beatifull works.
    I’m using Prestashop 1.7.3 I only worked on the generic field as a phone and on a TINYINT field:
    self :: $ definition [‘fields’] [‘privacy’] = [
                 ‘type’ => self :: TYPE__BOOL,
                 ‘required’ => false
             ];
    The fields are added to the database but when I try to open the registration form I receive:
    FatalErrorException in CustomerFormatter.php line 39:
    Parse Error: syntax error, unexpected end of file, expecting function (T_FUNCTION)

    at this row:
    private $ask_for_new_password = false;

    Can you help me find out what’s wrong?
    Thanks again,
    Elisabetta

  24. Hi and sorry if I post a new comment in English.

    I solved my problems and now the fields appear in the frontend, in the backend and in the database.

    But they are not saved and I have no errors reported.

    I write you my code but what test could I do to understand what’s wrong? The correspondence between the name of the fields is there and yet it is not working. Thank you very much.

    Class:
    public function __construct($id = null) {
    self::$definition[‘fields’][‘phone’] = [‘type’ => self::TYPE_STRING,
    ‘required’ => false, ‘size’ => 255
    ];
    self::$definition[‘fields’][‘privacy’] = [‘type’ => self::TYPE__BOOL,
    ‘validate’ => ‘isBool’, ‘required’ => false
    ];
    parent::__construct($id);
    }
    }

    $sqlInstall = « ALTER TABLE  » . _DB_PREFIX_ . « customer  »
    . « ADD phone VARCHAR(255) NULL,  »
    . « ADD privacy TINYINT(1) NULL »;

    public function hookAdditionalCustomerFormFields($params) {

    return [
    (new FormField)
    ->setName(‘phone’)
    ->setType(‘text’)
    ->setRequired(true)
    ->setLabel($this->l(‘Telefono’)),
    (new FormField)
    ->setName(‘privacy’)
    ->setType(‘checkbox’)
    ->setRequired(true)
    ->setValue(0)
    ->setLabel($this->l(‘Ho preso visione e accetto la Privacy Policy’))
    ];

    }

  25. Hi herve, thaks for your support.
    Yes, I’m in debug mode e cache disable and I also clear cache.

    Is there somethings wrong in my code?
    Or what kind of control can I add to understand where it crashes and why?

    1. Hi Elisabetta,

      The next step to debug is to identify if the error is linked with the model or with the data passed to it from the controller.
      To check that the best way is to programmaticaly create a customer with your new fields in a way like that

      $customer = new Customer();
      ... customer fields
      $customer->phone = '45645645';
      $customer->privacy = '1';

      try {
      $customer->save();
      } catch ( Exception $e ) {
      echo $e->getMessage();
      }

      If the data are well stored in the database, the model is well overrided and the problem should be linked to the controller.

      Regards,

  26. Bonjour,
    j’ai bien ajouter mon nouveau champs dans le formulaire d’ajout de client.
    J’ai deux questions:
    1 – L’ordre de l’affichage dans le formulaire:
    est ce que je peux modifier l’ordre de l’affichage de mon nouveau champs ( pas à la fin mais apres l’email)?

    2 – ce champs doit étre valide selon une réglé Spécificque ( par titre d’exemple ce champ doit commencé par CAM et doit avoir après 12 chiffres , comment je peut faire une fonction comme ‘validate’ => ‘isFloat’, )
    merci d’avance
    Cordialement,

    1. Bonjour,

      A ma connaissance il n’est pas possible de changer l’ordre d’affichage des éléments existant via un module,par défaut les champs ajoutés par les modules sont affichés à la fin.
      C’est sans doute gérable via une surcharge de la classe CustomerFormatter, mais assez chiant à réaliser.

      Pour mettre en place une validation spécifique pour votre champs vous pouvez utiliser le hook validateCustomerFormFields appellé dans classes/form/CustomerForm.php

      Cordialement,

  27. Merci.
    Vous avez un exmple de utilisation le hook validateCustomerFormFields ?
    J’ai essayé de l’utilisé mais sans réussite
    Vous pouvez nous faire un champ avec un validateur?
    Merci d’avance

  28. Bonjour hervé,

    Merci pour ce tutoriel !
    je suis en train de l’appliquer sur une Prestashop 1.6.1.20.

    Tout fonctionne, mise à part une chose : retrouver la valeur dans le formulaire de professional_id(hookActionAdminCustomersFormModifier) fields_value.

    savez-vous comment retrouver cette valeur en 1.6 (sachant que $params[‘object’] n’a pas l’air présent en 1.6 dans ce hook?) Dois-je instancier obligatoirement l’object depuis l’id Customer?

    merci

  29. Hi Hervé and thanks for your support.
    After some time I want to try this again with Prestashop 1.7.4 and only with a text field. However, as before, everything appears perfectly but the data is not saved in the db. Where should I enter the suggested customer programmatic creation?

  30. Bonjour, j’ai le même problème en 1.7.2.1. Les nouveau champs ne sont pas enregistrés dans la base de données. Quand je supprime le fichier “class_index.php” de app/cache/prod, il est recréé automatiquement tel quel. Y’a t-il une autre manipulation à effectuer ?

  31. Bonjour,
    En 1.7.5 j’ai le même problème.Cache supprimé. Les données ne se sauvegardent pas…par contre si je mets à jour la base. Les données s’affichent correctement. Si vous avez une idée..

  32. Bonjour,
    Je cherche à afficher le champs que j’ai crée sur la fiche client (et pas en édition uniquement).
    J’ai bien trouvé qu’il fallait utiliser le hook displayAdminCustomers mais je ne comprends pas comment l’utiliser dans le fichier nomdumodule.php.
    J’ai un simple champs texte pour le moment à afficher.

    Merci de votre travail

    1. Bonjour,

      En utilisant ce hook il faut afficher retourner votre propre contenu ( via un template smarty ou un simple return d’une chaine )

      Cordialement,
      Hervé

  33. Bonjour,
    Merci pour le tuto, je souhaiterais savoir comment faire pour ajouter un champs avec des checkbox à cocher ou on peut en sélectionner plusieurs.
    Est-ce qu’il y a une grande différence avec Prestashop 1.6.1.23 ?
    Je souhaite faire 5 cases à cocher dans mon formulaire de création de compte. Pour l’instant j’ai réussi sur une boutique test à créer mes cases mais je n’arrive pas à enregistrer le résultat dans la base.
    Un peu d’aide serait la bienvenue.

    1. Bonjour,
      Effectivement la logique est totalement différente sous Prestashop 1.7
      J’ai vu que vous aviez bien trouvé l’article qui correspond à ce problème pour les versions inférieures 😉

      Cordialement,
      Hervé

  34. Bonjour Hervé, un super tuto comme d’hab’. Vraiment cool l’aide que ça nous apporte !
    J’ai ajouté des champs sans problème avec le hook AdditionalCustomerFormFields cependant j’aimerais le faire avec le DisplayCustomerAccountFormTop car j’ai besoin de personnaliser en CSS et surtout afficher 2 champs masqués SI une checkbox est cochée. J’ai donc crée un template nommé compte.tpl dans mes hooks :

    check

    test

    De la même façon j’ai jouté deux champs text. J’ai bien surchargé la classe Customer et ajoutant les 3 définitions et les 3 champs additionnels sont bien dans la table.
    Sauf que lorsque je poste le formulaire et récupère les datas dans ActionCustomerAccountAdd mes 3 valeurs sont vides ! (alors que c’est OK avec ta méthode AdditionalCustomerFormFields).
    Je ne comprends pas pourquoi…
    En outre, la méthode ValidateCustomerFormFields ne renvoie aucune erreur même quand il y en a. Le formulaire passe. J’ai fait des tests, on dirait que le hook n’est même pas appelé (pourtant bien associé au module). Une idée ? D’avance merci. Renaud.

  35. Re,
    Après multiples tests, cela fonctionne uniquement avec ta méthode AdditionalCustomerFormFields et pas avec mon template.
    Mais du coup je trouve les options New FormField bien pauvres.Comment mettre un CSS ? Un lien vers une page (genre lire conditions vente) ? Et surtout comment rendre 2 champs visibles et obligatoires dès lors qu’une checkbox a été cochée ?
    Merci !

    1. Bonjour Renaud,

      Tu rencontres une problématique intéressante, je pense que c’est jouable via les hooks natifs
      Pour rajouter un css ou un js sur une page en particulier tu peux utiliser le hook displayHeader.
      Et ajouter en fonction du controller un css ou un js spécifique
      En l’occurrence pour le formulaire de création de compte tu peux utiliser la condition suivante :
      if ( $this->context->controller->php_self == 'authentication'){
      //Ajout css et/ou js
      }

      Via un javascript custom tu peux tout à fait détecter les actions sur le champs et donc afficher/masquer les éléments en fonction.
      ( Pour rendre le champ oligatoire il suffit d’y ajouter l’élément required )
      La validation de ces données peut ensuite être réalisée en php via le hook hookValidateCustomerFormFields puisque tu as accès aux valeurs de l’ensemble de tes champs.

      Cordialement,
      Hervé

  36. Merci Hervé de ta réponse. Personnaliser le form-group row et masquer/afficher des champs au click checkbox via JS n’est pas un problème. Cela fonctionne très bien. Sauf que pour cela je passe par le classique template et le hook DisplayCustomerAccountFormTop. Tout s’affiche comme je le souhaite, nickel.
    C’est après que ça cloche puisque les valeurs ne sont pas récupérées dans mon ActionCustomerAccountAdd/Update et que surtout ton hook ValidateCustomerFormFields ne se déclenche pas.
    Et c’est dingue puisque mon formulaire s’affiche très bien, le source est d’ailleurs le même que lorsque j’utilise AdditionalCustomerFormFields.

  37. Je progresse ! J’utilisais displayCustomerAccountFormTop et NON displayCustomerAccountForm et le premier n’est pas inclus dans la balise form. Donc forcément…Le FormTop ne sert qu’à afficher des infos. Du coup je récupère bien mes valeurs. Par contre cette méthode ne déclenche vraiment pas le ValidateCustomerFormFields et je vais devoir gérer les erreurs autrement, sans doute via les ActionCustomerAccountAdd/Update…

  38. Merci beaucoup pour ce tuto ! Tout fonctionne 🙂
    J’aimerais maintenant ajouter un champ avec une balise SELECT. Une idée de comment procéder ? Merci

  39. Bonjour,

    Pour information, à partir de la 1.7.6, et pour le back-office, il va falloir passer par le hook « actionCustomerFormBuilderModifier » et utiliser le formBuilder de synphony. Autrement la solution que vous proposez et que j’utilisez moi même ne fonctionnera plus :

    /**
    * Update the admin customer form edit
    * @param type $params
    */
    public function hookActionCustomerFormBuilderModifier($params)
    {
    /** @var FormBuilderInterface $formBuilder */
    $formBuilder = $params[‘form_builder’];
    $formBuilder->add(‘expiration’, DatePickerType::class, [
    ‘label’ => $this->getTranslator()->trans(‘Expiration date’, [], ‘Modules.Lkcustomer.Admin’),
    ‘required’ => false,
    ]);
    $params[‘data’][‘expiration’] = empty($params[‘data’][‘expiration’]) ? date(‘Y-m-d’) :$params[‘data’][‘expiration’] ;
    }

    Bien évidement il faudra ajouter le namespace du type de champs que l’on souhaite utiliser, Dans mon cas, Datepicker :
    use PrestaShopBundle\Form\Admin\Type\DatePickerType;

    Bien cordialement,

  40. J’ai effectivement vu cet article après mon commentaire et pour le coup je me suis trouvé un peu stupide de l’avoir écris.

    J’ai galéré 1 journée à comprendre pourquoi mon code ne fonctionnait plus avant de trouver sur la doc de prestashop l’information sur les controller gérés par synphony … Si j’avais un peu plus fouiller dans votre blog, j’aurai pu éviter ces mésaventures !

    Merci !

  41. Bonjour,
    j’ai testé en version 1.7.6 avec les modifications de François, mais je me heurte à un mur: je n’arrive pas à Upload le fichier en backoffice. En Front ça fonctionne bien.

    Avez-vous une piste par hasard pour modifier la fonction _uploadFile pour le backOffice ?

    Cordialement,
    Peter

    1. Bonjour Peter,
      Je rencontre le même problème d’upload de fichier sur le formulaire produit et j’ai un début de piste via l’utilisation de la lib dropzone.js ( comme pour les médias des produits )
      Via cette librairie j’arrive bien à uploader le fichier mais pas encore à l’enregistrer.
      J’ai prévu de faire un article sur cette problématique prochainement.

      Cordialement,
      Hervé

  42. Bonsoir,

    j’arrive pareil à upload le fichier via FileUploader, il est bien dans le module mais je n’arrive pas à persister le Customer avec le nom du fichier.

    if (isset($_FILES[‘customer’]) && $_FILES[‘customer’][‘name’][‘justificatif_upload’] != «  » && !$this->context->cookie->__isset(‘customer_justificatif_updated’)) {
    $fileUpload = $params[‘request’]->files->get(‘customer’)[‘justificatif_upload’];
    $originalFilename = pathinfo($fileUpload->getClientOriginalName(), PATHINFO_FILENAME);
    $newFilename = $originalFilename.’.’.$fileUpload->guessExtension();

    $fileUpload->move(
    dirname(__FILE__) . ‘/files/’,
    $newFilename
    );

    // ici je bloque

  43. Bonsoir Hervé et merci pour votre module !

    Mes champs supplémentaires s’ajoutent bien en BO et la sauvegarde se fait bien en base de données sauf lorsque je fais une recherche sur mes clients.
    En effet, dès que je lance une recherche ou un simple filtre « Activé : Oui/Non » ou que je change de page, et que je modifie mon nouveau champ, les modifications ne sont plus prises en compte.
    Vous avez une idée d’ou pourrait venir le problème ?

    Merci beaucoup, je bloque !! 🙂

  44. Bonjour Hervé,

    Je suis sur la 1.7.5.2. J’ai tenté l’installation du module sur un autre environnement (presta quasi vierge sur un autre serveur) et j’ai le même problème. Le champ apparaît et s’enregistre en BO et FO ms toujours pas lors d’une recherche.

    Cordialement

  45. Bonjour Hervé,

    Je suis sur la 1.7.5.2. J’ai tenté l’installation du module sur un autre environnement (presta quasi vierge sur un autre serveur) et j’ai le même problème. Le champ apparaît et s’enregistre en BO et FO ms toujours pas lors d’une recherche.

    Cordialement

  46. Hervé,
    Je voulais préciser que j’ai bien supprimé class_index, je suis en mode debug et je n’ai pas de message d’erreur.
    Pour pouvoir remodifier les champs après une recherche (ou filtre actif), je dois me déconnecter, fermer le navigateur ou utiliser un navigateur privé.

    Merci beaucoup pour votre aide !

    1. Bonjour,

      Merci pour toutes ces précisions !
      Je vous confirme que j’ai bien ce comportement également.
      En revanche je n’ai pas d’explications sur la cause de l’erreur, il va falloir que je creuse cela.

      Cordialement,
      Hervé

  47. Bonjour Hervé,

    Bonne année ! Je reviens vers vous pour savoir si vous avez pu trouver une solution concernant les champs qui ne s’enregistrent pas.
    Je recherche de mon côté également mais sans succès pour le moment.

    Cordialement

    1. Bonjour Sandra,

      Meilleurs voeux à vous également.
      J’ai encore été confronté récemment à ce problème mais je n’ai malheureusement pas encore trouvé de solution propre.
      Mon contournement pour être sur que les données soient enregistrées à chaque fois a été de le faire directement en sql dans le module sur les hooks d’actions des controllers .. ( à défaut )

      Cordialement,

  48. Bonjour Hervé,

    Serait-ce possible d’avoir un exemple ? Le site sur lequel j’utilise le module est en production. Le plus important est qu’il fonctionne, qu’importe la méthode 😉

    Bien à vous

  49. Bonjour Hervé,

    Merci pour ces précisions. Pourriez-vous me donner un exemple de code que je puisses tester de mon côté ? Le site sur lequel j’utilise votre module est en production, une solution même temporaire serait merveilleuse 🙂

    Bien à vous

    1. Pour le coup le code que j’ai n’ai pas lié aux clients mais la logique à reprendre serait la même :
      /**
      * Bugs dans le formulaire d'admin standard dans certains cas
      * Les données sont donc insérées en sql
      * @param $params
      */
      public function hookActionAdminStoresControllerSaveAfter($params)
      {
      $id_store = (int)Tools::getValue('id_store');
      if (Tools::isSubmit('submitAddstore') && $id_store > 0) {

      Db::getInstance()->update(
      'store',
      [
      'url' => pSQL(Tools::getValue('url')),
      'type' => pSQL(Tools::getValue('type'))
      ],
      'id_store=' . $id_store
      );
      }
      }

      Il faudrait gérer le hook actionAdminCustomersControllerSaveAfter dans votre cas.
      Cordialement,

  50. Bonjour,

    Merci pour ce tuto, top !
    Par contre sur Presta 1.7.6.3, l’utilisateur est bien créée mais le formulaire reste afficher sur la page (sans redirection).
    Lorsque je supprime l’override Customer.php (mes nouveaux disparaisses… logique MAIS le formulaire remarche et disparaît bien après la création).

    Merci pour votre aide.

    1. Bonjour,

      Est-ce que vous rencontrez ce problème au niveau client ( Front office ) ou dans l’administration ?
      Quels types de champs avez-vous ajouté ?

      Cordialement,
      Hervé

  51. Bonjour,
    J’ai colpié collé ce code et il ne fonctionen pas pour la partie BO pour presta 1.7.6.4

    Je voudrai me servie de cette méthode pour rajouter des champs persos dans l’adresse, mais là il y a aucune info, du moins pas assez sur ce sujet précis.
    merci.

    1. Bonjour,

      Merci de votre retour, la partie administration n’est effectivement plus fonctionnelle à partir de prestashop 1.7.6
      La page a été migrée vers symfony la gestion des formulaires et des hooks est donc différente.
      J’ai rajouté une note en début d’article pour informer les autres visiteurs.
      Vous pouvez trouvez des information sur le fonctionnement de base de ces nouvelles pages dans cet article : https://www.h-hennes.fr/blog/2019/08/05/prestashop-1-7-ajouter-des-champs-dans-un-formulaire-dadministration/

      Cordialement,

  52. Hi and sorry if I post a new comment in English.

    I managed to configure the file properly and now it allows the customers to upload a file when creating their accounts, but I haven’t been able to make the field required. I don’t understand PHP enough to make it work.

    I tried modifying this snippet with no success.

    public function hookValidateCustomerFormFields($params)
    {
    foreach ( $params[‘fields’] as $field){

    /** @var FormField $field */
    //Validation custom du champ professionnal id si celui-ci n’est pas vide
    if ( $field->getName() == ‘professionnal_id’ && $field->getValue() != «  ») {

    //Mise en place de notre vérification ( ex: 6 caractère pour le champ)
    if ( strlen($field->getValue()) != 6 ){
    $field->setErrors(array($this->l(‘This code must have 6 characters’)));
    }
    }
    }

    //Renvoi du tableau des paramètres au validateur
    return $params[‘fields’];
    }

    Can you please help? All that I’m lacking now is that the form fails to post and shows the user an error if no file is uploaded.

    1. Hello,

      No need to add a custom validation to make the field required.
      As shown in the article you just have to uncomment the following line.
      //->setRequired(true) Décommenter pour rendre obligatoir
      Then your new field will be required.

      Regards,
      Hervé

  53. Hello, I did the tutorial, as you indicate, but when I try to save in BD nothing happens, I have version 1.7.6.4, and I know that there are other users who have had the same thing, and I have done what you indicate to clear the cache.

    1. Hello Debora,
      Unfortunalely you miss something in the content of this article

      « La page des clients a été migrée vers symfony à partir de prestashop 1.7.6 , les informations liées à l’administration dans cet article ne sont donc plus valides à partir de cette version »
      Which means that this tutorial does not works anymore starting from prestashop 1.7.6 as the management page was migrated to symfony.
      You can see how to add new fields to symonfony page in this article : https://www.h-hennes.fr/blog/2019/08/05/prestashop-1-7-ajouter-des-champs-dans-un-formulaire-dadministration/

      Regards,
      Hervé

  54. Merci Hervé pour votre tuto très bien fait.
    J’ai une demande toute simple (mais pas si simple pour moi en fait !).
    Dans la page de création de compte client dans le Back Office, je souhaite juste modifier le libellé d’un champ.
    Pouvez-vous m’indiquer dans quel fichier je peux trouver la liste des champs utilisés dans cette page ?
    Merci d’avance !

    1. Bonjour Phil,
      Quel est votre version de prestashop ?
      Sur la dernière version 1.7.6 la page est passé sous symfony et la gestion est donc différente.

      Cordialement,
      hervé

    1. Bonjour,

      Oui il existe le hook displayCustomerAccountFormTop qui permets d’ajouter du contenu à cet emplacement.
      Après il faut que votre thème l’implémente. ( c’est le cas du thème classic et de ses dérivés )

      Cordialement,
      Hervé

  55. Bonjour,

    je viens de m’apercevoir qu’à partir de la version 1.7.6., le hook actionAdminCustomersFormModifier a été modifié et il faut
    utiliser hookActionCustomerFormBuilderModifier, comme indiqué dans l’un de vos articles.

    Peut-être devriez vous spécifier que cette solution fonctionne à 100% que pour les Prestashop inférieur à la version 1.7.6 (à confirmer!)

    bien à vous,

    1. Bonjour Alex,
      C’est ce que j’ai mis dans l’article qu’il n’est plus compatible à partir de la version 1.7.6
      Il faut que je le mettes plus en avant du coup. 🙂

      Merci de votre retour,
      Cordialement,
      Hervé

  56. Merci pour ce module très complet !
    J’ai suivi vos conseils à la lettre et ça m’a plutôt bien réussi ! J’ai pu ajouter les champs nécessaires pour mes clients, un grand merci de votre aide !

  57. Bonjour,
    Sur mon PS 1.7.5.1, j’ai ajouté
    – un fichier « hhcustomer.php » dans « /modules/hhcustomer/ »
    – un fichier « Customer.php » dans « /override/classes/ »
    Mais ensuite je ne comprends pas comment faire pour déclencher l’install du module.
    Merci de votre aide.

  58. Bonjour Hervé,
    Merci pour l’ensemble des tutos.
    Concernant celui-ci, fonctionne t-il toujours sur prestashop 1.7.7.8 ?
    Après avoir suivi la démarche, la fenêtre d’installation du module mouline pendant des heures …
    J’ai bien suivi la démarche avec la création du fichier hhcustomer.php dans le dossier hhcustomer (/module) puis customer.php dans /override /classes. Zip le tout et dépot sur l’assistant d’installation.

    Merci !

  59. Dear Herve,

    i am using your module to add two additional fields in FO-Checkout delivery step. These are two input text fields. I install module, seems everything working fine (database fields are added). I am using displayAfterCarrier hook. So i manage to display some text there. But when i try to display the form:
    public function hookAdditionalCustomerFormFields($params) {

    return [
    (new FormField)
    ->setName(‘professionnal_id’)
    ->setType(‘text’)
    //->setRequired(true) Décommenter pour rendre obligatoire
    ->setLabel($this->l(‘Professionnal id’)),
    (new FormField)
    ->setName(‘justificatif_upload’)
    ->setType(‘file’)
    ->setLabel($this->l(‘document ID’))
    ];

    In the hook position in FO is diplayed only « Array » – this word. Seems that it passes the variable , but could not create the input form. In console i see:

    Array

    And nothing else. Where is the problem? If you could point me where to look after.

    1. Hello Plamen,

      Could you please be more specific ?
      AFAIK When you speak about the checkout delivery step, the fields are not related with the customer entity but with its address.
      But you can also add your custom fields to the address using the hook additionalCustomerAddressFields

      Regards,
      Hervé

Répondre à debora Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *