Пользовательская коллекция в Doctrine2

Просто начну работать с Doctrine2, и мне интересно, как/если я могу использовать собственный класс коллекции. Поиски указывают мне на эту часть документации:

Поля и свойства, связанные с коллекцией, должны быть определены в терминах интерфейса Doctrine\Common\Collections\Collection. Тип реализации коллекции может использоваться приложением для инициализации полей или свойств до того, как объект станет постоянным. Когда объект становится управляемым (или отсоединенным), последующий доступ должен быть через тип интерфейса.

Хотя я уверен, что это ясно для кого-то, я немного расплывчатый.

Если я настрою свой Entity для инициализации (скажем, в __construct()), переменная коллекции для класса, который реализует правильный интерфейс, будет ли Doctrine2 продолжать использовать этот класс в качестве коллекции? Я правильно понимаю это?

Обновление. Кроме того, я собираюсь из разных потоков, что объект-заполнитель, используемый при ленивой загрузке, может влиять на то, как можно использовать пользовательскую коллекцию.

Ответы

Ответ 1

Позвольте мне попытаться выяснить, что возможно, невозможно и запланировано с примерами.

Цитата из руководства в основном означает, что у вас может быть следующий тип специальной реализации:

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 (не УПРАВЛЯЕМАЯ, ДЕТАЛЬНАЯ или УДАЛЕНА), вы можете использовать конкретный тип реализации коллекций, даже если это не очень. Если это не NEW, вы должны получить доступ только к типу интерфейса (и, в идеале, к нему наброски). Это означает, что тип реализации не имеет большого значения. Когда постоянный экземпляр MyEntity извлекается из базы данных, он не будет использовать MyCollection (конструкторы не будут вызываться Doctrine, поскольку Doctrine только восстанавливает уже существующие/постоянные объекты, он никогда не создает "новые" ). И поскольку такой объект MANAGED, доступ должен происходить через тип интерфейса в любом случае.

Теперь к тому, что планируется. Более красивый способ создания пользовательских коллекций также иметь собственный тип интерфейса, например IMyCollection и MyCollection в качестве типа реализации. Затем, чтобы заставить его работать с службами Persistence 2 persistence, вам нужно будет реализовать пользовательскую реализацию PersistentCollection, скажем, MyPersistentCollection, которая выглядит так:

class MyPersistentCollection implements IMyCollection {
    // ...
}

Затем вы должны указать Doctrine в сопоставлении использовать оболочку MyPersistentCollection для этой коллекции (помните, PersistentCollection wraps тип реализации коллекции, реализующий один и тот же интерфейс, чтобы он мог выполнять все настойчивость работа до/после делегирования к типу реализации базового набора).

Таким образом, реализация пользовательской коллекции будет состоять из трех частей:

  • Тип интерфейса
  • Тип реализации (реализует тип интерфейса)
  • Постоянный тип оболочки (реализует тип интерфейса)

Это позволит не только создавать пользовательские коллекции, которые без труда работают с ORM Doctrine 2, но и писать только настраиваемый постоянный тип обертки, например, для оптимизации поведения ленивой загрузки/инициализации конкретной коллекции для конкретных приложений.

Пока это невозможно, но это будет. Это единственный действительно элегантный и полностью функциональный способ написания и использования полностью настраиваемых коллекций, которые безупречно интегрируются в прозрачную схему сохранения, предоставляемую Doctrine 2.

Ответ 2

Нет, всякий раз, когда Doctrine возвращает вам реализацию интерфейса Doctrine\Common\Collections\Collection, это будет экземпляр Doctrine\ORM\PersistentCollection. Вы не можете добавить больше пользовательской логики в коллекцию. Однако это даже не нужно.

Скажите, что у вас есть сущность (у Ордена есть много OrderItems), тогда метод вычисления общей суммы заказа не должен располагаться в коллекции, а в элементе заказа. Так как это место, где сумма имеет смысл в вашей модели домена:

class Order
{
    private $items;

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

Однако коллекции - это только технические части ORM, они помогают внедрять и управлять ссылками между объектами, не более того.