我有一个类,它是一种表单类型(并且反过来嵌入到另一种表单中),用于选择公社、地区和国家,每个都有一个下拉列表(地区取决于国家)。我希望在构建国家/地区列表时默认选择某个国家/地区。这是我的:
$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。在这种情况下,如何设置选定的默认值?
最佳答案
好吧,我想我终于明白了如何将其作为一项服务。 “你为什么要把它变成一项服务?”,你可能会问?好吧,因为我需要为此注入(inject)实体管理器。希望以下教程对您有所帮助。
自定义表单类型中的 Preferred_choices
假设您在数据库中保存了多个国家/地区,它们是一个 Country
实体,在 Doctrine 中正确定义。但有一个问题——全局有近 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
根据您的选择,您会得到一个异常(exception)。出于某种奇怪的原因,这样做:
$defaultCountry = new Country();
$defaultCountry->setId(15);
然后
'preferred_choices' => array($defaultCountry)
也不行。
这里是乐趣的开始。
第 2 步:添加 EntityManager
为了搜索我们需要的实体,我们将不得不查询数据库。现在我们无法访问它,因为我们没有 Doctrine EntityManager
。我们要做的是将一个添加到我们的类中,将其作为参数传递给构造函数并将其存储为类的私有(private)属性。
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
传递给它,尤其是当我们不是从 Controller 调用它而是嵌入它时?这是施展魔法的地方。
第 3 步:使其成为服务
为什么?因为这样我们可以向它注入(inject)一个 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 }
这里有一些注意事项:
- 传递给服务的参数是另一个服务,即 Doctrine
EntityManager
。这个参数被传递给函数的构造函数并从其他地方注入(inject)。这样我们将确保我们始终有一个EntityManager
。 - 在标签中,确保包含两个已命名的标签。
alias
标记必须匹配从getName()
返回的自定义类型中的任何内容,在本例中为countrytype
。
如果您想了解更多有关依赖注入(inject)和服务的信息,请访问此处:Service Container.
现在,最大的问题是:我们如何调用它?
第四步:调用服务
这非常容易做到。还记得这句话吗?
$builder->add('country', new CountryType());
现在将其更改为以下内容:
$builder->add('country', 'countrytype');
就是这样!现在您的自定义类型附加了一个实体管理器,并且无需传递任何参数。祝你下一个项目好运!
关于php - 具有默认值和嵌入形式的 Symfony2 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18628368/