📝

Formularios Symfony en modulos PrestaShop 8/9

Actualizado: 2024-12-01

PrestaShop 8+ utiliza el componente Symfony Form para las paginas de configuracion del Back Office. El patron recomendado usa tres clases: el Form Type (estructura de campos), el DataConfiguration (mapeo a la tabla Configuration) y el FormHandler (orquesta carga, guardado y hooks).

#El patron triple: Type + DataConfiguration + DataProvider

ClaseResponsabilidadUbicacion
MyCustomTypeDefine los campos del formulariosrc/Form/MyCustomType.php
MyDataConfigurationMapea campos a claves de Configurationsrc/Form/MyDataConfiguration.php
ConfigurableFormDataProviderCarga y guarda datos del formClase del core — instanciar en services.yml
FormHandlerOrquesta form factory, hooks y data providerClase del core — instanciar en services.yml

#Form Type

src/Form/MyCustomType.php
php
<?php

declare(strict_types=1);

namespace MyModule\Form;

use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;

final class MyCustomType extends TranslatorAwareType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('my_setting', TextType::class, [
                'label'    => $this->trans('Nombre del ajuste', 'Modules.Mymodule.Admin'),
                'required' => false,
            ])
            ->add('my_flag', CheckboxType::class, [
                'label'    => $this->trans('Activar funcionalidad', 'Modules.Mymodule.Admin'),
                'required' => false,
            ]);
    }
}

#Data Configuration

src/Form/MyDataConfiguration.php — mapeo a ps_configuration
php
<?php

declare(strict_types=1);

namespace MyModule\Form;

use PrestaShop\PrestaShop\Core\Configuration\DataConfigurationInterface;
use PrestaShop\PrestaShop\Adapter\Configuration;

final class MyDataConfiguration implements DataConfigurationInterface
{
    private Configuration $configuration;

    public function __construct(Configuration $configuration)
    {
        $this->configuration = $configuration;
    }

    /**
     * Devuelve los valores actuales para pre-rellenar el formulario.
     */
    public function getConfiguration(): array
    {
        return [
            'my_setting' => $this->configuration->get('MY_MODULE_SETTING', ''),
            'my_flag'    => (bool) $this->configuration->get('MY_MODULE_FLAG', false),
        ];
    }

    /**
     * Guarda los valores enviados por el formulario.
     * Devuelve array de errores (vacio = exito).
     */
    public function updateConfiguration(array $config): array
    {
        $this->configuration->set('MY_MODULE_SETTING', $config['my_setting']);
        $this->configuration->set('MY_MODULE_FLAG', (int) $config['my_flag']);

        return []; // sin errores
    }

    /**
     * Validacion previa (opcional — dejar en true si usas Form Validation).
     */
    public function validateConfiguration(array $configuration): bool
    {
        return true;
    }
}

#Registro en services.yml

config/services.yml — declaracion de todos los servicios del formulario
yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: true

  # 1. Form Type
  my_module.form.type:
    class: MyModule\Form\MyCustomType
    parent: 'form.type.translatable.aware'
    tags:
      - { name: form.type }

  # 2. Data Configuration (mapea campos <-> Configuration)
  my_module.form.data_configuration:
    class: MyModule\Form\MyDataConfiguration
    arguments: ['@prestashop.adapter.legacy.configuration']

  # 3. Data Provider (usa la clase del core)
  my_module.form.data_provider:
    class: PrestaShop\PrestaShop\Core\Form\ConfigurableFormDataProvider
    arguments:
      - '@my_module.form.data_configuration'
      - '@prestashop.core.localization.locale.context'

  # 4. Form Handler (orquesta todo)
  my_module.form.handler:
    class: PrestaShop\PrestaShop\Core\Form\FormHandler
    arguments:
      - '@form.factory'
      - '@prestashop.core.hook.dispatcher'
      - '@my_module.form.data_provider'
      - 'MyModule\Form\MyCustomType'
      - 'MyModuleForm'   # sufijo para los hooks: actionMyModuleFormSave, etc.

#Renderizar en el Controller

src/Controller/Admin/ConfigurationController.php
php
<?php

declare(strict_types=1);

namespace MyModule\Controller\Admin;

use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ConfigurationController extends FrameworkBundleAdminController
{
    public function indexAction(Request $request): Response
    {
        $formHandler = $this->get('my_module.form.handler');
        $form = $formHandler->getForm();
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $errors = $formHandler->save($form->getData());

            if (empty($errors)) {
                $this->addFlash(
                    'success',
                    $this->trans('Configuracion guardada correctamente.', 'Admin.Notifications.Success')
                );
            } else {
                foreach ($errors as $error) {
                    $this->addFlash('error', $error);
                }
            }
        }

        return $this->render(
            '@Modules/my_module/views/templates/admin/configure.html.twig',
            ['form' => $form->createView()]
        );
    }
}

#Tipos especiales de PrestaShop

Tipos de campo disponibles en PrestaShopBundle
php
<?php

// Switch on/off (toggle)
use PrestaShopBundle\Form\Admin\Type\SwitchType;

// Campo de texto multilingual
use PrestaShopBundle\Form\Admin\Type\TranslatableType;

// Selector de categorias
use PrestaShopBundle\Form\Admin\Type\CategoryChoiceTreeType;

// Selector de impuestos
use PrestaShopBundle\Form\Admin\Type\TaxChoiceType;

// Selector de moneda
use PrestaShopBundle\Form\Admin\Type\CurrencyChoiceType;

// Textarea con TinyMCE (editor rico)
use PrestaShopBundle\Form\Admin\Type\FormattedTextareaType;

// Ejemplo con SwitchType
$builder->add('active', SwitchType::class, [
    'label'    => $this->trans('Activo', 'Admin.Global'),
    'required' => false,
]);

// Ejemplo con TranslatableType (campo multilingual)
$builder->add('description', TranslatableType::class, [
    'label'   => $this->trans('Descripcion', 'Admin.Global'),
    'type'    => FormattedTextareaType::class,
    'options' => ['required' => false],
]);
💡
CSRF incluido automaticamente

Al usar FormHandler del core, la proteccion CSRF de Symfony se aplica automaticamente. No es necesario añadir nada extra.

Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.