如何在 Symfony 4 中使用自定义集合
How to use a custom collection in Symfony 4
我想为我的 Symfony 4 应用程序使用自定义集合 class。以下场景是我要实现的示例:
我有一个 post 集合 class,它具有一些用于过滤和映射数据的实用程序。
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;
});
}
}
还有用户 class,它是一个 Doctrine 实体。
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;
}
}
然后在助手或控制器中有一个方法将访问用户的数据,如下所示:
public function showPublishedPostTitlesForUser(User $user)
{
$publishedPostTitles = $user->getPosts()
->filterPublishedAfterDate(new DateTime())
->mapTitles();
// Render the titles...
}
以上内容在手动创建新对象时有效,例如在单元测试中。但是从存储库加载实体时它不会工作,因为那样集合将充满 Doctrine\ORM\PersistentCollection
个对象。
我现在的问题是,如何配置我的应用程序以便在加载实体时可以使用自定义持久集合(例如 PersistentPostCollection
)?
我确实找到了这个页面 https://www.doctrine-project.org/projects/doctrine-collections/en/latest/lazy-collections.html#lazy-collections,但是我找不到如何将它集成到 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.
您找到的是 Doctrine Collections 包的文档。
Doctrine ORM 正在使用 Doctrine Collections 包,但它们是彼此独立的包。因此,您可以创建自定义集合这一事实并不意味着 ORM 会尊重它。
现在用 Doctrine ORM 做不到你想做的事。
feature of custom collections is scheduled for next major Doctrine ORM version.
您的自定义集合必须充当装饰器并检查您的 getPosts()
方法(如果它是您的自定义集合)。
PostArrayCollection
看起来像这样
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
}
User
class 看起来像这样。
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;
}
}
优秀的解决方案。就我而言,这不是一个完整的解决方案,因为我使用的是 DDD,并且我想让域与 Doctrine 无关。我正在使用自定义集合,但我不知道如何将 Doctrine Collection 映射到我的自定义集合
我想为我的 Symfony 4 应用程序使用自定义集合 class。以下场景是我要实现的示例:
我有一个 post 集合 class,它具有一些用于过滤和映射数据的实用程序。
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;
});
}
}
还有用户 class,它是一个 Doctrine 实体。
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;
}
}
然后在助手或控制器中有一个方法将访问用户的数据,如下所示:
public function showPublishedPostTitlesForUser(User $user)
{
$publishedPostTitles = $user->getPosts()
->filterPublishedAfterDate(new DateTime())
->mapTitles();
// Render the titles...
}
以上内容在手动创建新对象时有效,例如在单元测试中。但是从存储库加载实体时它不会工作,因为那样集合将充满 Doctrine\ORM\PersistentCollection
个对象。
我现在的问题是,如何配置我的应用程序以便在加载实体时可以使用自定义持久集合(例如 PersistentPostCollection
)?
我确实找到了这个页面 https://www.doctrine-project.org/projects/doctrine-collections/en/latest/lazy-collections.html#lazy-collections,但是我找不到如何将它集成到 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.
您找到的是 Doctrine Collections 包的文档。
Doctrine ORM 正在使用 Doctrine Collections 包,但它们是彼此独立的包。因此,您可以创建自定义集合这一事实并不意味着 ORM 会尊重它。
现在用 Doctrine ORM 做不到你想做的事。
feature of custom collections is scheduled for next major Doctrine ORM version.
您的自定义集合必须充当装饰器并检查您的 getPosts()
方法(如果它是您的自定义集合)。
PostArrayCollection
看起来像这样
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
}
User
class 看起来像这样。
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;
}
}
优秀的解决方案。就我而言,这不是一个完整的解决方案,因为我使用的是 DDD,并且我想让域与 Doctrine 无关。我正在使用自定义集合,但我不知道如何将 Doctrine Collection 映射到我的自定义集合