实体类型和具有额外字段关系的多对多显示为下拉列表 (select)
EntityType and many to many with extra field relation presented as dropdown (select)
我创建了一个这样的表格
$builder->add('employees', EntityType::class, [
'class' => ActivityEmployee::class,
'choice_label' => function (ActivityEmployee $employee) {
return sprintf('%s %s', $employee->getEmployee()->getName(), $employee->getEmployee()->getLastName());
},
'multiple' => true,
])
因此,它可以很好地呈现现有数据。它向我显示了与已编辑 activity.
有关的所有员工
然而 choices
应该有所有雇员选择(employee
实体)并且 selected data
在 activity 雇员关系中只有雇员就像现在一样。
我试图添加一个 query_builder
选项来提供所有雇员的列表,但我只能使用 EntityRepository
这意味着 ActivityEmployeesRepository
而不是 EmployeesRepository
本身。
A 不知道如何实现它。基本上这种关系可以通过自定义 activityEmployeeType
的 CollectionType
来完成,但我想为 selecting 员工使用 multi-select。
我可以使用另一种方法来不将我的员工字段映射到那样的实体
$currentEmployees = [];
foreach ($activity->getEmployees() as $activityEmployee) {
$currentEmployees[] = $activityEmployee->getEmployee();
}
$builder->add('employees', EntityType::class, [
'class' => Employee::class,
'choice_label' => function (Employee $employee) {
return sprintf('%s %s', $employee->getName(), $employee->getLastName());
},
'mapped' => false,
'multiple' => true,
'data' => $currentEmployees,
]);
它工作正常,但我需要自己处理更新关系。没关系,但是我想知道如何在第一种方法中实现这样的事情。
实施细节很重要。据我所知,您有以下实体:
Activity (entity)
- employees (OneToMany -> ActivityEmployee)
ActivityEmployee (entity)
- activity (ManyToOne -> Activity)
- employee (ManyToOne -> Employee)
Employee (entity)
- activities (OneToMany -> ActivityEmployee) - this one might be missing, actually.
现在您显然没有隐藏任何实现细节。意思是,你的 Activity::getEmployees()
returns []ActivityEmployee
.
我会这样做:
class Activity {
/** @ORM\OneToMany(targetEntity=ActivityEmployee::class) */
private $activityEmployees;
/** @return Employee[] */
public function getEmployees() :Collection {
return $this->activityEmployees->map(function(ActivityEmployee $ae) {
return $ae->getEmployee();
});
}
public function addEmployee(Employee $employee) {
// check, if the employee is already registered, add only then!
if(!$this->getEmployees()->contains($employee)) {
$this->activityEmployees->add(new ActivityEmployee($this, $employee));
}
}
public function removeEmployee(Employee $employee) {
foreach($this->activityEmployees as $activityEmployee) {
if($activityEmployee->getEmployee() === $employee) {
$this->activityEmployees->removeElement($activityEmployee);
}
}
}
}
通过这种方式,您隐藏了 Activity
如何处理员工和外部世界(特别是表单组件使用的 PropertyAccessor),它看起来好像 Activity
有一个 属性 employees
实际上是 Employee[]
.
如果你这样实现它,你的第一个表单实际上应该可以正常工作(显然是将 ActivityEmployee 换成 Employee)- 假设我没有犯一些重大错误。当然,当我实际上特别需要关系对象时,我也会添加像 getActivityEmployees
这样的方法。
如果你的多对多可以包含重复项,那么整个事情肯定就不那么漂亮了。
如果 你的 ActivityEmployee 实际上除了 activity
和 employee
没有其他属性,你显然可以用 @ORM\ManyToMany
替换整个东西并且只使用 Employee[]
而不是 ActivityEmployee[]
。但是,我假设您有一些额外的列,例如 created
或其他列。
我创建了一个这样的表格
$builder->add('employees', EntityType::class, [
'class' => ActivityEmployee::class,
'choice_label' => function (ActivityEmployee $employee) {
return sprintf('%s %s', $employee->getEmployee()->getName(), $employee->getEmployee()->getLastName());
},
'multiple' => true,
])
因此,它可以很好地呈现现有数据。它向我显示了与已编辑 activity.
有关的所有员工然而 choices
应该有所有雇员选择(employee
实体)并且 selected data
在 activity 雇员关系中只有雇员就像现在一样。
我试图添加一个 query_builder
选项来提供所有雇员的列表,但我只能使用 EntityRepository
这意味着 ActivityEmployeesRepository
而不是 EmployeesRepository
本身。
A 不知道如何实现它。基本上这种关系可以通过自定义 activityEmployeeType
的 CollectionType
来完成,但我想为 selecting 员工使用 multi-select。
我可以使用另一种方法来不将我的员工字段映射到那样的实体
$currentEmployees = [];
foreach ($activity->getEmployees() as $activityEmployee) {
$currentEmployees[] = $activityEmployee->getEmployee();
}
$builder->add('employees', EntityType::class, [
'class' => Employee::class,
'choice_label' => function (Employee $employee) {
return sprintf('%s %s', $employee->getName(), $employee->getLastName());
},
'mapped' => false,
'multiple' => true,
'data' => $currentEmployees,
]);
它工作正常,但我需要自己处理更新关系。没关系,但是我想知道如何在第一种方法中实现这样的事情。
实施细节很重要。据我所知,您有以下实体:
Activity (entity)
- employees (OneToMany -> ActivityEmployee)
ActivityEmployee (entity)
- activity (ManyToOne -> Activity)
- employee (ManyToOne -> Employee)
Employee (entity)
- activities (OneToMany -> ActivityEmployee) - this one might be missing, actually.
现在您显然没有隐藏任何实现细节。意思是,你的 Activity::getEmployees()
returns []ActivityEmployee
.
我会这样做:
class Activity {
/** @ORM\OneToMany(targetEntity=ActivityEmployee::class) */
private $activityEmployees;
/** @return Employee[] */
public function getEmployees() :Collection {
return $this->activityEmployees->map(function(ActivityEmployee $ae) {
return $ae->getEmployee();
});
}
public function addEmployee(Employee $employee) {
// check, if the employee is already registered, add only then!
if(!$this->getEmployees()->contains($employee)) {
$this->activityEmployees->add(new ActivityEmployee($this, $employee));
}
}
public function removeEmployee(Employee $employee) {
foreach($this->activityEmployees as $activityEmployee) {
if($activityEmployee->getEmployee() === $employee) {
$this->activityEmployees->removeElement($activityEmployee);
}
}
}
}
通过这种方式,您隐藏了 Activity
如何处理员工和外部世界(特别是表单组件使用的 PropertyAccessor),它看起来好像 Activity
有一个 属性 employees
实际上是 Employee[]
.
如果你这样实现它,你的第一个表单实际上应该可以正常工作(显然是将 ActivityEmployee 换成 Employee)- 假设我没有犯一些重大错误。当然,当我实际上特别需要关系对象时,我也会添加像 getActivityEmployees
这样的方法。
如果你的多对多可以包含重复项,那么整个事情肯定就不那么漂亮了。
如果 你的 ActivityEmployee 实际上除了 activity
和 employee
没有其他属性,你显然可以用 @ORM\ManyToMany
替换整个东西并且只使用 Employee[]
而不是 ActivityEmployee[]
。但是,我假设您有一些额外的列,例如 created
或其他列。