115 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Repository\Household;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Persistence\ObjectRepository;
final class HouseholdRepository implements ObjectRepository
{
private const SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION = <<<'SQL'
WITH participations AS (
SELECT DISTINCT part.accompanyingperiod_id
FROM chill_person_accompanying_period_participation AS part
WHERE person_id = ?),
other_participants AS (
SELECT person_id, startDate, endDate
FROM chill_person_accompanying_period_participation
JOIN participations USING (accompanyingperiod_id)
WHERE person_id != ?
),
households AS (SELECT DISTINCT household.*
FROM chill_person_household_members AS hmembers
JOIN other_participants AS op USING (person_id)
JOIN chill_person_household AS household ON hmembers.household_id = household.id
WHERE daterange(op.startDate, op.endDate) && daterange(hmembers.startDate, hmembers.endDate)
)
SELECT {select} FROM households {limits}
SQL;
private readonly EntityManagerInterface $em;
private readonly EntityRepository $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(Household::class);
$this->em = $entityManager;
}
public function countByAccompanyingPeriodParticipation(Person $person)
{
return $this->buildQueryByAccompanyingPeriodParticipation($person, true);
}
public function find($id)
{
return $this->repository->find($id);
}
public function findAll()
{
return $this->repository->findAll();
}
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findByAccompanyingPeriodParticipation(Person $person, int $limit, int $offset)
{
return $this->buildQueryByAccompanyingPeriodParticipation($person, false, $limit, $offset);
}
public function findOneBy(array $criteria)
{
return $this->findOneBy($criteria);
}
public function getClassName()
{
return Household::class;
}
private function buildQueryByAccompanyingPeriodParticipation(Person $person, bool $isCount = false, int $limit = 50, int $offset = 0)
{
$rsm = new ResultSetMappingBuilder($this->em);
$rsm->addRootEntityFromClassMetadata(Household::class, 'h');
if ($isCount) {
$rsm->addScalarResult('count', 'count');
$sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [
'{select}' => 'COUNT(households.*) AS count',
'{limits}' => '',
]);
} else {
$sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [
'{select}' => $rsm->generateSelectClause(['h' => 'households']),
'{limits}' => "OFFSET {$offset} LIMIT {$limit}",
]);
}
$native = $this->em->createNativeQuery($sql, $rsm);
$native->setParameters([0 => $person->getId(), 1 => $person->getId()]);
if ($isCount) {
return $native->getSingleScalarResult();
}
return $native->getResult();
}
}