chill-bundles/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProvider.php
Julien Fastré d2323e91ca
new cs rule: single_line_empty_body
Rule is added to the last version of php-cs-fixer
2023-09-12 15:58:59 +02:00

193 lines
7.8 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\CalendarBundle\Service\GenericDoc\Providers;
use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Entity\CalendarDoc;
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\MappingException;
use Service\GenericDoc\Providers\AccompanyingPeriodCalendarGenericDocProviderTest;
use Symfony\Component\Security\Core\Security;
/**
* @see AccompanyingPeriodCalendarGenericDocProviderTest
*/
final readonly class AccompanyingPeriodCalendarGenericDocProvider implements GenericDocForAccompanyingPeriodProviderInterface, GenericDocForPersonProviderInterface
{
public const KEY = 'accompanying_period_calendar_document';
public function __construct(
private Security $security,
private EntityManagerInterface $em
) {}
/**
* @throws MappingException
*/
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
{
$classMetadata = $this->em->getClassMetadata(CalendarDoc::class);
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
$calendarMetadata = $this->em->getClassMetadata(Calendar::class);
$query = new FetchQuery(
self::KEY,
sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')),
'cd.'.$storedObjectMetadata->getColumnName('createdAt'),
$classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd'
);
$query->addJoinClause(
sprintf(
'JOIN %s doc_store ON doc_store.%s = cd.%s',
$storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(),
$storedObjectMetadata->getColumnName('id'),
$classMetadata->getSingleAssociationJoinColumnName('storedObject')
)
);
$query->addJoinClause(
sprintf(
'JOIN %s calendar ON calendar.%s = cd.%s',
$calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(),
$calendarMetadata->getColumnName('id'),
$classMetadata->getSingleAssociationJoinColumnName('calendar')
)
);
$query->addWhereClause(
sprintf(
'calendar.%s = ?',
$calendarMetadata->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]['name']
),
[$accompanyingPeriod->getId()],
[Types::INTEGER]
);
return $query;
}
public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool
{
return $this->security->isGranted(CalendarVoter::SEE, $accompanyingPeriod);
}
public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
{
$classMetadata = $this->em->getClassMetadata(CalendarDoc::class);
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
$calendarMetadata = $this->em->getClassMetadata(Calendar::class);
$query = new FetchQuery(
self::KEY,
sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')),
'cd.'.$storedObjectMetadata->getColumnName('createdAt'),
$classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd'
);
$query->addJoinClause(
sprintf(
'JOIN %s doc_store ON doc_store.%s = cd.%s',
$storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(),
$storedObjectMetadata->getColumnName('id'),
$classMetadata->getSingleAssociationJoinColumnName('storedObject')
)
);
$query->addJoinClause(
sprintf(
'JOIN %s calendar ON calendar.%s = cd.%s',
$calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(),
$calendarMetadata->getColumnName('id'),
$classMetadata->getSingleAssociationJoinColumnName('calendar')
)
);
// get the documents associated with accompanying periods in which person participates
$or = [];
$orParams = [];
$orTypes = [];
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
if (!$this->security->isGranted(CalendarVoter::SEE, $participation->getAccompanyingPeriod())) {
continue;
}
$or[] = sprintf(
'(calendar.%s = ? AND cd.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))',
$calendarMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'),
$storedObjectMetadata->getColumnName('createdAt')
);
$orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(),
DateTimeImmutable::createFromInterface($participation->getStartDate()),
null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())];
$orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE];
}
if ([] === $or) {
$query->addWhereClause('TRUE = FALSE');
return $query;
}
$query->addWhereClause(implode(" OR ", $or), $orParams, $orTypes);
return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content);
}
public function isAllowedForPerson(Person $person): bool
{
// check that the person is allowed to see an accompanying period. If yes, the
// ACL on each accompanying period will be checked when the query is build
return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person);
}
private function addWhereClausesToQuery(FetchQuery $query, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?string $content): FetchQuery
{
$storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class);
if (null !== $startDate) {
$query->addWhereClause(
sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')),
[$startDate],
[Types::DATE_IMMUTABLE]
);
}
if (null !== $endDate) {
$query->addWhereClause(
sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')),
[$endDate],
[Types::DATE_IMMUTABLE]
);
}
if (null !== $content) {
$query->addWhereClause(
sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')),
['%' . $content . '%'],
[Types::STRING]
);
}
return $query;
}
}