Doctrine2 中的自定义集合

发布于 2024-09-19 03:58:43 字数 559 浏览 5 评论 0原文

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

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

虽然我确信这对某些人来说是非常清楚的,但我对此有点模糊。

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

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

Just starting to work with Doctrine2, and am wondering how/if I can use a custom collection class. Searches point me to this part of the documentation:

Collection-valued persistent fields and properties must be defined in terms of the Doctrine\Common\Collections\Collection interface. The collection implementation type may be used by the application to initialize fields or properties before the entity is made persistent. Once the entity becomes managed (or detached), subsequent access must be through the interface type.

While I'm sure that's crystal clear to someone, I'm a little fuzzy on it.

If I setup my Entity to initialize (say in __construct()) the collection variable to a class that implements the correct interface - will Doctrine2 continue to use that class as the collection? Am I understanding that correctly?

Update: Also, I gather from various threads that the placeholder object used in lazy loading may influence how a custom collection can be used.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雪化雨蝶 2024-09-26 03:58:43

让我尝试通过示例来阐明什么是可能的、什么是不可能的以及计划的。

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

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,则必须仅访问接口类型(最好是其上的类型提示)。这意味着实现类型并不重要。当从数据库中检索持久性 MyEntity 实例时,它不会使用 MyCollection(构造函数不会被 Doctrine 调用,因为 Doctrine 只重构已经存在/持久的对象,它从不创建“新”对象)。由于这样的实体是受管理的,因此无论如何访问都必须通过接口类型进行。

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

class MyPersistentCollection implements IMyCollection {
    // ...
}

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

因此,自定义集合实现将由 3 部分组成:

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

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

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

Let me try to clarify what is possible, not possible and planned with examples.

The quote from the manual basically means you could have the following custom implementation type:

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() { ... }
}

Now you could use it as follows:

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

In other words, as long as an entity is NEW (not MANAGED, DETACHED or REMOVED) you are free to use the concrete implementation type of collections, even if its not pretty. If it is not NEW, you must access only the interface type (and ideally type-hint on it). That means the implementation type does not really matter. When a persistent MyEntity instance is retrieved from the database, it will not use a MyCollection (constructors are not invoked by Doctrine, ever, since Doctrine only reconstitutes already existing/persistent objects, it never creates "new" ones). And since such an entity is MANAGED, access must happen through the interface type anyways.

Now to what is planned. The more beautiful way to have custom collections is to also have a custom interface type, say IMyCollection and MyCollection as the implementation type. Then, to make it work perfectly with the Doctrine 2 persistence services you would need to implement a custom PersistentCollection implementation, say, MyPersistentCollection which looks like this:

class MyPersistentCollection implements IMyCollection {
    // ...
}

Then you would tell Doctrine in the mapping to use the MyPersistentCollection wrapper for that collection (remember, a PersistentCollection wraps a collection implementation type, implementing the same interface, so that it can do all the persistence work before/after delegating to the underlying collection implementation type).

So a custom collection implementation would consist of 3 parts:

  1. Interface type
  2. Implementation type (implements interface type)
  3. Persistent wrapper type (implements interface type)

This will not only make it possible to write custom collections that work seemlessly with the Doctrine 2 ORM but also to write only a custom persistent wrapper type, for example to optimise the lazy-loading/initialization behavior of a particular collection to specific application needs.

It is not yet possible to do this but it will be. This is the only really elegant and fully functional way to write and use completely custom collections that integrate flawlessly in the transparent persistence scheme provided by Doctrine 2.

累赘 2024-09-26 03:58:43

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

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

class Order
{
    private $items;

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

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

No, whenever Doctrine gives you back an implementation of the Doctrine\Common\Collections\Collection interface, it will be a Doctrine\ORM\PersistentCollection instance. You cannot put more custom logic on the collection. However that is not even necessary.

Say you have an entity (Order has many OrderItems), then a method to calculate the total sum of the order should not be located on the collection, but on the Order item. Since that is the location where the sum has meaning in your domain model:

class Order
{
    private $items;

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

Collections however are only technical parts of the ORM, they help to implement and manage references between objects, nothing more.

耳钉梦 2024-09-26 03:58:43

同样的问题此处,并参考官方学说 Jira 问题页面,其中包含此“功能”的详细信息和状态。 .您可以跟踪那里的发展!

Same question here, with a reference to the official doctrine Jira issue page with the details and status of this 'feature'... You can keep track of the development there!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文