Reputation: 250
I want to use a custom collection class for my Symfony 4 application. The following scenario is an example of what I am trying to achieve:
I have a post collection class which has some utility for filtering and mapping data.
class PostArrayCollection extends ArrayCollection implements PostCollectionInterface
{
public function mapTitles()
{
return $this->map(function (Post $post) {
return $post->getTitle();
});
}
public function filterPublishedAfterDate(DateTime $from)
{
return $this->filter(function (Post $post) use ($from) {
return $post->publishedDate() > $from;
});
}
}
Also the user class which is a Doctrine Entity.
class User
{
/**
* @ORM\OneToMany(targetEntity="App\Entity\Post", mappedBy="post", cascade={"persist"})
*/
private $posts;
public function __construct()
{
$this->posts = new PostArrayCollection();
}
public function getPosts(): PostCollectionInterface
{
return $this->posts;
}
}
Then there is a method in a helper or controller which will access the user's data like the following:
public function showPublishedPostTitlesForUser(User $user)
{
$publishedPostTitles = $user->getPosts()
->filterPublishedAfterDate(new DateTime())
->mapTitles();
// Render the titles...
}
The above works when creating a new object by hand, for example in a unit test. But it will not work when loading the entity from the repository, because then the collections will be filled with Doctrine\ORM\PersistentCollection
objects.
My question now is, how do I configure my app so I can use a custom persistent collection (for example PersistentPostCollection
) when loading entities?
I did find this page https://www.doctrine-project.org/projects/doctrine-collections/en/latest/lazy-collections.html#lazy-collections, but I cannot find how to integrate this into Symfony 4.
Note: The above scenario is a simple example for the sake of keeping this question short and simple to get into. I am aware that this whole problem can be avoided when using a repository to get the correct data. But that is not what I am looking for here. This question is about understanding what is possible with Doctrine collections in Symfony 4.
Upvotes: 3
Views: 4007
Reputation: 83
Excelent solution. In my case it's not a complete solution because I'm usin DDD and I want to make domain agnostic to Doctrine. I'm using custom collections and I don't know how to map Doctrine Collection tu my custom collections
Upvotes: 1
Reputation: 1427
Your custom collection must act as a decorator and check in your getPosts()
method if it is your custom collection.
The PostArrayCollection
will look like this
class PostArrayCollection implements Collection, Selectable, PostCollectionInterface
{
/**
* @var ArrayCollection|PersistentCollection
*/
private $collection;
public static function fromItems(Post ...$elements)
{
return new self(new ArrayCollection($elements));
}
public static function fromDoctrine(PersistentCollection $collection)
{
return new self($collection);
}
private function __construct(Collection $collection)
{
$this->collection = $collection;
}
public function mapTitles()
{
return $this->collection->map(function (Post $post) {
return $post->getTitle();
});
}
public function filterPublishedAfterDate(DateTime $from)
{
return $this->collection->filter(function (Post $post) use ($from) {
return $post->publishedDate() > $from;
});
}
// TODO implement all other methods and delegate it to $this->collection
}
The User
class will look like this.
class User
{
/**
* @ORM\OneToMany(targetEntity="App\Entity\Post", mappedBy="post", cascade={"persist"})
*/
private $posts;
public function __construct()
{
$this->posts = PostArrayCollection::fromItems();
}
public function getPosts(): PostCollectionInterface
{
if ($this->posts instanceof PersistentCollection) {
$this->posts = PostArrayCollection::fromDoctrine($this->posts);
}
return $this->posts;
}
}
Upvotes: 2
Reputation: 15656
What you've found is doc for Doctrine Collections package.
Doctrine ORM is using Doctrine Collections package, but they are separate packages from each other. Therefore the fact that you can create a custom collection doesn't mean ORM will respect that.
What you want to do is not possible right now with Doctrine ORM.
The feature of custom collections is scheduled for next major Doctrine ORM version.
Upvotes: 5