📝 Formularios Symfony — 6 modulos de ejemplo

Actualizado: 2026-04
ℹ️
6 modulos, un patron

PrestaShop ofrece 6 modulos de ejemplo para formularios Symfony, cada uno mostrando un aspecto diferente: hooks, upload, CQRS, FormTypes reutilizables, configuracion simple y DataProviders.

#demoextendsymfonyform1 — Identifiable Object hooks

Ensena como usar hooks de identifiable object y grid para anadir campos a formularios existentes del BO (ej: formulario de proveedor, fabricante, etc.).

Hooks para extender formularios de objetos existentes
php
<?php
// Anadir campo al formulario de Supplier
public function hookActionSupplierFormBuilderModifier(array $params): void
{
    /** @var FormBuilderInterface $formBuilder */
    $formBuilder = $params['form_builder'];
    $supplierId = $params['id'];

    // Anadir campo custom al formulario
    $formBuilder->add('demo_custom_field', TextType::class, [
        'label'    => 'My custom field',
        'required' => false,
        'data'     => $this->getCustomFieldValue($supplierId),
    ]);
}

// Guardar el valor cuando se envie el formulario
public function hookActionAfterUpdateSupplierFormHandler(array $params): void
{
    $supplierId = $params['id'];
    $formData   = $params['form_data'];

    $this->saveCustomFieldValue(
        $supplierId,
        $formData['demo_custom_field'] ?? ''
    );
}

// Tambien capturar la creacion
public function hookActionAfterCreateSupplierFormHandler(array $params): void
{
    $this->hookActionAfterUpdateSupplierFormHandler($params);
}

#demoextendsymfonyform2 — Upload image + Doctrine

Demuestra como insertar un campo upload de imagen en el formulario Symfony de 'Editar Proveedor' y como usar Doctrine ORM para gestionar el estado en BD de un objeto custom.

Campo upload image en formulario Symfony
php
<?php
use PrestaShop\PrestaShop\Core\Form\IdentifiableObject\Builder\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Validator\Constraints\Image;

public function hookActionSupplierFormBuilderModifier(array $params): void
{
    $formBuilder = $params['form_builder'];

    $formBuilder->add('demo_supplier_logo', FileType::class, [
        'label'       => 'Custom logo',
        'required'    => false,
        'constraints' => [
            new Image([
                'maxSize'   => '2M',
                'mimeTypes' => ['image/jpeg', 'image/png', 'image/webp'],
            ]),
        ],
        'attr' => [
            'accept' => 'image/jpeg,image/png,image/webp',
        ],
    ]);
}

// Guardar la imagen subida
public function hookActionAfterUpdateSupplierFormHandler(array $params): void
{
    $formData = $params['form_data'];
    $file = $formData['demo_supplier_logo'] ?? null;

    if ($file instanceof UploadedFile) {
        $filename = uniqid('supplier_') . '.' . $file->guessExtension();
        $file->move(_PS_IMG_DIR_ . 'demo/', $filename);

        // Guardar referencia en Doctrine entity
        $this->entityManager->persist(new SupplierLogo(
            $params['id'],
            $filename
        ));
        $this->entityManager->flush();
    }
}

#demoextendsymfonyform3 — Patron CQRS

Demuestra el patron CQRS (Command Query Responsibility Segregation) con hooks. Usa Commands para escritura y Queries para lectura, el patron recomendado en PS 9.x.

CQRS — Command para escritura
php
<?php
// Command: accion de escritura
namespace PrestaShop\Module\DemoExtendSymfonyForm3\CQRS\Command;

class UpdateSupplierExtraDataCommand
{
    private int $supplierId;
    private string $extraField;

    public function __construct(int $supplierId, string $extraField)
    {
        $this->supplierId = $supplierId;
        $this->extraField = $extraField;
    }

    public function getSupplierId(): int { return $this->supplierId; }
    public function getExtraField(): string { return $this->extraField; }
}

// Handler: ejecuta el command
class UpdateSupplierExtraDataHandler
{
    public function __construct(
        private readonly Connection $connection,
        private readonly string $dbPrefix
    ) {}

    public function handle(UpdateSupplierExtraDataCommand $command): void
    {
        $this->connection->executeStatement(
            'INSERT INTO ' . $this->dbPrefix . 'demo_supplier_extra
             (id_supplier, extra_field) VALUES (:id, :val)
             ON DUPLICATE KEY UPDATE extra_field = :val',
            [
                'id'  => $command->getSupplierId(),
                'val' => $command->getExtraField(),
            ]
        );
    }
}

// En el hook del formulario:
public function hookActionAfterUpdateSupplierFormHandler(array $params): void
{
    $this->commandBus->handle(new UpdateSupplierExtraDataCommand(
        $params['id'],
        $params['form_data']['extra_field'] ?? ''
    ));
}

#demosymfonyform — FormTypes de PS en pagina nueva

Demuestra como crear una pagina nueva en el BO usando FormTypes que ya existen en PrestaShop (CountryChoiceType, CurrencyChoiceType, etc.).

Reutilizar FormTypes existentes de PrestaShop
php
<?php
use PrestaShop\PrestaShop\Core\Form\FormChoiceProviderInterface;
use PrestaShopBundle\Form\Admin\Type\CountryChoiceType;
use PrestaShopBundle\Form\Admin\Type\Material\MaterialChoiceTableType;

class DemoConfigurationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            // Selector de pais con todos los paises de PS
            ->add('country', CountryChoiceType::class, [
                'label' => 'Select country',
            ])
            // Selector de moneda
            ->add('currency', CurrencyChoiceType::class, [
                'label' => 'Select currency',
            ])
            // Switch on/off (estilo Material Design)
            ->add('enable_feature', SwitchType::class, [
                'label' => 'Enable feature',
            ])
            // Tabla de seleccion multiple (estilo PS)
            ->add('categories', MaterialChoiceTableType::class, [
                'label'   => 'Categories',
                'choices' => $this->categoryChoices,
            ]);
    }
}

#demosymfonyformsimple — Config page simple

El ejemplo mas sencillo: crear una pagina de configuracion para tu modulo usando Symfony FormTypes. Ideal como punto de partida.

Pagina de configuracion basica con Symfony
php
<?php
// Controller del modulo
class DemoConfigurationController extends FrameworkBundleAdminController
{
    public function indexAction(Request $request): Response
    {
        $form = $this->createForm(DemoConfigurationType::class, [
            'config_text'  => Configuration::get('DEMO_CONFIG_TEXT'),
            'config_bool'  => (bool) Configuration::get('DEMO_CONFIG_BOOL'),
        ]);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $data = $form->getData();
            Configuration::updateValue('DEMO_CONFIG_TEXT', $data['config_text']);
            Configuration::updateValue('DEMO_CONFIG_BOOL', $data['config_bool']);

            $this->addFlash('success', 'Settings updated!');
            return $this->redirectToRoute('demo_configuration');
        }

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

// FormType
class DemoConfigurationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('config_text', TextType::class, [
                'label' => 'Text setting',
            ])
            ->add('config_bool', SwitchType::class, [
                'label' => 'Enable feature',
            ]);
    }
}

#demoformdataproviders — FormDataProvider hooks

Ilustra los hooks FormDataProviderData y FormDataProviderDefaultData para inyectar datos en formularios existentes sin modificar el FormType. Compatible desde PS 8.0.

Hooks de FormDataProvider
php
<?php
// Inyectar datos por defecto en formulario de creacion
public function hookActionManufacturerFormDataProviderDefaultData(array &$params): void
{
    // Datos por defecto al crear un nuevo fabricante
    $params['data']['my_custom_field'] = 'Valor por defecto';
}

// Inyectar datos al editar un objeto existente
public function hookActionManufacturerFormDataProviderData(array &$params): void
{
    $manufacturerId = $params['data']['id'] ?? null;
    if ($manufacturerId) {
        $params['data']['my_custom_field'] = $this->getStoredValue($manufacturerId);
    }
}

#demoproductform — Extender producto BO

Demuestra las multiples opciones de extender el formulario de producto en el BO. Requiere PS 9.0+ (nueva pagina de producto).

Anadir tab y campos al formulario de producto
php
<?php
// Anadir un tab personalizado al formulario de producto
public function hookActionProductFormBuilderModifier(array $params): void
{
    $formBuilder = $params['form_builder'];
    $productId   = $params['id'];

    // Anadir tab completo con NavigationTabType
    $formBuilder->add('demo_tab', NavigationTabType::class, [
        'label' => 'Demo Custom Tab',
    ]);

    // Anadir campos dentro del tab
    $formBuilder->get('demo_tab')
        ->add('custom_text', TextType::class, [
            'label'    => 'Custom text field',
            'required' => false,
            'data'     => $this->getProductCustomText($productId),
        ])
        ->add('custom_toggle', SwitchType::class, [
            'label' => 'Enable custom feature',
            'data'  => $this->isFeatureEnabled($productId),
        ]);
}

public function hookActionAfterUpdateProductFormHandler(array $params): void
{
    $productId = $params['id'];
    $formData  = $params['form_data'];

    $this->saveProductCustomData(
        $productId,
        $formData['demo_tab']['custom_text'] ?? '',
        $formData['demo_tab']['custom_toggle'] ?? false
    );
}
💡
Cual usar segun tu necesidad

- Campo en formulario existente: demoextendsymfonyform1 (hooks FormBuilder) - Upload de archivos: demoextendsymfonyform2 - CQRS avanzado: demoextendsymfonyform3 - Pagina nueva con FormTypes PS: demosymfonyform - Config page simple: demosymfonyformsimple (punto de partida) - Solo inyectar datos: demoformdataproviders - Tab en producto: demoproductform

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