{"id":1624,"date":"2017-10-10T13:42:13","date_gmt":"2017-10-10T11:42:13","guid":{"rendered":"https:\/\/www.h-hennes.fr\/blog\/?p=1624"},"modified":"2022-10-01T16:21:20","modified_gmt":"2022-10-01T14:21:20","slug":"prestashop-1-7-ajouter-des-champs-clients","status":"publish","type":"post","link":"https:\/\/www.h-hennes.fr\/blog\/2017\/10\/10\/prestashop-1-7-ajouter-des-champs-clients\/","title":{"rendered":"Prestashop 1.7 : Ajouter des champs clients"},"content":{"rendered":"<p>La version 1.7 de prestashop apporte des changements dans la gestion des champs clients.<br \/>\nCet article est une mise \u00e0 jour avec\u00a0 des articles suivants\u00a0 qui ne fonctionnent donc plus sur prestashop 1.7<\/p>\n<ul>\n<li><a href=\"https:\/\/www.h-hennes.fr\/blog\/2016\/02\/18\/prestashop-envoyer-des-fichiers-lors-de-la-creation-du-compte-client\/\" target=\"_blank\" rel=\"noopener noreferrer\">Prestashop Envoyer des fichiers lors de la cr\u00e9ation du compte client<\/a><\/li>\n<li><a href=\"https:\/\/www.h-hennes.fr\/blog\/2015\/06\/29\/prestashop-ajouter-des-champs-a-linscription\/\" target=\"_blank\" rel=\"noopener noreferrer\">Prestashop ajouter des champs \u00e0 l&rsquo;inscription<\/a><\/li>\n<\/ul>\n<p>Le but de ce tutoriel va d&rsquo;\u00eatre d&rsquo;ajouter 2 nouveaux champs \u00e0 l&rsquo;entit\u00e9 client :<\/p>\n<ul>\n<li><em>professionnal_id<\/em> =&gt; champ standard qui sera un input text<\/li>\n<li><em>justificatif<\/em> =&gt; champ de type file<\/li>\n<\/ul>\n<p>Vous trouverez l&rsquo;ensemble du code en fin d&rsquo;article.<\/p>\n<p><strong><em>La page des clients a \u00e9t\u00e9 migr\u00e9e vers symfony \u00e0 partir de prestashop 1.7.6 , les informations li\u00e9es \u00e0 l&rsquo;administration dans cet article ne sont donc plus valides \u00e0 partir de cette version<\/em><\/strong><\/p>\n<p>Nous allons voir la base du module qui s&rsquo;appellera <strong>hhcustomer<\/strong> et son fonctionnement global.<\/p>\n<p>Pour commencer voici le code d&rsquo;initialisation, d&rsquo;installation \/ d\u00e9sinstallation du module.<\/p>\n<pre lang=\"php\" escaped=\"true\">class HhCustomer extends Module {\r\n\r\n    public function __construct() {\r\n\r\n        $this-&gt;name = 'hhcustomer';\r\n        $this-&gt;tab = 'others';\r\n        $this-&gt;author = 'hhennes';\r\n        $this-&gt;version = '0.1.0';\r\n        $this-&gt;need_instance = 0;\r\n        $this-&gt;bootstrap = true;\r\n\r\n        parent::__construct();\r\n\r\n        $this-&gt;displayName = $this-&gt;l('hhcustomer');\r\n        $this-&gt;description = $this-&gt;l('add new fields to customer');\r\n        $this-&gt;ps_versions_compliancy = array('min' =&gt; '1.7.1', 'max' =&gt; _PS_VERSION_);\r\n    }\r\n\r\n    \/**\r\n     * Installation du module\r\n     * @return boolean\r\n     *\/\r\n    public function install() {\r\n        if (!parent::install() \r\n               \/\/ Install Sql du module\r\n                || !$this-&gt;_installSql() \r\n                \/\/Hooks Admin\r\n                || !$this-&gt;registerHook('actionAdminCustomersControllerSaveAfter') \r\n                || !$this-&gt;registerHook('actionAdminCustomersFormModifier')\r\n                \/\/Hooks Front        \r\n                || !$this-&gt;registerHook('additionalCustomerFormFields')\r\n                \/\/Hooks objects \r\n                || !$this-&gt;registerHook('actionObjectCustomerAddAfter') \r\n                || !$this-&gt;registerHook('actionObjectCustomerUpdateAfter')\r\n                \/\/Hook validation des champs\r\n                || !$this->registerHook('validateCustomerFormFields') \r\n        ) {\r\n            return false;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    \/**\r\n     * D\u00e9sinstallation du module\r\n     * @return boolean\r\n     *\/\r\n    public function uninstall() {\r\n        return parent::uninstall() &amp;&amp; $this-&gt;_unInstallSql();\r\n    }\r\n\r\n    \/**\r\n     * Modifications sql du module\r\n     * @return boolean\r\n     *\/\r\n    protected function _installSql() {\r\n        $sqlInstall = \"ALTER TABLE \" . _DB_PREFIX_ . \"customer \"\r\n                . \"ADD professionnal_id VARCHAR(255) NULL, \"\r\n                . \"ADD justificatif VARCHAR(255) NULL\";\r\n\r\n        return Db::getInstance()-&gt;execute($sqlInstall);\r\n    }\r\n\r\n    \/**\r\n     * Suppression des modification sql du module\r\n     * @return boolean\r\n     *\/\r\n    protected function _unInstallSql() {\r\n        $sqlUnInstall = \"ALTER TABLE \" . _DB_PREFIX_ . \"customer \"\r\n                . \"DROP professionnal_id,\"\r\n                . \" DROP justificatif\";\r\n\r\n        return Db::getInstance()-&gt;execute($sqlUnInstall);\r\n    }\r\n}\r\n<\/pre>\n<p>Ce module ajoute donc 2 colonnes correspondants \u00e0 nos 2 champs suppl\u00e9mentaires dans la table customer.<br \/>\nIl se greffe \u00e9galement sur les hooks suivants :<\/p>\n<ul>\n<li><strong>actionAdminCustomersControllerSaveAfter<\/strong> : Ex\u00e9cut\u00e9 apr\u00e8s la sauvegarde d&rsquo;un client en back office<\/li>\n<li><strong>actionAdminCustomersFormModifier<\/strong> : Ex\u00e9cut\u00e9 avant l&rsquo;affichage du formulaire d&rsquo;\u00e9dition en back office<\/li>\n<li><strong>additionalCustomerFormFields<\/strong> : Ajout de champs suppl\u00e9mentaires dans le formulaire d&rsquo;\u00e9dition client<\/li>\n<li><strong>actionObjectCustomerAddAfter<\/strong> : Ex\u00e9cut\u00e9 apr\u00e8s l&rsquo;ajout d&rsquo;un nouveau client<\/li>\n<li><strong>actionObjectCustomerUpdateAfter<\/strong> : Ex\u00e9cut\u00e9 apr\u00e8s la mise \u00e0 jour d&rsquo;un client<\/li>\n<\/ul>\n<p>Nous verrons plus loin le d\u00e9tails des diff\u00e9rentes fonctions.<\/p>\n<p>Il est \u00e9galement n\u00e9cessaire de surcharger l&rsquo;objet Customer et de lui ajouter ces nouveaux champs.<br \/>\nPour cela cr\u00e9\u00e9r un fichier Customer.php avec le contenu suivant dans le dossier override\/classes du module.<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php \r\nclass Customer extends CustomerCore { \r\n\/\/Nouveaux param\u00e8tres de classe \r\npublic $professionnal_id; \r\npublic $justificatif;\r\n \r\npublic function __construct($id = null) { \r\n\/\/D\u00e9finition du nouveau champ professionnal_id \r\n       self::$definition['fields']['professionnal_id'] = [ 'type' =&gt; self::TYPE_STRING,\r\n            'required' =&gt; false, 'size' =&gt; 255\r\n        ];\r\n        \/\/D\u00e9finition du nouveau champ justificatif\r\n        self::$definition['fields']['justificatif']     = [\r\n            'type' =&gt; self::TYPE_STRING,\r\n            'required' =&gt; false, 'size' =&gt; 255\r\n        ];\r\n        parent::__construct($id);\r\n    }\r\n}\r\n<\/pre>\n<p>lors de l&rsquo;installation du module ce fichier sera automatiquement plac\u00e9 dans le dossier des override par prestashop.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Ajout d&rsquo;un nouveau champ standard (pour le client) :<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Le fonctionnement est tr\u00e8s simple, ( apr\u00e8s l&rsquo;ex\u00e9cution des \u00e9tapes pr\u00e9c\u00e9dentes ), nous utiliserons le hook <strong>AdditionalCustomerFormFields<\/strong> dans la fonction hookAdditionalCustomerFormFields du module.<\/p>\n<p>il faut d\u00e9clarer les nouveaux champs de la mani\u00e8re suivante :<\/p>\n<pre lang=\"php\" escaped=\"true\">   \/**\r\n     * Ajout d'un champ client suppl\u00e9mentaire en FO\r\n     * @param type $params\r\n     *\/\r\n    public function hookAdditionalCustomerFormFields($params) {\r\n\r\n        return [\r\n                    (new FormField)\r\n                    -&gt;setName('professionnal_id')\r\n                    -&gt;setType('text')\r\n                    \/\/-&gt;setRequired(true) D\u00e9commenter pour rendre obligatoire\r\n                    -&gt;setLabel($this-&gt;l('Professionnal id')),\r\n                    (new FormField)\r\n                    -&gt;setName('justificatif_upload')\r\n                    -&gt;setType('file')\r\n                    -&gt;setLabel($this-&gt;l('document ID'))\r\n        ];\r\n    }\r\n<\/pre>\n<p>Et puis c&rsquo;est tout &#8230; :), tout fonctionne tr\u00e8s bien ensuite tant que l&rsquo;attribut \u00ab\u00a0name\u00a0\u00bb de votre FormField correspond bien au nom du champ dans la classe et dans la base de donn\u00e9e, prestashop enregistera automatiquement les nouvelles informations<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Ajout d&rsquo;un nouveau champ standard (dans l&rsquo;administration ) :<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Pour l&rsquo;ajout des champs dans l&rsquo;administration je ne d\u00e9taille pas, vous pouvez voir le fonctionnement g\u00e9n\u00e9ral dans cet article : <a href=\"https:\/\/www.h-hennes.fr\/blog\/2017\/06\/21\/prestashop-ajouter-des-champs-dans-un-formulaire-dadministration\/\" target=\"_blank\" rel=\"noopener noreferrer\">Prestashop : Ajouter des champs dans un formulaire d&rsquo;administration<\/a><\/p>\n<p>Nous utlisons le hook <strong>actionAdminCustomersFormModifier<\/strong> pour ajouter les nouveaux champs et d\u00e9finir leur valeur.<\/p>\n<pre lang=\"php\" escaped=\"true\">\/**\r\n * Modification du formulaire d'\u00e9dition d'un client en BO\r\n * @param type $params\r\n *\/\r\npublic function hookActionAdminCustomersFormModifier($params) {\r\n\r\n\t$params['fields'][0]['form']['input'][] = [\r\n\t\t'type' =&gt; 'text',\r\n\t\t'label' =&gt; $this-&gt;l('Professionnal id'),\r\n\t\t'name' =&gt; 'professionnal_id',\r\n\t\t'class' =&gt; 'input fixed-width-xxl',\r\n\t\t'hint' =&gt; $this-&gt;l('Professionnal id')\r\n\t];\r\n\r\n\t\/\/D\u00e9finition de la valeur du champ suppl\u00e9mentaire\r\n\t$params['fields_value']['professionnal_id'] = $params['object']-&gt;professionnal_id;\r\n}\r\n<\/pre>\n<p>Et voila l&rsquo;enregistrement du nouveau champ fonctionne \u00e9galement dans le backoffice.<br \/>\nVous vous dites sans-doute que nous n&rsquo;avons pas utilis\u00e9 l&rsquo;ensemble des hooks \u00e9nonc\u00e9s plus hauts&#8230;, c&rsquo;est pourquoi nous allons voir un cas particulier, l&rsquo;ajout d&rsquo;un champ de type file<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Cas particulier : ajout d&rsquo;un nouveau champ de type file<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>Pour les champs de type file 2 contraintes s&rsquo;ajoutent par rapport aux champs standards :<\/p>\n<ul>\n<li>Upload de la pi\u00e8ce jointe<\/li>\n<li>Mise \u00e0 jour du champ ( et aucune action si celui-ci est vide )<\/li>\n<\/ul>\n<p>J&rsquo;ai eut un peu de mal \u00e0 trouver une solution propre pour g\u00e9rer la mise \u00e0 jour de cette donn\u00e9es, mais finalement je suis pass\u00e9 par le contournement suivant :<\/p>\n<p>Dans les formulaires , le nom du champ ajout\u00e9 n&rsquo;est pas celui-correspondant \u00e0 la propri\u00e9t\u00e9 de la classe.<\/p>\n<p>Par exemple pour le champ \u00ab\u00a0<strong>justificatif<\/strong>\u00a0\u00bb j&rsquo;ai rajout\u00e9 dans les formulaires un champ \u00ab\u00a0<strong>justificatif_upload<\/strong>\u00a0\u00bb<br \/>\nL&rsquo;assignation de la valeur au client est ensuite g\u00e9r\u00e9e via des hooks prestashop.<\/p>\n<p><strong>Dans l&rsquo;administration :<\/strong><\/p>\n<p>Affichage du champ + ajout d&rsquo;un champ pour g\u00e9rer sa suppression<\/p>\n<pre lang=\"php\" escaped=\"true\">\/**\r\n* Modification du formulaire d'\u00e9dition d'un client en BO\r\n* @param type $params\r\n*\/\r\npublic function hookActionAdminCustomersFormModifier($params) {\r\n\r\n$params['fields'][0]['form']['input'][] = [\r\n'type' =&gt; 'file',\r\n'label' =&gt; $this-&gt;l('File upload'),\r\n'name' =&gt; 'justificatif_upload',\r\n'hint' =&gt; $this-&gt;l('File upload field add with a module')\r\n];\r\n\r\n\/\/Si la pi\u00e8ce jointe est d\u00e9j\u00e0 assign\u00e9e on donne la possibilit\u00e9 de la supprimer\r\nif ($params['object']-&gt;justificatif &amp;&amp; $params['object']-&gt;justificatif != '') {\r\n$fileUrl = $this-&gt;context-&gt;link-&gt;getBaseLink() . 'modules\/' . $this-&gt;name . '\/files\/' . $params['object']-&gt;justificatif;\r\n$params['fields'][0]['form']['input'][] = [\r\n'type' =&gt; 'html',\r\n'label' =&gt; $this-&gt;l('Delete justificatif'),\r\n'name' =&gt; 'delete_justificatif',\r\n'html_content' =&gt; '&lt;div class=\"checkbox\"&gt;\r\n&lt;p&gt;' . $this-&gt;l('Current File') . ': &lt;a href=\"' . $fileUrl . '\" target=\"_blank\"&gt;' . $params['object']-&gt;justificatif . '&lt;\/a&gt;&lt;\/p&gt;\r\n&lt;label for=\"delete_justificatif\"&gt;\r\n&lt;input type=\"checkbox\" name=\"delete_justificatif\" value=\"' . $params['object']-&gt;justificatif . '\"\/&gt;\r\n' . $this-&gt;l('Delete File ?') . '\r\n&lt;\/label&gt;\r\n&lt;\/div&gt;',\r\n'hint' =&gt; $this-&gt;l('Check this to delete current justificatif')\r\n];\r\n}\r\n\r\n}\r\n<\/pre>\n<p>Gestion de la suppression via le hook <strong>adminCustomersControllerSaveAfter<\/strong><\/p>\n<pre lang=\"php\" escaped=\"true\">\/**\r\n     * Ev\u00e9nement apr\u00e8s la sauvegarde du client dans le back-office\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionAdminCustomersControllerSaveAfter($params) {\r\n\r\n        \/\/Suppression du fichier actuel si d\u00e9fini\r\n        if ($deletejustificatif = Tools::getValue('delete_justificatif')) {\r\n\r\n            $currentFile = dirname(__FILE__) . '\/files\/' . $justificatif;\r\n            if (is_file($currentFile)) {\r\n                unlink($currentFile);\r\n            }\r\n\r\n            try {\r\n                $params['return']-&gt;justificatif = '';\r\n                $params['return']-&gt;save();\r\n            } catch (Exception $ex) {\r\n                PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<p><strong>Sur le front office :<\/strong><\/p>\n<p>Attention pour permettre l&rsquo;envoi de fichiers via la formulaire d&rsquo;inscription il faut ajouter la propri\u00e9t\u00e9 suivante : <em>enctype=\u00a0\u00bbmultipart\/form-data\u00a0\u00bb<\/em> au formulaire de cr\u00e9ation de compte de compte dans le fichier :<br \/>\nthemes\/votre-theme\/customer\/__partials\/customer-form.tpl<\/p>\n<p>Lors de la cr\u00e9ation d&rsquo;un compte client ( en front office ou via l&rsquo;administration ) nous allons utiliser le hook <strong>actionObjectCustomerAddAfter<\/strong> via le code suivant :<\/p>\n<pre lang=\"php\" escaped=\"true\">\/**\r\n     * Ajout de la pi\u00e8ce jointe \u00e0 la cr\u00e9ation du compte\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionObjectCustomerAddAfter($params) {\r\n        \/\/Gestion de l'upload du fichier lors de la cr\u00e9ation de compte en Front office et en BO\r\n        if (\r\n                $this-&gt;context-&gt;controller-&gt;php_self == 'authentication'\r\n                || $this-&gt;context-&gt;controller instanceof AdminCustomersController\r\n            ) {\r\n\r\n            if (isset($_FILES['justificatif_upload']) &amp;&amp; $_FILES['justificatif_upload']['name'] != \"\") {\r\n                $fileUpload = $this-&gt;_uploadFile('justificatif_upload');\r\n                \/\/En cas d'erreur on supprime la valeur\r\n                if ($fileUpload[0]['error'] == '0') {\r\n                    $params['object']-&gt;justificatif = $fileUpload[0]['name'];\r\n                    try {\r\n                        $params['object']-&gt;save();\r\n                    } catch (Exception $ex) {\r\n                        PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<p>Celui-ci permet de n&rsquo;effectuer ce traitement uniquement dans les pages de cr\u00e9ation de compte client.<\/p>\n<p>Pour finir pour g\u00e9rer la mise \u00e0 jour du client nous utiliserons le hook : <strong>actionObjectCustomerUpdateAfter<\/strong><\/p>\n<pre lang=\"php\" escaped=\"true\">\/**\r\n     * Action effectu\u00e9e APRES la mise \u00e0 jour d'un client\r\n     * Gestion de l'upload de la pi\u00e8ce jointe si il y'a an une\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionObjectCustomerUpdateAfter($params) {\r\n\r\n        if (\r\n                $this-&gt;context-&gt;controller-&gt;php_self == 'identity'\r\n                || $this-&gt;context-&gt;controller instanceof AdminCustomersController\r\n            ) {\r\n\r\n            if (isset($_FILES['justificatif_upload']) &amp;&amp; $_FILES['justificatif_upload']['name'] != \"\" &amp;&amp; !$this-&gt;context-&gt;cookie-&gt;__isset('customer_justificatif_updated')) {\r\n\r\n                $fileUpload = $this-&gt;_uploadFile('justificatif_upload');\r\n\r\n                \/\/En cas d'erreur on supprime la valeur\r\n                if ($fileUpload[0]['error'] != '0') {\r\n                    $params['object']-&gt;justificatif = '';\r\n                } else {\r\n                    $params['object']-&gt;justificatif = $fileUpload[0]['name'];\r\n                }\r\n\r\n                try {\r\n                    \/\/Mise en place d'un flag pour \u00e9viter une boucle de redirection\r\n                    $this-&gt;context-&gt;cookie-&gt;__set('customer_justificatif_updated', 1);\r\n                    $params['object']-&gt;save();\r\n                } catch (Exception $ex) {\r\n                    PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n                }\r\n            } else {\r\n                $this-&gt;context-&gt;cookie-&gt;__unset('customer_justificatif_updated');\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<p>La principale difficult\u00e9 dans ce hook \u00e9tant qu&rsquo;il est effectu\u00e9 lors de la mise \u00e0 jour d&rsquo;un client, et que ce code g\u00e9n\u00e8re la mise \u00e0 jour d&rsquo;un client&#8230;<br \/>\nPour \u00e9viter les boucles infinies il est donc n\u00e9cessaire de mettre en place un cookie d\u00e9finissant que le client a d\u00e9j\u00e0 \u00e9t\u00e9 mis \u00e0 jour.<\/p>\n<p>Edit 2018-03-13 :<br \/>\n<strong>Ajout d&rsquo;une validation sur les champs personnalis\u00e9s :<\/strong><\/p>\n<p>Il est \u00e9galement possible de rajouter une validation personnalis\u00e9e sur ces champs pour emp\u00eacher la soumission du formulaire si ceux-ci contiennent une erreur.<br \/>\nPour cela il faut que le module utilise le hook <strong>validateCustomerFormFields<\/strong>.<\/p>\n<p>Le module obtiendra uniquement les instances des champs qui lui sont li\u00e9.<br \/>\nVoici un exemple pour v\u00e9rifier si le champ professionnal_id comprends 6 caract\u00e8res, mais vous pouvez appliquer ici toutes les r\u00e8gles de validation souhait\u00e9es.<\/p>\n<pre lang=\"php\" escaped=\"true\">\r\n\/**\r\n     * Validation des champs du formulaire client\r\n     * @param type $params array : Tableau des champs du formulaire client li\u00e9 au module\r\n     * Instance de Field\r\n     * cf. https:\/\/github.com\/PrestaShop\/PrestaShop\/pull\/6374\r\n     *\/\r\n    public function hookValidateCustomerFormFields($params)\r\n    {\r\n        foreach ( $params['fields'] as $field){\r\n           \r\n            \/** @var FormField $field *\/          \r\n            \/\/Validation custom du champ professionnal id si celui-ci n'est pas vide\r\n            if ( $field->getName() == 'professionnal_id' && $field->getValue() != \"\") {\r\n                \r\n                \/\/Mise en place de notre v\u00e9rification ( ex: 6 caract\u00e8re pour le champ)\r\n                if ( strlen($field->getValue()) != 6 ){\r\n                   \/\/D\u00e9finition de l'erreur.\r\n                    $field->setErrors(array($this->l('This code must have 6 characters')));\r\n                }\r\n            }\r\n        }\r\n        \r\n        \/\/Renvoi du tableau des param\u00e8tres\r\n        return $params['fields'];\r\n    }\r\n<\/pre>\n<p>Dans le cas ou le champ n&rsquo;est pas valide le message d&rsquo;erreur est affich\u00e9 et le formulaire n&rsquo;est pas pris en compte, comme vous pouvez le voir sur la capture ci-dessous.<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2017\/10\/champs-erreurs.jpg\" alt=\"Champs erreurs\" width=\"721\" height=\"785\" class=\"alignnone size-full wp-image-1829\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2017\/10\/champs-erreurs.jpg 721w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2017\/10\/champs-erreurs-276x300.jpg 276w\" sizes=\"auto, (max-width: 721px) 100vw, 721px\" \/><\/p>\n<p>Nous en avons fini avec cette probl\u00e8matique d&rsquo;ajout des nouveau champs, vous pouvez voir le code complet du module ci-dessous :<\/p>\n<pre lang=\"php\" escaped=\"true\"> \r\n&lt;?php class HhCustomer extends Module { public function __construct() { $this-&gt;name = 'hhcustomer';\r\n        $this-&gt;tab = 'others';\r\n        $this-&gt;author = 'hhennes';\r\n        $this-&gt;version = '0.1.0';\r\n        $this-&gt;need_instance = 0;\r\n        $this-&gt;bootstrap = true;\r\n\r\n        parent::__construct();\r\n\r\n        $this-&gt;displayName = $this-&gt;l('hhcustomer');\r\n        $this-&gt;description = $this-&gt;l('add new fields to customer');\r\n        $this-&gt;ps_versions_compliancy = array('min' =&gt; '1.7.1', 'max' =&gt; _PS_VERSION_);\r\n    }\r\n\r\n    \/**\r\n     * @return boolean\r\n     *\/\r\n    public function install() {\r\n        if (!parent::install() || !$this-&gt;_installSql()\r\n                \/\/Hooks Admin\r\n                || !$this-&gt;registerHook('actionAdminCustomersControllerSaveAfter') \r\n                || !$this-&gt;registerHook('actionAdminCustomersFormModifier')\r\n                \/\/Hooks Front        \r\n                || !$this-&gt;registerHook('additionalCustomerFormFields')\r\n                \/\/Hooks objects \r\n                || !$this-&gt;registerHook('actionObjectCustomerAddAfter') \r\n                || !$this-&gt;registerHook('actionObjectCustomerUpdateAfter')\r\n                \/\/Hook validation des champs\r\n                || !$this->registerHook('validateCustomerFormFields')\r\n        ) {\r\n            return false;\r\n        }\r\n\r\n        return true;\r\n    }\r\n\r\n    public function uninstall() {\r\n        return parent::uninstall() &amp;&amp; $this-&gt;_unInstallSql();\r\n    }\r\n\r\n    \/**\r\n     * Modifications sql du module\r\n     * @return boolean\r\n     *\/\r\n    protected function _installSql() {\r\n        $sqlInstall = \"ALTER TABLE \" . _DB_PREFIX_ . \"customer \"\r\n                . \"ADD professionnal_id VARCHAR(255) NULL, \"\r\n                . \"ADD justificatif VARCHAR(255) NULL\";\r\n\r\n        return Db::getInstance()-&gt;execute($sqlInstall);\r\n    }\r\n\r\n    \/**\r\n     * Suppression des modification sql du module\r\n     * @return boolean\r\n     *\/\r\n    protected function _unInstallSql() {\r\n        $sqlUnInstall = \"ALTER TABLE \" . _DB_PREFIX_ . \"customer \"\r\n                . \"DROP professionnal_id,\"\r\n                . \" DROP justificatif\";\r\n\r\n        return Db::getInstance()-&gt;execute($sqlUnInstall);\r\n    }\r\n    \r\n    \/**\r\n     * Ev\u00e9nement apr\u00e8s la sauvegarde du client dans le back-office\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionAdminCustomersControllerSaveAfter($params) {\r\n\r\n        \/\/Suppression du fichier actuel si d\u00e9fini\r\n        if ($deletejustificatif = Tools::getValue('delete_justificatif')) {\r\n\r\n            $currentFile = dirname(__FILE__) . '\/files\/' . $justificatif;\r\n            if (is_file($currentFile)) {\r\n                unlink($currentFile);\r\n            }\r\n\r\n            try {\r\n                $params['return']-&gt;justificatif = '';\r\n                $params['return']-&gt;save();\r\n            } catch (Exception $ex) {\r\n                PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n            }\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Modification du formulaire d'\u00e9dition d'un client en BO\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionAdminCustomersFormModifier($params) {\r\n\r\n        $params['fields'][0]['form']['input'][] = [\r\n            'type' =&gt; 'text',\r\n            'label' =&gt; $this-&gt;l('Professionnal id'),\r\n            'name' =&gt; 'professionnal_id',\r\n            'class' =&gt; 'input fixed-width-xxl',\r\n            'hint' =&gt; $this-&gt;l('Professionnal id')\r\n        ];\r\n\r\n        $params['fields'][0]['form']['input'][] = [\r\n            'type' =&gt; 'file',\r\n            'label' =&gt; $this-&gt;l('File upload'),\r\n            'name' =&gt; 'justificatif_upload',\r\n            'hint' =&gt; $this-&gt;l('File upload field add with a module')\r\n        ];\r\n\r\n       \/\/Si la pi\u00e8ce jointe est d\u00e9j\u00e0 assign\u00e9e on donne la possibilit\u00e9 de la supprimer\r\n         if ($params['object']-&gt;justificatif &amp;&amp; $params['object']-&gt;justificatif != '') {\r\n           $fileUrl = $this-&gt;context-&gt;link-&gt;getBaseLink() . 'modules\/' . $this-&gt;name . '\/files\/' . $params['object']-&gt;justificatif;\r\n           $params['fields'][0]['form']['input'][] = [\r\n           'type' =&gt; 'html',\r\n           'label' =&gt; $this-&gt;l('Delete justificatif'),\r\n           'name' =&gt; 'delete_justificatif',\r\n           'html_content' =&gt; '&lt;div class=\"checkbox\"&gt;\r\n           &lt;p&gt;' . $this-&gt;l('Current File') . ': &lt;a href=\"' . $fileUrl . '\" target=\"_blank\"&gt;' . $params['object']-&gt;justificatif . '&lt;\/a&gt;&lt;\/p&gt;\r\n           &lt;label for=\"delete_justificatif\"&gt;\r\n           &lt;input type=\"checkbox\" name=\"delete_justificatif\" value=\"' . $params['object']-&gt;justificatif . '\"\/&gt;\r\n           ' . $this-&gt;l('Delete File ?') . '\r\n           &lt;\/label&gt;\r\n           &lt;\/div&gt;',\r\n           'hint' =&gt; $this-&gt;l('Check this to delete current justificatif')\r\n          ];\r\n         }\r\n\r\n        \/\/D\u00e9finition de la valeur du champ suppl\u00e9mentaire\r\n        $params['fields_value']['professionnal_id'] = $params['object']-&gt;professionnal_id;\r\n    }\r\n\r\n    \/**\r\n     * Ajout d'un champ client suppl\u00e9mentaire en FO\r\n     * @param type $params\r\n     *\/\r\n    public function hookAdditionalCustomerFormFields($params) {\r\n\r\n        return [\r\n                    (new FormField)\r\n                    -&gt;setName('professionnal_id')\r\n                    -&gt;setType('text')\r\n                    -&gt;setLabel($this-&gt;l('Professionnal id')),\r\n                    (new FormField)\r\n                    -&gt;setName('justificatif_upload')\r\n                    -&gt;setType('file')\r\n                    -&gt;setLabel($this-&gt;l('document ID'))\r\n        ];\r\n    }\r\n\r\n    \/**\r\n     * Ajout de la pi\u00e8ce jointe \u00e0 la cr\u00e9ation du compte\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionObjectCustomerAddAfter($params) {\r\n        \/\/Gestion de l'upload du fichier lors de la cr\u00e9ation de compte en Front office et en BO\r\n        if (\r\n                $this-&gt;context-&gt;controller-&gt;php_self == 'authentication'\r\n                || $this-&gt;context-&gt;controller instanceof AdminCustomersController\r\n            ) {\r\n\r\n            if (isset($_FILES['justificatif_upload']) &amp;&amp; $_FILES['justificatif_upload']['name'] != \"\") {\r\n                $fileUpload = $this-&gt;_uploadFile('justificatif_upload');\r\n                \/\/En cas d'erreur on supprime la valeur\r\n                if ($fileUpload[0]['error'] == '0') {\r\n                    $params['object']-&gt;justificatif = $fileUpload[0]['name'];\r\n                    try {\r\n                        $params['object']-&gt;save();\r\n                    } catch (Exception $ex) {\r\n                        PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Action effectu\u00e9e APRES la mise \u00e0 jour d'un client\r\n     * Gestion de l'upload de la pi\u00e8ce jointe si il y'a an une\r\n     * @param type $params\r\n     *\/\r\n    public function hookActionObjectCustomerUpdateAfter($params) {\r\n\r\n        if (\r\n                $this-&gt;context-&gt;controller-&gt;php_self == 'identity'\r\n                || $this-&gt;context-&gt;controller instanceof AdminCustomersController\r\n            ) {\r\n\r\n            if (isset($_FILES['justificatif_upload']) &amp;&amp; $_FILES['justificatif_upload']['name'] != \"\" &amp;&amp; !$this-&gt;context-&gt;cookie-&gt;__isset('customer_justificatif_updated')) {\r\n\r\n                $fileUpload = $this-&gt;_uploadFile('justificatif_upload');\r\n\r\n                \/\/En cas d'erreur on supprime la valeur\r\n                if ($fileUpload[0]['error'] != '0') {\r\n                    $params['object']-&gt;justificatif = '';\r\n                } else {\r\n                    $params['object']-&gt;justificatif = $fileUpload[0]['name'];\r\n                }\r\n\r\n                try {\r\n                    \/\/Mise en place d'un flag pour \u00e9viter une boucle de redirection\r\n                    $this-&gt;context-&gt;cookie-&gt;__set('customer_justificatif_updated', 1);\r\n                    $params['object']-&gt;save();\r\n                } catch (Exception $ex) {\r\n                    PrestaShopLogger::addLog($this-&gt;l('Error in customer in module ' . $this-&gt;name));\r\n                }\r\n            } else {\r\n                $this-&gt;context-&gt;cookie-&gt;__unset('customer_justificatif_updated');\r\n            }\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Envoi du fichier en Front et en back\r\n     *\/\r\n    protected function _uploadFile($index) {\r\n        $_registration_allowed_extensions = array('txt', 'rtf', 'doc', 'docx', 'pdf', 'png', 'jpeg', 'gif', 'jpg');\r\n        $uploader = new Uploader($index); \/\/Renseigner ici le nom du champ input\r\n        return $uploader-&gt;setAcceptTypes($_registration_allowed_extensions) \/\/ D\u00e9finition des extensions autoris\u00e9es\r\n                        -&gt;setCheckFileSize(Uploader::DEFAULT_MAX_SIZE) \/\/Taille maximum des fichiers \u00e0 envoyer\r\n                        -&gt;setSavePath(dirname(__FILE__) . '\/files\/') \/\/ R\u00e9pertoire de destination\r\n                        -&gt;process(); \/\/ Traitement de l'envoi\r\n    }\r\n\r\n   \/**\r\n     * Validation des champs du formulaire client\r\n     * @param type $params array : Tableau des champs du formulaire client li\u00e9 au module\r\n     * Instance de Field\r\n     * cf. https:\/\/github.com\/PrestaShop\/PrestaShop\/pull\/6374\r\n     *\/\r\n    public function hookValidateCustomerFormFields($params)\r\n    {\r\n        foreach ( $params['fields'] as $field){\r\n           \r\n            \/** @var FormField $field *\/          \r\n            \/\/Validation custom du champ professionnal id si celui-ci n'est pas vide\r\n            if ( $field->getName() == 'professionnal_id' && $field->getValue() != \"\") {\r\n                \r\n                \/\/Mise en place de notre v\u00e9rification ( ex: 6 caract\u00e8re pour le champ)\r\n                if ( strlen($field->getValue()) != 6 ){\r\n                    $field->setErrors(array($this->l('This code must have 6 characters')));\r\n                }\r\n            }\r\n        }\r\n        \r\n        \/\/Renvoi du tableau des param\u00e8tres au validateur\r\n        return $params['fields'];\r\n    }\r\n\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>La version 1.7 de prestashop apporte des changements dans la gestion des champs clients. Cet article est une mise \u00e0 jour avec\u00a0 des articles suivants\u00a0 qui ne fonctionnent donc plus sur prestashop 1.7 Prestashop Envoyer des fichiers lors de la cr\u00e9ation du compte client Prestashop ajouter des champs \u00e0 l&rsquo;inscription Le but de ce tutoriel [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[245],"tags":[504,383,483],"class_list":["post-1624","post","type-post","status-publish","format-standard","hentry","category-prestashop-2","tag-champs-additonnel","tag-client","tag-prestashop-1-7","prestashop-1-4","prestashop-1-6","prestashop-1-7","prestashop-1-7-2","prestashop-1-7-3","prestashop-1-7-4","prestashop-1-7-5","prestashop-1-7-6","prestashop-1-7-7","prestashop-1-7-8","prestashop-8-0","prestashop-8-1"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/1624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/comments?post=1624"}],"version-history":[{"count":10,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/1624\/revisions"}],"predecessor-version":[{"id":2114,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/1624\/revisions\/2114"}],"wp:attachment":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/media?parent=1624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/categories?post=1624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/tags?post=1624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}