Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change data of form field after submit

Tags:

forms

php

symfony

I have Message entity with field 'url'. And MessageType form. User can type different urls in 'url' but only host is persisted to the database. I need to use Symfony2 Form Event. So I try to implement it in next code:

class MessageType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('url'); 

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

                    $data = $event->getData();
                    $url = $data->getUrl();
                    $form->setData(parse_url($url), PHP_URL_HOST);
                }
        );
    }
}

I get the following notice:

"Notice: Array to string conversion"

What does this mean?

My Message entity has method __toString():

public function __toString()
{
    return $this->getUrl();
}

Thank You

like image 307
Antin Avatar asked Dec 04 '25 10:12

Antin


1 Answers

You could try using a Data Transformer which is designed for this purpose. For example:

namespace Vendor\MyBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class HostFromUrlTransformer implements DataTransformerInterface
{
    public function transform($host)
    {
        return ($host === null) ? "" : $host;
    }

    public function reverseTransform($url)
    {
        return parse_url($url, PHP_URL_HOST);
    }
}

Then implementing in the form:

use Vendor\MyBundle\Form\DataTransformer\HostFromUrlTransformer;

class MessageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add(
            $builder->create('url')
                ->addModelTransformer(new HostFromUrlTransformer())
        );
    }
}

This method definitely has its faults, however. You would not be able to add an Assert\URL on the entity because the validation happens after the transformations, and the just having the host portion would no longer make it valid. You could work around this by passing in the Symfony validator to your data transformer, then validating the $url against Assert\Url similar to a method here: Combine constraints and data transformers , but that also feels a bit hacky.

An easier solution than all of this would simply be to update the setUrl($url) method in your entity to something like this:

public function setUrl($url)
{
    $host = parse_url($url, PHP_URL_HOST);
    $this->url = $host ?: $url;
}

So in that case, if you are passing in a URL it saves as just the $host, and if you are using setUrl() and it's already transformed, it would just keep the already-existing value.

Even better still, you could simply save the full URL they send you, which would allow you to maintain the @Assert\URL validation, and then add the following two functions:

public function getHost()
{
    return parse_url($this->url, PHP_URL_HOST);
}

public function __toString()
{
    return $this->getHost();
}

The above allows you to keep all data that was saved, and changes the work of parsing the URL to be done by your application, rather than try to parse out in the database layer. The __toString() method will always return the host, and you still have access to full URL that was passed in if you need it. You could even get rid of the getHost() function above.

If you want to use a FormEvent, you are on the right track but the code is a little off. See http://symfony.com/doc/current/components/form/form_events.html#b-the-formevents-submit-event for more details.

$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event)
{
    $data = $event->getData();
    $data['url'] = parse_url($data['url'], PHP_URL_HOST);

    $event->setData($data);

    // this one-liner might also work in place of the 3 lines above
    $event->setData('url', parse_url($event->getData('url'), PHP_URL_HOST));
});
like image 181
Jason Roman Avatar answered Dec 07 '25 00:12

Jason Roman