Merge branch 'person-change-center-history' into '111_exports_suite'

Track the change of person's centers

See merge request Chill-Projet/chill-bundles!454
This commit is contained in:
Julien Fastré 2022-09-28 13:52:55 +00:00
commit b777e9c819
25 changed files with 1030 additions and 69 deletions

View File

@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -83,6 +85,10 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('activity');
$qb
@ -90,6 +96,18 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
->select('AVG(activity.durationTime) as export_avg_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
return $qb;
}

View File

@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -84,6 +86,10 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('activity');
$qb
@ -92,6 +98,18 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
->andWhere($qb->expr()->isNotNull('activity.travelTime'))
;
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
return $qb;
}

View File

@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -84,11 +86,25 @@ class CountActivity implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'acp');
}
$qb = $this->repository
->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp');
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb->select('COUNT(DISTINCT activity.id) as export_count_activity');

View File

@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -84,15 +86,29 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'acp');
}
$qb = $this->repository
->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp');
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
return $qb;
}

View File

@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -84,15 +86,29 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'acp');
}
$qb = $this->repository
->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp');
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
return $qb;
}

View File

@ -84,16 +84,25 @@ class CountActivity implements ExportInterface, GroupedExportInterface
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->activityRepository->createQueryBuilder('activity');
if (!in_array('person', $qb->getAllAliases(), true)) {
$qb->join('activity.person', 'person');
}
$qb = $this->activityRepository
->createQueryBuilder('activity')
->join('activity.person', 'person')
->join('person.centerHistory', 'centerHistory')
;
$qb->select('COUNT(activity.id) as export_count_activity');
$qb
->where($qb->expr()->in('person.center', ':centers'))
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull('centerHistory.endDate'),
$qb->expr()->gt('centerHistory.endDate', 'activity.date')
)
)
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
return $qb;

View File

@ -119,11 +119,24 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
$select = 'SUM(activity.durationTime) AS export_stat_activity';
}
return $qb->select($select)
$qb->select($select)
->join('activity.person', 'person')
->join('actperson.center', 'actcenter')
->where($qb->expr()->in('actcenter', ':centers'))
->setParameter(':centers', $centers);
->join('person.centerHistory', 'centerHistory');
$qb
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull('centerHistory.endDate'),
$qb->expr()->gt('centerHistory.endDate', 'activity.date')
)
)
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
return $qb;
}
public function requiredRole(): string

View File

@ -27,6 +27,8 @@ use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
use Chill\PersonBundle\Entity\Person\PersonCenterCurrent;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Entity\Person\PersonCurrentAddress;
use Chill\PersonBundle\Entity\Person\PersonResource;
use Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequential;
@ -180,9 +182,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* The person's center.
*
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center")
* @deprecated
*/
private ?Center $center = null;
/**
* @ORM\OneToMany(targetEntity=PersonCenterHistory::class, mappedBy="person")
* @var Collection|PersonCenterHistory[]
*/
private Collection $centerHistory;
/**
* @ORM\OneToOne(targetEntity=PersonCenterCurrent::class, mappedBy="person")
*/
private ?PersonCenterCurrent $centerCurrent = null;
/**
* Array where customfield's data are stored.
*
@ -523,6 +537,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
$this->budgetResources = new ArrayCollection();
$this->budgetCharges = new ArrayCollection();
$this->resources = new ArrayCollection();
$this->centerHistory = new ArrayCollection();
}
/**
@ -897,7 +912,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
public function getCenter(): ?Center
{
return $this->center;
return null === $this->centerCurrent ? null : $this->centerCurrent->getCenter();
}
public function getCFData(): ?array
@ -1510,17 +1525,60 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* Associate the center with the person. The association start on 'now'.
*
* @param Center $center
* @return $this
*/
public function setCenter(Center $center): self
{
$this->center = $center;
$modification = new DateTimeImmutable('now');
foreach ($this->centerHistory as $centerHistory) {
if (null === $centerHistory->getEndDate()) {
$centerHistory->setEndDate($modification);
}
}
$this->centerHistory[] = $new = new PersonCenterHistory($this, $center, $modification);
$this->centerCurrent = new PersonCenterCurrent($new);
return $this;
}
/**
* @return Report
* @return Collection
*/
public function setCFData(?array $cFData)
public function getCenterHistory(): Collection
{
return $this->centerHistory;
}
/**
* @param Collection $centerHistory
* @return Person
*/
public function setCenterHistory(Collection $centerHistory): Person
{
$this->centerHistory = $centerHistory;
return $this;
}
/**
* @return PersonCenterCurrent|null
*/
public function getCenterCurrent(): ?PersonCenterCurrent
{
return $this->centerCurrent;
}
/**
* @return Person
*/
public function setCFData(?array $cFData): self
{
$this->cFData = $cFData;

View File

@ -0,0 +1,112 @@
<?php
namespace Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\Person;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* Associate a Person with the current center.
*
* The process of selecting the current center is done on database side,
* using a SQL view.
*
* @ORM\Entity(readOnly=true)
* @ORM\Table(name="view_chill_person_person_center_history_current")
* @psalm-internal Chill\PersonBundle\Entity
*/
class PersonCenterCurrent
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="centerCurrent")
*/
private Person $person;
/**
* @ORM\ManyToOne(targetEntity=Center::class)
*/
private Center $center;
/**
* @ORM\Column(type="date_immutable", nullable=false)
*/
private \DateTimeImmutable $startDate;
/**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
*/
private ?\DateTimeImmutable $endDate = null;
/**
* Populate the properties person, center, start and end date from history.
*
* The creator and updatedby are not filled.
*
* @internal Should not be instantied, unless inside Person entity
* @param PersonCenterHistory $history
*/
public function __construct(PersonCenterHistory $history)
{
$this->person = $history->getPerson();
$this->center = $history->getCenter();
$this->startDate = $history->getStartDate();
$this->endDate = $history->getEndDate();
$this->id = $history->getId();
}
/**
* The id will be the same as the current @link{PersonCenterHistory::class}
*
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return Person
*/
public function getPerson(): Person
{
return $this->person;
}
/**
* @return Center
*/
public function getCenter(): Center
{
return $this->center;
}
/**
* @return \DateTimeImmutable
*/
public function getStartDate(): \DateTimeImmutable
{
return $this->startDate;
}
/**
* @return \DateTimeImmutable|null
*/
public function getEndDate(): ?\DateTimeImmutable
{
return $this->endDate;
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\Mapping as ORM;
/**
* Associate a Person with a Center. The association may change on date intervals
*
* @ORM\Entity
* @ORM\Table(name="chill_person_person_center_history")
*/
class PersonCenterHistory implements TrackCreationInterface, TrackUpdateInterface
{
use TrackCreationTrait;
use TrackUpdateTrait;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="centerHistory")
*/
private ?Person $person = null;
/**
* @ORM\ManyToOne(targetEntity=Center::class)
*/
private ?Center $center = null;
/**
* @ORM\Column(type="date_immutable", nullable=false)
*/
private ?\DateTimeImmutable $startDate = null;
/**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
*/
private ?\DateTimeImmutable $endDate = null;
/**
* @param Person|null $person
* @param Center|null $center
* @param \DateTimeImmutable|null $startDate
*/
public function __construct(?Person $person = null, ?Center $center = null, ?\DateTimeImmutable $startDate = null)
{
$this->person = $person;
$this->center = $center;
$this->startDate = $startDate;
}
/**
* @return int|null
*/
public function getId(): ?int
{
return $this->id;
}
/**
* @return Person|null
*/
public function getPerson(): ?Person
{
return $this->person;
}
/**
* @param Person|null $person
*/
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
/**
* @return Center|null
*/
public function getCenter(): ?Center
{
return $this->center;
}
/**
* @param Center|null $center
*/
public function setCenter(?Center $center): self
{
$this->center = $center;
return $this;
}
/**
* @return \DateTimeImmutable|null
*/
public function getStartDate(): ?\DateTimeImmutable
{
return $this->startDate;
}
/**
* @param \DateTimeImmutable|null $startDate
*/
public function setStartDate(?\DateTimeImmutable $startDate): self
{
$this->startDate = $startDate;
return $this;
}
/**
* @return \DateTimeImmutable|null
*/
public function getEndDate(): ?\DateTimeImmutable
{
return $this->endDate;
}
/**
* @param \DateTimeImmutable|null $endDate
*/
public function setEndDate(?\DateTimeImmutable $endDate): self
{
$this->endDate = $endDate;
return $this;
}
}

View File

@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
@ -90,9 +92,25 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('acp');
$qb->select('COUNT(acp.id) AS export_result');
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb->select('COUNT(DISTINCT acp.id) AS export_result');
return $qb;
}

View File

@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
@ -88,6 +90,10 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('acp');
if (!in_array('acpw', $qb->getAllAliases(), true)) {
@ -98,6 +104,18 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface
$qb->join('acpw.accompanyingPeriodWorkEvaluations', 'workeval');
}
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb->select('COUNT(DISTINCT workeval.id) AS export_result');
return $qb;

View File

@ -15,6 +15,9 @@ use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\HouseholdVoter;
use Doctrine\ORM\EntityManagerInterface;
@ -88,23 +91,29 @@ class CountHousehold implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('acp');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('acppart', $qb->getAllAliases(), true)) {
$qb->join('acp.participations', 'acppart');
}
$qb = $this->repository
->createQueryBuilder('acp')
->join('acp.participations', 'acppart')
// little optimization: we remove joins and make a direct join between participations and household members
->join(HouseholdMember::class, 'member', Query\Expr\Join::WITH, 'IDENTITY(acppart.person) = IDENTITY(member.person)')
->join('member.household', 'household')
;
if (!in_array('partperson', $qb->getAllAliases(), true)) {
$qb->join('acppart.person', 'partperson');
}
if (!in_array('member', $qb->getAllAliases(), true)) {
$qb->join('partperson.householdParticipations', 'member');
}
if (!in_array('household', $qb->getAllAliases(), true)) {
$qb->join('member.household', 'household');
}
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb->select('COUNT(DISTINCT household.id) AS export_result');

View File

@ -14,9 +14,11 @@ namespace Chill\PersonBundle\Export\Export;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use LogicException;
@ -100,9 +102,12 @@ class CountPerson implements ExportInterface, GroupedExportInterface
$qb = $this->personRepository->createQueryBuilder('person');
$qb->select('COUNT(person.id) AS export_result')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'
)
)
->setParameter('authorized_centers', $centers);
return $qb;
}

View File

@ -15,6 +15,7 @@ use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
@ -88,6 +89,10 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('acp');
if (!in_array('acppart', $qb->getAllAliases(), true)) {
@ -98,6 +103,12 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor
$qb->join('acppart.person', 'person');
}
$qb->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'
)
)->setParameter('authorized_centers', $centers);
$qb->select('COUNT(DISTINCT person.id) AS export_result');
return $qb;

View File

@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
@ -90,13 +92,26 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('acp');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('acpw', $qb->getAllAliases(), true)) {
$qb->join('acp.works', 'acpw');
}
$qb = $this->repository->createQueryBuilder('acp')
->join('acp.works', 'acpw');
$qb->select('COUNT(acpw.id) as export_result');
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb->select('COUNT(DISTINCT acpw.id) as export_result');
return $qb;
}

View File

@ -16,6 +16,8 @@ use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use DateTime;
@ -94,15 +96,27 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->repository->createQueryBuilder('acp');
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers)
;
$qb
->select('AVG(
( CASE
WHEN acp.closingDate IS NOT NULL
THEN acp.closingDate
ELSE :force_closingDate
END ) - acp.openingDate
COALESCE(acp.closingDate, :force_closingDate) - acp.openingDate
) AS export_result')
->setParameter('force_closingDate', $data['closingdate']);

View File

@ -0,0 +1,10 @@
<?php
namespace Chill\PersonBundle\Repository\Person;
use Doctrine\Persistence\ObjectRepository;
interface PersonCenterHistoryInterface extends ObjectRepository
{
}

View File

@ -0,0 +1,48 @@
<?php
namespace Chill\PersonBundle\Repository\Person;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
class PersonCenterHistoryRepository implements PersonCenterHistoryInterface
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository($this->getClassName());
}
public function find($id): ?PersonCenterHistory
{
return $this->repository->find($id);
}
/**
* @return array|PersonCenterHistory[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @return array|PersonCenterHistory[]
*/
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?PersonCenterHistory
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return PersonCenterHistory::class;
}
}

View File

@ -16,6 +16,7 @@ use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Search\ParsingException;
use Chill\MainBundle\Search\SearchApiQuery;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTimeInterface;
@ -34,7 +35,7 @@ use function implode;
final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterface
{
private AuthorizationHelper $authorizationHelper;
private AuthorizationHelperInterface $authorizationHelper;
private CountryRepository $countryRepository;
@ -46,7 +47,7 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
Security $security,
EntityManagerInterface $em,
CountryRepository $countryRepository,
AuthorizationHelper $authorizationHelper
AuthorizationHelperInterface $authorizationHelper
) {
$this->security = $security;
$this->em = $em;
@ -310,9 +311,10 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
}
return $query
->setFromClause($query->getFromClause() . ' JOIN view_chill_person_person_center_history_current vcppchc ON vcppchc.person_id = person.id', $query->getFromParams())
->andWhereClause(
strtr(
'person.center_id IN ({{ center_ids }})',
'vcppchc.center_id IN ({{ center_ids }})',
[
'{{ center_ids }}' => implode(
', ',

View File

@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Entity;
use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
@ -191,4 +192,29 @@ final class PersonTest extends \PHPUnit\Framework\TestCase
$this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD);
}
public function testSetCenter()
{
$person = new Person();
$centerA = new Center();
$centerB = new Center();
$this->assertCount(0, $person->getCenterHistory());
$this->assertNull($person->getCenter());
$this->assertNull($person->getCenterCurrent());
$person->setCenter($centerA);
$this->assertCount(1, $person->getCenterHistory());
$this->assertSame($centerA, $person->getCenter());
$this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
$this->assertSame($centerA, $person->getCenterCurrent()->getCenter());
$person->setCenter($centerB);
$this->assertCount(2, $person->getCenterHistory());
$this->assertSame($centerB, $person->getCenter());
$this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
$this->assertSame($centerB, $person->getCenterCurrent()->getCenter());
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace Chill\PersonBundle\Tests\Repository;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\PersonACLAwareRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Security\Core\Security;
class PersonACLAwareRepositoryTest extends KernelTestCase
{
use ProphecyTrait;
private EntityManagerInterface $entityManager;
private CountryRepository $countryRepository;
private CenterRepositoryInterface $centerRepository;
protected function setUp(): void
{
self::bootKernel();
$this->entityManager = self::$container->get(EntityManagerInterface::class);
$this->countryRepository = self::$container->get(CountryRepository::class);
$this->centerRepository = self::$container->get(CenterRepositoryInterface::class);
}
public function testCountByCriteria()
{
$user = new User();
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(PersonVoter::SEE))
->willReturn($this->centerRepository->findAll());
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$repository = new PersonACLAwareRepository($security->reveal(), $this->entityManager, $this->countryRepository,
$authorizationHelper->reveal());
$number = $repository->countBySearchCriteria('diallo');
$this->assertGreaterThan(0, $number);
}
public function testFindByCriteria()
{
$user = new User();
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(PersonVoter::SEE))
->willReturn($this->centerRepository->findAll());
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$repository = new PersonACLAwareRepository($security->reveal(), $this->entityManager, $this->countryRepository,
$authorizationHelper->reveal());
$results = $repository->findBySearchCriteria(0, 5, false, 'diallo');
$this->assertGreaterThan(0, count($results));
$this->assertContainsOnlyInstancesOf(Person::class, $results);
foreach ($results as $person) {
$this->assertStringContainsString('diallo', strtolower($person->getFirstName() . ' ' . $person->getLastName()));
}
}
}

View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Person;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20220926154347 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add a center history on person';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE chill_person_person_center_history_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_person_person_center_history (
id INT NOT NULL, person_id INT DEFAULT NULL, center_id INT DEFAULT NULL,
startDate DATE NOT NULL, endDate DATE DEFAULT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL,
updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_CACA67FA217BBB47 ON chill_person_person_center_history (person_id)');
$this->addSql('CREATE INDEX IDX_CACA67FA5932F377 ON chill_person_person_center_history (center_id)');
$this->addSql('CREATE INDEX IDX_CACA67FA3174800F ON chill_person_person_center_history (createdBy_id)');
$this->addSql('CREATE INDEX IDX_CACA67FA65FF1AEC ON chill_person_person_center_history (updatedBy_id)');
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.startDate IS \'(DC2Type:date_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.endDate IS \'(DC2Type:date_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.createdAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.updatedAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA5932F377 FOREIGN KEY (center_id) REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
// check consistency of history on database side
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CHECK (startdate <= enddate)');
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT ' .
'chill_internal_person_person_center_history_not_overlaps EXCLUDE USING GIST(
-- extension btree_gist required to include comparaison with integer
person_id WITH =,
daterange(startdate, enddate, \'[)\') WITH &&
)
INITIALLY DEFERRED');
// create index on search by person and date
$this->addSql('CREATE INDEX chill_internal_person_person_center_history_by_date ON chill_person_person_center_history (person_id DESC, startdate DESC, enddate DESC NULLS FIRST)');
// create a view to get the current center on a person
$this->addSql(
'CREATE VIEW view_chill_person_person_center_history_current AS
SELECT id, person_id, center_id, startDate, endDate, createdAt, updatedAt, createdBy_id, updatedBy_id
FROM chill_person_person_center_history WHERE startDate <= NOW() AND (enddate IS NULL OR enddate > NOW())'
);
$this->addSql('INSERT INTO chill_person_person_center_history (id, person_id, center_id, startdate)
SELECT nextval(\'chill_person_person_center_history_id_seq\'), id, center_id, COALESCE(createdat, NOW())
FROM chill_person_person WHERE center_id IS NOT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('DROP VIEW view_chill_person_person_center_history_current');
$this->addSql('DROP SEQUENCE chill_person_person_center_history_id_seq CASCADE');
$this->addSql('DROP TABLE chill_person_person_center_history');
}
}

View File

@ -13,6 +13,7 @@ namespace Chill\TaskBundle\Repository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\TaskBundle\Entity\SingleTask;
@ -31,14 +32,14 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
{
private AuthorizationHelperInterface $authorizationHelper;
private CenterResolverDispatcherInterface $centerResolverDispatcher;
private CenterResolverManagerInterface $centerResolverDispatcher;
private EntityManagerInterface $em;
private Security $security;
public function __construct(
CenterResolverDispatcherInterface $centerResolverDispatcher,
CenterResolverManagerInterface $centerResolverDispatcher,
EntityManagerInterface $em,
Security $security,
AuthorizationHelperInterface $authorizationHelper
@ -304,14 +305,18 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
QueryBuilder $qb,
$entity
): QueryBuilder {
$scopes = $this->authorizationHelper->getReachableScopes(
$this->security->getUser(),
TaskVoter::SHOW,
$this->centerResolverDispatcher->resolveCenter($entity)
);
foreach ($this->centerResolverDispatcher->resolveCenters($entity) as $center) {
$scopes = $this->authorizationHelper->getReachableScopes(
$this->security->getUser(),
TaskVoter::SHOW,
$center
);
return $qb->andWhere($qb->expr()->in('t.circle', ':scopes'))
->setParameter('scopes', $scopes);
$qb->andWhere($qb->expr()->in('t.circle', ':scopes'))
->setParameter('scopes', $scopes);
}
return $qb;
}
private function addACLGlobal(
@ -329,7 +334,10 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
$qb->leftJoin('t.person', 'person')
->leftJoin('t.course', 'course')
->leftJoin('course.participations', 'participation')
->leftJoin('participation.person', 'person_p');
->leftJoin('participation.person', 'person_p')
->leftJoin('person.centerCurrent', 'center_current_person')
->leftJoin('person_p.centerCurrent', 'center_current_participation')
;
$qb->distinct(true);
$k = 0;
@ -344,8 +352,8 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
$and = $qb->expr()->andX(
$qb->expr()->orX(
$qb->expr()->eq('person.center', ':center_' . $k),
$qb->expr()->eq('person_p.center', ':center_' . $k)
$qb->expr()->eq('center_current_person.center', ':center_' . $k),
$qb->expr()->eq('center_current_participation.center', ':center_' . $k)
),
$qb->expr()->in('t.circle', ':scopes_' . $k)
);

View File

@ -0,0 +1,211 @@
<?php
namespace Chill\TaskBundle\Tests\Repository;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
use Chill\PersonBundle\DataFixtures\Helper\PersonRandomHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\TaskBundle\Entity\SingleTask;
use Chill\TaskBundle\Repository\SingleTaskAclAwareRepository;
use Chill\TaskBundle\Security\Authorization\TaskVoter;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Security\Core\Security;
class SingleTaskACLAwareRepositoryTest extends KernelTestCase
{
private EntityManagerInterface $em;
private UserRepository $userRepository;
private AuthorizationHelperInterface $authorizationHelper;
private CenterRepositoryInterface $centerRepository;
private ScopeRepository $scopeRepository;
private PersonRepository $personRepository;
use PersonRandomHelper;
use ProphecyTrait;
protected function setUp(): void
{
self::bootKernel();
$this->em = self::$container->get(EntityManagerInterface::class);
$this->userRepository = self::$container->get(UserRepository::class);
$this->centerRepository = self::$container->get(CenterRepositoryInterface::class);
$this->scopeRepository = self::$container->get(ScopeRepository::class);
$this->personRepository = self::$container->get(PersonRepository::class);
}
public function testCountByPerson(): void
{
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
$user = new User();
$scopes = $this->scopeRepository->findAll();
$person = $this->getRandomPerson($this->em);
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
->willReturn([$centerA]);
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
->willReturn($scopes);
$repository = new SingleTaskAclAwareRepository(
$centerResolverDispatcher->reveal(),
$this->em,
$security->reveal(),
$authorizationHelper->reveal()
);
$nb = $repository->countByPerson($person, null, []);
$this->assertGreaterThanOrEqual(0, $nb);
}
public function testFindByPerson(): void
{
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
$user = new User();
$scopes = $this->scopeRepository->findAll();
$person = $this->getRandomPerson($this->em);
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
->willReturn([$centerA]);
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
->willReturn($scopes);
$repository = new SingleTaskAclAwareRepository(
$centerResolverDispatcher->reveal(),
$this->em,
$security->reveal(),
$authorizationHelper->reveal()
);
$tasks = $repository->findByPerson($person, null, []);
$this->assertGreaterThanOrEqual(0, count($tasks));
}
public function testFindByAllViewable(): void
{
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
$user = new User();
$scopes = $this->scopeRepository->findAll();
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
->willReturn([$centerA]);
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(TaskVoter::SHOW))
->willReturn([$centerA]);
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
->willReturn($scopes);
$repository = new SingleTaskAclAwareRepository(
$centerResolverDispatcher->reveal(),
$this->em,
$security->reveal(),
$authorizationHelper->reveal()
);
$tasks = $repository->findByAllViewable(null, []);
$this->assertGreaterThanOrEqual(0, count($tasks));
}
public function testCountByAllViewable(): void
{
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
$user = new User();
$scopes = $this->scopeRepository->findAll();
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
->willReturn([$centerA]);
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(TaskVoter::SHOW))
->willReturn([$centerA]);
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
->willReturn($scopes);
$repository = new SingleTaskAclAwareRepository(
$centerResolverDispatcher->reveal(),
$this->em,
$security->reveal(),
$authorizationHelper->reveal()
);
$nb = $repository->countByAllViewable(null, []);
$this->assertGreaterThanOrEqual(0, $nb);
}
public function testFindByCourse(): void
{
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
$user = new User();
$scopes = $this->scopeRepository->findAll();
/** @var Person $person */
$person = $this->em->createQuery(
'SELECT p FROM '.Person::class.' p JOIN p.centerCurrent cc
WHERE SIZE(p.accompanyingPeriodParticipations) > 0
AND cc.center = :center'
)
->setParameter('center', $centerA)
->setMaxResults(1)
->getSingleResult()
;
$period = $person->getAccompanyingPeriodParticipations()->first()->getAccompanyingPeriod();
$security = $this->prophesize(Security::class);
$security->getUser()->willReturn($user);
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
$centerResolverDispatcher->resolveCenters(Argument::type(AccompanyingPeriod::class), Argument::any())
->willReturn([$centerA]);
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::any())
->willReturn($scopes);
$repository = new SingleTaskAclAwareRepository(
$centerResolverDispatcher->reveal(),
$this->em,
$security->reveal(),
$authorizationHelper->reveal()
);
$tasks = $repository->findByCourse($period);
$this->assertGreaterThanOrEqual(0, count($tasks));
}
}