-
-
Notifications
You must be signed in to change notification settings - Fork 504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
doc: Review custom collections and repository docs #2653
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,6 @@ | |
Custom Collections | ||
================== | ||
|
||
.. note:: | ||
This feature was introduced in version 1.1 | ||
|
||
By default, Doctrine uses ``ArrayCollection`` implementation of its ``Collection`` | ||
interface to hold both embedded and referenced documents. That collection may then | ||
be wrapped by a ``PersistentCollection`` to allow for change tracking and other | ||
|
@@ -16,14 +13,16 @@ persistence-related features. | |
<?php | ||
|
||
use Doctrine\Common\Collections\ArrayCollection; | ||
use Doctrine\Common\Collections\Collection; | ||
|
||
#[Document] | ||
class Application | ||
{ | ||
// ... | ||
|
||
/** @var Collection<Section> */ | ||
#[EmbedMany(targetDocument: Section::class)] | ||
private $sections; | ||
public Collection $sections; | ||
|
||
public function __construct() | ||
{ | ||
|
@@ -41,11 +40,6 @@ owning document's class. | |
Custom Collection Classes | ||
------------------------- | ||
|
||
.. note:: | ||
You may want to check `malarzm/collections <https://github.com/malarzm/collections>`_ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This package is not compatible with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to remove just yet, the package will be compatible soon ™️ :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On a more serious note, feel free ;) |
||
which provides alternative implementations of Doctrine's ``Collection`` interface and | ||
aims to kickstart development of your own collections. | ||
|
||
Using your own ``Collection`` implementation is as simple as specifying the | ||
``collectionClass`` parameter in the ``#[EmbedMany]`` or ``#[ReferenceMany]`` mapping | ||
and ensuring that your custom class is initialized in the owning class' constructor: | ||
|
@@ -65,7 +59,7 @@ and ensuring that your custom class is initialized in the owning class' construc | |
collectionClass: SectionCollection::class, | ||
targetDocument: Section::class, | ||
)] | ||
private $sections; | ||
private Collection $sections; | ||
|
||
public function __construct() | ||
{ | ||
|
@@ -104,12 +98,9 @@ Alternatively, you may want to implement the whole class from scratch: | |
|
||
class SectionCollection implements Collection | ||
{ | ||
private $elements = []; | ||
|
||
public function __construct(array $elements = []) | ||
{ | ||
$this->elements = $elements; | ||
} | ||
public function __construct( | ||
private array $elements = [] | ||
) {} | ||
|
||
// your implementation of all methods interface requires | ||
} | ||
|
@@ -120,40 +111,99 @@ Taking Control of the Collection's Constructor | |
By default, Doctrine assumes that it can instantiate your collections in same | ||
manner as an ``ArrayCollection`` (i.e. the only parameter is an optional PHP | ||
array); however, you may want to inject additional dependencies into your | ||
custom collection class(es). This will require you to create a | ||
`PersistentCollectionFactory implementation <https://github.com/doctrine/mongodb-odm/blob/2.2.x/lib/Doctrine/ODM/MongoDB/PersistentCollection/PersistentCollectionFactory.php>`_, | ||
which Doctrine will then use to construct its persistent collections. | ||
You may decide to implement this class from scratch or extend our | ||
``AbstractPersistentCollectionFactory``: | ||
custom collection class(es). | ||
|
||
For this example, we assume that you want to pass Symfony's event dispatcher | ||
to your custom collection class. To do this, you need to modify the | ||
constructor to accept this dependency. You also need to override the | ||
``createFrom`` method to pass the dependency to the collection constructor when | ||
methods such as ``map`` or ``filter`` are called: | ||
|
||
.. code-block:: php | ||
|
||
<?php | ||
|
||
use Doctrine\ODM\MongoDB\PersistentCollection\AbstractPersistentCollectionFactory; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Doctrine\Common\Collections\ArrayCollection; | ||
use Doctrine\Common\Collections\Collection; | ||
|
||
final class YourPersistentCollectionFactory extends AbstractPersistentCollectionFactory | ||
class SectionCollection extend ArrayCollection | ||
{ | ||
private $eventDispatcher; | ||
public function __construct( | ||
private EventDispatcherInterface $eventDispatcher, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The doc doesn't say how to inject the dependency when creating a new I think, it must be done when creating the #[Document]
class Application
{
public function __construct(
#[EmbedMany(
collectionClass: SectionCollection::class,
targetDocument: Section::class,
)]
public Collection $sections;
) {}
} $application = new Application(
sections: new SectionCollection($eventDispatcher),
); Or keeping the #[Document]
class Application
{
#[EmbedMany(
collectionClass: SectionCollection::class,
targetDocument: Section::class,
)]
public Collection $sections;
public function __construct(
EventDispatcherInterface $eventDispatcher,
) {
$this->sections = new SectionCollection($eventDispatcher);
}
} $application = new Application($eventDispatcher); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, instantiating the class for new documents is totally on user and was left as an exercise ;) Feel free to propose these 2 ways! Although in first one you should pass a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've chosen to keep only the first example. The 2nd is just a syntax variation. Since it's an advanced example, it's intended for developers who will be able to find the alternative if needed. |
||
private array $elements = [], | ||
) {} | ||
|
||
public function __construct(EventDispatcherInterface $eventDispatcher) | ||
public function createFrom(array $elements): static | ||
{ | ||
$this->eventDispatcher = $eventDispatcher; | ||
return new static($this->eventDispatcher, $elements); | ||
} | ||
|
||
protected function createCollectionClass(string $collectionClass) | ||
// your custom methods | ||
} | ||
|
||
When you instantiate a new document, it's your responsibility to pass the | ||
dependency to the collection constructor. | ||
|
||
.. code-block:: php | ||
|
||
<?php | ||
|
||
/** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher */ | ||
$eventDispatcher = $container->get('event_dispatcher'); | ||
$sections = new SectionCollection($eventDispatcher); | ||
$application = new Application($sections); | ||
|
||
The ``$sections`` property cannot have a default value in the ``Application`` | ||
class:: | ||
|
||
.. code-block:: php | ||
|
||
<?php | ||
|
||
#[Document] | ||
class Application | ||
{ | ||
#[EmbedMany( | ||
collectionClass: SectionCollection::class, | ||
targetDocument: Section::class, | ||
)] | ||
private Collection $sections; | ||
|
||
public function __construct( | ||
SectionCollection $sections, | ||
) { | ||
$this->sections = $sections; | ||
} | ||
} | ||
|
||
In addition, you need to create a class that implement ``PersistentCollectionFactory``, | ||
which Doctrine ODM will then use to construct its persistent collections. | ||
You should extend ``AbstractPersistentCollectionFactory``: | ||
|
||
.. code-block:: php | ||
|
||
<?php | ||
|
||
use Doctrine\Common\Collections\Collection; | ||
use Doctrine\ODM\MongoDB\PersistentCollection\AbstractPersistentCollectionFactory; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
|
||
final class YourPersistentCollectionFactory extends AbstractPersistentCollectionFactory | ||
{ | ||
public function __construct( | ||
private EventDispatcherInterface $eventDispatcher, | ||
) {} | ||
|
||
protected function createCollectionClass(string $collectionClass): Collection | ||
{ | ||
switch ($collectionClass) { | ||
case SectionCollection::class: | ||
return new $collectionClass([], $this->eventDispatcher); | ||
default: | ||
return new $collectionClass(); | ||
} | ||
return match ($collectionClass) { | ||
SectionCollection::class => new SectionCollection([], $this->eventDispatcher), | ||
default => new $collectionClass(), | ||
}; | ||
Comment on lines
+199
to
+202
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
} | ||
} | ||
|
||
The factory class must then be registered in the ``Configuration``: | ||
The factory class is then registered in the ``Configuration``: | ||
|
||
.. code-block:: php | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are v2.9, no need to mention such an old version.