Skip to content

NEW Operator for DTO construction supporting entities aswell as scalar expressions #9406

@AndreRudolph

Description

@AndreRudolph
Q A
New Feature yes
RFC yes/no
BC Break no

Let's assume I have a scenario where I have a collection and a link entity. A Collection can have multiple links assigned to.

Collection class (minimized example):

class Collection
{
    #[Id]
    #[Column(type: "integer", nullable: false)]
    #[GeneratedValue('AUTO')]
    private ?int $id = null;

    #[OneToMany(mappedBy: 'collection', targetEntity: Link::class, cascade: ['all'])]
    private \Doctrine\Common\Collections\Collection $links;
 
    // ...
}

and Link class (minimized example):

class Link
{
    #[Id]
    #[Column(type: "integer", nullable: false)]
    #[GeneratedValue('AUTO')]
    private ?int $id = null;

    #[ManyToOne(targetEntity: Collection::class, inversedBy: 'links')]
    private Collection $collection;

}

Let's say I want to retrieve a list of collections with a count of assigned links for each collection. Since I don't want to have an array and instead just one object per row I checked the doctrines documentation and it is possible to create objects from classes that don't need to be an entity itself:

$this->getQueryBuilder()
            ->addSelect('new App\Entity\ViewModels\CollectionLinkCountViewModel(c.id, c.name, c.description, COUNT(links))')
            ->from(Collection::class, 'c')
            ->innerJoin('c.links', 'links')
            ->groupBy('c')
            ->getQuery()
            ->getResult();

According to https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/dql-doctrine-query-language.html#new-operator-syntax it is only possible to pass scalar expressions to a NEW constructor in DQL. I am wondering what the reason was to only allow scalar expressions and not an entity itself?

If I want to have all the informations of the collection entity (name, description, etc.) would have to create possibly a very large and unmaintainable constructor and query string by listing every single column (property) field of c. Wouldn't it be nice to just pass "c" as the collection entity directly into the CollectionLinkCountViewModel constructor? Like this:

$this->getQueryBuilder()
            ->addSelect('new App\Entity\ViewModels\CollectionLinkCountViewModel(c, COUNT(links))')
            ->from(Collection::class, 'c')
            ->innerJoin('c.links', 'links')
            ->groupBy('c')
            ->getQuery()
            ->getResult();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions