【问题标题】:Prevent Doctrine from using ArrayCollection for relations防止 Doctrine 将 ArrayCollection 用于关系
【发布时间】:2020-10-22 10:51:02
【问题描述】:

有没有办法防止 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 放入用户中,这导致错误 500。 我知道我可以删除输入并只执行 $collection->toArray(),但这意味着我的模型符合 ORM,它应该是相反的。

有没有办法配置 Doctrine 以返回一个本地数组来表示关系? YML、XML 或 PHP 都可以。

【问题讨论】:

    标签: symfony doctrine relation arraycollection


    【解决方案1】:

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

    【讨论】:

    • 我不喜欢拥有 2 个模型的想法。 My Domain 层只是操作数据的建模,数据的使用方式在另一层(应用程序),然后是基础架构(ORM)和 UI(通过 http 交互)。我认为最适合我的解决方案是注释属性的类型并在方法中转换为数组,通过不添加额外的类,我的队友必须理解的代码会更少。将就学说提出拉取请求:p 无论如何感谢您的提议,它们将被研究以供以后使用。
    • 是的,有两个模型似乎有点开销。简单是最好的,并且强制转换为数组以获得干净的公共界面听起来就足够了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 2012-01-10
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多