symfony - EntityType 和多对多,额外字段关系显示为下拉列表(选择)
问题描述
我创建了一个这样的表格
$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,
])
因此,它可以很好地呈现已经存在的数据。它向我显示了与已编辑活动相关的所有员工。
但是,choices
因为应该有所有的雇员来选择(employee
实体),并且data
像现在一样在 activityEmployee 关系中选择了唯一的雇员。
我试图添加一个query_builder
选项来提供所有雇员的列表,但我只能使用EntityRepository
这意味着ActivityEmployeesRepository
不是EmployeesRepository
本身。
A无法弄清楚如何实现它。基本上这种关系可以通过CollectionType
自定义来完成,activityEmployeeType
但我想使用多选来选择员工。
我可以使用另一种方法来不将我的员工字段映射到这样的实体
$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()
回报[]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
and之外没有其他属性employee
,那么您显然可以将整个内容替换为 a@ORM\ManyToMany
并且只使用Employee[]
而不是ActivityEmployee[]
. 但是,我假设您有一些额外的列,例如created
。
推荐阅读
- pandas - 如何基于逻辑表达式使用 groupby 创建新列
- c++ - 将数据附加到 C++ 中的数组
- python - 在python操作行中读取文件
- android - 我的 Android Studio 项目与 android 9 和 10 不兼容
- excel - 如何在 vba excel 中不同工作表的两列之间执行连接?
- angular - 导航到 url 时未执行 dataPersistence.navigation
- http - Coldfusion从其他服务器读取HTTP post请求
- python - Python:从 txt 文件打印到列表
- c# - 如何将 ac# 列表序列化为 JSON
- r - 根据 R 中的 id 和日期合并数据