具有默认值和嵌入表单的Symfony2实体


Symfony2 entity with default value and embedded forms

我有一个类,它是一种表单类型(反过来,嵌入到另一个表单中),用于选择社区、地区和国家,每个都有一个下拉列表(地区取决于国家)。我希望在构建国家/地区列表时默认选择某个国家/地区。这就是我所拥有的:

$factory = $builder->getFormFactory();
$builder->add('pais', 'entity', array(
'class' => 'Codesin'ColegiosBundle'Localidad'Pais',
'property' => 'nombre',
'query_builder' => function (EntityRepository $repositorio) {
    $qb = $repositorio->createQueryBuilder('pais')
        ->orderBy('pais.nombre');
        return $qb;
    }
));

我尝试过使用preferred_value(它说我需要一个对象,由于我在类中没有数据库访问权限,所以我无法从任何地方获取该对象)和data(它不起作用)。我尝试在这两种情况下都使用实体的id。在这种情况下,如何设置选定的默认值?

好吧,我想我终于明白了如何将其作为一项服务。你可能会问:"你为什么要把它作为一项服务?"?好吧,因为我需要将实体管理器注入其中。我希望下面的教程有任何用处。

自定义表单类型中的首选项(_C)

假设你的数据库中保存了几个国家,它们是一个Country实体,在条令中有正确的定义。但有一个问题——全球有近250个国家,用户很可能来自一个国家!所以,比方说,你需要一个国家在默认情况下被选中,或者在列表的顶部。

步骤1:填充字段

假设我们正在构建一个自定义表单类型CountryType。让我们定义一下。

class CountryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('country', 'entity', array(
             'class' => 'Acme'AcmeBundle'Locality'Country',
             'property' => 'name',
             'query_builder' => function (EntityRepository $repository) {
                 $qb = $repository->createQueryBuilder('country')->orderBy('country.name');
                 return $qb;
             }
        ));
    }
    public function getDefaultOptions(array $options)
    {
        return array('data_class' => 'Acme'AcmeBundle'Locality'Country');
    }
    public function getName()
    {
        return 'countrytype';
    }
}

当你从某个地方打电话时,比如在

$builder->add('country', new CountryType());

这一切都很好,只是默认情况下你不会得到一个选定的国家。更糟糕的是,如果你试图添加

'preferred_choices' => array(15) //Say, 15 is the id of the country

对于您的选项,您将获得一个例外。出于某种奇怪的原因,这样做:

$defaultCountry = new Country();
$defaultCountry->setId(15);

然后

'preferred_choices' => array($defaultCountry)

也不起作用。

这就是乐趣的开始。

步骤2:添加EntityManager

为了搜索我们需要的实体,我们必须查询数据库。现在我们无法访问它,因为我们没有EntityManager条令。我们要做的是向类中添加一个,将其作为参数传递给构造函数,并将其存储为类的私有属性。

class CountryType extends AbstractType
{
    //Add this
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('country', 'entity', array(
             'class' => 'Acme'AcmeBundle'Locality'Country',
             'property' => 'name',
             'query_builder' => function (EntityRepository $repository) {
                 $qb = $repository->createQueryBuilder('country')->orderBy('country.name');
                 return $qb;
             }
        ));
    }
    public function getDefaultOptions(array $options)
    {
        return array('data_class' => 'Acme'AcmeBundle'Locality'Country');
    }
    public function getName()
    {
        return 'countrytype';
    }
    //Add this
    private $em;
}

之后我们查询数据库。

class CountryType extends AbstractType
{
    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //Add the following lines
        $qb = $this->em->createQueryBuilder();
        $resultset = $qb->select('country')
                        ->from('Acme'AcmeBundle'Locality'Country', 'country')
                        ->where('country.id = ?1')
                        ->setParameter(1, 15)
                        ->getQuery()
                        ->execute();
        $default = $resultset[0];
        $builder->add('country', 'entity', array(
             'class' => 'Acme'AcmeBundle'Locality'Country',
             'property' => 'name',
             'preferred_choices' => array($default), //Add this too
             'query_builder' => function (EntityRepository $repository) {
                 $qb = $repository->createQueryBuilder('country')->orderBy('country.name');
                 return $qb;
             }
        ));
    }
    public function getDefaultOptions(array $options)
    {
        return array('data_class' => 'Acme'AcmeBundle'Locality'Country');
    }
    public function getName()
    {
        return 'countrytype';
    }
    private $em;
}

但现在我们遇到了一个问题:我们不能再叫它了!!我们如何给它传递EntityManager,特别是如果我们不是从控制器调用它,而是嵌入它?这就是魔术的用武之地。

第三步:让它成为一项服务

为什么?因为通过这种方式,我们可以向其注入EntityManager。转到Acme/AcmeBundle/Resources/cofig/services.yml并添加以下行:

acme.acmebundle.countrytype:
    class: Acme'AcmeBundle'Types'CountryType
    arguments: ["@doctrine.orm.entity_manager"]
    tags:
        - { name: form.type, alias: countrytype }

这里的一些注意事项:

  • 传递给军种的论点是另一种军种,即条令EntityManager。这个参数被传递给函数的构造函数,并从其他地方注入。通过这种方式,我们将确保始终拥有EntityManager
  • 在标记中,确保包含两个名为的标记。alias标记必须与自定义类型(在本例中为countrytype)中从getName()返回的内容相匹配

如果您想了解更多关于依赖注入和服务的信息,请访问此处:服务容器。

现在,最大的问题是:我们该怎么称呼它?

步骤4:调用服务

这非常容易。还记得这句话吗?

$builder->add('country', new CountryType());

现在将其更改为以下内容:

$builder->add('country', 'countrytype');

就是这样!现在,您的自定义类型已经附加了一个实体管理器,并且不需要传递任何参数。祝你的下一个项目好运!

如果将表单类型与模型对象一起使用,请在对象本身上设置默认值。

尝试SET_DATAPOstrongET_DATA表单事件:您可以在lambda函数中执行以下操作:

$data = $event->getData();
$form = $event->getForm();
// search in the form for the right entity to set as country.. let's consider $country
$data->setCountry($country);
$event->setData($data);

它可能会起作用。试着让我们知道的进展

您需要插入这个现成的捆绑包https://github.com/shtumi/ShtumiUsefulBundle

并在此处配置https://github.com/shtumi/ShtumiUsefulBundle/blob/master/Resources/doc/dependent_filtered_entity.rst

我使用该框架制作依赖表单