Darkstarone Darkstarone - 1 month ago 11
PHP Question

Symfony - modifying default data in prototypes

So say I have a

Category
and a
Product
entity, where
Category
has many
Product
entities. My
Category
form builder looks like this:

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('products', CollectionType::class, array(
'entry_type' => ProductType::class,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'prototype' => true,
'prototype_name' => '__product_prot__'))
->add('save', SubmitType::class))
;
}


And my
Product
form builder looks like this:

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('dateAdded', DateType::class)
;
}


What I would like to know is how to set the value of
dateAdded
so that whenever a new prototype is added, it displays today's date?

Some people have suggested using the Entity
__construct()
function to create the default, but this doesn't appear to work for prototypes. I've also found the placeholder option, but I'm not sure how to use it so that it always has today's date - i.e this doesn't appear to work:

->add('addDate', DateType::class, array(
'placeholder' => new \DateTime();
))


As the error is:
Attempted to call function "DateTime" from the global namespace


Additionally, I've found the prototype_data field in the
CollectionType
field, but again, I'm not sure how to specify to only put data in a single field, and to make it dynamic.

Can someone tell me the best method to use - and the correct syntax?

Edit:

So my
__construct()
looks like:

public function __construct()
{
$this->addDate = new \DateTime();
}


Which works fine for the
Category
entity (if I give it a date field for testing), but not the prototyped
Product
entity. When I load the prototype into the form, I just get a default date of 1st Jan 2011. The prototype looks like:

{% block _category_products_entry_row %}
<li>
{{ form_row(form.name) }}
{{ form_row(form.dateAdded) }}
</li>
{% endblock %}


Interestingly, I've also found if I load the new form with a
Product
entity created already in the
Category
controller, the
dateAdded
field that appears due to:

{% for product in form.products %}
{{ form_row(product) }}
{% endfor %}


Has today's date as it's default value. This would suggest to me that the loading of the prototypes which is done in the same fashion as the How to Embed a Collection of Forms tutorial - is causing the issue.

Answer

To set a default value to a form field, you can use "data" property and use FormEvent to handle form on update. Here is the result:

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('name', TextType::class) 
        ->add('dateAdded', DateType::class, array(
            'data' => new \DateTime(),
        ))
    ;

    $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) {
        $product = $event->getData();
        $form = $event->getForm();

        if (!$product) {
            return;
        }

        if ($dateAdded = $product->getDateAdded()) {
            $form->add('dateAdded', DateType::class, array(
                'data' => $dateAdded,
            ));
        }
    });
}

On PRE_SET_DATA, you can override the default value on the dateAdded field with the data you fetched.

For more info, you can visit http://symfony.com/doc/current/reference/forms/types/date.html#data and https://symfony.com/doc/current/form/events.html

Hope it helps

Comments