18

刚开始使用 Doctrine2,我想知道如何/是否可以使用自定义集合类。搜索将我指向文档的这一部分

集合值的持久字段和属性必须根据Doctrine\Common\Collections\Collection接口定义。应用程序可以使用集合实现类型在实体持久化之前初始化字段或属性。一旦实体被管理(或分离),后续访问必须通过接口类型。

虽然我确信这对某人来说很清楚,但我对此有点模糊。

如果我将我的实体设置为__construct()将集合变量初始化(例如在 中)为实现正确接口的类 - Doctrine2 会继续使用该类作为集合吗?我理解正确吗?

更新:此外,我从各种线程中收集到延迟加载中使用的占位符对象可能会影响自定义集合的使用方式。

4

3 回答 3

23

让我试着用例子来阐明什么是可能的、不可能的和计划的。

手册中的引用基本上意味着您可以拥有以下自定义实现类型:

use Doctrine\Common\Collections\Collection;

// MyCollection is the "implementation type"
class MyCollection implements Collection {
    // ... interface implementation

    // This is not on the Collection interface
    public function myCustomMethod() { ... }
}

现在您可以按如下方式使用它:

class MyEntity {
    private $items;
    public function __construct() {
        $this->items = new MyCollection;
    }
    // ... accessors/mutators ...
}

$e = new MyEntity;
$e->getItems()->add(new Item);
$e->getItems()->add(new Item);
$e->getItems()->myCustomMethod(); // calling method on implementation type

// $em instanceof EntityManager
$em->persist($e);

// from now on $e->getItems() may only be used through the interface type

换句话说,只要一个实体是新的(不是 MANAGED、DETACHED 或 REMOVED),你就可以自由地使用集合的具体实现类型,即使它并不漂亮。如果它不是新的,您必须只访问接口类型(最好是类型提示)。这意味着实现类型并不重要。当从数据库中检索持久化 MyEntity 实例时,它不会使用 MyCollection(构造函数不会被 Doctrine 调用,因为 Doctrine 只重构已经存在/持久化的对象,它永远不会创建“新”对象)。而且由于这样的实体是 MANAGED 的,因此无论如何都必须通过接口类型进行访问。

现在到什么计划。拥有自定义集合的更漂亮的方法是同时拥有自定义接口类型,例如 IMyCollection 和 MyCollection 作为实现类型。然后,要使其与 Doctrine 2 持久性服务完美配合,您需要实现自定义 PersistentCollection 实现,例如 MyPersistentCollection,如下所示:

class MyPersistentCollection implements IMyCollection {
    // ...
}

然后你会告诉映射中的 Doctrine 为该集合使用 MyPersistentCollection 包装器(请记住,PersistentCollection包装了一个集合实现类型,实现了相同的接口,以便它可以在委托给底层集合实现之前/之后完成所有持久性工作类型)。

因此,自定义集合实现将包含 3 个部分:

  1. 接口类型
  2. 实现类型(实现接口类型)
  3. 持久包装类型(实现接口类型)

这不仅可以编写与 Doctrine 2 ORM 无缝协作的自定义集合,还可以仅编写自定义持久包装器类型,例如优化特定集合的延迟加载/初始化行为以满足特定应用程序的需求。

目前还不可能做到这一点,但它会做到的。这是编写和使用完全自定义集合的唯一真正优雅且功能齐全的方法,这些集合完美地集成到 Doctrine 2 提供的透明持久性方案中。

于 2010-09-12T08:44:53.503 回答
1

不,只要 Doctrine 将 Doctrine\Common\Collections\Collection 接口的实现返回给您,它将是一个 Doctrine\ORM\PersistentCollection 实例。您不能在集合上放置更多自定义逻辑。然而,这甚至没有必要。

假设你有一个实体(Order 有很多 OrderItems),那么计算订单总和的方法不应该位于集合上,而是位于 Order 项上。因为那是总和在您的域模型中有意义的位置:

class Order
{
    private $items;

    public function getTotalSum()
    {
        $total = 0;
        foreach ($this->items AS $item) {
            $total += $item->getSum();
        }
        return $total;
    }
}

然而,集合只是 ORM 的技术部分,它们有助于实现和管理对象之间的引用,仅此而已。

于 2010-09-11T19:50:43.937 回答
0

同样的问题在这里,参考官方教义 Jira 问题页面,其中包含此“功能”的详细信息和状态......您可以在那里跟踪开发!

于 2013-09-06T15:06:14.607 回答