好吧,我想我终于明白如何将其作为服务了。“你为什么要把它变成一项服务?”,你可能会问?好吧,因为我需要为此注入实体管理器。我希望下面的教程有任何用处。
自定义表单类型中的 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
根据您的选择,您将获得例外。出于某种奇怪的原因,这样做:
$defaultCountry = new Country();
$defaultCountry->setId(15);
进而
'preferred_choices' => array($defaultCountry)
也不起作用。
这就是乐趣开始的地方。
第 2 步:添加 EntityManager
为了搜索我们需要的实体,我们必须查询数据库。现在我们无法访问它,因为我们没有 Doctrine 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
,特别是如果我们不是从控制器调用它而是嵌入它?这就是施展魔法的地方。
第 3 步:使其成为服务
为什么?因为这样我们可以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
。这个参数被传递给函数的构造函数并从其他地方注入。这样,我们将确保我们始终拥有一个EntityManager
.
- 在标签中,确保包含两个已命名的标签。该
alias
标记必须与getName()
您的自定义类型中返回的任何内容相匹配,在本例中为countrytype
.
如果您想了解更多关于依赖注入和服务的信息,请访问:服务容器。
现在,最大的问题是:我们如何称呼它?
第四步:调用服务
这非常容易做到。还记得这条线吗?
$builder->add('country', new CountryType());
现在将其更改为以下内容:
$builder->add('country', 'countrytype');
就是这样!现在,您的自定义类型附加了一个实体管理器,并且无需传递任何参数。祝你下一个项目好运!