提交后更改表单字段的数据

Ant*_*tin 2 php forms symfony

我有字段'url'的Message实体.和MessageType表单.用户可以在"url"中键入不同的URL,但只有主机持久保存到数据库中.我需要使用Symfony2 Form Event.所以我尝试在下一个代码中实现它:

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);
                }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到以下通知:

"注意:数组转换为字符串"

这是什么意思?

我的Message实体有方法__toString():

public function __toString()
{
    return $this->getUrl();
}
Run Code Online (Sandbox Code Playgroud)

谢谢

Jas*_*man 5

您可以尝试使用专为此目的而设计的Data Transformer.例如:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后以表格形式实施:

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())
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,这种方法肯定有其缺点.您将无法Assert\URL在实体上添加,因为验证在转换后发生,并且只有主机部分将不再使其有效.你可以通过将Symfony验证器传递给你的数据转换器来解决这个问题,然后验证$ url,Assert\Url类似于这里的方法:结合约束和数据转换器,但这也感觉有点hacky.

比所有这一切更简单的解决方案就是将setUrl($url)实体中的方法更新为以下内容:

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

因此,在这种情况下,如果您传入一个URL,它只保存为$ host,如果您使用setUrl()并且它已经被转换,它将保留已存在的值.

更妙的是,您可以简单地保存他们发送给您的完整URL,这样您就可以维护@Assert\URL验证,然后添加以下两个函数:

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

public function __toString()
{
    return $this->getHost();
}
Run Code Online (Sandbox Code Playgroud)

上面允许您保留所有已保存的数据,并更改解析URL的工作由您的应用程序完成,而不是尝试在数据库层中解析.该__toString()方法将始终返回主机,并且您仍然可以访问在需要时传入的完整URL.你甚至可以摆脱getHost()上面的功能.

如果你想使用FormEvent,你就是在正确的轨道上,但代码有点偏.有关详细信息,请参阅http://symfony.com/doc/current/components/form/form_events.html#b-the-formevents-submit-event.

$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));
});
Run Code Online (Sandbox Code Playgroud)