Mus*_*mal 5 symfony-forms symfony
我有一个Company有很多Employees 的。在我的表单中,我希望用户能够动态添加员工(足够简单)。EmployeeType(an AbstractType) 是复合词,包含名字和姓氏。在提交表单时,Symfony 似乎没有将表单中的数据传递到“新”员工的构造函数中。我收到一个错误
ArgumentCountError:函数 Employee::__construct() 的参数太少...传入了 0 个...并且预期正好有 3 个
显示和编辑现有的员工作品,因此我确信我的关系等都是正确的。
缩写代码:
class Company
{
protected $employees;
public function __construct()
{
$this->employees = new ArrayCollection();
}
public function addEmployee(Employee $employee)
{
if ($this->employees->contains($employee)) {
return;
}
$this->employees->add($employee);
}
public function removeEmployee(Employee $employee)
{
if (!$this->employees->contains($employee)) {
return;
}
$this->employees->removeElement($employee);
}
}
Run Code Online (Sandbox Code Playgroud)
class Employee
{
// ... firstName and lastName properties...
public function __construct(Company $company, $firstName, $lastName)
{
$this->company = $company;
$this->company->addEmployee($this);
}
// ...getter and setter for firstName / lastName...
}
Run Code Online (Sandbox Code Playgroud)
class CompanyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('employees', CollectionType::class, [
'entry_type' => EmployeeType::class,
'allow_add' => true,
'allow_delete' => false,
'required' => false,
]);
// ...other fields, some are CollectionType of TextTypes that work correctly...
}
}
Run Code Online (Sandbox Code Playgroud)
class EmployeeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('firstName')
->add('lastName');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Employee::class,
]);
}
}
Run Code Online (Sandbox Code Playgroud)
class CompanyController
{
// Never mind that this is a show and not edit, etc.
public function showAction()
{
// Assume $this->company is a new or existing Company
$form = $this->createForm(CompanyType::class, $this->company);
$form->handleRequest($this->request);
if ($form->isSubmitted() && $form->isValid()) {
$company = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($company);
$entityManager->flush();
}
// set flash message, redirect, etc.
}
// ...render view...
}
Run Code Online (Sandbox Code Playgroud)
上述内容在修改现有员工时有效,但在创建新员工时无效。从 Symfony 代码中调试,我可以看到新员工不存在任何数据,因此它试图找到empty_datain的闭包或定义CompanyType。我已经尝试过各种方式(通过configureOptions, 和empty_data构建CompanyType::buildForm表单时的选项),例如https://symfony.com/doc/current/form/use_empty_data.html。我的直觉告诉我,我什至不需要这样做,因为表单数据不应该为空(我明确填写了字段)。
我也尝试使用模型变压器。在这种情况下,形式的转换(传递给 的第二个函数参数new CallbackTransformer)甚至不会被命中。
添加新员工字段(例如 等)时,视图会正确设置名称属性form[employees][1][firstName]。这不是问题。它还将正确的数据发送到控制器。CompanyType::onPreSubmit我通过(使用事件侦听器)检查表单提交数据来确认这一点。
我还有一个CollectionTypeof TextTypes 用于其他事情CompanyType,这些工作正常。所以这个问题似乎与EmployeeType复合(包含多个字段)这一事实有关。
希望以上内容足以说明问题。有任何想法吗?
更新:
问题似乎是没有EmployeeSymfony 可以使用的实例。在内部,每个字段都会传递到Symfony\Component\Form\Form::submit(). 对于现有员工,还有一个Employee传入的员工。对于新员工,它是null。这解释了为什么它正在寻找empty_data,但我不知道为什么我无法empty_data上班。
解决方案是以复合形式定义empty_data,而不是CollectionType形式。
我的情况有点奇怪,因为我还需要Companymy 中的实例EmployeeType,因为它必须传递给 for 的构造函数Employee。我通过将 Company 作为表单选项传递到configureOptions(由控制器提供),然后传递到entry_options. 我不知道这是否是最佳实践,但它有效:
确保我们传入 Company 实例,以便在EmployeeType构建新实例时可以使用它Employee:
$form = $this->createForm(CompanyType::class, $this->company, [
// This is a form option, valid because it's in CompanyType::configureOptions()
'company' => $this->company,
]);
Run Code Online (Sandbox Code Playgroud)
class CompanyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('employees', CollectionType::class, [
// ...
// Pass the Company instance to the EmployeeType.
'entry_options' => [ 'company' => $options['company'] ],
// This was also needed, apparently.
'by_reference' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
// Allows the controller to pass in a Company instance.
'company' => null,
]);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们确保empty_data从表单数据正确构建员工。
class EmployeeType extends AbstractType
{
private $company;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('firstName')
->add('lastName');
// A little weird to set a class property here, but we need the Company
// instance in the 'empty_data' definition in configureOptions(),
// at which point we otherwise wouldn't have access to the Company.
$this->company = $options['company'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Employee::class,
'empty_data' => function (FormInterface $form) use ($resolver) {
return new Employee(
$this->company,
$form->get('firstName')->getData(),
$form->get('lastName')->getData(),
);
},
]);
}
}
Run Code Online (Sandbox Code Playgroud)
中提琴!我现在可以添加新员工。
希望这对其他人有帮助!
| 归档时间: |
|
| 查看次数: |
1152 次 |
| 最近记录: |