5

我正在尝试在首页插入自定义奏鸣曲表单字段类型,而不是在 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 Sonata\AdminBundle\Form\ChoiceList\ModelChoiceList::__construct() must implement interface Sonata\AdminBundle\Model\ModelManagerInterface, null given

如果奏鸣曲表单字段类型是服务,我无法理解为什么 Symfony 会抛出该错误。

4

3 回答 3

3

感谢@gabtzi 的回答,我在 Sonata Admin 的源代码中四处寻找,并提出了一个非常相似的解决方案。假设我们有两个实体Movie并且Genre它们之间存在多对多关系(Movie即拥有方),Symfony 4 和 Sonata Admin 3.x 中的解决方案将如下所示:

<?php

namespace App\Form\Type;

use App\Entity\Movie;
use App\Entity\Genre;
use Symfony\Component\Form\AbstractType;
use Sonata\AdminBundle\Form\Type\ModelType;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

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,
        ));
    }
}

这是一个非常基本的示例,但应该给出如何进一步进行的想法。重要的事情是:

  • 如果您使用自动装配,则不必将表单类型注册为服务。检查您autowire的. 阅读官方文档了解更多详细信息;trueconfig/services.yaml

  • 传递ContainerInterface给构造函数获取容器;

  • 你不再使用sonata_type_model了。你必须使用ModelType::class. 注意使用说明;

  • 您可以为 M2M 关系设置mutipletrue,否则默认为false;

  • 您必须将实体类传递给class- 在这种情况下Movie::class

  • 您可以指定property使用Genre. __toString如果您在实体类中定义了方法,则不必声明它。然后会使用这个方法的返回值;

  • 最重要的是:现在你有了容器,获取服务sonata.admin.manager.orm并将其传递给model_manager. 没有这个,一切都会落入水中。

但是,我还没有设法显示 button + Add new。值得一提的是,相关属性的管理类必须存在并且可以访问(适当的权限集) - 在这种情况下GenreAdmin需要,否则按钮甚至在理论上都无法工作。

于 2019-03-22T07:49:40.433 回答
2

我刚刚遇到了和你一样的问题,但由于这是我在谷歌遇到的第一个问题,我只是发布了我为解决这个问题所做的工作。我假设您在控制器中动态创建表单。如果不是,您需要将您的类声明为服务并将服务注入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')
    ))
;

之后它为我正确呈现,就像在管理上下文中一样。

于 2017-08-09T15:25:42.940 回答
-2

sonata_type_model 需要知道什么样的实体与你的领域相关。如果您在管理类中定义它,奏鸣曲使用自己的内部方法来检查关系。因此,如果您在 admin 之外定义它,则将其设置为 null 而不是 entity

于 2014-11-08T18:48:35.023 回答