我试图在首页插入自定义的奏鸣曲表单字段类型,而不是在SonataAdmin中,类似于以下内容:
$form = $this->createFormBuilder($content)
->add('titleEs', 'text', array('required' => true, 'label' => 'label.title.spanish', 'attr' => array('class' => 'col-xs-12 form-control input-lg')))
->add('contentEs', 'ckeditor', array('required' => true,'label' => 'label.content.spanish', 'attr' => array('class' => 'col-xs-12')))
->add('titleEn', 'text', array('required' => true,'label' => 'label.title.english', 'attr' => array('class' => 'col-xs-12 form-control input-lg')))
->add('contentEn', 'ckeditor', array('required' => true, 'label' => 'label.content.english', 'attr' => array('class' => 'col-xs-12')))
->add('header', 'sonata_type_model', array('required' => true,'label' => 'label.content.headerImage'), array('link_parameters' => array('context' => 'content/front', 'size' => 'big')))
//->add('coverImage', 'sonata_type_model_list', array('required' => true,'label' => 'label.content.coverImage'), array('link_parameters' => array('context' => 'content/front', 'size' => 'small')))
//->add('sliderImage', 'sonata_type_model_list', array('required' => false,'label' => 'label.content.sliderImage'), array('link_parameters' => array('context' => 'content/slider', 'size' => 'normal')))
->getForm();
但当我执行时,它会抛出一个错误:
Catchable Fatal Error: Argument 1 passed to SonataAdminBundleFormChoiceListModelChoiceList::__construct() must implement interface SonataAdminBundleModelModelManagerInterface, null given
如果Sonata Form字段类型是服务,我不明白Symfony为什么会抛出这个错误。
感谢@gabtzi的回答,我在Sonata Admin的源代码中找到了一个非常相似的解决方案。假设我们有两个实体Movie
和Genre
,它们之间存在多对多关系(Movie
是拥有方),Symfony 4和Sonata Admin 3.x中的解决方案将如下所示:
<?php
namespace AppFormType;
use AppEntityMovie;
use AppEntityGenre;
use SymfonyComponentFormAbstractType;
use SonataAdminBundleFormTypeModelType;
use SymfonyComponentDependencyInjectionContainerInterface;
use SymfonyComponentOptionsResolverOptionsResolver;
class MovieType extends AbstractType
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// add fields
->add('genres', ModelType::class, [
'multiple' => true,
'class' => Genre::class,
'property' => 'name', // assuming Genre has property name
'model_manager' => $this->container->get('sonata.admin.manager.orm'),
'by_reference' => false
])
// add more fields
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Movie::class,
));
}
}
这是一个非常基本的例子,但应该给出如何进一步进行的想法。重要的是:
如果使用autowiring,则不必将表单类型注册为服务。检查
config/services.yaml
中的autowire
是否设置为true
。阅读官方文件了解更多详细信息;将
ContainerInterface
传递给构造函数以获取容器;您不再使用
sonata_type_model
。你必须使用ModelType::class
。注意使用说明;M2M关系可以将
mutiple
设置为true
,否则默认为false
;您必须将实体类传递给
class
——在本例中为Movie::class
;您可以指定
property
来使用Genre
的某些属性。如果您已经在实体类中定义了__toString
方法,则不必声明此方法。然后将使用此方法的返回值;最重要的是:既然有了容器,就获取服务
sonata.admin.manager.orm
并将其传递给model_manager
。没有这些,一切都会泡汤。
然而,我还没有设法显示按钮+添加新。值得一提的是,相关属性的管理类必须存在并且可以访问(设置了适当的权限)——在这种情况下,需要GenreAdmin
,否则按钮理论上甚至无法工作。
我刚刚遇到了和你相同的问题,但由于这是我在谷歌上遇到的第一个问题,我只是发布了我为解决这个问题所做的工作。我假设您在一个控制器中动态地创建表单。如果没有,则需要将类声明为服务,并向其注入sonata.admin.manager.orm
服务
$form = $this->createFormBuilder()
->add('<name_of_field>', 'sonata_type_model', array(
'multiple' => true,
'class' => <className>::class,
'property' => '<propertyName>',
'model_manager' => $this->get('sonata.admin.manager.orm')
))
;
之后,它正确地呈现给我,就像它在管理上下文中一样。
sona_type_model需要知道与字段相关的实体类型。如果您在admin类中定义了这一点,sonata将使用自己的内部方法来检查关系。因此,如果您在admin之外定义它,它将被置为null,而不是实体