问题描述
有没有一种方法可以防止Doctrine在获取关系时使用数组集合?目标是禁止实体(域层)中的ORM代码(包括),因此层是独立的,我正在使用干净的体系结构。
我有这堂课
class User extends AbstractModel implements UserInterface
{
// some other fields
/**
* @var array|RoleInterface[]
*/
private array $roles = [];
/**
* @return RoleInterface[]
*/
final public function getRoles(): array
{
return (array) $this->roles;
}
public function hasRole(RoleInterface $role): bool
{
return in_array($role,$this->roles);
}
/**
* @param RoleInterface[]
*
* @return self
*/
final public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
final public function addRole(RoleInterface $role): self
{
if (! $this->hasRole($role)) {
$this->setRoles([...$this->roles,$role]);
}
return $this;
}
final public function removeRole(RoleInterface $role): self
{
if ($this->hasRole($role)) {
$this->setRoles(array_filter(
$this->roles,fn (Role $current) => $current === $role
));
}
return $this;
}
}
并且映射是通过XML完成的
<doctrine-mapping xmlns="https://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd">
<entity name="App\Domain\Model\User\User">
<!-- some other fields -->
<many-to-many field="roles" target-entity="App\Domain\Model\Role\Role">
<join-table name="user_role">
<join-columns>
<join-column name="user_id" referenced-column-name="id" nullable="false" unique="false" />
</join-columns>
<inverse-join-columns>
<join-column name="role_id" referenced-column-name="id" nullable="false" unique="false" />
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
</doctrine-mapping>
问题是,在获取用户时,Doctrine尝试将ArrayCollection放入用户,这会导致en错误500。 我知道我可以删除类型并只执行$ collection-> toArray(),但这意味着我的模型符合ORM,应该相反。
有没有一种方法可以配置Doctrine,使其返回用于关系的本机数组?可以使用YML,XML或PHP。
解决方法
Doctrine使用内部对象返回对象集合(基于Doctrine \ Common \ Collections \ Collection接口)。恐怕很难改变。实际上,这样做是没有意义的,因为将ORM与关系和集合一起使用是其中的重要部分。
为了保持模型清洁,您有不同的选择。例如,您可以在应用程序的基础结构层上具有一个用于持久性目的的单独模型,然后通过基础结构层和域层之间的DTO将持久性模型转移到域模型。
另一个选择是在域层上只有一个模型同时用于持久性和域目的。如果使用第二种方法,则可以使用$ collection-> toArray(),这样域模型的公共接口就不会引入任何不必要的依赖关系。
class User extends AbstractModel implements UserInterface
{
/**
* @var Collection|RoleInterface[]
*/
private Collection $roles;
public function __construct()
{
$this->roles = new ArrayCollection();
}
/**
* @return RoleInterface[]
*/
public function getRoles(): array
{
return $this->roles->toArray();
}
}