Merge remote-tracking branch 'origin/testing' into chill_amli

This commit is contained in:
2022-09-29 10:58:05 +02:00
184 changed files with 5397 additions and 1195 deletions

View File

@@ -11,6 +11,11 @@ and this project adheres to
## Unreleased ## Unreleased
<!-- write down unreleased development here --> <!-- write down unreleased development here -->
* [person][export] Fixed: rename the alias for `accompanying_period` to `acp` in filter associated with person
* [activity][export] Feature: improve label for aliases in "Filter by activity type"
* [activity][export] DX/Feature: use of an `ActivityTypeRepositoryInterface` instead of the old-style EntityRepository
* [person][export] Fixed: some inconsistency with date filter on accompanying courses
* [person][export] Fixed: use left join for related entities in accompanying course aggregators
## Test releases ## Test releases

View File

@@ -11,10 +11,10 @@ AccompanyingPeriod::class,,,acp
,User::class,acp.user,acpuser ,User::class,acp.user,acpuser
AccompanyingPeriodWork::class,,,acpw AccompanyingPeriodWork::class,,,acpw
,AccompanyingPeriodWorkEvaluation::class,acpw.accompanyingPeriodWorkEvaluations,workeval ,AccompanyingPeriodWorkEvaluation::class,acpw.accompanyingPeriodWorkEvaluations,workeval
,Goal::class,acpw.goals,goal
,User::class,acpw.referrers,acpwuser ,User::class,acpw.referrers,acpwuser
,Result::class,acpw.results,acpwresult
,SocialAction::class,acpw.socialAction,acpwsocialaction ,SocialAction::class,acpw.socialAction,acpwsocialaction
,Goal::class,acpw.goals,goal
,Result::class,acpw.results,result
AccompanyingPeriodParticipation::class,,,acppart AccompanyingPeriodParticipation::class,,,acppart
,Person::class,acppart.person,partperson ,Person::class,acppart.person,partperson
AccompanyingPeriodWorkEvaluation::class,,,workeval AccompanyingPeriodWorkEvaluation::class,,,workeval
@@ -23,23 +23,23 @@ Goal::class,,,goal
,Result::class,goal.results,goalresult ,Result::class,goal.results,goalresult
Person::class,,,person Person::class,,,person
,Center::class,person.center,center ,Center::class,person.center,center
,HouseholdMember::class,partperson.householdParticipations,member ,HouseholdMember::class,partperson.householdParticipations,householdmember
,MaritalStatus::class,person.maritalStatus,personmarital ,MaritalStatus::class,person.maritalStatus,personmarital
,VendeePerson::class,,vp
,VendeePersonMineur::class,,vpm
ResidentialAddress::class,,,resaddr ResidentialAddress::class,,,resaddr
,Person::class,resaddr.person,resaddrperson
,Center::class,resaddrperson.center,resaddrcenter
,ThirdParty::class,resaddr.hostThirdParty,tparty ,ThirdParty::class,resaddr.hostThirdParty,tparty
ThirdParty::class,,,tparty ThirdParty::class,,,tparty
,ThirdPartyCategory::class,tparty.categories,tpartycat ,ThirdPartyCategory::class,tparty.categories,tpartycat
HouseholdMember::class,,,member HouseholdMember::class,,,householdmember
,Household::class,member.household,household ,Household::class,householdmember.household,household
,Person::class,member.person,memberperson ,Person::class,householdmember.person,memberperson
,,memberperson.center,membercenter ,,memberperson.center,membercenter
Household::class,,,household Household::class,,,household
,HouseholdComposition::class,household.compositions,composition ,HouseholdComposition::class,household.compositions,composition
Activity::class,,,activity Activity::class,,,activity
,Person::class,activity.person,actperson ,Person::class,activity.person,actperson
,AccompanyingPeriod::class,activity.accompanyingPeriod,actacp ,AccompanyingPeriod::class,activity.accompanyingPeriod,acp
,Person::class,activity_person_having_activity.person,person_person_having_activity ,Person::class,activity_person_having_activity.person,person_person_having_activity
,ActivityReason::class,activity_person_having_activity.reasons,reasons_person_having_activity ,ActivityReason::class,activity_person_having_activity.reasons,reasons_person_having_activity
,ActivityType::class,activity.activityType,acttype ,ActivityType::class,activity.activityType,acttype
@@ -58,11 +58,6 @@ Calendar::class,,,cal
,Location::class,cal.location,calloc ,Location::class,cal.location,calloc
,User::class,cal.user,caluser ,User::class,cal.user,caluser
VendeePerson::class,,,vp VendeePerson::class,,,vp
,Person::class,vp.person,vpperson
,Center::class,vpperson.center,vpcenter
,SituationProfessionelle::class,vp.situationProfessionelle,vpprof ,SituationProfessionelle::class,vp.situationProfessionelle,vpprof
,StatutLogement::class,vp.statutLogement,vplog ,StatutLogement::class,vp.statutLogement,vplog
,TempsDeTravail::class,vp.tempsDeTravail,vptt ,TempsDeTravail::class,vp.tempsDeTravail,vptt
VendeePersonMineur::class,,,vpm
,Person::class,vpm.person,vpmperson
,Center::class,vpmperson.center,vpmcenter
1 Entity Join Attribute Alias
11 User::class acp.user acpuser
12 AccompanyingPeriodWork::class acpw
13 AccompanyingPeriodWorkEvaluation::class acpw.accompanyingPeriodWorkEvaluations workeval
Goal::class acpw.goals goal
14 User::class acpw.referrers acpwuser
Result::class acpw.results acpwresult
15 SocialAction::class acpw.socialAction acpwsocialaction
16 Goal::class acpw.goals goal
17 Result::class acpw.results result
18 AccompanyingPeriodParticipation::class acppart
19 Person::class acppart.person partperson
20 AccompanyingPeriodWorkEvaluation::class workeval
23 Result::class goal.results goalresult
24 Person::class person
25 Center::class person.center center
26 HouseholdMember::class partperson.householdParticipations member householdmember
27 MaritalStatus::class person.maritalStatus personmarital
28 VendeePerson::class vp
29 VendeePersonMineur::class vpm
30 ResidentialAddress::class resaddr
Person::class resaddr.person resaddrperson
Center::class resaddrperson.center resaddrcenter
31 ThirdParty::class resaddr.hostThirdParty tparty
32 ThirdParty::class tparty
33 ThirdPartyCategory::class tparty.categories tpartycat
34 HouseholdMember::class member householdmember
35 Household::class member.household householdmember.household household
36 Person::class member.person householdmember.person memberperson
37 memberperson.center membercenter
38 Household::class household
39 HouseholdComposition::class household.compositions composition
40 Activity::class activity
41 Person::class activity.person actperson
42 AccompanyingPeriod::class activity.accompanyingPeriod actacp acp
43 Person::class activity_person_having_activity.person person_person_having_activity
44 ActivityReason::class activity_person_having_activity.reasons reasons_person_having_activity
45 ActivityType::class activity.activityType acttype
58 Location::class cal.location calloc
59 User::class cal.user caluser
60 VendeePerson::class vp
Person::class vp.person vpperson
Center::class vpperson.center vpcenter
61 SituationProfessionelle::class vp.situationProfessionelle vpprof
62 StatutLogement::class vp.statutLogement vplog
63 TempsDeTravail::class vp.tempsDeTravail vptt
VendeePersonMineur::class vpm
Person::class vpm.person vpmperson
Center::class vpmperson.center vpmcenter

View File

@@ -6,7 +6,7 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt
These are alias conventions : These are alias conventions :
| Entity | Join | Attribute | Alias | | Entity | Join | Attribute | Alias |
| :--- | :--- |:-------------------------------------------|:----------------------------------| |:----------------------------------------|:----------------------------------------|:-------------------------------------------|:----------------------------------|
| AccompanyingPeriod::class | | | acp | | AccompanyingPeriod::class | | | acp |
| | AccompanyingPeriodWork::class | acp.works | acpw | | | AccompanyingPeriodWork::class | acp.works | acpw |
| | AccompanyingPeriodParticipation::class | acp.participations | acppart | | | AccompanyingPeriodParticipation::class | acp.participations | acppart |
@@ -19,10 +19,10 @@ These are alias conventions :
| | User::class | acp.user | acpuser | | | User::class | acp.user | acpuser |
| AccompanyingPeriodWork::class | | | acpw | | AccompanyingPeriodWork::class | | | acpw |
| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval | | | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval |
| | Goal::class | acpw.goals | goal |
| | User::class | acpw.referrers | acpwuser | | | User::class | acpw.referrers | acpwuser |
| | Result::class | acpw.results | acpwresult |
| | SocialAction::class | acpw.socialAction | acpwsocialaction | | | SocialAction::class | acpw.socialAction | acpwsocialaction |
| | Goal::class | acpw.goals | goal |
| | Result::class | acpw.results | result |
| AccompanyingPeriodParticipation::class | | | acppart | | AccompanyingPeriodParticipation::class | | | acppart |
| | Person::class | acppart.person | partperson | | | Person::class | acppart.person | partperson |
| AccompanyingPeriodWorkEvaluation::class | | | workeval | | AccompanyingPeriodWorkEvaluation::class | | | workeval |
@@ -31,23 +31,23 @@ These are alias conventions :
| | Result::class | goal.results | goalresult | | | Result::class | goal.results | goalresult |
| Person::class | | | person | | Person::class | | | person |
| | Center::class | person.center | center | | | Center::class | person.center | center |
| | HouseholdMember::class | partperson.householdParticipations | member | | | HouseholdMember::class | partperson.householdParticipations | householdmember |
| | MaritalStatus::class | person.maritalStatus | personmarital | | | MaritalStatus::class | person.maritalStatus | personmarital |
| | VendeePerson::class | | vp |
| | VendeePersonMineur::class | | vpm |
| ResidentialAddress::class | | | resaddr | | ResidentialAddress::class | | | resaddr |
| | Person::class | resaddr.person | resaddrperson |
| | Center::class | resaddrperson.center | resaddrcenter |
| | ThirdParty::class | resaddr.hostThirdParty | tparty | | | ThirdParty::class | resaddr.hostThirdParty | tparty |
| ThirdParty::class | | | tparty | | ThirdParty::class | | | tparty |
| | ThirdPartyCategory::class | tparty.categories | tpartycat | | | ThirdPartyCategory::class | tparty.categories | tpartycat |
| HouseholdMember::class | | | member | | HouseholdMember::class | | | householdmember |
| | Household::class | member.household | household | | | Household::class | householdmember.household | household |
| | Person::class | member.person | memberperson | | | Person::class | householdmember.person | memberperson |
| | | memberperson.center | membercenter | | | | memberperson.center | membercenter |
| Household::class | | | household | | Household::class | | | household |
| | HouseholdComposition::class | household.compositions | composition | | | HouseholdComposition::class | household.compositions | composition |
| Activity::class | | | activity | | Activity::class | | | activity |
| | Person::class | activity.person | actperson | | | Person::class | activity.person | actperson |
| | AccompanyingPeriod::class | activity.accompanyingPeriod | actacp | | | AccompanyingPeriod::class | activity.accompanyingPeriod | acp |
| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity | | | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity |
| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity | | | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity |
| | ActivityType::class | activity.activityType | acttype | | | ActivityType::class | activity.activityType | acttype |
@@ -66,11 +66,6 @@ These are alias conventions :
| | Location::class | cal.location | calloc | | | Location::class | cal.location | calloc |
| | User::class | cal.user | caluser | | | User::class | cal.user | caluser |
| VendeePerson::class | | | vp | | VendeePerson::class | | | vp |
| | Person::class | vp.person | vpperson |
| | Center::class | vpperson.center | vpcenter |
| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof | | | SituationProfessionelle::class | vp.situationProfessionelle | vpprof |
| | StatutLogement::class | vp.statutLogement | vplog | | | StatutLogement::class | vp.statutLogement | vplog |
| | TempsDeTravail::class | vp.tempsDeTravail | vptt | | | TempsDeTravail::class | vp.tempsDeTravail | vptt |
| VendeePersonMineur::class | | | vpm |
| | Person::class | vpm.person | vpmperson |
| | Center::class | vpmperson.center | vpmcenter |

View File

@@ -17,7 +17,7 @@ use Chill\ActivityBundle\Form\ActivityType;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository; use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Repository\LocationRepository; use Chill\MainBundle\Repository\LocationRepository;
@@ -56,7 +56,7 @@ final class ActivityController extends AbstractController
private ActivityTypeCategoryRepository $activityTypeCategoryRepository; private ActivityTypeCategoryRepository $activityTypeCategoryRepository;
private ActivityTypeRepository $activityTypeRepository; private ActivityTypeRepositoryInterface $activityTypeRepository;
private CenterResolverManagerInterface $centerResolver; private CenterResolverManagerInterface $centerResolver;
@@ -78,7 +78,7 @@ final class ActivityController extends AbstractController
public function __construct( public function __construct(
ActivityACLAwareRepositoryInterface $activityACLAwareRepository, ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
ActivityTypeRepository $activityTypeRepository, ActivityTypeRepositoryInterface $activityTypeRepository,
ActivityTypeCategoryRepository $activityTypeCategoryRepository, ActivityTypeCategoryRepository $activityTypeCategoryRepository,
PersonRepository $personRepository, PersonRepository $personRepository,
ThirdPartyRepository $thirdPartyRepository, ThirdPartyRepository $thirdPartyRepository,
@@ -91,7 +91,6 @@ final class ActivityController extends AbstractController
SerializerInterface $serializer, SerializerInterface $serializer,
UserRepositoryInterface $userRepository, UserRepositoryInterface $userRepository,
CenterResolverManagerInterface $centerResolver CenterResolverManagerInterface $centerResolver
) { ) {
$this->activityACLAwareRepository = $activityACLAwareRepository; $this->activityACLAwareRepository = $activityACLAwareRepository;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
@@ -107,7 +106,6 @@ final class ActivityController extends AbstractController
$this->serializer = $serializer; $this->serializer = $serializer;
$this->userRepository = $userRepository; $this->userRepository = $userRepository;
$this->centerResolver = $centerResolver; $this->centerResolver = $centerResolver;
} }
/** /**

View File

@@ -516,6 +516,11 @@ class ActivityType
return $this->userVisible; return $this->userVisible;
} }
public function hasCategory(): bool
{
return null !== $this->getCategory();
}
/** /**
* Is active * Is active
* return true if the type is active. * return true if the type is active.

View File

@@ -41,18 +41,11 @@ class BySocialActionAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('actsocialaction', $qb->getAllAliases(), true)) { if (!in_array('actsocialaction', $qb->getAllAliases(), true)) {
$qb->join('activity.socialActions', 'actsocialaction'); $qb->leftJoin('activity.socialActions', 'actsocialaction');
} }
$qb->addSelect('actsocialaction.id AS socialaction_aggregator'); $qb->addSelect('actsocialaction.id AS socialaction_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialaction_aggregator'); $qb->addGroupBy('socialaction_aggregator');
} else {
$qb->groupBy('socialaction_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class BySocialActionAggregator implements AggregatorInterface
return 'Social action'; return 'Social action';
} }
if (null === $value) {
return '';
}
$sa = $this->actionRepository->find($value); $sa = $this->actionRepository->find($value);
return $this->actionRender->renderString($sa, []); return $this->actionRender->renderString($sa, []);

View File

@@ -41,18 +41,11 @@ class BySocialIssueAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('actsocialissue', $qb->getAllAliases(), true)) { if (!in_array('actsocialissue', $qb->getAllAliases(), true)) {
$qb->join('activity.socialIssues', 'actsocialissue'); $qb->leftJoin('activity.socialIssues', 'actsocialissue');
} }
$qb->addSelect('actsocialissue.id AS socialissue_aggregator'); $qb->addSelect('actsocialissue.id AS socialissue_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialissue_aggregator'); $qb->addGroupBy('socialissue_aggregator');
} else {
$qb->groupBy('socialissue_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class BySocialIssueAggregator implements AggregatorInterface
return 'Social issues'; return 'Social issues';
} }
if (null === $value) {
return '';
}
$i = $this->issueRepository->find($value); $i = $this->issueRepository->find($value);
return $this->issueRender->renderString($i, []); return $this->issueRender->renderString($i, []);

View File

@@ -41,18 +41,11 @@ class ByThirdpartyAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acttparty', $qb->getAllAliases(), true)) { if (!in_array('acttparty', $qb->getAllAliases(), true)) {
$qb->join('activity.thirdParties', 'acttparty'); $qb->leftJoin('activity.thirdParties', 'acttparty');
} }
$qb->addSelect('acttparty.id AS thirdparty_aggregator'); $qb->addSelect('acttparty.id AS thirdparty_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('thirdparty_aggregator'); $qb->addGroupBy('thirdparty_aggregator');
} else {
$qb->groupBy('thirdparty_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class ByThirdpartyAggregator implements AggregatorInterface
return 'Accepted thirdparty'; return 'Accepted thirdparty';
} }
if (null === $value) {
return '';
}
$tp = $this->thirdPartyRepository->find($value); $tp = $this->thirdPartyRepository->find($value);
return $this->thirdPartyRender->renderString($tp, []); return $this->thirdPartyRender->renderString($tp, []);

View File

@@ -41,18 +41,11 @@ class ByUserAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('actusers', $qb->getAllAliases(), true)) { if (!in_array('actusers', $qb->getAllAliases(), true)) {
$qb->join('activity.users', 'actusers'); $qb->leftJoin('activity.users', 'actusers');
} }
$qb->addSelect('actusers.id AS users_aggregator'); $qb->addSelect('actusers.id AS users_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('users_aggregator'); $qb->addGroupBy('users_aggregator');
} else {
$qb->groupBy('users_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class ByUserAggregator implements AggregatorInterface
return 'Accepted users'; return 'Accepted users';
} }
if (null === $value) {
return '';
}
$u = $this->userRepository->find($value); $u = $this->userRepository->find($value);
return $this->userRender->renderString($u, []); return $this->userRender->renderString($u, []);

View File

@@ -49,18 +49,15 @@ class DateAggregator implements AggregatorInterface
switch ($data['frequency']) { switch ($data['frequency']) {
case 'month': case 'month':
$fmt = 'MM'; $fmt = 'YYYY-MM';
break; break;
case 'week': case 'week':
$fmt = 'IW'; $fmt = 'YYYY-IW';
break; break;
case 'year': case 'year':
$fmt = 'YYYY'; $order = 'DESC'; $fmt = 'YYYY'; $order = 'DESC';
break; // order DESC does not works ! break; // order DESC does not works !
default: default:
@@ -68,22 +65,8 @@ break; // order DESC does not works !
} }
$qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt)); $qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt));
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('date_aggregator'); $qb->addGroupBy('date_aggregator');
} else {
$qb->groupBy('date_aggregator');
}
$orderBy = $qb->getDQLPart('orderBy');
if (!empty($orderBy)) {
$qb->addOrderBy('date_aggregator', $order); $qb->addOrderBy('date_aggregator', $order);
} else {
$qb->orderBy('date_aggregator', $order);
}
} }
public function applyOn(): string public function applyOn(): string
@@ -109,15 +92,12 @@ break; // order DESC does not works !
return 'by ' . $data['frequency']; return 'by ' . $data['frequency'];
} }
if (null === $value) {
return '';
}
switch ($data['frequency']) { switch ($data['frequency']) {
case 'month': case 'month':
$month = DateTime::createFromFormat('!m', $value);
return sprintf(
'%02d (%s)',
$value,
$month->format('M')
);
case 'week': case 'week':
//return $this->translator->trans('for week') .' '. $value ; //return $this->translator->trans('for week') .' '. $value ;

View File

@@ -41,18 +41,11 @@ class LocationTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('actloc', $qb->getAllAliases(), true)) { if (!in_array('actloc', $qb->getAllAliases(), true)) {
$qb->join('activity.location', 'actloc'); $qb->leftJoin('activity.location', 'actloc');
} }
$qb->addSelect('IDENTITY(actloc.locationType) AS locationtype_aggregator'); $qb->addSelect('IDENTITY(actloc.locationType) AS locationtype_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('locationtype_aggregator'); $qb->addGroupBy('locationtype_aggregator');
} else {
$qb->groupBy('locationtype_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class LocationTypeAggregator implements AggregatorInterface
return 'Accepted locationtype'; return 'Accepted locationtype';
} }
if (null === $value) {
return '';
}
$lt = $this->locationTypeRepository->find($value); $lt = $this->locationTypeRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -41,18 +41,11 @@ class UserScopeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('actuser', $qb->getAllAliases(), true)) { if (!in_array('actuser', $qb->getAllAliases(), true)) {
$qb->join('activity.user', 'actuser'); $qb->leftJoin('activity.user', 'actuser');
} }
$qb->addSelect('IDENTITY(actuser.mainScope) AS userscope_aggregator'); $qb->addSelect('IDENTITY(actuser.mainScope) AS userscope_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('userscope_aggregator'); $qb->addGroupBy('userscope_aggregator');
} else {
$qb->groupBy('userscope_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +65,10 @@ class UserScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value) {
return '';
}
$s = $this->scopeRepository->find($value); $s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Closure; use Closure;
@@ -25,12 +25,12 @@ class ActivityTypeAggregator implements AggregatorInterface
{ {
public const KEY = 'activity_type_aggregator'; public const KEY = 'activity_type_aggregator';
protected ActivityTypeRepository $activityTypeRepository; protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper; protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct( public function __construct(
ActivityTypeRepository $activityTypeRepository, ActivityTypeRepositoryInterface $activityTypeRepository,
TranslatableStringHelperInterface $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
@@ -49,14 +49,7 @@ class ActivityTypeAggregator implements AggregatorInterface
} }
$qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY));
$groupby = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy(self::KEY); $qb->addGroupBy(self::KEY);
} else {
$qb->groupBy(self::KEY);
}
} }
public function applyOn(): string public function applyOn(): string
@@ -79,6 +72,10 @@ class ActivityTypeAggregator implements AggregatorInterface
return 'Activity type'; return 'Activity type';
} }
if (null === $value) {
return '';
}
$t = $this->activityTypeRepository->find($value); $t = $this->activityTypeRepository->find($value);
return $this->translatableStringHelper->localize($t->getName()); return $this->translatableStringHelper->localize($t->getName());

View File

@@ -61,14 +61,15 @@ class ActivityUserAggregator implements AggregatorInterface
public function getLabels($key, $values, $data): Closure public function getLabels($key, $values, $data): Closure
{ {
// preload users at once
$this->userRepository->findBy(['id' => $values]);
return function ($value) { return function ($value) {
if ('_header' === $value) { if ('_header' === $value) {
return 'Activity user'; return 'Activity user';
} }
if (null === $value) {
return '';
}
$u = $this->userRepository->find($value); $u = $this->userRepository->find($value);
return $this->userRender->renderString($u, []); return $this->userRender->renderString($u, []);

View File

@@ -55,10 +55,10 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
{ {
// add select element // add select element
if ('reasons' === $data['level']) { if ('reasons' === $data['level']) {
$elem = 'reasons.id'; $elem = 'actreasons.id';
$alias = 'activity_reasons_id'; $alias = 'activity_reasons_id';
} elseif ('categories' === $data['level']) { } elseif ('categories' === $data['level']) {
$elem = 'category.id'; $elem = 'actreasoncat.id';
$alias = 'activity_categories_id'; $alias = 'activity_categories_id';
} else { } else {
throw new RuntimeException('The data provided are not recognized.'); throw new RuntimeException('The data provided are not recognized.');

View File

@@ -17,6 +17,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@@ -34,7 +35,6 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
// TODO: Implement buildForm() method.
} }
public function getAllowedFormattersTypes(): array public function getAllowedFormattersTypes(): array
@@ -55,7 +55,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ('export_avg_activity_duration' !== $key) { if ('export_avg_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export"); throw new \LogicException("the key {$key} is not used by this export");
} }
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period duration' : $value; return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period duration' : $value;
@@ -83,10 +83,12 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{ {
$qb = $this->repository->createQueryBuilder('activity') $qb = $this->repository->createQueryBuilder('activity');
->join('activity.accompanyingPeriod', 'actacp');
$qb->select('AVG(activity.durationTime) as export_avg_activity_duration'); $qb
->join('activity.accompanyingPeriod', 'acp')
->select('AVG(activity.durationTime) as export_avg_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
return $qb; return $qb;
} }

View File

@@ -17,6 +17,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@@ -55,7 +56,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ('export_avg_activity_visit_duration' !== $key) { if ('export_avg_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export"); throw new \LogicException("the key {$key} is not used by this export");
} }
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period visit duration' : $value; return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period visit duration' : $value;
@@ -83,10 +84,13 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{ {
$qb = $this->repository->createQueryBuilder('activity') $qb = $this->repository->createQueryBuilder('activity');
->join('activity.accompanyingPeriod', 'actacp');
$qb->select('AVG(activity.travelTime) as export_avg_activity_visit_duration'); $qb
->join('activity.accompanyingPeriod', 'acp')
->select('AVG(activity.travelTime) as export_avg_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'))
;
return $qb; return $qb;
} }

View File

@@ -86,11 +86,11 @@ class CountActivity implements ExportInterface, GroupedExportInterface
{ {
$qb = $this->repository->createQueryBuilder('activity'); $qb = $this->repository->createQueryBuilder('activity');
if (!in_array('actacp', $qb->getAllAliases(), true)) { if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp'); $qb->join('activity.accompanyingPeriod', 'acp');
} }
$qb->select('COUNT(activity.id) as export_count_activity'); $qb->select('COUNT(DISTINCT activity.id) as export_count_activity');
return $qb; return $qb;
} }

View File

@@ -17,6 +17,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@@ -55,7 +56,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ('export_sum_activity_duration' !== $key) { if ('export_sum_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export"); throw new \LogicException("the key {$key} is not used by this export");
} }
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period duration' : $value; return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period duration' : $value;
@@ -85,11 +86,12 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
{ {
$qb = $this->repository->createQueryBuilder('activity'); $qb = $this->repository->createQueryBuilder('activity');
if (!in_array('actacp', $qb->getAllAliases(), true)) { if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp'); $qb->join('activity.accompanyingPeriod', 'acp');
} }
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration'); $qb->select('SUM(activity.durationTime) as export_sum_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
return $qb; return $qb;
} }

View File

@@ -17,6 +17,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface; use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
@@ -55,7 +56,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ('export_sum_activity_visit_duration' !== $key) { if ('export_sum_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export"); throw new \LogicException("the key {$key} is not used by this export");
} }
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period visit duration' : $value; return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period visit duration' : $value;
@@ -85,11 +86,12 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
{ {
$qb = $this->repository->createQueryBuilder('activity'); $qb = $this->repository->createQueryBuilder('activity');
if (!in_array('actacp', $qb->getAllAliases(), true)) { if (!in_array('acp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp'); $qb->join('activity.accompanyingPeriod', 'acp');
} }
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration'); $qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
return $qb; return $qb;
} }

View File

@@ -86,8 +86,8 @@ class CountActivity implements ExportInterface, GroupedExportInterface
$qb = $this->activityRepository->createQueryBuilder('activity'); $qb = $this->activityRepository->createQueryBuilder('activity');
if (!in_array('actperson', $qb->getAllAliases(), true)) { if (!in_array('person', $qb->getAllAliases(), true)) {
$qb->join('activity.person', 'actperson'); $qb->join('activity.person', 'person');
} }
$qb->select('COUNT(activity.id) as export_count_activity'); $qb->select('COUNT(activity.id) as export_count_activity');
@@ -109,7 +109,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
return [ return [
Declarations::ACTIVITY, Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON, Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE, PersonDeclarations::PERSON_TYPE,
]; ];
} }
} }

View File

@@ -210,7 +210,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
$qb $qb
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'actperson') ->join('activity.person', 'person')
->join('actperson.center', 'actcenter') ->join('actperson.center', 'actcenter')
->andWhere('actcenter IN (:authorized_centers)') ->andWhere('actcenter IN (:authorized_centers)')
->setParameter('authorized_centers', $centers); ->setParameter('authorized_centers', $centers);

View File

@@ -120,7 +120,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
} }
return $qb->select($select) return $qb->select($select)
->join('activity.person', 'actperson') ->join('activity.person', 'person')
->join('actperson.center', 'actcenter') ->join('actperson.center', 'actcenter')
->where($qb->expr()->in('actcenter', ':centers')) ->where($qb->expr()->in('actcenter', ':centers'))
->setParameter(':centers', $centers); ->setParameter(':centers', $centers);

View File

@@ -9,26 +9,31 @@
declare(strict_types=1); declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
/**
* TODO merge with ActivityTypeFilter in ChillActivity (!?).
*/
class ActivityTypeFilter implements FilterInterface class ActivityTypeFilter implements FilterInterface
{ {
private TranslatableStringHelper $translatableStringHelper; private ActivityTypeRepositoryInterface $activityTypeRepository;
public function __construct(TranslatableStringHelper $translatableStringHelper) private TranslatableStringHelperInterface $translatableStringHelper;
{
public function __construct(
ActivityTypeRepositoryInterface $activityTypeRepository,
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->activityTypeRepository = $activityTypeRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
@@ -39,31 +44,14 @@ class ActivityTypeFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// One2many between activity and accompanyingperiod is not reversed ! if (!in_array('activity', $qb->getAllAliases(), true)) {
// we replace indicator 'from' clause by 'act', and put 'acp' in a join $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp');
$qb->resetDQLPart('from');
$qb->from('ChillActivityBundle:Activity', 'activity');
if (!in_array('actacp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp');
} }
if (!in_array('acttype', $qb->getAllAliases(), true)) { $clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
$qb->join('activity.activityType', 'acttype');
}
$where = $qb->getDQLPart('where'); $qb->andWhere($clause);
$clause = $qb->expr()->in('acttype.id', ':activitytypes'); $qb->setParameter('selected_activity_types', $data['types']);
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('activitytypes', $data['accepted_activitytypes']);
} }
public function applyOn() public function applyOn()
@@ -75,8 +63,12 @@ class ActivityTypeFilter implements FilterInterface
{ {
$builder->add('accepted_activitytypes', EntityType::class, [ $builder->add('accepted_activitytypes', EntityType::class, [
'class' => ActivityType::class, 'class' => ActivityType::class,
'choices' => $this->activityTypeRepository->findAllActive(),
'choice_label' => function (ActivityType $aty) { 'choice_label' => function (ActivityType $aty) {
return $this->translatableStringHelper->localize($aty->getName()); return
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName());
}, },
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
@@ -92,7 +84,7 @@ class ActivityTypeFilter implements FilterInterface
} }
return ['Filtered by activity types: only %activitytypes%', [ return ['Filtered by activity types: only %activitytypes%', [
'%activitytypes%' => implode(', ou ', $types), '%activitytypes%' => implode(', ', $types),
]]; ]];
} }

View File

@@ -13,7 +13,7 @@ namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
@@ -28,13 +28,13 @@ use function count;
class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInterface class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInterface
{ {
protected ActivityTypeRepository $activityTypeRepository; protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper; protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct( public function __construct(
TranslatableStringHelperInterface $translatableStringHelper, TranslatableStringHelperInterface $translatableStringHelper,
ActivityTypeRepository $activityTypeRepository ActivityTypeRepositoryInterface $activityTypeRepository
) { ) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
@@ -47,16 +47,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('activity.activityType', ':selected_activity_types'); $clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
if ($where instanceof Expr\Andx) { $qb->andWhere($clause);
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('selected_activity_types', $data['types']); $qb->setParameter('selected_activity_types', $data['types']);
} }
@@ -68,11 +61,26 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('types', EntityType::class, [ $builder->add('types', EntityType::class, [
'choices' => $this->activityTypeRepository->findAllActive(),
'class' => ActivityType::class, 'class' => ActivityType::class,
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()), 'choice_label' => function (ActivityType $aty) {
'group_by' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getCategory()->getName()), return
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName());
},
'group_by' => function (ActivityType $type) {
if (!$type->hasCategory()) {
return null;
}
return $this->translatableStringHelper->localize($type->getCategory()->getName());
},
'multiple' => true, 'multiple' => true,
'expanded' => false, 'expanded' => false,
'attr' => [
'class' => 'select2'
]
]); ]);
} }

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\PersonFilters; namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityReasonRepository; use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
@@ -59,10 +60,10 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// create a query for activity // create a subquery for activity
$sqb = $qb->getEntityManager()->createQueryBuilder(); $sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select('person_person_having_activity.id') $sqb->select('person_person_having_activity.id')
->from('ChillActivityBundle:Activity', 'activity_person_having_activity') ->from(Activity::class, 'activity_person_having_activity')
->join('activity_person_having_activity.person', 'person_person_having_activity'); ->join('activity_person_having_activity.person', 'person_person_having_activity');
// add clause between date // add clause between date
@@ -197,7 +198,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
public function getTitle() public function getTitle()
{ {
return 'Filtered by person having an activity in a period'; return 'Filter by person having an activity in a period';
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)

View File

@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Form\Type; namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@@ -23,37 +23,25 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class TranslatableActivityType extends AbstractType class TranslatableActivityType extends AbstractType
{ {
protected ActivityTypeRepository $activityTypeRepository; protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper; protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct( public function __construct(
TranslatableStringHelperInterface $helper, TranslatableStringHelperInterface $helper,
ActivityTypeRepository $activityTypeRepository ActivityTypeRepositoryInterface $activityTypeRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** @var QueryBuilder $qb */
$qb = $options['query_builder'];
if (true === $options['active_only']) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, Types::BOOLEAN);
}
}
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults( $resolver->setDefaults(
[ [
'class' => ActivityType::class, 'class' => ActivityType::class,
'active_only' => true, 'active_only' => true,
'query_builder' => $this->activityTypeRepository 'choices' => $this->activityTypeRepository->findAllActive(),
->createQueryBuilder('at'),
'choice_label' => function (ActivityType $type) { 'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName()); return $this->translatableStringHelper->localize($type->getName());
}, },

View File

@@ -13,18 +13,58 @@ namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
use UnexpectedValueException;
final class ActivityTypeRepository implements ActivityTypeRepositoryInterface
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository(ActivityType::class);
}
/** /**
* @method ActivityType|null find($id, $lockMode = null, $lockVersion = null) * @return array|ActivityType[]
* @method ActivityType|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityType[] findAll()
* @method ActivityType[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/ */
class ActivityTypeRepository extends ServiceEntityRepository public function findAllActive(): array
{ {
public function __construct(ManagerRegistry $registry) return $this->findBy(['active' => true]);
}
public function find($id): ?ActivityType
{ {
parent::__construct($registry, ActivityType::class); return $this->repository->find($id);
} }
/**
* @return array|ActivityType[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @return array|ActivityType[]
*/
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): ?ActivityType
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return ActivityType::class;
}
} }

View File

@@ -0,0 +1,15 @@
<?php
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Persistence\ObjectRepository;
interface ActivityTypeRepositoryInterface extends ObjectRepository
{
/**
* @return array|ActivityType[]
*/
public function findAllActive(): array;
}

View File

@@ -13,10 +13,10 @@ namespace Chill\ActivityBundle\Security\Authorization;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use function in_array;
class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{ {
@@ -24,14 +24,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
public const STATS = 'CHILL_ACTIVITY_STATS'; public const STATS = 'CHILL_ACTIVITY_STATS';
/** protected VoterHelperInterface $helper;
* @var AuthorizationHelper
*/
protected $helper;
public function __construct(AuthorizationHelper $helper) public function __construct(VoterHelperFactoryInterface $voterHelperFactory)
{ {
$this->helper = $helper; $this->helper = $voterHelperFactory
->generate(self::class)
->addCheckFor(Center::class, [self::STATS, self::LISTS])
->build();
} }
public function getRoles(): array public function getRoles(): array
@@ -49,30 +49,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
return $this->getAttributes(); return $this->getAttributes();
} }
protected function getSupportedClasses() protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{ {
return [Center::class]; return $this->helper->voteOnAttribute($attribute, $subject, $token);
}
protected function isGranted($attribute, $object, $user = null)
{
if (!$user instanceof \Symfony\Component\Security\Core\User\UserInterface) {
return false;
}
return $this->helper->userHasAccess($user, $object, $attribute);
} }
protected function supports($attribute, $subject) protected function supports($attribute, $subject)
{ {
if ( return $this->helper->supports($attribute, $subject);
$subject instanceof Center
&& in_array($attribute, $this->getAttributes(), true)
) {
return true;
}
return false;
} }
private function getAttributes() private function getAttributes()

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialActionAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class BySocialActionAggregatorTest extends AbstractAggregatorTest
{
private BySocialActionAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.bysocialaction_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.socialActions', 'actsocialaction')
,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialIssueAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class BySocialIssueAggregatorTest extends AbstractAggregatorTest
{
private BySocialIssueAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.bysocialissue_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.socialIssues', 'actsocialissue')
,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByThirdpartyAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class ByThirdpartyAggregatorTest extends AbstractAggregatorTest
{
private ByThirdpartyAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.bythirdparty_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.thirdParties', 'acttparty')
,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByUserAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class ByUserAggregatorTest extends AbstractAggregatorTest
{
private ByUserAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.byuser_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.users', 'actusers')
,
];
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\DateAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class DateAggregatorTest extends AbstractAggregatorTest
{
private DateAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.date_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[
'frequency' => 'month',
],
[
'frequency' => 'week',
],
[
'frequency' => 'year',
]
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\LocationTypeAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class LocationTypeAggregatorTest extends AbstractAggregatorTest
{
private LocationTypeAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.locationtype_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.location', 'actloc')
,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\UserScopeAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class UserScopeAggregatorTest extends AbstractAggregatorTest
{
private UserScopeAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.userscope_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.accompanyingPeriod', 'acp')
->join('activity.user', 'actuser')
,
];
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator; namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
@@ -21,10 +22,7 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
*/ */
final class ActivityReasonAggregatorTest extends AbstractAggregatorTest final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
{ {
/** private ActivityReasonAggregator $aggregator;
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/
private $aggregator;
protected function setUp(): void protected function setUp(): void
{ {

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator; namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityTypeAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
@@ -21,10 +22,7 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
*/ */
final class ActivityTypeAggregatorTest extends AbstractAggregatorTest final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
{ {
/** private ActivityTypeAggregator $aggregator;
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/
private $aggregator;
protected function setUp(): void protected function setUp(): void
{ {

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator; namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
@@ -21,10 +22,7 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
*/ */
final class ActivityUserAggregatorTest extends AbstractAggregatorTest final class ActivityUserAggregatorTest extends AbstractAggregatorTest
{ {
/** private ActivityUserAggregator $aggregator;
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
*/
private $aggregator;
protected function setUp(): void protected function setUp(): void
{ {

View File

@@ -0,0 +1,65 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
{
private ActivityReasonAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$this->aggregator = self::$container->get('chill.activity.export.reason_aggregator');
}
public function getAggregator()
{
return $this->aggregator;
}
public function getFormData(): array
{
return [
[
'level' => 'reasons',
],
[
'level' => 'categories',
]
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.person', 'actperson')
->innerJoin('activity.reasons', 'actreasons')
->join('actreasons.category', 'actreasoncat')
,
];
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Export\Filter\ACPFilters\ActivityTypeFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\Expr;
/**
* @internal
* @coversNothing
*/
final class ActivityTypeFilterTest extends AbstractFilterTest
{
private ActivityTypeFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.filter_activitytype');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(ActivityType::class, 'at')
->select('at')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_activitytypes' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(AccompanyingPeriod::class, 'acp')
->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp')
->join('activity.activityType', 'acttype'),
];
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialActionFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class BySocialActionFilterTest extends AbstractFilterTest
{
private BySocialActionFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.bysocialaction_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(SocialAction::class, 'sa')
->select('sa')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_socialactions' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.socialActions', 'actsocialaction'),
];
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialIssueFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class BySocialIssueFilterTest extends AbstractFilterTest
{
private BySocialIssueFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.bysocialissue_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(SocialIssue::class, 'si')
->select('si')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_socialissues' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.socialIssues', 'actsocialissue')
,
];
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\ByUserFilter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class ByUserFilterTest extends AbstractFilterTest
{
private ByUserFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.byuser_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(User::class, 'u')
->select('u')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_users' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.users', 'actusers'),
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\EmergencyFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class EmergencyFilterTest extends AbstractFilterTest
{
private EmergencyFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.emergency_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
return [
['accepted_emergency' => true ],
['accepted_emergency' => false ],
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class LocationTypeFilterTest extends AbstractFilterTest
{
private LocationTypeFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.locationtype_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(LocationType::class, 'lt')
->select('lt')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_locationtype' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.location', 'actloc'),
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\SentReceivedFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class SentReceivedFilterTest extends AbstractFilterTest
{
private SentReceivedFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.sentreceived_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
return [
['accepted_sentreceived' => Activity::SENTRECEIVED_SENT ],
['accepted_sentreceived' => Activity::SENTRECEIVED_RECEIVED ]
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\UserFilter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class UserFilterTest extends AbstractFilterTest
{
private UserFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.user_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(User::class, 'u')
->select('u')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_users' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ACPFilters\UserScopeFilter;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class UserScopeFilterTest extends AbstractFilterTest
{
private UserScopeFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.userscope_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(Scope::class, 's')
->select('s')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'accepted_userscope' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.user', 'actuser'),
];
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Filter\ActivityDateFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class ActivityDateFilterTest extends AbstractFilterTest
{
private ActivityDateFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.date_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
return [
[
'date_from' => \DateTime::createFromFormat('Y-m-d', '2020-01-01'),
'date_to' => \DateTime::createFromFormat('Y-m-d', '2021-01-01'),
]
];
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter; namespace Chill\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Export\Filter\PersonFilters\ActivityReasonFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@@ -20,10 +21,7 @@ use Doctrine\Common\Collections\ArrayCollection;
*/ */
final class ActivityReasonFilterTest extends AbstractFilterTest final class ActivityReasonFilterTest extends AbstractFilterTest
{ {
/** private ActivityReasonFilter $filter;
* @var \Chill\PersonBundle\Export\Filter\GenderFilter
*/
private $filter;
protected function setUp(): void protected function setUp(): void
{ {

View File

@@ -9,13 +9,13 @@
declare(strict_types=1); declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Export\Filter\AccompanyingCourseFilters; namespace Chill\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Export\Filter\ActivityTypeFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters\ActivityTypeFilter;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/** /**
* @internal * @internal
@@ -27,16 +27,15 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
protected function setUp(): void protected function setUp(): void
{ {
//parent::setUp();
self::bootKernel(); self::bootKernel();
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$request = $this->prophesize(); $request = $this->prophesize();
$request->willExtend(Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.person.export.filter_activitytype'); $this->filter = self::$container->get('chill.activity.export.type_filter');
} }
public function getFilter() public function getFilter()
@@ -56,8 +55,10 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
$data = []; $data = [];
foreach ($array as $t) { foreach ($array as $a) {
$data[] = ['accepted_activitytypes' => $t]; $data[] = [
'types' => $a
];
} }
return $data; return $data;
@@ -73,8 +74,8 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
return [ return [
$em->createQueryBuilder() $em->createQueryBuilder()
->from('ChillPersonBundle:AccompanyingPeriod', 'acp') ->select('count(activity.id)')
->select('acp.id'), ->from(Activity::class, 'activity'),
]; ];
} }
} }

View File

@@ -0,0 +1,82 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Export\Filter\PersonFilters\ActivityReasonFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class ActivityReasonFilterTest extends AbstractFilterTest
{
private ActivityReasonFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.reason_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(ActivityReason::class, 'ar')
->select('ar')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'reasons' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity')
->join('activity.reasons', 'actreasons'),
];
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* 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.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Export\Filter\PersonFilters\PersonHavingActivityBetweenDateFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
{
private PersonHavingActivityBetweenDateFilter $filter;
protected function setUp(): void
{
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.activity.export.person_having_an_activity_between_date_filter');
}
public function getFilter()
{
return $this->filter;
}
public function getFormData(): array
{
$em = self::$container->get(EntityManagerInterface::class);
$array = $em->createQueryBuilder()
->from(ActivityReason::class, 'ar')
->select('ar')
->getQuery()
->getResult();
$data = [];
foreach ($array as $a) {
$data[] = [
'date_from' => \DateTime::createFromFormat('Y-m-d', '2021-07-01'),
'date_to' => \DateTime::createFromFormat('Y-m-d', '2022-07-01'),
'reasons' => $a
];
}
return $data;
}
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from(Activity::class, 'activity'),
];
}
}

View File

@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter; namespace Chill\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Export\Filter\PersonFilters\PersonHavingActivityBetweenDateFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use DateTime; use DateTime;
use function array_slice; use function array_slice;
@@ -21,10 +22,7 @@ use function array_slice;
*/ */
final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
{ {
/** private PersonHavingActivityBetweenDateFilter $filter;
* @var \Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
*/
private $filter;
protected function setUp(): void protected function setUp(): void
{ {

View File

@@ -67,6 +67,11 @@ services:
name: chill.export_filter name: chill.export_filter
alias: 'activity_person_having_ac_bw_date_filter' alias: 'activity_person_having_ac_bw_date_filter'
chill.activity.export.filter_activitytype:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\ActivityTypeFilter
tags:
- { name: chill.export_filter, alias: 'accompanyingcourse_activitytype_filter' }
chill.activity.export.locationtype_filter: chill.activity.export.locationtype_filter:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter
tags: tags:

View File

@@ -143,7 +143,7 @@ class MapCalendarToUser
public function writeMetadata(User $user): User public function writeMetadata(User $user): User
{ {
if (null === $user->getEmail() OR '' === $user->getEmail()) { if (null === $user->getEmail() || '' === $user->getEmail()) {
return $user; return $user;
} }

View File

@@ -1,104 +1,104 @@
services: #services:
#
## Indicators # Indicators
chill.calendar.export.count_appointments: # chill.calendar.export.count_appointments:
class: Chill\CalendarBundle\Export\Export\CountAppointments # class: Chill\CalendarBundle\Export\Export\CountAppointments
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export, alias: count_appointments } # - { name: chill.export, alias: count_appointments }
#
chill.calendar.export.average_duration_appointments: # chill.calendar.export.average_duration_appointments:
class: Chill\CalendarBundle\Export\Export\StatAppointmentAvgDuration # class: Chill\CalendarBundle\Export\Export\StatAppointmentAvgDuration
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export, alias: average_duration_appointments } # - { name: chill.export, alias: average_duration_appointments }
#
chill.calendar.export.sum_duration_appointments: # chill.calendar.export.sum_duration_appointments:
class: Chill\CalendarBundle\Export\Export\StatAppointmentSumDuration # class: Chill\CalendarBundle\Export\Export\StatAppointmentSumDuration
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export, alias: sum_duration_appointments } # - { name: chill.export, alias: sum_duration_appointments }
#
## Filters # Filters
#
chill.calendar.export.agent_filter: # chill.calendar.export.agent_filter:
class: Chill\CalendarBundle\Export\Filter\AgentFilter # class: Chill\CalendarBundle\Export\Filter\AgentFilter
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_filter, alias: agent_filter } # - { name: chill.export_filter, alias: agent_filter }
#
chill.calendar.export.job_filter: # chill.calendar.export.job_filter:
class: Chill\CalendarBundle\Export\Filter\JobFilter # class: Chill\CalendarBundle\Export\Filter\JobFilter
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_filter, alias: job_filter } # - { name: chill.export_filter, alias: job_filter }
#
chill.calendar.export.scope_filter: # chill.calendar.export.scope_filter:
class: Chill\CalendarBundle\Export\Filter\ScopeFilter # class: Chill\CalendarBundle\Export\Filter\ScopeFilter
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_filter, alias: scope_filter } # - { name: chill.export_filter, alias: scope_filter }
#
chill.calendar.export.between_dates_filter: # chill.calendar.export.between_dates_filter:
class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter # class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_filter, alias: between_dates_filter } # - { name: chill.export_filter, alias: between_dates_filter }
#
## Aggregator # Aggregator
#
chill.calendar.export.agent_aggregator: # chill.calendar.export.agent_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator # class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: agent_aggregator } # - { name: chill.export_aggregator, alias: agent_aggregator }
#
chill.calendar.export.job_aggregator: # chill.calendar.export.job_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\JobAggregator # class: Chill\CalendarBundle\Export\Aggregator\JobAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: job_aggregator } # - { name: chill.export_aggregator, alias: job_aggregator }
#
chill.calendar.export.scope_aggregator: # chill.calendar.export.scope_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator # class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: scope_aggregator } # - { name: chill.export_aggregator, alias: scope_aggregator }
#
chill.calendar.export.location_type_aggregator: # chill.calendar.export.location_type_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator # class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: location_type_aggregator } # - { name: chill.export_aggregator, alias: location_type_aggregator }
#
chill.calendar.export.location_aggregator: # chill.calendar.export.location_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator # class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: location_aggregator } # - { name: chill.export_aggregator, alias: location_aggregator }
#
chill.calendar.export.cancel_reason_aggregator: # chill.calendar.export.cancel_reason_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator # class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: cancel_reason_aggregator } # - { name: chill.export_aggregator, alias: cancel_reason_aggregator }
#
chill.calendar.export.month_aggregator: # chill.calendar.export.month_aggregator:
class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator # class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator
autowire: true # autowire: true
autoconfigure: true # autoconfigure: true
tags: # tags:
- { name: chill.export_aggregator, alias: month_aggregator } # - { name: chill.export_aggregator, alias: month_aggregator }

View File

@@ -102,4 +102,3 @@ Job: Métier
Location type: Type de localisation Location type: Type de localisation
Location: Lieu de rendez-vous Location: Lieu de rendez-vous
by month and year: Par mois et année by month and year: Par mois et année

View File

@@ -126,7 +126,7 @@ class Version20160318111334 extends AbstractMigration
$this->addSql('ALTER TABLE chill_event_participation ' $this->addSql('ALTER TABLE chill_event_participation '
. 'ADD CONSTRAINT FK_4E7768AC217BBB47 ' . 'ADD CONSTRAINT FK_4E7768AC217BBB47 '
. 'FOREIGN KEY (person_id) ' . 'FOREIGN KEY (person_id) '
. 'REFERENCES chill_person_person(id) ' . 'REFERENCES Person (id) '
. 'NOT DEFERRABLE INITIALLY IMMEDIATE'); . 'NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_event_participation ' $this->addSql('ALTER TABLE chill_event_participation '
. 'ADD CONSTRAINT FK_4E7768ACD60322AC ' . 'ADD CONSTRAINT FK_4E7768ACD60322AC '

View File

@@ -23,6 +23,7 @@ use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
@@ -142,10 +143,8 @@ class ExportController extends AbstractController
/** /**
* Render the list of available exports. * Render the list of available exports.
*
* @return \Symfony\Component\HttpFoundation\Response
*/ */
public function indexAction(Request $request) public function indexAction(): Response
{ {
$exportManager = $this->exportManager; $exportManager = $this->exportManager;

View File

@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Export;
use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\ExportType;
use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Form\Type\Export\PickCenterType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Generator; use Generator;
@@ -42,52 +43,38 @@ class ExportManager
/** /**
* The collected aggregators, injected by DI. * The collected aggregators, injected by DI.
* *
* @var AggregatorInterface[] * @var array|AggregatorInterface[]
*/ */
private $aggregators = []; private array $aggregators = [];
/** private AuthorizationCheckerInterface $authorizationChecker;
* @var AuthorizationChecker
*/
private $authorizationChecker;
/** private AuthorizationHelperInterface $authorizationHelper;
* @var AuthorizationHelper
*/
private $authorizationHelper;
/** private EntityManagerInterface $em;
* @var EntityManagerInterface
*/
private $em;
/** /**
* Collected Exports, injected by DI. * Collected Exports, injected by DI.
* *
* @var ExportInterface[] * @var array|ExportInterface[]
*/ */
private $exports = []; private array $exports = [];
/** /**
* The collected filters, injected by DI. * The collected filters, injected by DI.
* *
* @var FilterInterface[] * @var array|FilterInterface[]
*/ */
private $filters = []; private array $filters = [];
/** /**
* Collected Formatters, injected by DI. * Collected Formatters, injected by DI.
* *
* @var FormatterInterface[] * @var array|FormatterInterface[]
*/ */
private $formatters = []; private array $formatters = [];
/** private LoggerInterface $logger;
* a logger.
*
* @var LoggerInterface
*/
private $logger;
/** /**
* @var \Symfony\Component\Security\Core\User\UserInterface * @var \Symfony\Component\Security\Core\User\UserInterface
@@ -98,7 +85,7 @@ class ExportManager
LoggerInterface $logger, LoggerInterface $logger,
EntityManagerInterface $em, EntityManagerInterface $em,
AuthorizationCheckerInterface $authorizationChecker, AuthorizationCheckerInterface $authorizationChecker,
AuthorizationHelper $authorizationHelper, AuthorizationHelperInterface $authorizationHelper,
TokenStorageInterface $tokenStorage TokenStorageInterface $tokenStorage
) { ) {
$this->logger = $logger; $this->logger = $logger;
@@ -549,19 +536,16 @@ class ExportManager
. 'an ExportInterface.'); . 'an ExportInterface.');
} }
if (null === $centers) { if (null === $centers || [] !== $centers) {
$centers = $this->authorizationHelper->getReachableCenters( // we want to try if at least one center is reachabler
return [] !== $this->authorizationHelper->getReachableCenters(
$this->user, $this->user,
$role $role
); );
} }
if (count($centers) === 0) {
return false;
}
foreach ($centers as $center) { foreach ($centers as $center) {
if ($this->authorizationChecker->isGranted($role, $center) === false) { if (false === $this->authorizationChecker->isGranted($role, $center)) {
//debugging //debugging
$this->logger->debug('user has no access to element', [ $this->logger->debug('user has no access to element', [
'method' => __METHOD__, 'method' => __METHOD__,
@@ -570,10 +554,6 @@ class ExportManager
'role' => $role, 'role' => $role,
]); ]);
///// Bypasse les autorisations qui empêche d'afficher les nouveaux exports
return true;
///// TODO supprimer le return true
return false; return false;
} }
} }

View File

@@ -230,7 +230,8 @@ class SpreadSheetFormatter implements FormatterInterface
$worksheet->fromArray( $worksheet->fromArray(
$sortedResults, $sortedResults,
null, null,
'A' . $line 'A' . $line,
true
); );
return $line + count($sortedResults) + 1; return $line + count($sortedResults) + 1;
@@ -495,9 +496,14 @@ class SpreadSheetFormatter implements FormatterInterface
// 3. iterate on `keysExportElementAssociation` to store the callable // 3. iterate on `keysExportElementAssociation` to store the callable
// in cache // in cache
foreach ($keysExportElementAssociation as $key => [$element, $data]) { foreach ($keysExportElementAssociation as $key => [$element, $data]) {
// handle the case when there is not results lines (query is empty)
if ([] === $allValues) {
$this->cacheDisplayableResult[$key] = $element->getLabels($key, ['_header'], $data);
} else {
$this->cacheDisplayableResult[$key] = $this->cacheDisplayableResult[$key] =
$element->getLabels($key, array_unique($allValues[$key]), $data); $element->getLabels($key, array_unique($allValues[$key]), $data);
} }
}
// the cache is initialized ! // the cache is initialized !
$this->cacheDisplayableResultIsInitialized = true; $this->cacheDisplayableResultIsInitialized = true;

View File

@@ -15,6 +15,7 @@ use Chill\MainBundle\Center\GroupingCenterInterface;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
@@ -24,6 +25,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use function array_intersect; use function array_intersect;
use function array_key_exists; use function array_key_exists;
use function array_merge; use function array_merge;
@@ -38,30 +40,24 @@ class PickCenterType extends AbstractType
{ {
public const CENTERS_IDENTIFIERS = 'c'; public const CENTERS_IDENTIFIERS = 'c';
/** protected AuthorizationHelperInterface $authorizationHelper;
* @var AuthorizationHelper
*/ protected ExportManager $exportManager;
protected $authorizationHelper;
/** /**
* @var ExportManager * @var array|GroupingCenterInterface[]
*/ */
protected $exportManager; protected array $groupingCenters = [];
/**
* @var GroupingCenterInterface[]
*/
protected $groupingCenters = [];
/** /**
* @var \Symfony\Component\Security\Core\User\UserInterface * @var \Symfony\Component\Security\Core\User\UserInterface
*/ */
protected $user; protected UserInterface $user;
public function __construct( public function __construct(
TokenStorageInterface $tokenStorage, TokenStorageInterface $tokenStorage,
ExportManager $exportManager, ExportManager $exportManager,
AuthorizationHelper $authorizationHelper AuthorizationHelperInterface $authorizationHelper
) { ) {
$this->exportManager = $exportManager; $this->exportManager = $exportManager;
$this->user = $tokenStorage->getToken()->getUser(); $this->user = $tokenStorage->getToken()->getUser();
@@ -78,22 +74,12 @@ class PickCenterType extends AbstractType
$export = $this->exportManager->getExport($options['export_alias']); $export = $this->exportManager->getExport($options['export_alias']);
$centers = $this->authorizationHelper->getReachableCenters( $centers = $this->authorizationHelper->getReachableCenters(
$this->user, $this->user,
(string) $export->requiredRole() $export->requiredRole()
); );
$builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [ $builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [
'class' => Center::class, 'class' => Center::class,
'query_builder' => static function (EntityRepository $er) use ($centers) { 'choices' => $centers,
$qb = $er->createQueryBuilder('c');
$ids = array_map(
static function (Center $el) {
return $el->getId();
},
$centers
);
return $qb->where($qb->expr()->in('c.id', $ids));
},
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choice_label' => static function (Center $c) { 'choice_label' => static function (Center $c) {

View File

@@ -16,7 +16,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository; use Doctrine\Persistence\ObjectRepository;
final class CenterRepository implements ObjectRepository final class CenterRepository implements CenterRepositoryInterface
{ {
private EntityRepository $repository; private EntityRepository $repository;
@@ -30,6 +30,11 @@ final class CenterRepository implements ObjectRepository
return $this->repository->find($id, $lockMode, $lockVersion); return $this->repository->find($id, $lockMode, $lockVersion);
} }
public function findActive(): array
{
return $this->findAll();
}
/** /**
* @return Center[] * @return Center[]
*/ */

View File

@@ -0,0 +1,18 @@
<?php
namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\Center;
use Doctrine\Persistence\ObjectRepository;
interface CenterRepositoryInterface extends ObjectRepository
{
/**
* Return all active centers
*
* Note: this is a teaser: active will comes later on center entity
*
* @return Center[]
*/
public function findActive(): array;
}

View File

@@ -517,3 +517,9 @@ div.popover {
div.v-toast { div.v-toast {
z-index: 10000!important; z-index: 10000!important;
} }
div.grouped {
padding: 1em;
border: 1px solid black;
margin-bottom: 2em;
}

View File

@@ -23,13 +23,7 @@
{% block js %} {% block js %}
{{ encore_entry_script_tags('page_export') }} {{ encore_entry_script_tags('page_export') }}
{% if export_alias == 'count_social_work_actions' %} {% if export_alias == 'count_social_work_actions' %}
{# {{ encore_entry_script_tags('vue_export_action_goal_result') }}
TODO: [debug] comprendre pq l'activation du composant Vue bloque le passage de
http://localhost:8001/fr/exports/new/count_social_work_actions?step=export
vers http://localhost:8001/fr/exports/new/count_social_work_actions?step=formatter
{{ encore_entry_script_tags('vue_form_action_goal_result') }}
#}
{% endif %} {% endif %}
{% endblock js %} {% endblock js %}

View File

@@ -19,24 +19,23 @@ class ChillExportVoter extends Voter
{ {
public const EXPORT = 'chill_export'; public const EXPORT = 'chill_export';
protected AuthorizationHelperInterface $authorizationHelper; private VoterHelperInterface $helper;
public function __construct(AuthorizationHelperInterface $authorizationHelper) public function __construct(VoterHelperFactoryInterface $voterHelperFactory)
{ {
$this->authorizationHelper = $authorizationHelper; $this->helper = $voterHelperFactory
->generate(self::class)
->addCheckFor(null, [self::EXPORT])
->build();
} }
protected function supports($attribute, $subject): bool protected function supports($attribute, $subject): bool
{ {
return self::EXPORT === $attribute; return $this->helper->supports($attribute, $subject);
} }
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{ {
if (!$token->getUser() instanceof User) { return $this->helper->voteOnAttribute($attribute, $subject, $token);
return false;
}
return [] !== $this->authorizationHelper->getReachableCenters($token->getUser(), $attribute);
} }
} }

View File

@@ -25,7 +25,6 @@ use function is_string;
/** /**
* Helper which creates a set of test for aggregators. * Helper which creates a set of test for aggregators.
* *
* @internal
*/ */
abstract class AbstractAggregatorTest extends KernelTestCase abstract class AbstractAggregatorTest extends KernelTestCase
{ {

View File

@@ -24,7 +24,6 @@ use function is_string;
/** /**
* Helper to test filters. * Helper to test filters.
* *
* @internal
*/ */
abstract class AbstractFilterTest extends KernelTestCase abstract class AbstractFilterTest extends KernelTestCase
{ {

View File

@@ -18,6 +18,7 @@ namespace Chill\MainBundle\Test;
* and use tearDownTrait after usage. * and use tearDownTrait after usage.
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @deprecated use @class{Prophecy\PhpUnit\ProphecyTrait} instead
*/ */
trait ProphecyTrait trait ProphecyTrait
{ {

View File

@@ -74,5 +74,4 @@ module.exports = function(encore, entries)
// Vue entrypoints // Vue entrypoints
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js'); encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
encore.addEntry('vue_onthefly', __dirname + '/Resources/public/vuejs/OnTheFly/index.js'); encore.addEntry('vue_onthefly', __dirname + '/Resources/public/vuejs/OnTheFly/index.js');
encore.addEntry('vue_form_action_goal_result', __dirname + '/Resources/public/vuejs/FormActionGoalResult/index.js');
}; };

View File

@@ -89,12 +89,8 @@ services:
- { name: validator.constraint_validator, alias: 'role_scope_scope_presence' } - { name: validator.constraint_validator, alias: 'role_scope_scope_presence' }
Chill\MainBundle\Export\ExportManager: Chill\MainBundle\Export\ExportManager:
arguments: autoconfigure: true
- "@logger" autowire: true
- "@doctrine.orm.entity_manager"
- "@security.authorization_checker"
- "@chill.main.security.authorization.helper"
- "@security.token_storage"
Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface: '@Chill\MainBundle\Security\Resolver\CenterResolverDispatcher' Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface: '@Chill\MainBundle\Security\Resolver\CenterResolverDispatcher'

View File

@@ -81,12 +81,8 @@ services:
chill.main.form.pick_centers_type: chill.main.form.pick_centers_type:
class: Chill\MainBundle\Form\Type\Export\PickCenterType class: Chill\MainBundle\Form\Type\Export\PickCenterType
arguments: autowire: true
- "@security.token_storage" autoconfigure: true
- '@Chill\MainBundle\Export\ExportManager'
- "@chill.main.security.authorization.helper"
tags:
- { name: form.type }
chill.main.form.formatter_type: chill.main.form.formatter_type:
class: Chill\MainBundle\Form\Type\Export\FormatterType class: Chill\MainBundle\Form\Type\Export\FormatterType

View File

@@ -25,23 +25,17 @@ class AbstractAccompanyingPeriodExportElement
*/ */
protected function addJoinAccompanyingPeriod(QueryBuilder $query): void protected function addJoinAccompanyingPeriod(QueryBuilder $query): void
{ {
if (false === $this->havingAccompanyingPeriodInJoin($query)) {
if (false === in_array('person', $query->getAllAliases(), true)) { if (false === in_array('person', $query->getAllAliases(), true)) {
throw new LogicException("the alias 'person' does not exists in " throw new LogicException("the alias 'person' does not exists in "
. 'query builder'); . 'query builder');
} }
$query->join('person.accompanyingPeriods', 'accompanying_period'); if (!in_array('acppart', $query->getAllAliases(), true)) {
} $query->join('person.accompanyingPeriodParticipations', 'acppart');
} }
/** if (!in_array('acp', $query->getAllAliases(), true)) {
* Return true if "accompanying_period" alias is present in the query alises. $query->join('acppart.accompanyingPeriod', 'acp');
*/ }
protected function havingAccompanyingPeriodInJoin(QueryBuilder $query): bool
{
$joins = $query->getDQLPart('join') ?? [];
return in_array('accompanying_period', $query->getAllAliases(), true);
} }
} }

View File

@@ -40,18 +40,11 @@ class AdministrativeLocationAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acploc', $qb->getAllAliases(), true)) { if (!in_array('acploc', $qb->getAllAliases(), true)) {
$qb->join('acp.administrativeLocation', 'acploc'); $qb->leftJoin('acp.administrativeLocation', 'acploc');
} }
$qb->addSelect('IDENTITY(acp.administrativeLocation) AS location_aggregator'); $qb->addSelect('IDENTITY(acp.administrativeLocation) AS location_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('location_aggregator'); $qb->addGroupBy('location_aggregator');
} else {
$qb->groupBy('location_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -71,6 +64,10 @@ class AdministrativeLocationAggregator implements AggregatorInterface
return 'Administrative location'; return 'Administrative location';
} }
if (null === $value) {
return '';
}
$l = $this->locationRepository->find($value); $l = $this->locationRepository->find($value);
return $l->getName() . ' (' . $this->translatableStringHelper->localize($l->getLocationType()->getTitle()) . ')'; return $l->getName() . ' (' . $this->translatableStringHelper->localize($l->getLocationType()->getTitle()) . ')';

View File

@@ -15,21 +15,23 @@ use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
class ClosingMotiveAggregator implements AggregatorInterface class ClosingMotiveAggregator implements AggregatorInterface
{ {
private EntityManagerInterface $em; private ClosingMotiveRepositoryInterface $motiveRepository;
private TranslatableStringHelper $translatableStringHelper; private TranslatableStringHelper $translatableStringHelper;
public function __construct( public function __construct(
EntityManagerInterface $em, ClosingMotiveRepositoryInterface $motiveRepository,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelper $translatableStringHelper
) { ) {
$this->motiveRepository = $em->getRepository(ClosingMotive::class); $this->motiveRepository = $motiveRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
@@ -40,19 +42,8 @@ class ClosingMotiveAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpmotive', $qb->getAllAliases(), true)) {
$qb->join('acp.closingMotive', 'acpmotive');
}
$qb->addSelect('IDENTITY(acp.closingMotive) AS closingmotive_aggregator'); $qb->addSelect('IDENTITY(acp.closingMotive) AS closingmotive_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('closingmotive_aggregator'); $qb->addGroupBy('closingmotive_aggregator');
} else {
$qb->groupBy('closingmotive_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +63,10 @@ class ClosingMotiveAggregator implements AggregatorInterface
return 'Closing motive'; return 'Closing motive';
} }
if (NULL === $value) {
return '';
}
$cm = $this->motiveRepository->find($value); $cm = $this->motiveRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -35,14 +35,7 @@ class ConfidentialAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->addSelect('acp.confidential AS confidential_aggregator'); $qb->addSelect('acp.confidential AS confidential_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('confidential_aggregator'); $qb->addGroupBy('confidential_aggregator');
} else {
$qb->groupBy('confidential_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -44,15 +44,8 @@ final class DurationAggregator implements AggregatorInterface
// et ajouter une fonction custom qui calcule plus précisément les intervals, comme doctrineum/date-interval // et ajouter une fonction custom qui calcule plus précisément les intervals, comme doctrineum/date-interval
// https://packagist.org/packages/doctrineum/date-interval#3.1.0 (mais composer fait un conflit de dépendance) // https://packagist.org/packages/doctrineum/date-interval#3.1.0 (mais composer fait un conflit de dépendance)
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('duration_aggregator'); $qb->addGroupBy('duration_aggregator');
} else { $qb->addOrderBy('duration_aggregator');
$qb->groupBy('duration_aggregator');
}
$qb->orderBy('duration_aggregator');
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -35,14 +35,7 @@ class EmergencyAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->addSelect('acp.emergency AS emergency_aggregator'); $qb->addSelect('acp.emergency AS emergency_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('emergency_aggregator'); $qb->addGroupBy('emergency_aggregator');
} else {
$qb->groupBy('emergency_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -41,22 +41,15 @@ final class EvaluationAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpw', $qb->getAllAliases(), true)) { if (!in_array('acpw', $qb->getAllAliases(), true)) {
$qb->join('acp.works', 'acpw'); $qb->leftJoin('acp.works', 'acpw');
} }
if (!in_array('workeval', $qb->getAllAliases(), true)) { if (!in_array('workeval', $qb->getAllAliases(), true)) {
$qb->join('acpw.accompanyingPeriodWorkEvaluations', 'workeval'); $qb->leftJoin('acpw.accompanyingPeriodWorkEvaluations', 'workeval');
} }
$qb->addSelect('IDENTITY(workeval.evaluation) AS evaluation_aggregator'); $qb->addSelect('IDENTITY(workeval.evaluation) AS evaluation_aggregator');
$groupby = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('evaluation_aggregator'); $qb->addGroupBy('evaluation_aggregator');
} else {
$qb->groupBy('evaluation_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -76,6 +69,10 @@ final class EvaluationAggregator implements AggregatorInterface
return 'Evaluation'; return 'Evaluation';
} }
if (null === $value) {
return '';
}
$e = $this->evaluationRepository->find($value); $e = $this->evaluationRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -35,14 +35,7 @@ class IntensityAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->addSelect('acp.intensity AS intensity_aggregator'); $qb->addSelect('acp.intensity AS intensity_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('intensity_aggregator'); $qb->addGroupBy('intensity_aggregator');
} else {
$qb->groupBy('intensity_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -40,18 +40,11 @@ final class JobAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpjob', $qb->getAllAliases(), true)) { if (!in_array('acpjob', $qb->getAllAliases(), true)) {
$qb->join('acp.job', 'acpjob'); $qb->leftJoin('acp.job', 'acpjob');
} }
$qb->addSelect('IDENTITY(acp.job) AS job_aggregator'); $qb->addSelect('IDENTITY(acp.job) AS job_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('job_aggregator'); $qb->addGroupBy('job_aggregator');
} else {
$qb->groupBy('job_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -71,6 +64,10 @@ final class JobAggregator implements AggregatorInterface
return 'Job'; return 'Job';
} }
if (null === $value) {
return '';
}
$j = $this->jobRepository->find($value); $j = $this->jobRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -42,18 +42,11 @@ final class OriginAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acporigin', $qb->getAllAliases(), true)) { if (!in_array('acporigin', $qb->getAllAliases(), true)) {
$qb->join('acp.origin', 'acporigin'); $qb->leftJoin('acp.origin', 'acporigin');
} }
$qb->addSelect('o.id AS origin_aggregator'); $qb->addSelect('acporigin.id AS origin_aggregator');
$groupby = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('origin_aggregator'); $qb->addGroupBy('origin_aggregator');
} else {
$qb->groupBy('origin_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -73,6 +66,10 @@ final class OriginAggregator implements AggregatorInterface
return 'Origin'; return 'Origin';
} }
if (null === $value) {
return '';
}
$o = $this->repository->find($value); $o = $this->repository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -40,18 +40,11 @@ final class ReferrerAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpuser', $qb->getAllAliases(), true)) { if (!in_array('acpuser', $qb->getAllAliases(), true)) {
$qb->join('acp.user', 'acpuser'); $qb->leftJoin('acp.user', 'acpuser');
} }
$qb->addSelect('acpuser.id AS referrer_aggregator'); $qb->addSelect('acpuser.id AS referrer_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('referrer_aggregator'); $qb->addGroupBy('referrer_aggregator');
} else {
$qb->groupBy('referrer_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -71,6 +64,10 @@ final class ReferrerAggregator implements AggregatorInterface
return 'Referrer'; return 'Referrer';
} }
if (null === $value) {
return '';
}
$r = $this->userRepository->find($value); $r = $this->userRepository->find($value);
return $this->userRender->renderString($r, []); return $this->userRender->renderString($r, []);

View File

@@ -57,15 +57,7 @@ final class RequestorAggregator implements AggregatorInterface
END ) AS requestor_aggregator END ) AS requestor_aggregator
"); ");
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('requestor_aggregator'); $qb->addGroupBy('requestor_aggregator');
} else {
$qb->groupBy('requestor_aggregator');
}
// TODO 'order by' does not works !
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -40,18 +40,11 @@ final class ScopeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpscope', $qb->getAllAliases(), true)) { if (!in_array('acpscope', $qb->getAllAliases(), true)) {
$qb->join('acp.scopes', 'acpscope'); $qb->leftJoin('acp.scopes', 'acpscope');
} }
$qb->addSelect('acpscope.id as scope_aggregator'); $qb->addSelect('acpscope.id as scope_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('scope_aggregator'); $qb->addGroupBy('scope_aggregator');
} else {
$qb->groupBy('scope_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -71,6 +64,10 @@ final class ScopeAggregator implements AggregatorInterface
return 'Scope'; return 'Scope';
} }
if (null === $value) {
return '';
}
$s = $this->scopeRepository->find($value); $s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -41,18 +41,12 @@ final class SocialActionAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpw', $qb->getAllAliases(), true)) { if (!in_array('acpw', $qb->getAllAliases(), true)) {
// here, we will only see accompanying period linked with a socialAction
$qb->join('acp.works', 'acpw'); $qb->join('acp.works', 'acpw');
} }
$qb->addSelect('IDENTITY(acpw.socialAction) AS socialaction_aggregator'); // DISTINCT ?? $qb->addSelect('IDENTITY(acpw.socialAction) AS socialaction_aggregator');
$groupby = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialaction_aggregator'); $qb->addGroupBy('socialaction_aggregator');
} else {
$qb->groupBy('socialaction_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -72,6 +66,10 @@ final class SocialActionAggregator implements AggregatorInterface
return 'Social action'; return 'Social action';
} }
if (null === $value) {
return '';
}
$sa = $this->actionRepository->find($value); $sa = $this->actionRepository->find($value);
return $this->actionRender->renderString($sa, []); return $this->actionRender->renderString($sa, []);

View File

@@ -40,18 +40,12 @@ final class SocialIssueAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpsocialissue', $qb->getAllAliases(), true)) { if (!in_array('acpsocialissue', $qb->getAllAliases(), true)) {
// we will see accompanying period linked with social issues
$qb->join('acp.socialIssues', 'acpsocialissue'); $qb->join('acp.socialIssues', 'acpsocialissue');
} }
$qb->addSelect('acpsocialissue.id as socialissue_aggregator'); $qb->addSelect('acpsocialissue.id as socialissue_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialissue_aggregator'); $qb->addGroupBy('socialissue_aggregator');
} else {
$qb->groupBy('socialissue_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -41,15 +41,9 @@ final class StepAggregator implements AggregatorInterface //, FilterInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->addSelect('acp.step AS step_aggregator'); $qb->addSelect('acp.step AS step_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('step_aggregator'); $qb->addGroupBy('step_aggregator');
} else {
$qb->groupBy('step_aggregator');
}
/*
// add date in where clause // add date in where clause
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@@ -69,6 +63,7 @@ final class StepAggregator implements AggregatorInterface //, FilterInterface
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('ondate', $data['on_date'], Types::DATE_MUTABLE); $qb->setParameter('ondate', $data['on_date'], Types::DATE_MUTABLE);
*/
} }
public function applyOn(): string public function applyOn(): string

View File

@@ -39,15 +39,8 @@ class EvaluationTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->addSelect('IDENTITY(eval.evaluation) AS evaluationtype_aggregator'); $qb->addSelect('IDENTITY(workeval.evaluation) AS eval_evaluationtype_aggregator');
$qb->addGroupBy('eval_evaluationtype_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('evaluationtype_aggregator');
} else {
$qb->groupBy('evaluationtype_aggregator');
}
} }
public function applyOn(): string public function applyOn(): string
@@ -67,6 +60,10 @@ class EvaluationTypeAggregator implements AggregatorInterface
return 'Evaluation type'; return 'Evaluation type';
} }
if (null === $value) {
return '';
}
$ev = $this->evaluationRepository->find($value); $ev = $this->evaluationRepository->find($value);
return $this->translatableStringHelper->localize($ev->getTitle()); return $this->translatableStringHelper->localize($ev->getTitle());
@@ -75,7 +72,7 @@ class EvaluationTypeAggregator implements AggregatorInterface
public function getQueryKeys($data): array public function getQueryKeys($data): array
{ {
return ['evaluationtype_aggregator']; return ['eval_evaluationtype_aggregator'];
} }
public function getTitle(): string public function getTitle(): string

View File

@@ -16,6 +16,7 @@ use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use DateTime; use DateTime;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@@ -39,39 +40,23 @@ class ChildrenNumberAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('composition', $qb->getAllAliases(), true)) { if (!in_array('composition_children', $qb->getAllAliases(), true)) {
$qb->join('household.compositions', 'composition');
}
$qb->addSelect('composition.numberOfChildren AS childrennumber_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('childrennumber_aggregator');
} else {
$qb->groupBy('childrennumber_aggregator');
}
// add date in where clause
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->andX( $clause = $qb->expr()->andX(
$qb->expr()->lte('composition.startDate', ':ondate'), $qb->expr()->lte('composition_children.startDate', ':ondate_composition_children'),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->gt('composition.endDate', ':ondate'), $qb->expr()->gt('composition_children.endDate', ':ondate_composition_children'),
$qb->expr()->isNull('composition.endDate') $qb->expr()->isNull('composition_children.endDate')
) )
); );
if ($where instanceof Andx) { $qb->leftJoin('household.compositions', 'composition_children', Expr\Join::WITH, $clause);
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb
$qb->setParameter('ondate', $data['on_date'], Types::DATE_MUTABLE); ->addSelect('composition_children.numberOfChildren AS childrennumber_aggregator')
->addGroupBy('childrennumber_aggregator');
$qb->setParameter('ondate_composition_children', $data['on_date'], Types::DATE_MUTABLE);
} }
public function applyOn(): string public function applyOn(): string
@@ -93,12 +78,11 @@ class ChildrenNumberAggregator implements AggregatorInterface
return 'Number of children'; return 'Number of children';
} }
return $this->translator->trans( if (null === $value) {
'household_composition.numberOfChildren children in household', return '';
[ }
'numberOfChildren' => $value,
] return $value;
);
}; };
} }

View File

@@ -18,6 +18,7 @@ use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepository; use Chill\PersonBundle\Repository\Household\HouseholdCompositionTypeRepository;
use DateTime; use DateTime;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@@ -44,39 +45,23 @@ class CompositionAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('composition', $qb->getAllAliases(), true)) { if (!in_array('composition_type', $qb->getAllAliases(), true)) {
$qb->join('household.compositions', 'composition');
}
$qb->addSelect('IDENTITY(composition.householdCompositionType) AS composition_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('composition_aggregator');
} else {
$qb->groupBy('composition_aggregator');
}
// add date in where clause
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->andX( $clause = $qb->expr()->andX(
$qb->expr()->lte('composition.startDate', ':ondate'), $qb->expr()->lte('composition_type.startDate', ':ondate_composition_type'),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->gt('composition.endDate', ':ondate'), $qb->expr()->gt('composition_type.endDate', ':ondate_composition_type'),
$qb->expr()->isNull('composition.endDate') $qb->expr()->isNull('composition_type.endDate')
) )
); );
if ($where instanceof Andx) { $qb->leftJoin('household.compositions', 'composition_type', Expr\Join::WITH, $clause);
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb
$qb->setParameter('ondate', $data['on_date'], Types::DATE_MUTABLE); ->addSelect('IDENTITY(composition_type.householdCompositionType) AS composition_aggregator')
->addGroupBy('composition_aggregator');
$qb->setParameter('ondate_composition_type', $data['on_date'], Types::DATE_MUTABLE);
} }
public function applyOn(): string public function applyOn(): string
@@ -98,6 +83,10 @@ class CompositionAggregator implements AggregatorInterface
return 'Composition'; return 'Composition';
} }
if (null === $value) {
return '';
}
$c = $this->typeRepository->find($value); $c = $this->typeRepository->find($value);
return $this->translatableStringHelper->localize( return $this->translatableStringHelper->localize(

View File

@@ -62,6 +62,9 @@ final class GenderAggregator implements AggregatorInterface
case Person::BOTH_GENDER: case Person::BOTH_GENDER:
return $this->translator->trans('both'); return $this->translator->trans('both');
case Person::NO_INFORMATION:
return $this->translator->trans('unknown');
case null: case null:
return $this->translator->trans('Not given'); return $this->translator->trans('Not given');

View File

@@ -16,8 +16,10 @@ use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Repository\Household\PositionRepository; use Chill\PersonBundle\Repository\Household\PositionRepository;
use DateTime; use DateTime;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -31,8 +33,11 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl
private TranslatorInterface $translator; private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, PositionRepository $positionRepository) public function __construct(
{ TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper,
PositionRepository $positionRepository
) {
$this->translator = $translator; $this->translator = $translator;
$this->positionRepository = $positionRepository; $this->positionRepository = $positionRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
@@ -45,28 +50,25 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$qb->resetDQLPart('from'); if (!in_array('householdmember', $qb->getAllAliases(), true)) {
$qb->from(HouseholdMember::class, 'member'); $qb->join(HouseholdMember::class, 'householdmember', Expr\Join::WITH, 'householdmember.person = person');
if (!in_array('memberperson', $qb->getAllAliases(), true)) {
$qb->join('member.person', 'memberperson');
} }
if (!in_array('membercenter', $qb->getAllAliases(), true)) { if (!in_array('center', $qb->getAllAliases(), true)) {
$qb->join('memberperson.center', 'membercenter'); $qb->join('person.center', 'center');
} }
$qb->andWhere($qb->expr()->andX( $qb->andWhere($qb->expr()->andX(
$qb->expr()->lte('member.startDate', ':date'), $qb->expr()->lte('householdmember.startDate', ':date'),
$qb->expr()->orX( $qb->expr()->orX(
$qb->expr()->isNull('member.endDate'), $qb->expr()->isNull('householdmember.endDate'),
$qb->expr()->gte('member.endDate', ':date') $qb->expr()->gte('householdmember.endDate', ':date')
) )
)); ));
$qb->setParameter('date', $data['date_position']); $qb->setParameter('date', $data['date_position']);
$qb->addSelect('IDENTITY(member.position) AS household_position_aggregator'); $qb->addSelect('IDENTITY(householdmember.position) AS household_position_aggregator');
$groupBy = $qb->getDQLPart('groupBy'); $groupBy = $qb->getDQLPart('groupBy');
@@ -79,7 +81,7 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl
public function applyOn() public function applyOn()
{ {
return 'person'; return Declarations::PERSON_TYPE;
} }
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)

View File

@@ -59,6 +59,7 @@ final class MaritalStatusAggregator implements AggregatorInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
// no form
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)

View File

@@ -40,18 +40,11 @@ final class ActionTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('acpwsocialaction', $qb->getAllAliases(), true)) { if (!in_array('acpwsocialaction', $qb->getAllAliases(), true)) {
$qb->join('acpw.socialAction', 'acpwsocialaction'); $qb->leftJoin('acpw.socialAction', 'acpwsocialaction');
} }
$qb->addSelect('acpwsocialaction.id as action_type_aggregator'); $qb->addSelect('acpwsocialaction.id as action_type_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('action_type_aggregator'); $qb->addGroupBy('action_type_aggregator');
} else {
$qb->groupBy('action_type_aggregator');
}
} }
public function applyOn() public function applyOn()
@@ -71,6 +64,10 @@ final class ActionTypeAggregator implements AggregatorInterface
return 'Social Action Type'; return 'Social Action Type';
} }
if (null === $value) {
return '';
}
$sa = $this->socialActionRepository->find($value); $sa = $this->socialActionRepository->find($value);
return $this->actionRender->renderString($sa, []); return $this->actionRender->renderString($sa, []);

View File

@@ -38,21 +38,14 @@ final class GoalAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
if (!in_array('goal', $qb->getAllAliases(), true)) { if (!in_array('goal', $qb->getAllAliases(), true)) {
$qb->join('acpw.goals', 'goal'); $qb->leftJoin('acpw.goals', 'goal');
} }
$qb->addSelect('goal.id as goal_aggregator'); $qb->addSelect('IDENTITY(goal.goal) as acpw_goal_aggregator');
$qb->addGroupBy('acpw_goal_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('goal_aggregator');
} else {
$qb->groupBy('goal_aggregator');
}
} }
public function applyOn() public function applyOn(): string
{ {
return Declarations::SOCIAL_WORK_ACTION_TYPE; return Declarations::SOCIAL_WORK_ACTION_TYPE;
} }
@@ -69,18 +62,24 @@ final class GoalAggregator implements AggregatorInterface
return 'Goal Type'; return 'Goal Type';
} }
if (null === $value) {
return '';
}
$g = $this->goalRepository->find($value); $g = $this->goalRepository->find($value);
return $this->translatableStringHelper->localize($g->getTitle()); return $this->translatableStringHelper->localize(
$g->getTitle()
);
}; };
} }
public function getQueryKeys($data) public function getQueryKeys($data): array
{ {
return ['goal_aggregator']; return ['acpw_goal_aggregator'];
} }
public function getTitle() public function getTitle(): string
{ {
return 'Group social work actions by goal'; return 'Group social work actions by goal';
} }

Some files were not shown because too many files have changed in this diff Show More