具有多个数据库的 Symfony 3 表单始终使用默认实体管理器
Symfony 3 form with multiple databases always uses default entity manager
我最近创建了一个管理应用程序来管理我们所有的用户、客户等...
该应用程序配置了 2 个实体管理器,用于获取和设置数据到 'staging' 数据库和 'production' 数据库。
没问题,从不同的数据库中获取数据没有问题,但是当提交表单时,它总是需要默认的实体管理器来验证和保存输入的信息。
我可以在某处指定表单在创建时或 $form->handleRequest($request);
时应使用哪个实体管理器吗?
配置:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name2%'
user: '%database_user2%'
password: '%database_password2%'
charset: UTF8
prod:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
orm:
auto_generate_proxy_classes: '%kernel.debug%'
default_entity_manager: staging
entity_managers:
staging:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: default
mappings:
AppBundle: ~
prod:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: prod
mappings:
AppBundle: ~
CustomerController@CreateAction:
public function createAction(Request $request, $id, RegistryInterface $registry, $_env)
{
$em = $registry->getManager($_env);
$customer = $em->getRepository('AppBundle:Customer')->find($id);
$customer->init($this->getUser());
$form = $this->createForm(CustomerForm::class, $customer, ['action' => $this->generateUrl('customers_edit', ['id' => $id, '_env' => $_env]), 'trait_choices' => [$em]]);
$form->handleRequest($request);
我在 Symfony 的文档中找不到关于这个主题的词...
编辑
客户类型代码:
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Role;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CustomerType extends AbstractType
{
public function init($em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (isset($options['trait_choices'])) {
call_user_func_array(array($this, 'init'), $options['trait_choices']);
}
$builder->add('companyName', TextType::class, [
'label' => 'label.name',
'required' => true
]);
$builder->add('street', TextType::class, [
'label' => 'label.street',
'required' => true
]);
$builder->add('streetNr', NumberType::class, [
'label' => 'label.street_nr',
'required' => true
]);
$builder->add('streetBox', TextType::class, [
'label' => 'label.street_box',
'required' => false
]);
$builder->add('postalCode', TextType::class, [
'label' => 'label.postal_code',
'required' => true
]);
$builder->add('city', TextType::class, [
'label' => 'label.city',
'required' => true
]);
$builder->add('country', EntityType::class, [
'class' => 'AppBundle\Entity\Country',
'choice_label' => 'name',
'label' => 'label.country',
'required' => true,
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->add('vatNr', TextType::class, [
'label' => 'label.vat',
'required' => false
]);
$builder->add('phone', TextType::class, [
'label' => 'label.phone',
'required' => false
]);
$builder->add('email', TextType::class, [
'label' => 'label.email',
'required' => true
]);
$builder->add('roles', EntityType::class, [
'class' => Role::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.type = ?1')
->setParameter(1, Role::TYPE_CUSTOMER);
},
'label' => 'Roles',
'multiple' => true,
'expanded' => true,
'choice_label' => 'displayName',
'attr' => [
'class' => 'roles'
],
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->add('leadSources', EntityType::class, [
'label' => 'label.origin_lead',
'class' => 'AppBundle\Entity\LM\LeadSource',
'multiple' => true,
'expanded' => true,
'choice_label' => 'name',
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitListener'));
}
public function onPreSubmitListener(FormEvent $event)
{
$customer = $event->getForm()->getData();
if ($customer->getIdentifier() == null) {
$customer->setIdentifier(uniqid('dummy'));
$event->getForm()->setData($customer);
} else {
$event->getForm()->setData($customer);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Customer',
'trait_choices' => null,
'allow_extra_fields' => true,
]);
}
}
$_env 的值是如何注入的?尝试转储它以查看它实际上 return 是您期望的 return("prod" 或 "staging")
您遇到的行为表明它可能始终为空,因此在所有情况下都会创建默认实体管理器。
尝试类似
$env = $container->getParameter("kernel.environment")
PS
您对环境的使用有点奇怪。冒险从您的开发或暂存环境访问您的产品数据库可能不是一个好主意。
尝试使用参数和 .env 文件,因为它们应该被使用。
更新:
您可以在调用 createForm 函数时使用选项数组将实体管理器传递给您的表单类型
类似
$form = $this->createForm(
YourFormType::class,
$yourEntity,
[
'entityManager' => $this->getDoctrine()->getManager($_env),
]
);
然后在您的 buildForm 函数中,您可以从选项数组中检索它。
更新 2
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'entityManager' => null,
]);
}
我最近创建了一个管理应用程序来管理我们所有的用户、客户等...
该应用程序配置了 2 个实体管理器,用于获取和设置数据到 'staging' 数据库和 'production' 数据库。
没问题,从不同的数据库中获取数据没有问题,但是当提交表单时,它总是需要默认的实体管理器来验证和保存输入的信息。
我可以在某处指定表单在创建时或 $form->handleRequest($request);
时应使用哪个实体管理器吗?
配置:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name2%'
user: '%database_user2%'
password: '%database_password2%'
charset: UTF8
prod:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
orm:
auto_generate_proxy_classes: '%kernel.debug%'
default_entity_manager: staging
entity_managers:
staging:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: default
mappings:
AppBundle: ~
prod:
naming_strategy: doctrine.orm.naming_strategy.underscore
connection: prod
mappings:
AppBundle: ~
CustomerController@CreateAction:
public function createAction(Request $request, $id, RegistryInterface $registry, $_env)
{
$em = $registry->getManager($_env);
$customer = $em->getRepository('AppBundle:Customer')->find($id);
$customer->init($this->getUser());
$form = $this->createForm(CustomerForm::class, $customer, ['action' => $this->generateUrl('customers_edit', ['id' => $id, '_env' => $_env]), 'trait_choices' => [$em]]);
$form->handleRequest($request);
我在 Symfony 的文档中找不到关于这个主题的词...
编辑
客户类型代码:
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Role;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CustomerType extends AbstractType
{
public function init($em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (isset($options['trait_choices'])) {
call_user_func_array(array($this, 'init'), $options['trait_choices']);
}
$builder->add('companyName', TextType::class, [
'label' => 'label.name',
'required' => true
]);
$builder->add('street', TextType::class, [
'label' => 'label.street',
'required' => true
]);
$builder->add('streetNr', NumberType::class, [
'label' => 'label.street_nr',
'required' => true
]);
$builder->add('streetBox', TextType::class, [
'label' => 'label.street_box',
'required' => false
]);
$builder->add('postalCode', TextType::class, [
'label' => 'label.postal_code',
'required' => true
]);
$builder->add('city', TextType::class, [
'label' => 'label.city',
'required' => true
]);
$builder->add('country', EntityType::class, [
'class' => 'AppBundle\Entity\Country',
'choice_label' => 'name',
'label' => 'label.country',
'required' => true,
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->add('vatNr', TextType::class, [
'label' => 'label.vat',
'required' => false
]);
$builder->add('phone', TextType::class, [
'label' => 'label.phone',
'required' => false
]);
$builder->add('email', TextType::class, [
'label' => 'label.email',
'required' => true
]);
$builder->add('roles', EntityType::class, [
'class' => Role::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.type = ?1')
->setParameter(1, Role::TYPE_CUSTOMER);
},
'label' => 'Roles',
'multiple' => true,
'expanded' => true,
'choice_label' => 'displayName',
'attr' => [
'class' => 'roles'
],
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->add('leadSources', EntityType::class, [
'label' => 'label.origin_lead',
'class' => 'AppBundle\Entity\LM\LeadSource',
'multiple' => true,
'expanded' => true,
'choice_label' => 'name',
'choice_translation_domain' => 'messages',
'em' => $this->em
]);
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitListener'));
}
public function onPreSubmitListener(FormEvent $event)
{
$customer = $event->getForm()->getData();
if ($customer->getIdentifier() == null) {
$customer->setIdentifier(uniqid('dummy'));
$event->getForm()->setData($customer);
} else {
$event->getForm()->setData($customer);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Customer',
'trait_choices' => null,
'allow_extra_fields' => true,
]);
}
}
$_env 的值是如何注入的?尝试转储它以查看它实际上 return 是您期望的 return("prod" 或 "staging")
您遇到的行为表明它可能始终为空,因此在所有情况下都会创建默认实体管理器。
尝试类似 $env = $container->getParameter("kernel.environment")
PS 您对环境的使用有点奇怪。冒险从您的开发或暂存环境访问您的产品数据库可能不是一个好主意。 尝试使用参数和 .env 文件,因为它们应该被使用。
更新:
您可以在调用 createForm 函数时使用选项数组将实体管理器传递给您的表单类型
类似
$form = $this->createForm(
YourFormType::class,
$yourEntity,
[
'entityManager' => $this->getDoctrine()->getManager($_env),
]
);
然后在您的 buildForm 函数中,您可以从选项数组中检索它。
更新 2
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'entityManager' => null,
]);
}