防止 Doctrine 将 ArrayCollection 用于关系

Prevent Doctrine from using ArrayCollection for relations

有没有办法阻止 Doctrine 在获取关系时使用数组集合?目标是从实体(域层)中禁止 ORM 代码(包括),因此层是独立的,我正在玩干净的架构。

我有这个class

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 使其 returns 成为关系的原生数组? YML,XML 或 PHP 都可以。

Doctrine 使用内部对象来 return 对象集合(基于 Doctrine\Common\Collections\Collection 接口)。恐怕不容易改变。实际上这样做没有意义,因为您正在使用 ORM 关系和集合是其中的重要组成部分。

为了保持模型干净,您有不同的选择。例如,您可以在应用程序的基础结构层上有一个用于持久性目的的单独模型,并通过基础结构层和域层之间的 DTO 将持久性模型传输到域模型。

另一种选择是在域层上只有一个模型用于持久性和域目的。在第二个选项的情况下,您可以使用 $collection->toArray(),因此 public 领域模型的接口不会引入任何不必要的依赖项。

    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();
        }
    }