Doctrine2中的自定义集合

时间:2010-09-11 17:34:28

标签: php orm collections doctrine-orm

刚开始使用Doctrine2,我想知道如何/如果我可以使用自定义集合类。搜索指向this part of the documentation

  

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

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

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

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

3 个答案:

答案 0 :(得分:20)

让我试着通过例子来澄清可能的,不可能和有计划的。

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

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

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

现在计划好了。拥有自定义集合的更美妙的方法是也有一个自定义接口类型,比如IMyCollection和MyCollection作为实现类型。然后,为了使它与Doctrine 2持久性服务完美配合,您需要实现一个自定义PersistentCollection实现,比如MyPersistentCollection,如下所示:

class MyPersistentCollection implements IMyCollection {
    // ...
}

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

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

  1. 接口类型
  2. 实现类型(实现接口类型)
  3. 持久包装器类型(实现接口类型)
  4. 这不仅可以编写与Doctrine 2 ORM无缝协作的自定义集合,而且还可以只编写自定义持久性包装器类型,例如优化特定集合的延迟加载/初始化行为应用需求。

    目前尚无法做到这一点,但确实如此。这是编写和使用完全自定义集合的唯一真正优雅且功能齐全的方式,这些集合完美地集成在Doctrine 2提供的透明持久性方案中。

答案 1 :(得分:0)

不,只要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的技术部分,它们有助于实现和管理对象之间的引用,仅此而已。

答案 2 :(得分:0)

同样的问题here,引用了official doctrine Jira issue页面,其中包含此“功能”的详细信息和状态......您可以跟踪那里的开发情况!