Cet article est une mise à jour de l’article suivant https://www.h-hennes.fr/blog/2017/06/21/prestashop-ajouter-des-champs-dans-un-formulaire-dadministration/ qui s’applique aux controllers qui utilisent symfony, c’est le cas à partir 1.7.6 de Prestashop

Si vous avez des doutes si le controller sur lequel vous souhaitez ajouter des champs fonctionne avec ce méthode, n’hésitez pas à consulter l’article suivant pour l’identifier  : https://www.h-hennes.fr/blog/2019/07/25/prestashop-1-7-identifier-si-un-controller-admin-a-ete-migre-vers-symfony/

L’objectif est d’ajouter un nouveau champ dans un formulaire d’administration de manière propre via un module.

Fonctionnement technique

Comme pour les versions précédentes des hooks dynamiques sont présents dans le code prestashop pour vous permettre gérer des informations supplémentaires via vos modules dans les formulaires.

Pour ajouter des champs le hook est exécuté dans la fonction buildForm du fichier src/Core/Form/IdentifiableObject/Builder/FormBuilder.php

Les noms des hooks sont construits sous la forme suivante :

action . Container::camelize($formBuilder->getName()) . FormBuilderModifier

/**
     * @param string $formType
     * @param array $data
     * @param int|null $id
     * @param array $options
     *
     * @return FormInterface
     */
    private function buildForm($formType, $data, $id = null, array $options = [])
    {
        $formBuilder = $this->formFactory->createBuilder($formType, $data, $options);
        $this->hookDispatcher->dispatchWithParameters('action' . Container::camelize($formBuilder->getName()) . 'FormBuilderModifier', [
            'form_builder' => $formBuilder,
            'data' => &$data,
            'id' => $id,
        ]);
 
        return $formBuilder->getForm();
    }

Pour la création et la mise à jour des données les hooks sont appellés dans les fonctions handleFormUpdate ou handleFormCreate du fichier src/Core/Form/IdentifiableObject/Handler/FormHandler.php

Les noms des hooks sont construits sous la forme suivante :

actionBeforeUpdate . Container::camelize($form->getName()) . FormHandler
actionAfterUpdate. Container::camelize($form->getName()) . FormHandler

Voici le code exécuté par exemple après la mise à jour d’un formulaire

/**
     * @param FormInterface $form
     * @param int $id
     *
     * @return FormHandlerResultInterface
     */
    private function handleFormUpdate(FormInterface $form, $id)
    {
        $data = $form->getData();
 
        $this->hookDispatcher->dispatchWithParameters('actionBeforeUpdate' . Container::camelize($form->getName()) . 'FormHandler', [
            'form_data' => &$data,
            'id' => $id,
        ]);
 
        $this->dataHandler->update($id, $data);
 
        $this->hookDispatcher->dispatchWithParameters('actionAfterUpdate' . Container::camelize($form->getName()) . 'FormHandler', [
            'id' => $id,
            'form_data' => &$data,
        ]);
 
        return FormHandlerResult::createWithId($id);
    }

Exemples de noms de hooks

Suite aux informations précédentes voici donc des exemples de hook disponibles pour l’objet Category :

  • hookActionCategoryFormBuilderModifier
  • hookActionBeforeCreateCategoryFormHandler
  • hookActionAfterCreateCategoryFormHandler
  • hookActionBeforeUpdateCategoryFormHandler
  • hookActionAfterUpdateCategoryFormHandler

Objets disponibles.

A ce jour sur la version 1.7.6.0 ce fonctionnement est disponible pour les objets suivants :

  • SqlRequest
  • Customer
  • Language
  • Currency
  • WebserviceKey
  • Meta
  • Category
  • RootCategory
  • Contact
  • CmsPage
  • CmsPageCategory
  • Tax
  • Manufacturer
  • Employee
  • Profile
  • ManufacturerAddress

Exemple d’implémentation

Voici comment procéder pour rajouter des champs via un module qui s’appellera hh_sampleadminform

Pour l’exemple nous allons ajouter :

  • un champ simple
  • un champ langue

Voici le code complet du module avec l’implémentation des différents hooks évoqué plus hauts.

J’ai mis un maximum de commentaires directement dans le code pour expliquer les différentes possibilités.
( Et laissé le nom des classes complets pour s’y retrouver plus facilement )

Pour ceux qui utilisent déjà symfony la modification des formulaires sera relativement facile à comprendre

 

<?php
class Hh_SampleAdminForm extends Module
{
 
    /**
     * Hh_SampleAdminForm constructor
     * Instanciation du module
     */
    public function __construct()
    {
        $this->name = 'hh_sampleadminform';
        $this->tab = 'others';
        $this->version = '0.2.0';
        $this->author = 'hhennes';
        $this->bootstrap = true;
        parent::__construct();
 
        $this->displayName = $this->l('Sample Admin form');
        $this->description = $this->l('Sample module for admin form hooks for ps 1.7.6 and > ');
    }
 
    /**
     * Installation du module
     * @return bool
     */
    public function install()
    {
        if (!parent::install()
            //Installation des hooks
            || !$this->registerHook([
                'actionCategoryFormBuilderModifier',
                'actionAfterCreateCategoryFormHandler',
                'actionAfterUpdateCategoryFormHandler',
            ])
        ) {
            return false;
        }
 
        return true;
    }
 
    /**
     * Modification du formulaire de la catégorie
     * @param array $params
     */
    public function hookActionCategoryFormBuilderModifier(array $params)
    {
        //Récupération du form builder
        /** @var \Symfony\Component\Form\FormBuilder $formBuilder */
        $formBuilder = $params['form_builder'];
 
 
        //Ajout de notre champ spécifique
        $formBuilder->add($this->name . '_newfield1',
            //Cf génériques symonfy https://symfony.com/doc/current/reference/forms/types.html
            // et spécificiques prestashop https://devdocs.prestashop.com/1.7/development/components/form/types-reference/
            \Symfony\Component\Form\Extension\Core\Type\TextType::class,
            [
                'label' => $this->l('Custom field 1'), //Label du champ
                'required' => false, //Requis ou non
                'constraints' => [ //Contraintes du champs
                    //cf. génériques symfony : https://symfony.com/doc/current/reference/constraints.html
                    // Ou vous pouvez écrire la votre cf. https://symfony.com/doc/current/validation/custom_constraint.html
                    new \Symfony\Component\Validator\Constraints\Length([
                        'max' => 20,
                        'maxMessage' => $this->l('Max caracters allowed : 20'),
                    ]),
                ],
                //La valeur peut être setée ici
                'data' => 'test valeur' //Valeur du champ
            ]
        );
 
        //Ou surchargée ici
        $params['data'][$this->name . '_newfield1'] = 'Custom value 1';
 
      //Ajout d'un champ langue
        $formBuilder->add($this->name . '_newfield_lang',
            // cf. https://devdocs.prestashop.com/1.7/development/components/form/types-reference/
            \PrestaShopBundle\Form\Admin\Type\TranslatableType::class,
            [
                'label' => $this->l('Custom field Lang'), //Label du champ
                'required' => false, //Requis ou non
                'type' => \Symfony\Component\Form\Extension\Core\Type\TextType::class // OU TextAreaType::class
            ]
        );
        //Définition des données du champ langue
        $languages = Language::getLanguages(true);
        foreach ( $languages as $lang){
            $params['data'][$this->name . '_newfield_lang'][$lang['id_lang']] = 'Custom value for lang '.$lang['iso_code'];
        }
 
        //On peut également changer facilement la donnée de n'importe quel autre champ du formulaire
        $params['data']['active'] = false;
 
        //Il faut bien penser à mettre cette ligne pour mettre à jour les données au formulaire
        $formBuilder->setData($params['data']);
    }
 
    /**
     * Action effectuée après la création d'une catégorie
     * @param array $params
     */
    public function hookActionAfterCreateCategoryFormHandler(array $params)
    {
        $this->updateData($params['form_data']);
    }
 
    /**
     * Action effectuée après la mise à jour d'une catégorie
     * @param array $params
     */
    public function hookActionAfterUpdateCategoryFormHandler(array $params)
    {
        $this->updateData($params['form_data']);
    }
 
    /**
     * Fonction qui va effectuer la mise à jour
     * @param array $data
     */
    protected function updateData(array $data)
    {
        //Réalisation du traitement de mise à jour
    }
 
 
}

Les nouveaux champs sont ensuites bien présents dans la fiche d’édition de la catégorie 🙂

Champs catégorie

Il est à présent facile de réaliser les traitements souhaités sur les différents objets , n’hésitez pas à partager vos astuces ou à remonter les problèmes rencontrés sur cette partie