📝 Formularios Symfony — 6 modulos de ejemplo
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.).
<?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.
<?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.
<?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.).
<?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.
<?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.
<?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).
<?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
);
}
- 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