Merge branch '111_exports_suite' into calendar/finalization

This commit is contained in:
Julien Fastré 2022-10-05 15:28:37 +02:00
commit d95472ca9d
294 changed files with 10155 additions and 1612 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.composer/*
composer
composer.phar
composer.lock
docs/build/

View File

@ -11,6 +11,22 @@ and this project adheres to
## Unreleased
<!-- 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
### 2.0.0-beta2
* [workflow]: Fixed: the notification is sent when the user is added to the first step.
* [budget] Feature: allow to desactivate some charges and resources, adding an `active` key in the configuration
* [person] Feature: on Evaluation, allow to configure an URL from the admin
### 2022-06
* [workflow]: added pagination to workflow list page
* [homepage_widget]: null error on tasks widget fixed
* [person-thirdparty]: fix quick-add of names that consist of multiple parts (eg. De Vlieger) within onthefly modal person/thirdparty
@ -19,8 +35,6 @@ and this project adheres to
* [household]: Reposition and cut button for enfant hors menage have been deleted (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/620)
* [admin]: Add crud for composition type in admin (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/611)
## Test releases
### 2022-05-30
* fix creating a new AccompanyingPeriodWorkEvaluationDocument when replacing the document (the workflow was lost)

BIN
composer

Binary file not shown.

View File

@ -28,34 +28,42 @@ Requirements
- This project use `docker <https://docker.com>`_ to be run. As a developer, use `docker-compose <https://docs.docker.com/compose/overview/>`_ to bootstrap a dev environment in a glance. You do not need any other dependencies ;
- Make is used to automate scripts.
Installation in development mode
********************************
Installation
************
If you plan to run chill in production:
1. install it locally first, and check if everything is ok on your local machine;
2. once ready, build the image from your local machine, and deploy them.
If you want to develop some bundles, the first step is sufficient (until you deploy on production).
1. Get the code
===============
Clone or download the chill-app project and `cd` into the main directory.
Clone or download the chill-skeleton project and `cd` into the main directory.
.. code-block:: bash
git clone https://gitlab.com/Chill-Projet/chill-app.git
git clone https://gitlab.com/Chill-Projet/chill-skeleton-basic.git
cd chill-app
As a developer, the code will stay on your computer and will be executed in docker container. To avoid permission problem, the code should be run with the same uid/gid from your current user. This is why we get your current user id with the command ``id -u`` in each following scripts.
2. Prepare composer download of sources
=======================================
2. Prepare composer to download the sources
===========================================
As you are running in dev, you must configure an auth token for getting the source code.
As you are running in dev, you must configure an auth token for getting the source code.
.. warning
If you skip this part, the code will be downloaded from dist instead of source (with git repository). You will probably replace the source manually, but the next time you will run ```composer update```, your repository will be replaced and you might loose something.
1. Create a personal access token from https://gitlab.com/-/profile/personal_access_tokens, with the `read_api` scope.
2. add a file called ```.composer/auth.json```:
2. add a file called ```.composer/auth.json``` with this content:
.. code-block:: json
@ -68,13 +76,25 @@ As you are running in dev, you must configure an auth token for getting the sour
2. Prepare your variables and environment
=========================================
Copy ```docker-compose.override.dev.yml``` into ```docker-compose.override.yml```
Copy ```docker-compose.override.dev.yml``` into ```docker-compose.override.yml```
.. code-block:: bash
cp docker-compose.override.dev.template.yml docker-compose.override.yml
Configure your environment variables, by creating a .env.local file and override the desired variables.
2. Prepare your variables and docker-compose
============================================
Have a look at the variable in ``.env`` and check if you need to adapt them. If they do not adapt with your need, or if some are missing:
1. copy the file as ``.env.local``: ``cp .env .env.local``
2. you may replace some variables inside ``.env``
Prepare also you docker-compose installation, and adapt it to your needs:
1. If you plan to deploy on dev, copy the file ``docker-compose.override.dev.template.yml`` to ``docker-compose.override.yml``.
2. adapt to your needs.
**Note**: If you intend to use the bundle ``Chill-Doc-Store``, you will need to configure and install an openstack object storage container with temporary url middleware. You will have to configure `secret keys <https://docs.openstack.org/swift/latest/api/temporary_url_middleware.html#secret-keys>`_.
@ -90,10 +110,21 @@ This script can be run using `make`
This script will :
1. force docker-compose to, eventually, pull the base images and build the image used by this project ;
2. run an install script to download `composer <https://getcomposer.org>`_ ;
2. run an install script to download `composer <https://getcomposer.org>`_ ;
3. install the php dependencies
4. build assets
.. warning::
The script will work only if the binary ``docker-compose`` is located into your ``PATH``. If you use ``compose`` as a docker plugin,
you can simulate this binary by creating this file at (for instance), ``/usr/local/bin/docker-compose`` (and run ``chmod +x /usr/local/bin/docker-compose``):
.. code-block:: bash
#!/bin/bash
/usr/bin/docker compose "$@"
.. note::
@ -117,13 +148,20 @@ This script will :
.. code-block:: bash
make migrate
# mount into to container
./docker-php.sh
# and load fixtures
bin/console doctrine:migrations:migrate
Chill will be available at ``http://localhost:8001.`` Currently, there isn't any user or data. To add fixtures, run
.. code-block:: bash
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load --purge-with-truncate
# mount into to container
./docker-php.sh
# and load fixtures
bin/console doctrine:fixtures:load --purge-with-truncate
There are several users available:
@ -134,13 +172,14 @@ The password is always ``password``.
Now, read `Operations` below.
Operations
**********
Build assets
============
run those commands:
run those commands:
.. code-block:: bash
@ -152,8 +191,8 @@ How to execute the console ?
.. code-block:: bash
# if a container is running
docker-compose exec --user $(id -u) php bin/console
# if not
./docker-php.sh
# if not
docker-compose run --user $(id -u) php bin/console
How to create the database schema (= run migrations) ?
@ -162,8 +201,9 @@ How to create the database schema (= run migrations) ?
.. code-block:: bash
# if a container is running
docker-compose exec --user $(id -u) php bin/console doctrine:migrations:migrate
# if not
./docker-php.sh
bin/console doctrine:migrations:migrate
# if not
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
@ -180,8 +220,9 @@ How to load fixtures ? (development mode only)
.. code-block:: bash
# if a container is running
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load
# if not
./docker-php.sh
bin/console doctrine:fixtures:load
# if not
docker-compose run --user $(id -u) php bin/console doctrine:fixtures:load
How to open a terminal in the project
@ -190,8 +231,8 @@ How to open a terminal in the project
.. code-block:: bash
# if a container is running
docker-compose exec --user $(id -u) php /bin/bash
# if not
./docker-php.sh
# if not
docker-compose run --user $(id -u) php /bin/bash
How to run composer ?
@ -200,21 +241,22 @@ How to run composer ?
.. code-block:: bash
# if a container is running
docker-compose exec --user $(id -u) php ./composer.phar
# if not
docker-compose run --user $(id -u) php ./composer.phar
./docker-php.sh
composer
# if not
docker-compose run --user $(id -u) php composer
How to access to PGADMIN ?
==========================
Pgadmin is installed with docker-compose.
Pgadmin is installed with docker-compose, and is available **only if you uncomment the appropriate lines into ``docker-compose.override.yml``.
You can access it at ``http://localhost:8002``.
Credentials:
- login: admin@chill.social
- password: password
- login: from the variable you set into ``docker-composer.override.yml``
- password: same :-)
How to run tests ?
==================
@ -223,30 +265,48 @@ Tests reside inside the installed bundles. You must `cd` into that directory, do
**Note**: some bundle require the fixture to be executed. See the dedicated _how-tos_.
Exemple, for running test inside `main` bundle:
Exemple, for running test inside `main` bundle:
.. code-block:: bash
# mount into the php image
docker-compose run --user $(id -u) php /bin/bash
./docker-php.sh
# cd into main directory
cd vendor/chill-project/main
cd vendor/chill-project/chill-bundles
# download deps
php ../../../composer.phar install
git submodule init
git submodule update
composer install
# run tests
/vendor/bin/phpunit
bin/phpunit src/Bundle/path/to/your/test
How to run webpack interactively
================================
Executing :code:`bash docker-node.sh` will open a terminal in a node container, with volumes mounted.
Build the documentation API
===========================
How to switch the branch for chill-bundles, and get new dependencies
====================================================================
A basic configuration of `sami <https://github.com/FriendsOfPhp/Sami>`_ is embedded within the project.
During development, you will switch to new branches for chill-bundles. As long as the dependencies are equals, this does not cause any problem. But sometimes, a new branch introduces a new dependency, and you must download it.
A configuration file for `phpDocumentor <https://www.phpdoc.org>`_ is present.
.. warning::
Ensure that you have gitlab-token ready before updating your branches. See above.
In order to do that without pain, use those steps:
0. Ensuire you have a token, set
1. at the app's root, update the ``composer.json`` to your current branch:
.. code-block:: json
{
"require": {
"chill-bundles": "dev-<my-branch>@dev"
}
2. mount into the php container (``./docker-php.sh``), and run ``composer update``
Error `An exception has been thrown during the rendering of a template ("Asset manifest file "/var/www/app/web/build/manifest.json" does not exist.").` on first run
====================================================================================================================================================================
@ -260,8 +320,9 @@ Currently, to run this software in production, the *state of the art* is the fol
1. Run the software locally and tweak the configuration to your needs ;
2. Build the image and store them into a private container registry. This can be done using :code:`make build-and-push-image`.
To be sure to target the correct container registry, you have to adapt the values ``IMAGE_NGINX`` and ``IMAGE_PHP`` date in the ``.env`` file.
To be sure to target the correct container registry, you have to adapt the image names into your ``docker-compose.override.yml`` file.
3. Push the image on your registry, or upload them to the destination machine using ``docker image save`` and ``docker image load``.
3. Run the image on your production server, using docker-compose or eventually docker stack. You have to customize the variable set in docker-compose.
See also the :ref:`running-production-tips-and-tricks` below.
@ -293,7 +354,7 @@ It is worth having an eye on the configuration of logstash container.
Design principles
*****************
Why the DB URL is set in environment, and not in parameters.yml ?
Why the DB URL is also set in environment, and not in .env file ?
=================================================================
Because, at startup, a script does check the db is up and, if not, wait for a couple of seconds before running ``entrypoint.sh``. For avoiding double configuration, the configuration of the PHP app takes his configuration from environment also (and it will be standard in future releases, with symfony 4.0).

View File

@ -11,10 +11,10 @@ AccompanyingPeriod::class,,,acp
,User::class,acp.user,acpuser
AccompanyingPeriodWork::class,,,acpw
,AccompanyingPeriodWorkEvaluation::class,acpw.accompanyingPeriodWorkEvaluations,workeval
,Goal::class,acpw.goals,goal
,User::class,acpw.referrers,acpwuser
,Result::class,acpw.results,acpwresult
,SocialAction::class,acpw.socialAction,acpwsocialaction
,Goal::class,acpw.goals,goal
,Result::class,acpw.results,result
AccompanyingPeriodParticipation::class,,,acppart
,Person::class,acppart.person,partperson
AccompanyingPeriodWorkEvaluation::class,,,workeval
@ -23,23 +23,23 @@ Goal::class,,,goal
,Result::class,goal.results,goalresult
Person::class,,,person
,Center::class,person.center,center
,HouseholdMember::class,partperson.householdParticipations,member
,HouseholdMember::class,partperson.householdParticipations,householdmember
,MaritalStatus::class,person.maritalStatus,personmarital
,VendeePerson::class,,vp
,VendeePersonMineur::class,,vpm
ResidentialAddress::class,,,resaddr
,Person::class,resaddr.person,resaddrperson
,Center::class,resaddrperson.center,resaddrcenter
,ThirdParty::class,resaddr.hostThirdParty,tparty
ThirdParty::class,,,tparty
,ThirdPartyCategory::class,tparty.categories,tpartycat
HouseholdMember::class,,,member
,Household::class,member.household,household
,Person::class,member.person,memberperson
HouseholdMember::class,,,householdmember
,Household::class,householdmember.household,household
,Person::class,householdmember.person,memberperson
,,memberperson.center,membercenter
Household::class,,,household
,HouseholdComposition::class,household.compositions,composition
Activity::class,,,activity
,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
,ActivityReason::class,activity_person_having_activity.reasons,reasons_person_having_activity
,ActivityType::class,activity.activityType,acttype
@ -58,11 +58,6 @@ Calendar::class,,,cal
,Location::class,cal.location,calloc
,User::class,cal.user,caluser
VendeePerson::class,,,vp
,Person::class,vp.person,vpperson
,Center::class,vpperson.center,vpcenter
,SituationProfessionelle::class,vp.situationProfessionelle,vpprof
,StatutLogement::class,vp.statutLogement,vplog
,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

@ -5,72 +5,67 @@ Add condition with distinct alias on each export join clauses (Indicators + Filt
These are alias conventions :
| Entity | Join | Attribute | Alias |
| :--- | :--- |:-------------------------------------------|:----------------------------------|
| AccompanyingPeriod::class | | | acp |
| | AccompanyingPeriodWork::class | acp.works | acpw |
| | AccompanyingPeriodParticipation::class | acp.participations | acppart |
| | Location::class | acp.administrativeLocation | acploc |
| | ClosingMotive::class | acp.closingMotive | acpmotive |
| | UserJob::class | acp.job | acpjob |
| | Origin::class | acp.origin | acporigin |
| | Scope::class | acp.scopes | acpscope |
| | SocialIssue::class | acp.socialIssues | acpsocialissue |
| | User::class | acp.user | acpuser |
| AccompanyingPeriodWork::class | | | acpw |
| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval |
| | Goal::class | acpw.goals | goal |
| | User::class | acpw.referrers | acpwuser |
| | Result::class | acpw.results | acpwresult |
| | SocialAction::class | acpw.socialAction | acpwsocialaction |
| AccompanyingPeriodParticipation::class | | | acppart |
| | Person::class | acppart.person | partperson |
| AccompanyingPeriodWorkEvaluation::class | | | workeval |
| | Evaluation::class | workeval.evaluation | eval |
| Goal::class | | | goal |
| | Result::class | goal.results | goalresult |
| Person::class | | | person |
| | Center::class | person.center | center |
| | HouseholdMember::class | partperson.householdParticipations | member |
| | MaritalStatus::class | person.maritalStatus | personmarital |
| ResidentialAddress::class | | | resaddr |
| | Person::class | resaddr.person | resaddrperson |
| | Center::class | resaddrperson.center | resaddrcenter |
| | ThirdParty::class | resaddr.hostThirdParty | tparty |
| ThirdParty::class | | | tparty |
| | ThirdPartyCategory::class | tparty.categories | tpartycat |
| HouseholdMember::class | | | member |
| | Household::class | member.household | household |
| | Person::class | member.person | memberperson |
| | | memberperson.center | membercenter |
| Household::class | | | household |
| | HouseholdComposition::class | household.compositions | composition |
| Activity::class | | | activity |
| | Person::class | activity.person | actperson |
| | AccompanyingPeriod::class | activity.accompanyingPeriod | actacp |
| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity |
| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity |
| | ActivityType::class | activity.activityType | acttype |
| | Location::class | activity.location | actloc |
| | SocialAction::class | activity.socialActions | actsocialaction |
| | SocialIssue::class | activity.socialIssues | actsocialssue |
| | ThirdParty::class | activity.thirdParties | acttparty |
| | User::class | activity.user | actuser |
| | User::class | activity.users | actusers |
| | ActivityReason::class | activity.reasons | actreasons |
| | Center::class | actperson.center | actcenter |
| ActivityReason::class | | | actreasons |
| | ActivityReasonCategory::class | actreason.category | actreasoncat |
| Calendar::class | | | cal |
| | CancelReason::class | cal.cancelReason | calcancel |
| | Location::class | cal.location | calloc |
| | User::class | cal.user | caluser |
| VendeePerson::class | | | vp |
| | Person::class | vp.person | vpperson |
| | Center::class | vpperson.center | vpcenter |
| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof |
| | StatutLogement::class | vp.statutLogement | vplog |
| | TempsDeTravail::class | vp.tempsDeTravail | vptt |
| VendeePersonMineur::class | | | vpm |
| | Person::class | vpm.person | vpmperson |
| | Center::class | vpmperson.center | vpmcenter |
| Entity | Join | Attribute | Alias |
|:----------------------------------------|:----------------------------------------|:-------------------------------------------|:----------------------------------|
| AccompanyingPeriod::class | | | acp |
| | AccompanyingPeriodWork::class | acp.works | acpw |
| | AccompanyingPeriodParticipation::class | acp.participations | acppart |
| | Location::class | acp.administrativeLocation | acploc |
| | ClosingMotive::class | acp.closingMotive | acpmotive |
| | UserJob::class | acp.job | acpjob |
| | Origin::class | acp.origin | acporigin |
| | Scope::class | acp.scopes | acpscope |
| | SocialIssue::class | acp.socialIssues | acpsocialissue |
| | User::class | acp.user | acpuser |
| AccompanyingPeriodWork::class | | | acpw |
| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval |
| | User::class | acpw.referrers | acpwuser |
| | SocialAction::class | acpw.socialAction | acpwsocialaction |
| | Goal::class | acpw.goals | goal |
| | Result::class | acpw.results | result |
| AccompanyingPeriodParticipation::class | | | acppart |
| | Person::class | acppart.person | partperson |
| AccompanyingPeriodWorkEvaluation::class | | | workeval |
| | Evaluation::class | workeval.evaluation | eval |
| Goal::class | | | goal |
| | Result::class | goal.results | goalresult |
| Person::class | | | person |
| | Center::class | person.center | center |
| | HouseholdMember::class | partperson.householdParticipations | householdmember |
| | MaritalStatus::class | person.maritalStatus | personmarital |
| | VendeePerson::class | | vp |
| | VendeePersonMineur::class | | vpm |
| ResidentialAddress::class | | | resaddr |
| | ThirdParty::class | resaddr.hostThirdParty | tparty |
| ThirdParty::class | | | tparty |
| | ThirdPartyCategory::class | tparty.categories | tpartycat |
| HouseholdMember::class | | | householdmember |
| | Household::class | householdmember.household | household |
| | Person::class | householdmember.person | memberperson |
| | | memberperson.center | membercenter |
| Household::class | | | household |
| | HouseholdComposition::class | household.compositions | composition |
| Activity::class | | | activity |
| | Person::class | activity.person | actperson |
| | AccompanyingPeriod::class | activity.accompanyingPeriod | acp |
| | Person::class | activity\_person\_having\_activity.person | person\_person\_having\_activity |
| | ActivityReason::class | activity\_person\_having\_activity.reasons | reasons\_person\_having\_activity |
| | ActivityType::class | activity.activityType | acttype |
| | Location::class | activity.location | actloc |
| | SocialAction::class | activity.socialActions | actsocialaction |
| | SocialIssue::class | activity.socialIssues | actsocialssue |
| | ThirdParty::class | activity.thirdParties | acttparty |
| | User::class | activity.user | actuser |
| | User::class | activity.users | actusers |
| | ActivityReason::class | activity.reasons | actreasons |
| | Center::class | actperson.center | actcenter |
| ActivityReason::class | | | actreasons |
| | ActivityReasonCategory::class | actreason.category | actreasoncat |
| Calendar::class | | | cal |
| | CancelReason::class | cal.cancelReason | calcancel |
| | Location::class | cal.location | calloc |
| | User::class | cal.user | caluser |
| VendeePerson::class | | | vp |
| | SituationProfessionelle::class | vp.situationProfessionelle | vpprof |
| | StatutLogement::class | vp.statutLogement | vplog |
| | TempsDeTravail::class | vp.tempsDeTravail | vptt |

View File

@ -17,7 +17,7 @@ use Chill\ActivityBundle\Form\ActivityType;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Repository\LocationRepository;
@ -55,7 +55,7 @@ final class ActivityController extends AbstractController
private ActivityTypeCategoryRepository $activityTypeCategoryRepository;
private ActivityTypeRepository $activityTypeRepository;
private ActivityTypeRepositoryInterface $activityTypeRepository;
private CenterResolverManagerInterface $centerResolver;
@ -77,7 +77,7 @@ final class ActivityController extends AbstractController
public function __construct(
ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
ActivityTypeRepository $activityTypeRepository,
ActivityTypeRepositoryInterface $activityTypeRepository,
ActivityTypeCategoryRepository $activityTypeCategoryRepository,
PersonRepository $personRepository,
ThirdPartyRepository $thirdPartyRepository,

View File

@ -516,6 +516,11 @@ class ActivityType
return $this->userVisible;
}
public function hasCategory(): bool
{
return null !== $this->getCategory();
}
/**
* 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)
{
if (!in_array('actsocialaction', $qb->getAllAliases(), true)) {
$qb->join('activity.socialActions', 'actsocialaction');
$qb->leftJoin('activity.socialActions', 'actsocialaction');
}
$qb->addSelect('actsocialaction.id AS socialaction_aggregator');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('socialaction_aggregator');
} else {
$qb->groupBy('socialaction_aggregator');
}
$qb->addGroupBy('socialaction_aggregator');
}
public function applyOn(): string
@ -72,6 +65,10 @@ class BySocialActionAggregator implements AggregatorInterface
return 'Social action';
}
if (null === $value) {
return '';
}
$sa = $this->actionRepository->find($value);
return $this->actionRender->renderString($sa, []);

View File

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

View File

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

View File

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

View File

@ -13,7 +13,6 @@ namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use DateTime;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
@ -49,41 +48,27 @@ class DateAggregator implements AggregatorInterface
switch ($data['frequency']) {
case 'month':
$fmt = 'MM';
$fmt = 'YYYY-MM';
break;
break;
case 'week':
$fmt = 'IW';
$fmt = 'YYYY-IW';
break;
break;
case 'year':
$fmt = 'YYYY'; $order = 'DESC';
break; // order DESC does not works !
break; // order DESC does not works !
default:
throw new RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
}
$qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt));
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('date_aggregator');
} else {
$qb->groupBy('date_aggregator');
}
$orderBy = $qb->getDQLPart('orderBy');
if (!empty($orderBy)) {
$qb->addOrderBy('date_aggregator', $order);
} else {
$qb->orderBy('date_aggregator', $order);
}
$qb->addGroupBy('date_aggregator');
$qb->addOrderBy('date_aggregator', $order);
}
public function applyOn(): string
@ -109,16 +94,12 @@ break; // order DESC does not works !
return 'by ' . $data['frequency'];
}
if (null === $value) {
return '';
}
switch ($data['frequency']) {
case 'month':
$month = DateTime::createFromFormat('!m', $value);
return sprintf(
'%02d (%s)',
$value,
$month->format('M')
);
case 'week':
//return $this->translator->trans('for week') .' '. $value ;

View File

@ -41,18 +41,11 @@ class LocationTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
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');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('locationtype_aggregator');
} else {
$qb->groupBy('locationtype_aggregator');
}
$qb->addGroupBy('locationtype_aggregator');
}
public function applyOn(): string
@ -72,6 +65,10 @@ class LocationTypeAggregator implements AggregatorInterface
return 'Accepted locationtype';
}
if (null === $value) {
return '';
}
$lt = $this->locationTypeRepository->find($value);
return $this->translatableStringHelper->localize(

View File

@ -41,18 +41,11 @@ class UserScopeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
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');
$groupBy = $qb->getDQLPart('groupBy');
if (!empty($groupBy)) {
$qb->addGroupBy('userscope_aggregator');
} else {
$qb->groupBy('userscope_aggregator');
}
$qb->addGroupBy('userscope_aggregator');
}
public function applyOn(): string
@ -72,6 +65,10 @@ class UserScopeAggregator implements AggregatorInterface
return 'Scope';
}
if (null === $value) {
return '';
}
$s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize(

View File

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

View File

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

View File

@ -25,8 +25,8 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function array_key_exists;
use function count;
use function in_array;
class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface
{
@ -55,10 +55,10 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
{
// add select element
if ('reasons' === $data['level']) {
$elem = 'reasons.id';
$elem = 'actreasons.id';
$alias = 'activity_reasons_id';
} elseif ('categories' === $data['level']) {
$elem = 'category.id';
$elem = 'actreasoncat.id';
$alias = 'activity_categories_id';
} else {
throw new RuntimeException('The data provided are not recognized.');
@ -67,7 +67,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
$qb->addSelect($elem . ' as ' . $alias);
// make a jointure only if needed
if (!in_array( 'actreasons', $qb->getAllAliases(), true)) {
if (!in_array('actreasons', $qb->getAllAliases(), true)) {
$qb->innerJoin('activity.reasons', 'actreasons');
}

View File

@ -17,9 +17,13 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
class AvgActivityDuration implements ExportInterface, GroupedExportInterface
@ -34,7 +38,6 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getAllowedFormattersTypes(): array
@ -83,10 +86,27 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'actacp');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb->select('AVG(activity.durationTime) as export_avg_activity_duration');
$qb = $this->repository->createQueryBuilder('activity');
$qb
->join('activity.accompanyingPeriod', 'acp')
->select('AVG(activity.durationTime) as export_avg_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
return $qb;
}
@ -101,7 +121,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
PersonDeclarations::ACP_TYPE,
];
}
}

View File

@ -17,9 +17,13 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterface
@ -83,10 +87,27 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'actacp');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb->select('AVG(activity.travelTime) as export_avg_activity_visit_duration');
$qb = $this->repository->createQueryBuilder('activity');
$qb
->join('activity.accompanyingPeriod', 'acp')
->select('AVG(activity.travelTime) as export_avg_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
return $qb;
}
@ -101,7 +122,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
PersonDeclarations::ACP_TYPE,
];
}
}

View File

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

View File

@ -17,9 +17,13 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
class SumActivityDuration implements ExportInterface, GroupedExportInterface
@ -83,13 +87,27 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('actacp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp');
}
$qb = $this->repository
->createQueryBuilder('activity')
->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'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
return $qb;
}
@ -104,7 +122,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
PersonDeclarations::ACP_TYPE,
];
}
}

View File

@ -17,9 +17,13 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
class SumActivityVisitDuration implements ExportInterface, GroupedExportInterface
@ -83,13 +87,27 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->repository->createQueryBuilder('activity');
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
if (!in_array('actacp', $qb->getAllAliases(), true)) {
$qb->join('activity.accompanyingPeriod', 'actacp');
}
$qb = $this->repository
->createQueryBuilder('activity')
->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'));
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
return $qb;
}
@ -104,7 +122,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_ACP,
//PersonDeclarations::ACP_TYPE,
PersonDeclarations::ACP_TYPE,
];
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -13,12 +13,10 @@ namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
@ -28,13 +26,13 @@ use function count;
class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInterface
{
protected ActivityTypeRepository $activityTypeRepository;
protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
TranslatableStringHelperInterface $translatableStringHelper,
ActivityTypeRepository $activityTypeRepository
ActivityTypeRepositoryInterface $activityTypeRepository
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->activityTypeRepository = $activityTypeRepository;
@ -47,16 +45,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->andWhere($clause);
$qb->setParameter('selected_activity_types', $data['types']);
}
@ -68,11 +59,26 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('types', EntityType::class, [
'choices' => $this->activityTypeRepository->findAllActive(),
'class' => ActivityType::class,
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
'group_by' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getCategory()->getName()),
'choice_label' => function (ActivityType $aty) {
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,
'expanded' => false,
'attr' => [
'class' => 'select2',
],
]);
}

View File

@ -19,14 +19,13 @@ use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function array_key_exists;
use function count;
use function in_array;
class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInterface
{

View File

@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
@ -59,10 +60,10 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
public function alterQuery(QueryBuilder $qb, $data)
{
// create a query for activity
// create a subquery for activity
$sqb = $qb->getEntityManager()->createQueryBuilder();
$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');
// add clause between date
@ -197,7 +198,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
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)

View File

@ -12,48 +12,33 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TranslatableActivityType extends AbstractType
{
protected ActivityTypeRepository $activityTypeRepository;
protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
TranslatableStringHelperInterface $helper,
ActivityTypeRepository $activityTypeRepository
ActivityTypeRepositoryInterface $activityTypeRepository
) {
$this->translatableStringHelper = $helper;
$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)
{
$resolver->setDefaults(
[
'class' => ActivityType::class,
'active_only' => true,
'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'),
'choices' => $this->activityTypeRepository->findAllActive(),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
},

View File

@ -12,19 +12,54 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
/**
* @method ActivityType|null find($id, $lockMode = null, $lockVersion = null)
* @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
final class ActivityTypeRepository implements ActivityTypeRepositoryInterface
{
public function __construct(ManagerRegistry $registry)
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
parent::__construct($registry, ActivityType::class);
$this->repository = $em->getRepository(ActivityType::class);
}
public function find($id): ?ActivityType
{
return $this->repository->find($id);
}
/**
* @return array|ActivityType[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @return array|ActivityType[]
*/
public function findAllActive(): array
{
return $this->findBy(['active' => true]);
}
/**
* @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,23 @@
<?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\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\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 function in_array;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{
@ -24,14 +24,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
public const STATS = 'CHILL_ACTIVITY_STATS';
/**
* @var AuthorizationHelper
*/
protected $helper;
protected VoterHelperInterface $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
@ -49,30 +49,14 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
return $this->getAttributes();
}
protected function getSupportedClasses()
{
return [Center::class];
}
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)
{
if (
$subject instanceof Center
&& in_array($attribute, $this->getAttributes(), true)
) {
return true;
}
return $this->helper->supports($attribute, $subject);
}
return false;
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
return $this->helper->voteOnAttribute($attribute, $subject, $token);
}
private function getAttributes()

View File

@ -0,0 +1,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,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\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Aggregator\ACPAggregators\DateAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
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,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,62 @@
<?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;
/**
* @internal
* @coversNothing
*/
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,7 +11,10 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* Add tests for ActivityTypeAggregator.
@ -21,26 +24,22 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
*/
final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
{
/**
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/
private $aggregator;
use ProphecyTrait;
private ActivityTypeAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$container = self::$kernel->getContainer();
$this->aggregator = self::$container->get('chill.activity.export.type_aggregator');
$this->aggregator = $container->get('chill.activity.export.type_aggregator');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}
@ -62,8 +61,7 @@ final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
self::bootKernel();
}
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
@ -72,12 +70,7 @@ final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons'),
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons')
->join('reasons.category', 'category'),
->join('activity.activityType', 'acttype'),
];
}
}

View File

@ -11,7 +11,10 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
use Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* Add tests for ActivityUsernAggregator.
@ -21,26 +24,22 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
*/
final class ActivityUserAggregatorTest extends AbstractAggregatorTest
{
/**
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
*/
private $aggregator;
use ProphecyTrait;
private ActivityUserAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$container = self::$kernel->getContainer();
$this->aggregator = self::$container->get('chill.activity.export.user_aggregator');
$this->aggregator = $container->get('chill.activity.export.user_aggregator');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}
@ -49,35 +48,25 @@ final class ActivityUserAggregatorTest extends AbstractAggregatorTest
return $this->aggregator;
}
public function getFormData()
public function getFormData(): array
{
return [
[],
];
}
public function getQueryBuilders()
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity'),
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons'),
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons')
->join('reasons.category', 'category'),
];
}
}

View File

@ -9,38 +9,35 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
namespace Chill\ActivityBundle\Tests\Export\Aggregator\PersonAggregators;
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* Add tests for ActivityReasonAggregator.
*
* @internal
* @coversNothing
*/
final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
{
/**
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/
private $aggregator;
use ProphecyTrait;
private ActivityReasonAggregator $aggregator;
protected function setUp(): void
{
self::bootKernel();
$container = self::$kernel->getContainer();
$this->aggregator = self::$container->get('chill.activity.export.reason_aggregator');
$this->aggregator = $container->get('chill.activity.export.reason_aggregator');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}
@ -49,7 +46,7 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
return $this->aggregator;
}
public function getFormData()
public function getFormData(): array
{
return [
['level' => 'reasons'],
@ -57,14 +54,13 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
];
}
public function getQueryBuilders()
public function getQueryBuilders(): array
{
if (null === self::$kernel) {
self::bootKernel();
}
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$em = self::$container->get(EntityManagerInterface::class);
return [
$em->createQueryBuilder()
@ -73,12 +69,12 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons'),
->join('activity.reasons', 'actreasons'),
$em->createQueryBuilder()
->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons')
->join('reasons.category', 'category'),
->join('activity.reasons', 'actreasons')
->join('actreasons.category', 'actreasoncat'),
];
}
}

View File

@ -0,0 +1,51 @@
<?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\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityDuration;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
* @coversNothing
*/
final class AvgActivityDurationTest extends AbstractExportTest
{
private AvgActivityDuration $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get('chill.activity.export.avg_activity_duration_linked_to_acp');
}
public function getExport()
{
return $this->export;
}
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination(): array
{
return [
['activity'],
['activity', 'accompanying_period'],
];
}
}

View File

@ -0,0 +1,51 @@
<?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\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityVisitDuration;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
* @coversNothing
*/
final class AvgActivityVisitDurationTest extends AbstractExportTest
{
private AvgActivityVisitDuration $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get('chill.activity.export.avg_activity_visit_duration_linked_to_acp');
}
public function getExport()
{
return $this->export;
}
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination(): array
{
return [
['activity'],
['activity', 'accompanying_period'],
];
}
}

View File

@ -0,0 +1,51 @@
<?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\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
* @coversNothing
*/
final class CountActivityTest extends AbstractExportTest
{
private CountActivity $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get('chill.activity.export.count_activity_linked_to_acp');
}
public function getExport()
{
return $this->export;
}
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination(): array
{
return [
['activity'],
['activity', 'accompanying_period'],
];
}
}

View File

@ -0,0 +1,51 @@
<?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\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityDuration;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
* @coversNothing
*/
final class SumActivityDurationTest extends AbstractExportTest
{
private SumActivityDuration $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get('chill.activity.export.sum_activity_duration_linked_to_acp');
}
public function getExport()
{
return $this->export;
}
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination(): array
{
return [
['activity'],
['activity', 'accompanying_period'],
];
}
}

View File

@ -0,0 +1,51 @@
<?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\Export\LinkedToACP;
use Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityVisitDuration;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
* @internal
* @coversNothing
*/
final class SumActivityVisitDurationTest extends AbstractExportTest
{
private SumActivityVisitDuration $export;
protected function setUp(): void
{
self::bootKernel();
$this->export = self::$container->get('chill.activity.export.sum_activity_visit_duration_linked_to_acp');
}
public function getExport()
{
return $this->export;
}
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination(): array
{
return [
['activity'],
['activity', 'accompanying_period'],
];
}
}

View File

@ -9,8 +9,9 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export;
namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Export\Export\LinkedToPerson\CountActivity;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
@ -19,19 +20,13 @@ use Chill\MainBundle\Test\Export\AbstractExportTest;
*/
final class CountActivityTest extends AbstractExportTest
{
/**
* @var
*/
private $export;
private CountActivity $export;
protected function setUp(): void
{
self::bootKernel();
/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer();
$this->export = $container->get('chill.activity.export.count_activity');
$this->export = self::$container->get('chill.activity.export.count_activity_linked_to_person');
}
public function getExport()
@ -39,14 +34,14 @@ final class CountActivityTest extends AbstractExportTest
return $this->export;
}
public function getFormData()
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination()
public function getModifiersCombination(): array
{
return [
['activity'],

View File

@ -9,9 +9,11 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export;
namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Export\Export\LinkedToPerson\ListActivity;
use Chill\MainBundle\Test\Export\AbstractExportTest;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* @internal
@ -19,27 +21,22 @@ use Chill\MainBundle\Test\Export\AbstractExportTest;
*/
final class ListActivityTest extends AbstractExportTest
{
/**
* @var \Chill\ActivityBundle\Export\Export\ListActivity
*/
private $export;
use ProphecyTrait;
private ListActivity $export;
protected function setUp(): void
{
self::bootKernel();
/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer();
$this->export = self::$container->get('chill.activity.export.list_activity_linked_to_person');
$this->export = $container->get('chill.activity.export.list_activity');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}

View File

@ -9,8 +9,9 @@
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export;
namespace Chill\ActivityBundle\Tests\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Export\Export\LinkedToPerson\StatActivityDuration;
use Chill\MainBundle\Test\Export\AbstractExportTest;
/**
@ -19,21 +20,15 @@ use Chill\MainBundle\Test\Export\AbstractExportTest;
* @internal
* @coversNothing
*/
final class StatActivityDurationSumTest extends AbstractExportTest
final class StatActivityDurationTest extends AbstractExportTest
{
/**
* @var \Chill\ActivityBundle\Export\Export\StatActivityDuration
*/
private $export;
private StatActivityDuration $export;
protected function setUp(): void
{
self::bootKernel();
/** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer();
$this->export = $container->get('chill.activity.export.sum_activity_duration');
$this->export = self::$container->get('chill.activity.export.sum_activity_duration_linked_to_person');
}
public function getExport()
@ -41,14 +36,14 @@ final class StatActivityDurationSumTest extends AbstractExportTest
return $this->export;
}
public function getFormData()
public function getFormData(): array
{
return [
[],
];
}
public function getModifiersCombination()
public function getModifiersCombination(): array
{
return [
['activity'],

View File

@ -9,13 +9,15 @@
declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Export\Filter\AccompanyingCourseFilters;
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\Export\Filter\AccompanyingCourseFilters\ActivityTypeFilter;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\Query\Expr;
/**
* @internal
@ -27,16 +29,9 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
protected function setUp(): void
{
//parent::setUp();
self::bootKernel();
// add a fake request with a default locale (used in translatable string)
$request = $this->prophesize();
$request->willExtend(Request::class);
$request->getLocale()->willReturn('fr');
$this->filter = self::$container->get('chill.person.export.filter_activitytype');
$this->filter = self::$container->get('chill.activity.export.filter_activitytype');
}
public function getFilter()
@ -56,8 +51,10 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
$data = [];
foreach ($array as $t) {
$data[] = ['accepted_activitytypes' => $t];
foreach ($array as $a) {
$data[] = [
'accepted_activitytypes' => $a,
];
}
return $data;
@ -73,8 +70,10 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
return [
$em->createQueryBuilder()
->from('ChillPersonBundle:AccompanyingPeriod', 'acp')
->select('acp.id'),
->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,76 @@
<?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();
$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,76 @@
<?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();
$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,76 @@
<?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();
$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,61 @@
<?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();
$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,76 @@
<?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();
$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,61 @@
<?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();
$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,75 @@
<?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();
$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,76 @@
<?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();
$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,64 @@
<?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 DateTime;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class ActivityDateFilterTest extends AbstractFilterTest
{
private ActivityDateFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$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,8 +11,10 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Filter;
use Chill\ActivityBundle\Export\Filter\PersonFilters\ActivityReasonFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\Common\Collections\ArrayCollection;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* @internal
@ -20,26 +22,22 @@ use Doctrine\Common\Collections\ArrayCollection;
*/
final class ActivityReasonFilterTest extends AbstractFilterTest
{
/**
* @var \Chill\PersonBundle\Export\Filter\GenderFilter
*/
private $filter;
use ProphecyTrait;
private ActivityReasonFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$container = self::$kernel->getContainer();
$this->filter = self::$container->get('chill.activity.export.reason_filter');
$this->filter = $container->get('chill.activity.export.reason_filter');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}

View File

@ -0,0 +1,75 @@
<?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\Entity\ActivityType;
use Chill\ActivityBundle\Export\Filter\ActivityTypeFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class ActivityTypeFilterTest extends AbstractFilterTest
{
private ActivityTypeFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$this->filter = self::$container->get('chill.activity.export.type_filter');
}
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[] = [
'types' => $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,76 @@
<?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();
$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,78 @@
<?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 DateTime;
use Doctrine\ORM\EntityManagerInterface;
/**
* @internal
* @coversNothing
*/
final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
{
private PersonHavingActivityBetweenDateFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$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;
use Chill\ActivityBundle\Export\Filter\PersonFilters\PersonHavingActivityBetweenDateFilter;
use Chill\MainBundle\Test\Export\AbstractFilterTest;
use DateTime;
use function array_slice;
@ -21,27 +22,20 @@ use function array_slice;
*/
final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
{
/**
* @var \Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
*/
private $filter;
private PersonHavingActivityBetweenDateFilter $filter;
protected function setUp(): void
{
self::bootKernel();
$container = self::$kernel->getContainer();
$this->filter = self::$container->get('chill.activity.export.person_having_an_activity_between_date_filter');
$this->filter = $container->get('chill.activity.export.'
. 'person_having_an_activity_between_date_filter');
$request = $this->prophesize()
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
// add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
$container->get('request_stack')
self::$container->get('request_stack')
->push($request->reveal());
}

View File

@ -67,6 +67,11 @@ services:
name: chill.export_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:
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter
tags:

View File

@ -29,44 +29,58 @@ class ConfigRepository
$this->charges = $charges;
}
public function getChargesKeys(): array
public function getChargesKeys(bool $onlyActive = false): array
{
return array_map(static function ($element) { return $element['key']; }, $this->charges);
return array_map(static function ($element) { return $element['key']; }, $this->getCharges($onlyActive));
}
/**
* @return array where keys are the resource'key and label the ressource label
*/
public function getChargesLabels()
public function getChargesLabels(bool $onlyActive = false)
{
$charges = [];
foreach ($this->charges as $definition) {
foreach ($this->getCharges($onlyActive) as $definition) {
$charges[$definition['key']] = $this->normalizeLabel($definition['labels']);
}
return $charges;
}
public function getResourcesKeys(): array
public function getResourcesKeys(bool $onlyActive = false): array
{
return array_map(static function ($element) { return $element['key']; }, $this->resources);
return array_map(static function ($element) { return $element['key']; }, $this->getResources($onlyActive));
}
/**
* @return array where keys are the resource'key and label the ressource label
*/
public function getResourcesLabels()
public function getResourcesLabels(bool $onlyActive = false)
{
$resources = [];
foreach ($this->resources as $definition) {
foreach ($this->getResources($onlyActive) as $definition) {
$resources[$definition['key']] = $this->normalizeLabel($definition['labels']);
}
return $resources;
}
private function getCharges(bool $onlyActive = false): array
{
return $onlyActive ?
array_filter($this->charges, static function ($el) { return $el['active']; })
: $this->charges;
}
private function getResources(bool $onlyActive = false): array
{
return $onlyActive ?
array_filter($this->resources, static function ($el) { return $el['active']; })
: $this->resources;
}
private function normalizeLabel($labels)
{
$normalizedLabels = [];

View File

@ -14,11 +14,6 @@ namespace Chill\BudgetBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files.
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
@ -37,6 +32,7 @@ class Configuration implements ConfigurationInterface
->info('the key stored in database')
->example('salary')
->end()
->booleanNode('active')->defaultTrue()->end()
->arrayNode('labels')->isRequired()->requiresAtLeastOneElement()
->arrayPrototype()
->children()
@ -59,6 +55,7 @@ class Configuration implements ConfigurationInterface
->info('the key stored in database')
->example('salary')
->end()
->booleanNode('active')->defaultTrue()->end()
->arrayNode('labels')->isRequired()->requiresAtLeastOneElement()
->arrayPrototype()
->children()

View File

@ -103,7 +103,7 @@ class ChargeType extends AbstractType
private function getTypes()
{
$charges = $this->configRepository
->getChargesLabels();
->getChargesLabels(true);
// rewrite labels to filter in language
foreach ($charges as $key => $labels) {

View File

@ -87,7 +87,7 @@ class ResourceType extends AbstractType
private function getTypes()
{
$resources = $this->configRepository
->getResourcesLabels();
->getResourcesLabels(true);
// rewrite labels to filter in language
foreach ($resources as $key => $labels) {

View File

@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\Entity\UserRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
final class AgentAggregator implements AggregatorInterface
{

View File

@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class CancelReasonAggregator implements AggregatorInterface
{

View File

@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
final class JobAggregator implements AggregatorInterface
{

View File

@ -17,7 +17,7 @@ use Chill\MainBundle\Repository\LocationRepository;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use function in_array;
final class LocationAggregator implements AggregatorInterface
{

View File

@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
final class LocationTypeAggregator implements AggregatorInterface
{

View File

@ -16,7 +16,6 @@ use Chill\MainBundle\Export\AggregatorInterface;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class MonthYearAggregator implements AggregatorInterface
{

View File

@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
final class ScopeAggregator implements AggregatorInterface
{

View File

@ -20,6 +20,7 @@ use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function in_array;
class JobFilter implements FilterInterface
{

View File

@ -20,6 +20,7 @@ use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function in_array;
class ScopeFilter implements FilterInterface
{

View File

@ -41,11 +41,13 @@ class PersonDocumentType extends AbstractType
public function __construct(
TranslatableStringHelperInterface $translatableStringHelper,
ScopeResolverDispatcher $scopeResolverDispatcher,
ParameterBagInterface $parameterBag
ParameterBagInterface $parameterBag,
CenterResolverDispatcher $centerResolverDispatcher
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->scopeResolverDispatcher = $scopeResolverDispatcher;
$this->parameterBag = $parameterBag;
$this->centerResolverDispatcher = $centerResolverDispatcher;
}
public function buildForm(FormBuilderInterface $builder, array $options)

View File

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

View File

@ -0,0 +1,52 @@
<?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\MainBundle\Command;
use Chill\MainBundle\Service\Import\AddressReferenceBEFromBestAddress;
use Chill\MainBundle\Service\Import\PostalCodeBEFromBestAddress;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LoadAddressesBEFromBestAddressCommand extends Command
{
private AddressReferenceBEFromBestAddress $addressImporter;
private PostalCodeBEFromBestAddress $postalCodeBEFromBestAddressImporter;
public function __construct(
AddressReferenceBEFromBestAddress $addressImporter,
PostalCodeBEFromBestAddress $postalCodeBEFromBestAddressImporter
) {
parent::__construct();
$this->addressImporter = $addressImporter;
$this->postalCodeBEFromBestAddressImporter = $postalCodeBEFromBestAddressImporter;
}
protected function configure()
{
$this
->setName('chill:main:address-ref-from-best-addresses')
->addArgument('lang', InputArgument::REQUIRED)
->addArgument('list', InputArgument::IS_ARRAY, 'The list to add');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->postalCodeBEFromBestAddressImporter->import();
$this->addressImporter->import($input->getArgument('lang'), $input->getArgument('list'));
return 0;
}
}

View File

@ -0,0 +1,47 @@
<?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\MainBundle\Command;
use Chill\MainBundle\Service\Import\AddressReferenceFromBano;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LoadAddressesFRFromBANOCommand extends Command
{
private AddressReferenceFromBano $addressReferenceFromBano;
public function __construct(AddressReferenceFromBano $addressReferenceFromBano)
{
parent::__construct();
$this->addressReferenceFromBano = $addressReferenceFromBano;
}
protected function configure()
{
$this->setName('chill:main:address-ref-from-bano')
->addArgument('departementNo', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'a list of departement numbers')
->setDescription('Import addresses from bano (see https://bano.openstreetmap.fr');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
foreach ($input->getArgument('departementNo') as $departementNo) {
$output->writeln('Import addresses for ' . $departementNo);
$this->addressReferenceFromBano->import($departementNo);
}
return 0;
}
}

View File

@ -0,0 +1,42 @@
<?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\MainBundle\Command;
use Chill\MainBundle\Service\Import\PostalCodeFRFromOpenData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class LoadPostalCodeFR extends Command
{
private PostalCodeFRFromOpenData $loader;
public function __construct(PostalCodeFRFromOpenData $loader)
{
$this->loader = $loader;
parent::__construct();
}
public function configure(): void
{
$this->setName('chill:main:postal-code:load:FR')
->setDescription('Load France\'s postal code from online open data');
}
public function execute(InputInterface $input, OutputInterface $output): int
{
$this->loader->import();
return 0;
}
}

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\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@ -142,10 +143,8 @@ class ExportController extends AbstractController
/**
* Render the list of available exports.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
public function indexAction(): Response
{
$exportManager = $this->exportManager;
@ -443,6 +442,12 @@ class ExportController extends AbstractController
}
$rawData = unserialize($serialized);
$this->logger->notice('[export] choices for an export unserialized', [
'key' => $key,
'rawData' => json_encode($rawData),
]);
$alias = $rawData['alias'];
$formCenters = $this->createCreateFormExport($alias, 'generate_centers');

View File

@ -318,19 +318,12 @@ class WorkflowController extends AbstractController
);
}
// TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context)
$entityWorkflow->futureDestUsers = $transitionForm['future_dest_users']->getData();
$entityWorkflow->futureDestEmails = $transitionForm['future_dest_emails']->getData();
$workflow->apply($entityWorkflow, $transition);
foreach ($transitionForm['future_dest_users']->getData() as $user) {
$entityWorkflow->getCurrentStep()->addDestUser($user);
}
foreach ($transitionForm['future_dest_emails']->getData() as $email) {
$entityWorkflow->getCurrentStep()->addDestEmail($email);
}
$this->entityManager->flush();
return $this->redirectToRoute('chill_main_workflow_show', ['id' => $entityWorkflow->getId()]);

View File

@ -20,6 +20,9 @@ use Symfony\Component\Serializer\Annotation\Groups;
* @ORM\Entity
* @ORM\Table(name="chill_main_address_reference", indexes={
* @ORM\Index(name="address_refid", columns={"refId"})
* },
* uniqueConstraints={
* @ORM\UniqueConstraint(name="chill_main_address_reference_unicity", columns={"refId", "source"})
* })
* @ORM\HasLifecycleCallbacks
*/

View File

@ -14,15 +14,17 @@ namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_main_geographical_unit")
* @ORM\Entity
* @ORM\Table(name="chill_main_geographical_unit", uniqueConstraints={
* @ORM\UniqueConstraint(name="geographical_unit_refid", columns={"layer_id", "unitRefId"})
* })
* @ORM\Entity(readOnly=true)
*/
class GeographicalUnit
{
/**
* @ORM\Column(type="text", nullable=true)
*/
private $geom;
private string $geom;
/**
* @ORM\Id
@ -32,23 +34,28 @@ class GeographicalUnit
private ?int $id = null;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @ORM\ManyToOne(targetEntity=GeographicalUnitLayer::class, inversedBy="units")
*/
private $layerName;
private ?GeographicalUnitLayer $layer;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @ORM\Column(type="text", nullable=false, options={"default": ""})
*/
private $unitName;
private string $unitName;
/**
* @ORM\Column(type="text", nullable=false, options={"default": ""})
*/
private string $unitRefId;
public function getId(): ?int
{
return $this->id;
}
public function getLayerName(): ?string
public function getLayer(): ?GeographicalUnitLayer
{
return $this->layerName;
return $this->layer;
}
public function getUnitName(): ?string
@ -56,9 +63,9 @@ class GeographicalUnit
return $this->unitName;
}
public function setLayerName(?string $layerName): self
public function setLayer(?GeographicalUnitLayer $layer): GeographicalUnit
{
$this->layerName = $layerName;
$this->layer = $layer;
return $this;
}
@ -69,4 +76,18 @@ class GeographicalUnit
return $this;
}
public function setUnitRefId(string $unitRefId): GeographicalUnit
{
$this->unitRefId = $unitRefId;
return $this;
}
protected function setId(int $id): self
{
$this->id = $id;
return $this;
}
}

View File

@ -0,0 +1,79 @@
<?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\MainBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_main_geographical_unit_layer", uniqueConstraints={
* @ORM\UniqueConstraint(name="geographical_unit_layer_refid", columns={"refId"})
* })
* @ORM\Entity
*/
class GeographicalUnitLayer
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\Column(type="json", nullable=false, options={"default": "[]"})
*/
private array $name = [];
/**
* @ORM\Column(type="text", nullable=false, options={"default": ""})
*/
private string $refId = '';
/**
* @ORM\OneToMany(targetEntity=GeographicalUnit::class, mappedBy="layer")
*/
private Collection $units;
public function __construct()
{
$this->units = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): array
{
return $this->name;
}
public function getRefId(): string
{
return $this->refId;
}
public function getUnits(): Collection
{
return $this->units;
}
public function setName(array $name): GeographicalUnitLayer
{
$this->name = $name;
return $this;
}
}

View File

@ -12,6 +12,11 @@ declare(strict_types=1);
namespace Chill\MainBundle\Entity;
use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
@ -21,6 +26,10 @@ use Symfony\Component\Serializer\Annotation\Groups;
* @ORM\Entity
* @ORM\Table(
* name="chill_main_postal_code",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="postal_code_import_unicity", columns={"code", "refpostalcodeid", "postalcodesource"},
* options={"where": "refpostalcodeid is not null"})
* },
* indexes={
* @ORM\Index(name="search_name_code", columns={"code", "label"}),
* @ORM\Index(name="search_by_reference_code", columns={"code", "refpostalcodeid"})
@ -28,8 +37,12 @@ use Symfony\Component\Serializer\Annotation\Groups;
*
* @ORM\HasLifecycleCallbacks
*/
class PostalCode
class PostalCode implements TrackUpdateInterface, TrackCreationInterface
{
use TrackCreationTrait;
use TrackUpdateTrait;
/**
* This is an internal column which is populated by database.
*
@ -63,6 +76,11 @@ class PostalCode
*/
private $country;
/**
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": null})
*/
private ?DateTimeImmutable $deletedAt = null;
/**
* @var int
*

View File

@ -13,7 +13,7 @@ namespace Chill\MainBundle\Export;
use Chill\MainBundle\Form\Type\Export\ExportType;
use Chill\MainBundle\Form\Type\Export\PickCenterType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Generator;
@ -42,52 +42,38 @@ class ExportManager
/**
* The collected aggregators, injected by DI.
*
* @var AggregatorInterface[]
* @var array|AggregatorInterface[]
*/
private $aggregators = [];
private array $aggregators = [];
/**
* @var AuthorizationChecker
*/
private $authorizationChecker;
private AuthorizationCheckerInterface $authorizationChecker;
/**
* @var AuthorizationHelper
*/
private $authorizationHelper;
private AuthorizationHelperInterface $authorizationHelper;
/**
* @var EntityManagerInterface
*/
private $em;
private EntityManagerInterface $em;
/**
* Collected Exports, injected by DI.
*
* @var ExportInterface[]
* @var array|ExportInterface[]
*/
private $exports = [];
private array $exports = [];
/**
* The collected filters, injected by DI.
*
* @var FilterInterface[]
* @var array|FilterInterface[]
*/
private $filters = [];
private array $filters = [];
/**
* Collected Formatters, injected by DI.
*
* @var FormatterInterface[]
* @var array|FormatterInterface[]
*/
private $formatters = [];
private array $formatters = [];
/**
* a logger.
*
* @var LoggerInterface
*/
private $logger;
private LoggerInterface $logger;
/**
* @var \Symfony\Component\Security\Core\User\UserInterface
@ -98,7 +84,7 @@ class ExportManager
LoggerInterface $logger,
EntityManagerInterface $em,
AuthorizationCheckerInterface $authorizationChecker,
AuthorizationHelper $authorizationHelper,
AuthorizationHelperInterface $authorizationHelper,
TokenStorageInterface $tokenStorage
) {
$this->logger = $logger;
@ -277,8 +263,8 @@ class ExportManager
//handle aggregators
$this->handleAggregators($export, $query, $data[ExportType::AGGREGATOR_KEY], $centers);
$this->logger->debug('current query is ' . $query->getDQL(), [
'class' => self::class, 'function' => __FUNCTION__,
$this->logger->notice('[export] will execute this qb in export', [
'dql' => $query->getDQL(),
]);
} else {
throw new UnexpectedValueException('The method `intiateQuery` should return '
@ -547,19 +533,16 @@ class ExportManager
. 'an ExportInterface.');
}
if (null === $centers) {
$centers = $this->authorizationHelper->getReachableCenters(
if (null === $centers || [] !== $centers) {
// we want to try if at least one center is reachabler
return [] !== $this->authorizationHelper->getReachableCenters(
$this->user,
$role
);
}
if (count($centers) === 0) {
return false;
}
foreach ($centers as $center) {
if ($this->authorizationChecker->isGranted($role, $center) === false) {
if (false === $this->authorizationChecker->isGranted($role, $center)) {
//debugging
$this->logger->debug('user has no access to element', [
'method' => __METHOD__,
@ -568,10 +551,6 @@ class ExportManager
'role' => $role,
]);
///// Bypasse les autorisations qui empêche d'afficher les nouveaux exports
return true;
///// TODO supprimer le return true
return false;
}
}

View File

@ -230,7 +230,8 @@ class SpreadSheetFormatter implements FormatterInterface
$worksheet->fromArray(
$sortedResults,
null,
'A' . $line
'A' . $line,
true
);
return $line + count($sortedResults) + 1;
@ -495,8 +496,13 @@ class SpreadSheetFormatter implements FormatterInterface
// 3. iterate on `keysExportElementAssociation` to store the callable
// in cache
foreach ($keysExportElementAssociation as $key => [$element, $data]) {
$this->cacheDisplayableResult[$key] =
$element->getLabels($key, array_unique($allValues[$key]), $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] =
$element->getLabels($key, array_unique($allValues[$key]), $data);
}
}
// the cache is initialized !

View File

@ -14,8 +14,7 @@ namespace Chill\MainBundle\Form\Type\Export;
use Chill\MainBundle\Center\GroupingCenterInterface;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
@ -24,6 +23,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use function array_intersect;
use function array_key_exists;
use function array_merge;
@ -38,30 +38,21 @@ class PickCenterType extends AbstractType
{
public const CENTERS_IDENTIFIERS = 'c';
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected AuthorizationHelperInterface $authorizationHelper;
protected ExportManager $exportManager;
/**
* @var ExportManager
* @var array|GroupingCenterInterface[]
*/
protected $exportManager;
protected array $groupingCenters = [];
/**
* @var GroupingCenterInterface[]
*/
protected $groupingCenters = [];
/**
* @var \Symfony\Component\Security\Core\User\UserInterface
*/
protected $user;
protected UserInterface $user;
public function __construct(
TokenStorageInterface $tokenStorage,
ExportManager $exportManager,
AuthorizationHelper $authorizationHelper
AuthorizationHelperInterface $authorizationHelper
) {
$this->exportManager = $exportManager;
$this->user = $tokenStorage->getToken()->getUser();
@ -78,22 +69,12 @@ class PickCenterType extends AbstractType
$export = $this->exportManager->getExport($options['export_alias']);
$centers = $this->authorizationHelper->getReachableCenters(
$this->user,
(string) $export->requiredRole()
$export->requiredRole()
);
$builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [
'class' => Center::class,
'query_builder' => static function (EntityRepository $er) use ($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));
},
'choices' => $centers,
'multiple' => true,
'expanded' => true,
'choice_label' => static function (Center $c) {

View File

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

View File

@ -0,0 +1,27 @@
<?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\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

@ -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\MainBundle\Repository;
use Chill\MainBundle\Entity\GeographicalUnitLayer;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
final class GeographicalUnitLayerLayerRepository implements GeographicalUnitLayerRepositoryInterface
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository($this->getClassName());
}
public function find($id): ?GeographicalUnitLayer
{
return $this->repository->find($id);
}
/**
* @return array|GeographicalUnitLayer[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
public function findAllHavingUnits(): array
{
$qb = $this->repository->createQueryBuilder('l');
return $qb->where($qb->expr()->gt('SIZE(l.units)', 0))
->getQuery()
->getResult();
}
/**
* @return array|GeographicalUnitLayer[]
*/
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): ?GeographicalUnitLayer
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return GeographicalUnitLayer::class;
}
}

View File

@ -0,0 +1,23 @@
<?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\MainBundle\Repository;
use Chill\MainBundle\Entity\GeographicalUnitLayer;
use Doctrine\Persistence\ObjectRepository;
interface GeographicalUnitLayerRepositoryInterface extends ObjectRepository
{
/**
* @return array|GeographicalUnitLayer[]
*/
public function findAllHavingUnits(): array;
}

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\MainBundle\Repository;
use Chill\MainBundle\Entity\GeographicalUnit;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface
{
private EntityManagerInterface $em;
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository($this->getClassName());
$this->em = $em;
}
public function find($id): ?GeographicalUnit
{
return $this->repository->find($id);
}
/**
* Will return only partial object, where the @see{GeographicalUnit::geom} property is not loaded.
*
* @return array|GeographicalUnit[]
*/
public function findAll(): array
{
return $this->repository
->createQueryBuilder('gu')
->select('PARTIAL gu.{id,unitName,unitRefId,layer}')
->addOrderBy('IDENTITY(gu.layer)')
->addOrderBy(('gu.unitName'))
->getQuery()
->getResult();
}
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): ?GeographicalUnit
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?GeographicalUnit
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return GeographicalUnit::class;
}
}

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