doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.94k stars 2.52k forks source link

Custom Collections through delegation #11637

Open beberlei opened 1 month ago

beberlei commented 1 month ago

Users regularly want to introduce their own collections. We don't want to expose the Collection interface due to its complexity there is too much risk. MongoDB ODM has a code generated solution for this, for ORM I propose we do this with delegation.

  1. doctrine/collections introduces a DelegateCollection with all methods implemented as final, delegating to $delegatee, and one custom method getInternalDelgatee.
  2. In ORM association configuration, allow optional "collectionType" information. When present, ORM converts with logic:
    • create collection new $assoc['collectionType](new PersistentCollection(...)) everywhere a PersistentCollection is created.
    • introspect collection $col = $col instanceof DelegateeCollection ? $col->getDelegatee() : $col
  3. Improve AttributeDriver to detect that a collection type instanceof DelegateeCollection and set collectionType key automatically.
  4. Precondition: In ORM, if collection types are configured and Composer\PackageVersions for doctrine/collection is not high enough, throw.

Example code:

class CommentCollection extends DelegateCollection
{
    public function getEnabled() {
        return $this->delegatee->filter(fn ($comment) => $comment->isEnabled);
        }
}

class Post
{
        private CommentCollection $comments;

    public function getComments(): CommentCollection
        {
             return $this->comments;
         }
}

Reference:

stof commented 1 month ago

4. Precondition: In ORM, if collection types are configured and Composer\PackageVersions for doctrine/collection is not high enough, throw.

simpler version: bump the min version of the doctrine/collection in the ORM to be the minor version introducing this DelegateCollection.