feat: mailing to filtered teamer list

addresses #869dv9bur
This commit is contained in:
Björn Fromme
2026-08-11 16:25:53 +02:00
parent 48cd2d6b67
commit 6511f821ac
18 changed files with 1223 additions and 7 deletions
+47 -3
View File
@@ -5,9 +5,11 @@ namespace App\Repository;
use App\Entity\License;
use App\Entity\Teamer;
use App\Model\TeamerFilterDto;
use App\Model\TeamerMailingRecipient;
use App\Repository\Traits\QueryHelperTrait;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
/**
@@ -30,6 +32,50 @@ class TeamerRepository extends ServiceEntityRepository
}
public function getListQuery(TeamerFilterDto $filterDto): Query
{
return $this
->createListQueryBuilder($filterDto)
->addOrderBy('teamer.viewed', 'asc')
->addOrderBy('teamer.lastName', 'asc')
->getQuery()
;
}
/**
* The unpaginated list behind the filter, projected down to what a mailing needs.
*
* Hydrating entities here is a trap: the list query fetch-joins collections that would
* multiply every teamer into several rows, and a teamer drags in a user account that
* Doctrine cannot proxy - it is the inverse side of the relation - plus an EAGER photo,
* which together cost a round trip per row. Selecting the handful of fields the mailing
* reads avoids all of it and keeps the query at exactly one.
*
* @return TeamerMailingRecipient[]
*/
public function getMailingRecipients(TeamerFilterDto $filterDto): array
{
$rows = $this
->createListQueryBuilder($filterDto)
->distinct()
->select(
'teamer.id AS id',
'teamer.firstName AS firstName',
'teamer.lastName AS lastName',
'teamer.communication.email AS email',
'teamer.deletedAt AS deletedAt',
'user.disabledAt AS disabledAt'
)
// teamer.viewed says nothing about a mailing and a DISTINCT select cannot order
// by a field it does not carry, so this list sorts by name alone
->addOrderBy('teamer.lastName', 'asc')
->getQuery()
->getArrayResult()
;
return array_map(TeamerMailingRecipient::fromRow(...), $rows);
}
private function createListQueryBuilder(TeamerFilterDto $filterDto): QueryBuilder
{
$qb = $this->createQueryBuilder('teamer');
@@ -40,8 +86,6 @@ class TeamerRepository extends ServiceEntityRepository
->leftJoin('teamer.licenses', 'license')
->leftJoin('teamer.feedback', 'feedback')
->leftJoin('teamer.user', 'user')
->addOrderBy('teamer.viewed', 'asc')
->addOrderBy('teamer.lastName', 'asc')
;
if (null !== $filterDto->getName()) {
@@ -120,7 +164,7 @@ class TeamerRepository extends ServiceEntityRepository
;
}
return $qb->getQuery();
return $qb;
}
public function getAutocompletionData(string $search): array