从 Symfony 中的表单类型访问用户实体
Accessing User Entity From Form Type in Symfony
我正在尝试在 Symfony 中构建多租户支持,这样做我在我的用户中创建了一个 group_id
列,最重要的是,所有实体也有这个相同的列。这样用户只能访问他们组的数据。
我已经设法通过数据访问和显示解决了整个问题,但随后 EntityTypes
遇到了 Symfony Forms 的挑战。
问题基本上是,如何使 EntityType
仅显示该特定组输入的数据。按用户和联系人都具有的 group_id
对其进行排序。最好的传递方式是什么,这样用户只能访问他们的数据?
<?php
namespace ContactBundle\Form;
use ContactBundle\Entity\Contact;
use ContactBundle\Entity\Organization;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('first_name', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label' => 'First Name',])
->add('last_name', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Last Name',
])
->add('email', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Email Address'
])
->add('organization_id', EntityType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'class'=>'ContactBundle:Organization',
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
->add('phone', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Phone',
])
->add('role', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Role',
])
->add('submit', SubmitType::class, [
'label'=>'Submit',
'attr' => [
'class'=>'button-primary',
'style'=>'margin-top:30px;',]]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class'=>Contact::class,]);
}
}
?>
值得注意的是,我使用的是FOSUserBundle
。
创建表单时在控制器中
$form = $this->createForm(ContactType::class, $contact, ['group_id' => $groupId]);
在表单配置选项方法中
$resolver->setDefaults(['data_class'=>Contact::class, 'group_id' => null]);
在表单 buildForm 中,您可以通过
获得 group_id
$options['group_id']
在 Symfony 中,可以很容易地在需要的地方注入任何你需要的东西。
// ...
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class ContactType extends AbstractType
{
private $user;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->user = $tokenStorage->getToken()->getUser();
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('organization_id', EntityType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'class'=>'ContactBundle:Organization',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.group', '?0')
->setParameters([$this->user->getGroup()]);
},
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
// ...
如果您不使用自动装配和自动配置 (Symfony 3.3+),请手动将您的表单注册为服务并使用 form.type:
标记
# config/services.yaml
services:
AppBundle\Form\ContactType:
arguments: ['@security.token_storage']
tags: [form.type]
相关阅读
https://symfony.com/doc/current/form/form_dependencies.html#define-your-form-as-a-service
我明白了!
所以我最终做的是摆脱在表单端使用 EntityType 的整个想法。
然后我从控制器调用数据并将其作为选项传递。
像这样:
$contactManager = $this->get('contact.contact_manager');
$contact = new Contact($contactManager->nextId($group = $this->getUser()->getGroupId()), $group);
$form = $this->createForm(ContactType::class, $contact, ['organizations' => $this->get('contact.organization_manager')->findDataCollection($this->getUser()->getGroupId())]);
$form->handleRequest($request);
将我的 EntityType 转换为选择类型,并将组织数组作为选项传递到 'choices' 字段中。保持其他一切不变:
->add('organization_id', ChoiceType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'choices'=> $options['organizations'],
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
然后,当然,在选项中设置它,这样它就可以期待一个变量。
$resolver->setDefaults(['data_class'=>Contact::class, 'organizations' => null]);
感谢所有的帮助和想法!! :)
您可以通过几种不同的方式做到这一点,一种是结合使用 JavaScript 和 EntityType。
基本上只是加载所有实体并根据先前列表的选择用 JS 隐藏不需要的实体。您可以使用数据属性来指定使其工作所需的东西。
我正在尝试在 Symfony 中构建多租户支持,这样做我在我的用户中创建了一个 group_id
列,最重要的是,所有实体也有这个相同的列。这样用户只能访问他们组的数据。
我已经设法通过数据访问和显示解决了整个问题,但随后 EntityTypes
遇到了 Symfony Forms 的挑战。
问题基本上是,如何使 EntityType
仅显示该特定组输入的数据。按用户和联系人都具有的 group_id
对其进行排序。最好的传递方式是什么,这样用户只能访问他们的数据?
<?php
namespace ContactBundle\Form;
use ContactBundle\Entity\Contact;
use ContactBundle\Entity\Organization;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class ContactType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('first_name', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label' => 'First Name',])
->add('last_name', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Last Name',
])
->add('email', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Email Address'
])
->add('organization_id', EntityType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'class'=>'ContactBundle:Organization',
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
->add('phone', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Phone',
])
->add('role', TextType::Class, [
'attr' => ['class'=>'u-full-width'],
'label'=>'Role',
])
->add('submit', SubmitType::class, [
'label'=>'Submit',
'attr' => [
'class'=>'button-primary',
'style'=>'margin-top:30px;',]]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class'=>Contact::class,]);
}
}
?>
值得注意的是,我使用的是FOSUserBundle
。
创建表单时在控制器中
$form = $this->createForm(ContactType::class, $contact, ['group_id' => $groupId]);
在表单配置选项方法中
$resolver->setDefaults(['data_class'=>Contact::class, 'group_id' => null]);
在表单 buildForm 中,您可以通过
获得 group_id$options['group_id']
在 Symfony 中,可以很容易地在需要的地方注入任何你需要的东西。
// ...
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class ContactType extends AbstractType
{
private $user;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->user = $tokenStorage->getToken()->getUser();
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('organization_id', EntityType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'class'=>'ContactBundle:Organization',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.group', '?0')
->setParameters([$this->user->getGroup()]);
},
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
// ...
如果您不使用自动装配和自动配置 (Symfony 3.3+),请手动将您的表单注册为服务并使用 form.type:
标记# config/services.yaml
services:
AppBundle\Form\ContactType:
arguments: ['@security.token_storage']
tags: [form.type]
相关阅读
https://symfony.com/doc/current/form/form_dependencies.html#define-your-form-as-a-service
我明白了!
所以我最终做的是摆脱在表单端使用 EntityType 的整个想法。 然后我从控制器调用数据并将其作为选项传递。 像这样:
$contactManager = $this->get('contact.contact_manager');
$contact = new Contact($contactManager->nextId($group = $this->getUser()->getGroupId()), $group);
$form = $this->createForm(ContactType::class, $contact, ['organizations' => $this->get('contact.organization_manager')->findDataCollection($this->getUser()->getGroupId())]);
$form->handleRequest($request);
将我的 EntityType 转换为选择类型,并将组织数组作为选项传递到 'choices' 字段中。保持其他一切不变:
->add('organization_id', ChoiceType::Class, [
'attr' => ['class'=>'u-full-width'],
'required' => false,
'choices'=> $options['organizations'],
'choice_label'=>'name',
'choice_value'=>'id',
'label'=>'Organization'
])
然后,当然,在选项中设置它,这样它就可以期待一个变量。
$resolver->setDefaults(['data_class'=>Contact::class, 'organizations' => null]);
感谢所有的帮助和想法!! :)
您可以通过几种不同的方式做到这一点,一种是结合使用 JavaScript 和 EntityType。
基本上只是加载所有实体并根据先前列表的选择用 JS 隐藏不需要的实体。您可以使用数据属性来指定使其工作所需的东西。