mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-15 01:20:59 +00:00
279 lines
9.7 KiB
ReStructuredText
279 lines
9.7 KiB
ReStructuredText
Customizing Forms
|
|
=================
|
|
|
|
The forms in Sylius are placed in the ``Sylius\Bundle\*BundleName*\Form\Type`` namespaces and the extensions
|
|
will be placed in `App\Form\Extension`.
|
|
|
|
Why would you customize a Form?
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
There are plenty of reasons to modify forms that have already been defined in Sylius.
|
|
Your business needs may sometimes slightly differ from our internal assumptions.
|
|
|
|
You can:
|
|
|
|
* add completely **new fields**,
|
|
* **modify** existing fields, make them required, change their HTML class, change labels etc.,
|
|
* **remove** fields that are not used.
|
|
|
|
How to customize a Form?
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. tip::
|
|
|
|
You can browse the full implementation of this example on `this GitHub Pull Request.
|
|
<https://github.com/Sylius/Customizations/pull/8>`__
|
|
|
|
If you want to modify the form for the ``Customer Profile`` in your system there are a few steps that you should take.
|
|
Assuming that you would like to (for example):
|
|
|
|
* Add a ``secondaryPhoneNumber`` field,
|
|
* Remove the ``gender`` field,
|
|
* Change the label for the ``lastName`` from ``sylius.form.customer.last_name`` to ``app.form.customer.surname``
|
|
|
|
These will be the steps that you will have to take to achieve that:
|
|
|
|
**1.** If you are planning to add new fields remember that beforehand they need to be added on the model that the form type is based on.
|
|
|
|
In case of our example if you need to have the ``secondaryPhoneNumber`` on the model and the entity mapping for the ``Customer`` resource.
|
|
To get to know how to prepare that go :doc:`there </customization/model>`.
|
|
|
|
**2.** Create a **Form Extension**.
|
|
|
|
Your form has to extend a proper base class. How can you check that?
|
|
|
|
For the ``CustomerProfileType`` run:
|
|
|
|
.. code-block:: bash
|
|
|
|
php bin/console debug:container sylius.form.type.customer_profile
|
|
|
|
As a result you will get the ``Sylius\Bundle\CustomerBundle\Form\Type\CustomerProfileType`` - this is the class that you need to be extending.
|
|
|
|
.. code-block:: php
|
|
|
|
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Form\Extension;
|
|
|
|
use Sylius\Bundle\CustomerBundle\Form\Type\CustomerProfileType;
|
|
use Symfony\Component\Form\AbstractTypeExtension;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\Form\FormBuilderInterface;
|
|
|
|
final class CustomerProfileTypeExtension extends AbstractTypeExtension
|
|
{
|
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
{
|
|
$builder
|
|
// Adding new fields works just like in the parent form type.
|
|
->add('secondaryPhoneNumber', TextType::class, [
|
|
'required' => false,
|
|
'label' => 'app.form.customer.secondary_phone_number',
|
|
])
|
|
// To remove a field from a form simply call ->remove(`fieldName`).
|
|
->remove('gender')
|
|
// You can change the label by adding again the same field with a changed `label` parameter.
|
|
->add('lastName', TextType::class, [
|
|
'label' => 'app.form.customer.surname',
|
|
]);
|
|
}
|
|
|
|
public static function getExtendedTypes(): iterable
|
|
{
|
|
return [CustomerProfileType::class];
|
|
}
|
|
}
|
|
|
|
.. note::
|
|
Of course remember that you need to define new labels for your fields
|
|
in the ``translations\messages.en.yaml`` for english contents of your messages.
|
|
|
|
**3.** After creating your class, register this extension as a service in the ``config/services.yaml``:
|
|
|
|
.. caution::
|
|
Remember! Service registration is not needed if you have autoconfiguration enabled in your services container.
|
|
|
|
.. code-block:: yaml
|
|
|
|
services:
|
|
app.form.extension.type.customer_profile:
|
|
class: App\Form\Extension\CustomerProfileTypeExtension
|
|
tags:
|
|
- { name: form.type_extension, extended_type: Sylius\Bundle\CustomerBundle\Form\Type\CustomerProfileType }
|
|
|
|
.. note::
|
|
Of course remember that you need to render the new fields you have created,
|
|
and remove the rendering of the fields that you have removed **in your views**.
|
|
|
|
In our case you will need to copy the original template from ``vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Account/profileUpdate.html.twig``
|
|
to ``templates/bundles/SyliusShopBundle/Account/`` and add the fields inside the copy.
|
|
|
|
.. code-block:: twig
|
|
|
|
{{ form_row(form.phoneNumber) }}
|
|
{{ form_row(form.subscribedToNewsletter) }}
|
|
|
|
<!-- your fields -->
|
|
{{ form_row(form.birthday) }}
|
|
{{ form_row(form.secondaryPhoneNumber) }}
|
|
|
|
{{ sonata_block_render_event('sylius.shop.account.profile.update.form', {'customer': customer, 'form': form}) }}
|
|
|
|
Need more information?
|
|
----------------------
|
|
|
|
.. warning::
|
|
|
|
Some of the forms already have extensions in Sylius. Learn more about Extensions `here <https://symfony.com/doc/current/form/create_form_type_extension.html>`_.
|
|
|
|
For instance the ``ProductVariant`` admin form is defined under ``Sylius/Bundle/ProductBundle/Form/Type/ProductVariantType.php`` and later extended in
|
|
``Sylius/Bundle/CoreBundle/Form/Extension/ProductVariantTypeExtension.php``. If you again extend the base type form like this:
|
|
|
|
.. code-block:: yaml
|
|
|
|
services:
|
|
app.form.extension.type.product_variant:
|
|
class: App\Form\Extension\ProductVariantTypeMyExtension
|
|
tags:
|
|
- { name: form.type_extension, extended_type: Sylius\Bundle\ProductBundle\Form\Type\ProductVariantType, priority: -5 }
|
|
|
|
your form extension will also be executed. Whether before or after the other extensions depends on priority tag set.
|
|
|
|
`How to customize forms that are already extended in Core?`
|
|
-----------------------------------------------------------
|
|
|
|
.. tip::
|
|
|
|
You can browse the full implementation of this example on `this GitHub Pull Request.
|
|
<https://github.com/Sylius/Customizations/pull/9>`__
|
|
|
|
Having a look at the extensions and possible additionally defined event handlers can also be useful when form elements are embedded dynamically,
|
|
as is done in the ``ProductVariantTypeExtension`` by the ``CoreBundle``:
|
|
|
|
.. code-block:: php
|
|
|
|
<?php
|
|
|
|
// ...
|
|
|
|
final class ProductVariantTypeExtension extends AbstractTypeExtension
|
|
{
|
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
{
|
|
// ...
|
|
|
|
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
|
|
$productVariant = $event->getData();
|
|
|
|
$event->getForm()->add('channelPricings', ChannelCollectionType::class, [
|
|
'entry_type' => ChannelPricingType::class,
|
|
'entry_options' => function (ChannelInterface $channel) use ($productVariant) {
|
|
return [
|
|
'channel' => $channel,
|
|
'product_variant' => $productVariant,
|
|
'required' => false,
|
|
];
|
|
},
|
|
'label' => 'sylius.form.variant.price',
|
|
]);
|
|
});
|
|
}
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
The ``channelPricings`` get added on ``FormEvents::PRE_SET_DATA``, so when you wish to remove or alter this form definition,
|
|
you will also have to set up an event listener and then remove the field:
|
|
|
|
.. code-block:: php
|
|
|
|
<?php
|
|
|
|
//...
|
|
|
|
final class ProductVariantTypeMyExtension extends AbstractTypeExtension
|
|
{
|
|
// ...
|
|
|
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
{
|
|
//...
|
|
|
|
$builder
|
|
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
|
|
$event->getForm()->remove('channelPricings');
|
|
})
|
|
->addEventSubscriber(new AddCodeFormSubscriber(NULL, ['label' => 'app.form.my_other_code_label']))
|
|
;
|
|
|
|
// ...
|
|
|
|
|
|
}
|
|
}
|
|
|
|
Adding constraints inside a form extension
|
|
------------------------------------------
|
|
|
|
.. warning::
|
|
|
|
When adding your constraints dynamically from inside a form extension, be aware to add the correct validation groups.
|
|
|
|
Although it is advised to follow the :doc:`Validation Customization Guide </customization/validation>`, it might happen that you
|
|
want to define the form constraints from inside the form extension. They will not be used unless the correct validation group(s)
|
|
has been added. The example below shows how to add the default `sylius` group to a constraint.
|
|
|
|
.. tip::
|
|
|
|
You can browse the full implementation of this example on `this GitHub Pull Request.
|
|
<https://github.com/Sylius/Customizations/pull/8>`__
|
|
|
|
.. code-block:: php
|
|
|
|
<?php
|
|
|
|
// ...
|
|
|
|
final class CustomerProfileTypeExtension extends AbstractTypeExtension
|
|
{
|
|
// ...
|
|
|
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
|
{
|
|
//...
|
|
|
|
$builder
|
|
// Adding new fields works just like in the parent form type.
|
|
->add('secondaryPhoneNumber', TextType::class, [
|
|
'required' => false,
|
|
'label' => 'app.form.customer.secondary_phone_number',
|
|
'constraints' => [
|
|
new Length([
|
|
'min' => 6,
|
|
'max' => 10,
|
|
'groups' => ['sylius'],
|
|
]),
|
|
],
|
|
]);
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
Overriding forms completely
|
|
---------------------------
|
|
|
|
.. tip::
|
|
|
|
If you need to create a new form type on top of an existing one - create this new alternative form type and define `getParent()`
|
|
to the old one. `See details in the Symfony docs <https://symfony.com/doc/current/form/create_custom_field_type.html>`_.
|
|
|
|
.. include:: /customization/plugins.rst
|