我有字段'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);
}
);
}
}
我收到以下通知:
“注意:数组转换为字符串”
这是什么意思?
我的消息实体有方法__toString()
:
public function __toString()
{
return $this->getUrl();
}
谢谢
答案 0 :(得分: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);
}
}
然后以表格形式实施:
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())
);
}
}
然而,这种方法确实存在缺陷。您将无法在实体上添加Assert\URL
,因为验证在转换后发生,并且只是让主机部分不再使其有效。你可以通过将Symfony验证器传递给你的数据转换器来解决这个问题,然后验证$ Assert\Url
的$ url,类似于这里的方法:Combine constraints and data transformers,但这也感觉有点hacky。
比所有这些更简单的解决方案只是将实体中的setUrl($url)
方法更新为:
public function setUrl($url)
{
$host = parse_url($url, PHP_URL_HOST);
$this->url = $host ?: $url;
}
因此,在这种情况下,如果您传入一个URL,它只会保存为$ host,如果您使用的是setUrl()且它已经被转换,它只会保留已存在的值。
更好的是,您可以直接保存他们发送给您的完整网址,这样您就可以维护@Assert\URL
验证,然后添加以下两个功能:
public function getHost()
{
return parse_url($this->url, PHP_URL_HOST);
}
public function __toString()
{
return $this->getHost();
}
以上允许您保留所有已保存的数据,并更改解析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));
});
答案 1 :(得分:1)
根据parse_url()
的PHP文档:
如果省略组件参数,则为关联数组 返回。
http://php.net/manual/en/function.parse-url.php
看起来你没有在你的代码中正确传递组件参数,有一个错位的括号:
$form->setData(parse_url($url), PHP_URL_HOST);
应该是:
$form->setData(parse_url($url, PHP_URL_HOST));
另外,我不确定你是否按照自己的意愿设置数据,但我可能错了。这就是我认为你应该这样做的方式:
$form->get('url')->setData(parse_url($url, PHP_URL_HOST));
这是我想到的完整(和未经测试)的代码:
class MessageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('url');
$builder->addEventListener(
FormEvents::SUBMIT,
function(FormEvent $event) {
$form = $event->getForm(); // FormInterface
$data = $event->getData();
$url = $data->getUrl();
$host = parse_url($url, PHP_URL_HOST);
if ($host)
$form->get('url')->setData($host);
}
);
}
}