mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
Merge branch '111_exports_suite' into testing
This commit is contained in:
commit
4388331b2f
@ -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,28 +172,6 @@ The password is always ``password``.
|
||||
|
||||
Now, read `Operations` below.
|
||||
|
||||
Prepare for development
|
||||
***********************
|
||||
|
||||
Add a Gitlab token to ensure that you get always the source code:
|
||||
|
||||
1. generate a gitlab token there: https://gitlab.com/oauth/token
|
||||
2. run this command (in php container, at the app's root): :code:`composer config gitlab-token.gitlab.com <your token>`
|
||||
|
||||
The auth token should appears now in the directory :code:`.composer`:
|
||||
|
||||
.. code-block: bash
|
||||
|
||||
$ cat .composer/auth.json
|
||||
{
|
||||
"gitlab-token": {
|
||||
"gitlab.com": "<your token>"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
See also "how to switch branch and get new dependencies".
|
||||
|
||||
|
||||
Operations
|
||||
**********
|
||||
@ -163,7 +179,7 @@ Operations
|
||||
Build assets
|
||||
============
|
||||
|
||||
run those commands:
|
||||
run those commands:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -175,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) ?
|
||||
@ -185,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
|
||||
|
||||
|
||||
@ -203,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
|
||||
@ -213,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 ?
|
||||
@ -223,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 ?
|
||||
==================
|
||||
@ -246,18 +265,20 @@ 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
|
||||
================================
|
||||
@ -269,10 +290,14 @@ How to switch the branch for chill-bundles, and get new dependencies
|
||||
|
||||
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.
|
||||
|
||||
.. 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:
|
||||
1. at the app's root, update the ``composer.json`` to your current branch:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
@ -281,14 +306,7 @@ In order to do that without pain, use those steps:
|
||||
"chill-bundles": "dev-<my-branch>@dev"
|
||||
}
|
||||
|
||||
2. mount into the php container, and run `composer update`
|
||||
|
||||
Build the documentation API
|
||||
===========================
|
||||
|
||||
A basic configuration of `sami <https://github.com/FriendsOfPhp/Sami>`_ is embedded within the project.
|
||||
|
||||
A configuration file for `phpDocumentor <https://www.phpdoc.org>`_ is present.
|
||||
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
|
||||
====================================================================================================================================================================
|
||||
@ -302,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.
|
||||
@ -335,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).
|
||||
|
@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -83,6 +85,10 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
|
||||
$qb
|
||||
@ -90,6 +96,18 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
->select('AVG(activity.durationTime) as export_avg_activity_duration')
|
||||
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -84,6 +86,10 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
|
||||
$qb
|
||||
@ -92,6 +98,18 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
||||
->andWhere($qb->expr()->isNotNull('activity.travelTime'))
|
||||
;
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -84,11 +86,25 @@ class CountActivity implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
if (!in_array('acp', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.accompanyingPeriod', 'acp');
|
||||
}
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb->select('COUNT(DISTINCT activity.id) as export_count_activity');
|
||||
|
||||
|
@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -84,15 +86,29 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
if (!in_array('acp', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.accompanyingPeriod', 'acp');
|
||||
}
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration')
|
||||
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@ use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@ -84,15 +86,29 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity');
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
if (!in_array('acp', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.accompanyingPeriod', 'acp');
|
||||
}
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration')
|
||||
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
|
@ -84,16 +84,25 @@ class CountActivity implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->activityRepository->createQueryBuilder('activity');
|
||||
|
||||
if (!in_array('person', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.person', 'person');
|
||||
}
|
||||
$qb = $this->activityRepository
|
||||
->createQueryBuilder('activity')
|
||||
->join('activity.person', 'person')
|
||||
->join('person.centerHistory', 'centerHistory')
|
||||
;
|
||||
|
||||
$qb->select('COUNT(activity.id) as export_count_activity');
|
||||
|
||||
$qb
|
||||
->where($qb->expr()->in('person.center', ':centers'))
|
||||
->where(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('centerHistory.endDate'),
|
||||
$qb->expr()->gt('centerHistory.endDate', 'activity.date')
|
||||
)
|
||||
)
|
||||
)
|
||||
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
|
||||
->setParameter('centers', $centers);
|
||||
|
||||
return $qb;
|
||||
|
@ -119,11 +119,24 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
$select = 'SUM(activity.durationTime) AS export_stat_activity';
|
||||
}
|
||||
|
||||
return $qb->select($select)
|
||||
$qb->select($select)
|
||||
->join('activity.person', 'person')
|
||||
->join('actperson.center', 'actcenter')
|
||||
->where($qb->expr()->in('actcenter', ':centers'))
|
||||
->setParameter(':centers', $centers);
|
||||
->join('person.centerHistory', 'centerHistory');
|
||||
|
||||
$qb
|
||||
->where(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('centerHistory.endDate'),
|
||||
$qb->expr()->gt('centerHistory.endDate', 'activity.date')
|
||||
)
|
||||
)
|
||||
)
|
||||
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
|
||||
->setParameter('centers', $centers);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
|
@ -1,82 +0,0 @@
|
||||
<?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;
|
||||
|
||||
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
|
||||
/**
|
||||
* Add tests for ActivityReasonAggregator.
|
||||
*
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private ActivityReasonAggregator $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$container = self::$kernel->getContainer();
|
||||
|
||||
$this->aggregator = $container->get('chill.activity.export.reason_aggregator');
|
||||
|
||||
// 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')
|
||||
->push($request->reveal());
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
{
|
||||
return [
|
||||
['level' => 'reasons'],
|
||||
['level' => 'categories'],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders()
|
||||
{
|
||||
if (null === self::$kernel) {
|
||||
self::bootKernel();
|
||||
}
|
||||
|
||||
$em = self::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager');
|
||||
|
||||
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'),
|
||||
];
|
||||
}
|
||||
}
|
@ -11,8 +11,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Tests\Export\Aggregator;
|
||||
|
||||
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityTypeAggregator;
|
||||
use Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
|
||||
/**
|
||||
* Add tests for ActivityTypeAggregator.
|
||||
@ -22,23 +24,22 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
*/
|
||||
final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
@ -60,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()
|
||||
@ -70,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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ 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.
|
||||
@ -22,23 +24,22 @@ use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
*/
|
||||
final class ActivityUserAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
@ -47,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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,12 @@ use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
|
||||
final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
private ActivityReasonAggregator $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
@ -25,6 +28,14 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::$container->get('chill.activity.export.reason_aggregator');
|
||||
|
||||
$request = $this->prophesize()
|
||||
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
self::$container->get('request_stack')
|
||||
->push($request->reveal());
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
@ -35,12 +46,8 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'level' => 'reasons',
|
||||
],
|
||||
[
|
||||
'level' => 'categories',
|
||||
]
|
||||
['level' => 'reasons'],
|
||||
['level' => 'categories'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -55,11 +62,16 @@ final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('count(activity.id)')
|
||||
->from(Activity::class, 'activity')
|
||||
->join('activity.person', 'actperson')
|
||||
->innerJoin('activity.reasons', 'actreasons')
|
||||
->join('actreasons.category', 'actreasoncat')
|
||||
,
|
||||
->from('ChillActivityBundle:Activity', 'activity'),
|
||||
$em->createQueryBuilder()
|
||||
->select('count(activity.id)')
|
||||
->from('ChillActivityBundle:Activity', 'activity')
|
||||
->join('activity.reasons', 'actreasons'),
|
||||
$em->createQueryBuilder()
|
||||
->select('count(activity.id)')
|
||||
->from('ChillActivityBundle:Activity', 'activity')
|
||||
->join('activity.reasons', 'actreasons')
|
||||
->join('actreasons.category', 'actreasoncat'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -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'],
|
||||
];
|
||||
}
|
||||
}
|
@ -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'],
|
||||
];
|
||||
}
|
||||
}
|
@ -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'],
|
||||
];
|
||||
}
|
||||
}
|
@ -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'],
|
||||
];
|
||||
}
|
||||
}
|
@ -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'],
|
||||
];
|
||||
}
|
||||
}
|
@ -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'],
|
@ -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());
|
||||
}
|
||||
|
@ -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'],
|
@ -31,12 +31,6 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.filter_activitytype');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class BySocialActionFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.bysocialaction_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class BySocialIssueFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.bysocialissue_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class ByUserFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.byuser_filter');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class EmergencyFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.emergency_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class LocationTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.locationtype_filter');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class SentReceivedFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.sentreceived_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class UserFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.user_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class UserScopeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.userscope_filter');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class ActivityDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.date_filter');
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ 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
|
||||
@ -21,23 +22,22 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
*/
|
||||
final class ActivityReasonFilterTest extends AbstractFilterTest
|
||||
{
|
||||
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');
|
||||
|
||||
// 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 = $this->prophesize()
|
||||
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$container->get('request_stack')
|
||||
self::$container->get('request_stack')
|
||||
->push($request->reveal());
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class ActivityTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.type_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class ActivityReasonFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.reason_filter');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.activity.export.person_having_an_activity_between_date_filter');
|
||||
}
|
||||
|
||||
|
@ -28,18 +28,14 @@ final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\PersonBundle\Entity\Household\PersonHouseholdAddress;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterCurrent;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCurrentAddress;
|
||||
use Chill\PersonBundle\Entity\Person\PersonResource;
|
||||
use Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequential;
|
||||
@ -188,9 +190,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
* The person's center.
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center")
|
||||
* @deprecated
|
||||
*/
|
||||
private ?Center $center = null;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=PersonCenterHistory::class, mappedBy="person", cascade={"persist"})
|
||||
* @var Collection|PersonCenterHistory[]
|
||||
*/
|
||||
private Collection $centerHistory;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity=PersonCenterCurrent::class, mappedBy="person")
|
||||
*/
|
||||
private ?PersonCenterCurrent $centerCurrent = null;
|
||||
|
||||
/**
|
||||
* Array where customfield's data are stored.
|
||||
*
|
||||
@ -531,6 +545,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
$this->budgetResources = new ArrayCollection();
|
||||
$this->budgetCharges = new ArrayCollection();
|
||||
$this->resources = new ArrayCollection();
|
||||
$this->centerHistory = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -903,9 +918,43 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
return $this->budgetResources;
|
||||
}
|
||||
|
||||
private function getCurrentCenterHistory(): ?PersonCenterHistory
|
||||
{
|
||||
if (0 === $this->centerHistory->count()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$criteria = Criteria::create();
|
||||
$now = new DateTimeImmutable('now');
|
||||
$criteria->where(Criteria::expr()->lte('startDate', $now))
|
||||
->andWhere(Criteria::expr()->orX(
|
||||
Criteria::expr()->isNull('endDate'),
|
||||
Criteria::expr()->gt('endDate', $now)
|
||||
));
|
||||
|
||||
$histories = $this->centerHistory->matching($criteria);
|
||||
|
||||
switch ($histories->count()) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return $histories->first();
|
||||
default:
|
||||
throw new \UnexpectedValueException('It should not contains more than one center at a time');
|
||||
}
|
||||
}
|
||||
|
||||
public function getCenter(): ?Center
|
||||
{
|
||||
return $this->center;
|
||||
if (null !== $this->centerCurrent) {
|
||||
return $this->centerCurrent->getCenter();
|
||||
}
|
||||
|
||||
if (null === $currentCenterHistory = $this->getCurrentCenterHistory()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $currentCenterHistory->getCenter();
|
||||
}
|
||||
|
||||
public function getCFData(): ?array
|
||||
@ -1518,17 +1567,67 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the center with the person. The association start on 'now'.
|
||||
*
|
||||
* @param Center $center
|
||||
* @return $this
|
||||
*/
|
||||
public function setCenter(Center $center): self
|
||||
{
|
||||
$this->center = $center;
|
||||
|
||||
$modification = new DateTimeImmutable('now');
|
||||
|
||||
foreach ($this->centerHistory as $centerHistory) {
|
||||
if (null === $centerHistory->getEndDate()) {
|
||||
$centerHistory->setEndDate($modification);
|
||||
}
|
||||
}
|
||||
|
||||
$this->centerHistory[] = $new = new PersonCenterHistory($this, $center, $modification);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Report
|
||||
* @return Collection
|
||||
*/
|
||||
public function setCFData(?array $cFData)
|
||||
public function getCenterHistory(): Collection
|
||||
{
|
||||
return $this->centerHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $centerHistory
|
||||
* @return Person
|
||||
*/
|
||||
public function setCenterHistory(Collection $centerHistory): Person
|
||||
{
|
||||
$this->centerHistory = $centerHistory;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PersonCenterCurrent|null
|
||||
*/
|
||||
public function getCenterCurrent(): ?PersonCenterCurrent
|
||||
{
|
||||
if (null !== $this->centerCurrent) {
|
||||
return $this->centerCurrent;
|
||||
}
|
||||
|
||||
if (null === $currentCenterHistory = $this->getCurrentCenterHistory()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PersonCenterCurrent($currentCenterHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person
|
||||
*/
|
||||
public function setCFData(?array $cFData): self
|
||||
{
|
||||
$this->cFData = $cFData;
|
||||
|
||||
|
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\Person;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Associate a Person with the current center.
|
||||
*
|
||||
* The process of selecting the current center is done on database side,
|
||||
* using a SQL view.
|
||||
*
|
||||
* @ORM\Entity(readOnly=true)
|
||||
* @ORM\Table(name="view_chill_person_person_center_history_current")
|
||||
* @psalm-internal Chill\PersonBundle\Entity
|
||||
*/
|
||||
class PersonCenterCurrent
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="centerCurrent")
|
||||
*/
|
||||
private Person $person;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Center::class)
|
||||
*/
|
||||
private Center $center;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date_immutable", nullable=false)
|
||||
*/
|
||||
private \DateTimeImmutable $startDate;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
|
||||
*/
|
||||
private ?\DateTimeImmutable $endDate = null;
|
||||
|
||||
/**
|
||||
* Populate the properties person, center, start and end date from history.
|
||||
*
|
||||
* The creator and updatedby are not filled.
|
||||
*
|
||||
* @internal Should not be instantied, unless inside Person entity
|
||||
* @param PersonCenterHistory $history
|
||||
*/
|
||||
public function __construct(PersonCenterHistory $history)
|
||||
{
|
||||
$this->person = $history->getPerson();
|
||||
$this->center = $history->getCenter();
|
||||
$this->startDate = $history->getStartDate();
|
||||
$this->endDate = $history->getEndDate();
|
||||
$this->id = $history->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* The id will be the same as the current @link{PersonCenterHistory::class}
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person
|
||||
*/
|
||||
public function getPerson(): Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Center
|
||||
*/
|
||||
public function getCenter(): Center
|
||||
{
|
||||
return $this->center;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTimeImmutable
|
||||
*/
|
||||
public function getStartDate(): \DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTimeImmutable|null
|
||||
*/
|
||||
public function getEndDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\Person;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Associate a Person with a Center. The association may change on date intervals
|
||||
*
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="chill_person_person_center_history")
|
||||
*/
|
||||
class PersonCenterHistory implements TrackCreationInterface, TrackUpdateInterface
|
||||
{
|
||||
use TrackCreationTrait;
|
||||
use TrackUpdateTrait;
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="centerHistory")
|
||||
*/
|
||||
private ?Person $person = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Center::class)
|
||||
*/
|
||||
private ?Center $center = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date_immutable", nullable=false)
|
||||
*/
|
||||
private ?\DateTimeImmutable $startDate = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
|
||||
*/
|
||||
private ?\DateTimeImmutable $endDate = null;
|
||||
|
||||
/**
|
||||
* @param Person|null $person
|
||||
* @param Center|null $center
|
||||
* @param \DateTimeImmutable|null $startDate
|
||||
*/
|
||||
public function __construct(?Person $person = null, ?Center $center = null, ?\DateTimeImmutable $startDate = null)
|
||||
{
|
||||
$this->person = $person;
|
||||
$this->center = $center;
|
||||
$this->startDate = $startDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Person|null
|
||||
*/
|
||||
public function getPerson(): ?Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Person|null $person
|
||||
*/
|
||||
public function setPerson(?Person $person): self
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Center|null
|
||||
*/
|
||||
public function getCenter(): ?Center
|
||||
{
|
||||
return $this->center;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Center|null $center
|
||||
*/
|
||||
public function setCenter(?Center $center): self
|
||||
{
|
||||
$this->center = $center;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTimeImmutable|null
|
||||
*/
|
||||
public function getStartDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeImmutable|null $startDate
|
||||
*/
|
||||
public function setStartDate(?\DateTimeImmutable $startDate): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTimeImmutable|null
|
||||
*/
|
||||
public function getEndDate(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeImmutable|null $endDate
|
||||
*/
|
||||
public function setEndDate(?\DateTimeImmutable $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@ -90,9 +92,25 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
|
||||
$qb->select('COUNT(acp.id) AS export_result');
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb->select('COUNT(DISTINCT acp.id) AS export_result');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@ -88,6 +90,10 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
|
||||
if (!in_array('acpw', $qb->getAllAliases(), true)) {
|
||||
@ -98,6 +104,18 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface
|
||||
$qb->join('acpw.accompanyingPeriodWorkEvaluations', 'workeval');
|
||||
}
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb->select('COUNT(DISTINCT workeval.id) AS export_result');
|
||||
|
||||
return $qb;
|
||||
|
@ -15,6 +15,9 @@ use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\HouseholdVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@ -88,23 +91,29 @@ class CountHousehold implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
if (!in_array('acppart', $qb->getAllAliases(), true)) {
|
||||
$qb->join('acp.participations', 'acppart');
|
||||
}
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('acp')
|
||||
->join('acp.participations', 'acppart')
|
||||
// little optimization: we remove joins and make a direct join between participations and household members
|
||||
->join(HouseholdMember::class, 'member', Query\Expr\Join::WITH, 'IDENTITY(acppart.person) = IDENTITY(member.person)')
|
||||
->join('member.household', 'household')
|
||||
;
|
||||
|
||||
if (!in_array('partperson', $qb->getAllAliases(), true)) {
|
||||
$qb->join('acppart.person', 'partperson');
|
||||
}
|
||||
|
||||
if (!in_array('member', $qb->getAllAliases(), true)) {
|
||||
$qb->join('partperson.householdParticipations', 'member');
|
||||
}
|
||||
|
||||
if (!in_array('household', $qb->getAllAliases(), true)) {
|
||||
$qb->join('member.household', 'household');
|
||||
}
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb->select('COUNT(DISTINCT household.id) AS export_result');
|
||||
|
||||
|
@ -14,9 +14,11 @@ namespace Chill\PersonBundle\Export\Export;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
@ -100,9 +102,12 @@ class CountPerson implements ExportInterface, GroupedExportInterface
|
||||
$qb = $this->personRepository->createQueryBuilder('person');
|
||||
|
||||
$qb->select('COUNT(person.id) AS export_result')
|
||||
->join('person.center', 'center')
|
||||
->andWhere('center IN (:authorized_centers)')
|
||||
->setParameter('authorized_centers', $centers);
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@ -88,6 +89,10 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
|
||||
if (!in_array('acppart', $qb->getAllAliases(), true)) {
|
||||
@ -98,6 +103,12 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor
|
||||
$qb->join('acppart.person', 'person');
|
||||
}
|
||||
|
||||
$qb->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'
|
||||
)
|
||||
)->setParameter('authorized_centers', $centers);
|
||||
|
||||
$qb->select('COUNT(DISTINCT person.id) AS export_result');
|
||||
|
||||
return $qb;
|
||||
|
@ -15,6 +15,8 @@ use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@ -90,13 +92,26 @@ class CountSocialWorkActions implements ExportInterface, GroupedExportInterface
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
if (!in_array('acpw', $qb->getAllAliases(), true)) {
|
||||
$qb->join('acp.works', 'acpw');
|
||||
}
|
||||
$qb = $this->repository->createQueryBuilder('acp')
|
||||
->join('acp.works', 'acpw');
|
||||
|
||||
$qb->select('COUNT(acpw.id) as export_result');
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb->select('COUNT(DISTINCT acpw.id) as export_result');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Chill\PersonBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use DateTime;
|
||||
@ -94,15 +96,27 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->repository->createQueryBuilder('acp');
|
||||
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
|
||||
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
|
||||
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers)
|
||||
;
|
||||
|
||||
$qb
|
||||
->select('AVG(
|
||||
( CASE
|
||||
WHEN acp.closingDate IS NOT NULL
|
||||
THEN acp.closingDate
|
||||
ELSE :force_closingDate
|
||||
END ) - acp.openingDate
|
||||
COALESCE(acp.closingDate, :force_closingDate) - acp.openingDate
|
||||
) AS export_result')
|
||||
->setParameter('force_closingDate', $data['closingdate']);
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Person;
|
||||
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
interface PersonCenterHistoryInterface extends ObjectRepository
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Person;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class PersonCenterHistoryRepository implements PersonCenterHistoryInterface
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->repository = $em->getRepository($this->getClassName());
|
||||
}
|
||||
|
||||
public function find($id): ?PersonCenterHistory
|
||||
{
|
||||
return $this->repository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|PersonCenterHistory[]
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->repository->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|PersonCenterHistory[]
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
public function findOneBy(array $criteria): ?PersonCenterHistory
|
||||
{
|
||||
return $this->repository->findOneBy($criteria);
|
||||
}
|
||||
|
||||
public function getClassName(): string
|
||||
{
|
||||
return PersonCenterHistory::class;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ use Chill\MainBundle\Repository\CountryRepository;
|
||||
use Chill\MainBundle\Search\ParsingException;
|
||||
use Chill\MainBundle\Search\SearchApiQuery;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use DateTimeInterface;
|
||||
@ -34,7 +35,7 @@ use function implode;
|
||||
|
||||
final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterface
|
||||
{
|
||||
private AuthorizationHelper $authorizationHelper;
|
||||
private AuthorizationHelperInterface $authorizationHelper;
|
||||
|
||||
private CountryRepository $countryRepository;
|
||||
|
||||
@ -46,7 +47,7 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
|
||||
Security $security,
|
||||
EntityManagerInterface $em,
|
||||
CountryRepository $countryRepository,
|
||||
AuthorizationHelper $authorizationHelper
|
||||
AuthorizationHelperInterface $authorizationHelper
|
||||
) {
|
||||
$this->security = $security;
|
||||
$this->em = $em;
|
||||
@ -310,9 +311,10 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
|
||||
}
|
||||
|
||||
return $query
|
||||
->setFromClause($query->getFromClause() . ' JOIN view_chill_person_person_center_history_current vcppchc ON vcppchc.person_id = person.id', $query->getFromParams())
|
||||
->andWhereClause(
|
||||
strtr(
|
||||
'person.center_id IN ({{ center_ids }})',
|
||||
'vcppchc.center_id IN ({{ center_ids }})',
|
||||
[
|
||||
'{{ center_ids }}' => implode(
|
||||
', ',
|
||||
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\Tests\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
@ -191,4 +192,29 @@ final class PersonTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD);
|
||||
}
|
||||
|
||||
public function testSetCenter()
|
||||
{
|
||||
$person = new Person();
|
||||
$centerA = new Center();
|
||||
$centerB = new Center();
|
||||
|
||||
$this->assertCount(0, $person->getCenterHistory());
|
||||
$this->assertNull($person->getCenter());
|
||||
$this->assertNull($person->getCenterCurrent());
|
||||
|
||||
$person->setCenter($centerA);
|
||||
|
||||
$this->assertCount(1, $person->getCenterHistory());
|
||||
$this->assertSame($centerA, $person->getCenter());
|
||||
$this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
|
||||
$this->assertSame($centerA, $person->getCenterCurrent()->getCenter());
|
||||
|
||||
$person->setCenter($centerB);
|
||||
|
||||
$this->assertCount(2, $person->getCenterHistory());
|
||||
$this->assertSame($centerB, $person->getCenter());
|
||||
$this->assertInstanceOf(Person\PersonCenterCurrent::class, $person->getCenterCurrent());
|
||||
$this->assertSame($centerB, $person->getCenterCurrent()->getCenter());
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Tests\Export\Export;
|
||||
use Chill\MainBundle\Test\Export\AbstractExportTest;
|
||||
use Chill\PersonBundle\Export\Export\ListPerson;
|
||||
use DateTime;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
|
||||
/**
|
||||
* Test the export "ListPerson".
|
||||
@ -23,10 +24,9 @@ use DateTime;
|
||||
*/
|
||||
final class ListPersonTest extends AbstractExportTest
|
||||
{
|
||||
/**
|
||||
* @var ListPerson
|
||||
*/
|
||||
private $export;
|
||||
use ProphecyTrait;
|
||||
|
||||
private ListPerson $export;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -34,10 +34,9 @@ final class ListPersonTest extends AbstractExportTest
|
||||
|
||||
$this->export = self::$container->get('chill.person.export.list_person');
|
||||
|
||||
// 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 = $this->prophesize()
|
||||
->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
self::$container->get('request_stack')
|
||||
@ -49,7 +48,7 @@ final class ListPersonTest extends AbstractExportTest
|
||||
return $this->export;
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
['fields' => ['id', 'firstName', 'lastName']],
|
||||
@ -65,7 +64,7 @@ final class ListPersonTest extends AbstractExportTest
|
||||
];
|
||||
}
|
||||
|
||||
public function getModifiersCombination()
|
||||
public function getModifiersCombination(): array
|
||||
{
|
||||
return [
|
||||
['person'],
|
||||
|
@ -30,12 +30,6 @@ final class ActiveOnDateFilterTest extends AbstractFilterTest
|
||||
//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_activeondate');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class ActiveOneDayBetweenDatesFilterTest extends AbstractFilterTest
|
||||
//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_activeonedaybetweendates');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class AdministrativeLocationFilterTest extends AbstractFilterTest
|
||||
//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_administrative_location');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class ClosingMotiveFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_closingmotive');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class ConfidentialFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_confidential');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class CurrentUserJobFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_userjob');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class CurrentUserScopeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_userscope');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class EmergencyFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_emergency');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class EvaluationFilterTest extends AbstractFilterTest
|
||||
//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_evaluation');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class GeographicalUnitStatFilterTest extends AbstractFilterTest
|
||||
//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_geographicalunitstat');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class IntensityFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_intensity');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class OpenBetweenDatesFilterTest extends AbstractFilterTest
|
||||
//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_openbetweendates');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class OriginFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_origin');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class ReferrerFilterTest extends AbstractFilterTest
|
||||
{
|
||||
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_referrer');
|
||||
}
|
||||
|
||||
|
@ -26,15 +26,8 @@ final class RequestorFilterTest 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_requestor');
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,6 @@ final class SocialActionFilterTest extends AbstractFilterTest
|
||||
//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_socialaction');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class SocialIssueFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_socialissue');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class StepFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_step');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class EvaluationTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_evaluationtype');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class MaxDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_maxdate');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class CompositionFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_household_composition');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class AgeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_age');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class DeadOrAliveFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_dead_or_alive');
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,6 @@ final class DeathdateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_deathdate');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class GenderFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// 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');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_gender');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class MaritalStatusFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_marital_status');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class NationalityFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_nationality');
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,6 @@ final class ResidentialAddressAtThirdpartyFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_residential_address_at_thirdparty');
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,6 @@ final class ResidentialAddressAtUserFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_residential_address_at_user');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class JobFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_job');
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,6 @@ final class ReferrerFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_treatingagent');
|
||||
}
|
||||
|
||||
|
@ -27,12 +27,6 @@ final class ScopeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_scope');
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,6 @@ final class SocialWorkTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.person.export.filter_social_work_type');
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Tests\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
||||
use Chill\MainBundle\Repository\CountryRepository;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Repository\PersonACLAwareRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class PersonACLAwareRepositoryTest extends KernelTestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private CountryRepository $countryRepository;
|
||||
|
||||
private CenterRepositoryInterface $centerRepository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->entityManager = self::$container->get(EntityManagerInterface::class);
|
||||
$this->countryRepository = self::$container->get(CountryRepository::class);
|
||||
$this->centerRepository = self::$container->get(CenterRepositoryInterface::class);
|
||||
|
||||
}
|
||||
|
||||
public function testCountByCriteria()
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(PersonVoter::SEE))
|
||||
->willReturn($this->centerRepository->findAll());
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$repository = new PersonACLAwareRepository($security->reveal(), $this->entityManager, $this->countryRepository,
|
||||
$authorizationHelper->reveal());
|
||||
|
||||
$number = $repository->countBySearchCriteria('diallo');
|
||||
|
||||
$this->assertGreaterThan(0, $number);
|
||||
}
|
||||
|
||||
public function testFindByCriteria()
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(PersonVoter::SEE))
|
||||
->willReturn($this->centerRepository->findAll());
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$repository = new PersonACLAwareRepository($security->reveal(), $this->entityManager, $this->countryRepository,
|
||||
$authorizationHelper->reveal());
|
||||
|
||||
$results = $repository->findBySearchCriteria(0, 5, false, 'diallo');
|
||||
|
||||
$this->assertGreaterThan(0, count($results));
|
||||
$this->assertContainsOnlyInstancesOf(Person::class, $results);
|
||||
foreach ($results as $person) {
|
||||
$this->assertStringContainsString('diallo', strtolower($person->getFirstName() . ' ' . $person->getLastName()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Person;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20220926154347 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add a center history on person';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE SEQUENCE chill_person_person_center_history_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||
$this->addSql('CREATE TABLE chill_person_person_center_history (
|
||||
id INT NOT NULL, person_id INT DEFAULT NULL, center_id INT DEFAULT NULL,
|
||||
startDate DATE NOT NULL, endDate DATE DEFAULT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
|
||||
updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, createdBy_id INT DEFAULT NULL,
|
||||
updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_CACA67FA217BBB47 ON chill_person_person_center_history (person_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CACA67FA5932F377 ON chill_person_person_center_history (center_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CACA67FA3174800F ON chill_person_person_center_history (createdBy_id)');
|
||||
$this->addSql('CREATE INDEX IDX_CACA67FA65FF1AEC ON chill_person_person_center_history (updatedBy_id)');
|
||||
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.startDate IS \'(DC2Type:date_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.endDate IS \'(DC2Type:date_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.createdAt IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_person_person_center_history.updatedAt IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA5932F377 FOREIGN KEY (center_id) REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT FK_CACA67FA65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
|
||||
// check consistency of history on database side
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CHECK (startdate <= enddate)');
|
||||
$this->addSql('ALTER TABLE chill_person_person_center_history ADD CONSTRAINT ' .
|
||||
'chill_internal_person_person_center_history_not_overlaps EXCLUDE USING GIST(
|
||||
-- extension btree_gist required to include comparaison with integer
|
||||
person_id WITH =,
|
||||
daterange(startdate, enddate, \'[)\') WITH &&
|
||||
)
|
||||
INITIALLY DEFERRED');
|
||||
|
||||
// create index on search by person and date
|
||||
$this->addSql('CREATE INDEX chill_internal_person_person_center_history_by_date ON chill_person_person_center_history (person_id DESC, startdate DESC, enddate DESC NULLS FIRST)');
|
||||
|
||||
// create a view to get the current center on a person
|
||||
$this->addSql(
|
||||
'CREATE VIEW view_chill_person_person_center_history_current AS
|
||||
SELECT id, person_id, center_id, startDate, endDate, createdAt, updatedAt, createdBy_id, updatedBy_id
|
||||
FROM chill_person_person_center_history WHERE startDate <= NOW() AND (enddate IS NULL OR enddate > NOW())'
|
||||
);
|
||||
|
||||
$this->addSql('INSERT INTO chill_person_person_center_history (id, person_id, center_id, startdate)
|
||||
SELECT nextval(\'chill_person_person_center_history_id_seq\'), id, center_id, COALESCE(createdat, NOW())
|
||||
FROM chill_person_person WHERE center_id IS NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP VIEW view_chill_person_person_center_history_current');
|
||||
$this->addSql('DROP SEQUENCE chill_person_person_center_history_id_seq CASCADE');
|
||||
$this->addSql('DROP TABLE chill_person_person_center_history');
|
||||
}
|
||||
}
|
@ -28,12 +28,6 @@ final class ReportDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
// add a fake request with a default locale (used in translatable string)
|
||||
$request = $this->prophesize();
|
||||
|
||||
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||
$request->getLocale()->willReturn('fr');
|
||||
|
||||
$this->filter = self::$container->get('chill.report.export.filter_date');
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace Chill\TaskBundle\Repository;
|
||||
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\TaskBundle\Entity\SingleTask;
|
||||
@ -31,14 +32,14 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
|
||||
{
|
||||
private AuthorizationHelperInterface $authorizationHelper;
|
||||
|
||||
private CenterResolverDispatcherInterface $centerResolverDispatcher;
|
||||
private CenterResolverManagerInterface $centerResolverDispatcher;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(
|
||||
CenterResolverDispatcherInterface $centerResolverDispatcher,
|
||||
CenterResolverManagerInterface $centerResolverDispatcher,
|
||||
EntityManagerInterface $em,
|
||||
Security $security,
|
||||
AuthorizationHelperInterface $authorizationHelper
|
||||
@ -304,14 +305,18 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
|
||||
QueryBuilder $qb,
|
||||
$entity
|
||||
): QueryBuilder {
|
||||
$scopes = $this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
TaskVoter::SHOW,
|
||||
$this->centerResolverDispatcher->resolveCenter($entity)
|
||||
);
|
||||
foreach ($this->centerResolverDispatcher->resolveCenters($entity) as $center) {
|
||||
$scopes = $this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
TaskVoter::SHOW,
|
||||
$center
|
||||
);
|
||||
|
||||
return $qb->andWhere($qb->expr()->in('t.circle', ':scopes'))
|
||||
->setParameter('scopes', $scopes);
|
||||
$qb->andWhere($qb->expr()->in('t.circle', ':scopes'))
|
||||
->setParameter('scopes', $scopes);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function addACLGlobal(
|
||||
@ -329,7 +334,10 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
|
||||
$qb->leftJoin('t.person', 'person')
|
||||
->leftJoin('t.course', 'course')
|
||||
->leftJoin('course.participations', 'participation')
|
||||
->leftJoin('participation.person', 'person_p');
|
||||
->leftJoin('participation.person', 'person_p')
|
||||
->leftJoin('person.centerCurrent', 'center_current_person')
|
||||
->leftJoin('person_p.centerCurrent', 'center_current_participation')
|
||||
;
|
||||
$qb->distinct(true);
|
||||
|
||||
$k = 0;
|
||||
@ -344,8 +352,8 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository
|
||||
|
||||
$and = $qb->expr()->andX(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->eq('person.center', ':center_' . $k),
|
||||
$qb->expr()->eq('person_p.center', ':center_' . $k)
|
||||
$qb->expr()->eq('center_current_person.center', ':center_' . $k),
|
||||
$qb->expr()->eq('center_current_participation.center', ':center_' . $k)
|
||||
),
|
||||
$qb->expr()->in('t.circle', ':scopes_' . $k)
|
||||
);
|
||||
|
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\TaskBundle\Tests\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepository;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\PersonBundle\DataFixtures\Helper\PersonRandomHelper;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\TaskBundle\Entity\SingleTask;
|
||||
use Chill\TaskBundle\Repository\SingleTaskAclAwareRepository;
|
||||
use Chill\TaskBundle\Security\Authorization\TaskVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class SingleTaskACLAwareRepositoryTest extends KernelTestCase
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
private UserRepository $userRepository;
|
||||
private AuthorizationHelperInterface $authorizationHelper;
|
||||
private CenterRepositoryInterface $centerRepository;
|
||||
private ScopeRepository $scopeRepository;
|
||||
private PersonRepository $personRepository;
|
||||
|
||||
use PersonRandomHelper;
|
||||
|
||||
use ProphecyTrait;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->em = self::$container->get(EntityManagerInterface::class);
|
||||
$this->userRepository = self::$container->get(UserRepository::class);
|
||||
$this->centerRepository = self::$container->get(CenterRepositoryInterface::class);
|
||||
$this->scopeRepository = self::$container->get(ScopeRepository::class);
|
||||
$this->personRepository = self::$container->get(PersonRepository::class);
|
||||
}
|
||||
|
||||
public function testCountByPerson(): void
|
||||
{
|
||||
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
|
||||
$user = new User();
|
||||
$scopes = $this->scopeRepository->findAll();
|
||||
$person = $this->getRandomPerson($this->em);
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
|
||||
->willReturn([$centerA]);
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
|
||||
->willReturn($scopes);
|
||||
|
||||
$repository = new SingleTaskAclAwareRepository(
|
||||
$centerResolverDispatcher->reveal(),
|
||||
$this->em,
|
||||
$security->reveal(),
|
||||
$authorizationHelper->reveal()
|
||||
);
|
||||
|
||||
$nb = $repository->countByPerson($person, null, []);
|
||||
|
||||
$this->assertGreaterThanOrEqual(0, $nb);
|
||||
}
|
||||
|
||||
public function testFindByPerson(): void
|
||||
{
|
||||
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
|
||||
$user = new User();
|
||||
$scopes = $this->scopeRepository->findAll();
|
||||
$person = $this->getRandomPerson($this->em);
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
|
||||
->willReturn([$centerA]);
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
|
||||
->willReturn($scopes);
|
||||
|
||||
$repository = new SingleTaskAclAwareRepository(
|
||||
$centerResolverDispatcher->reveal(),
|
||||
$this->em,
|
||||
$security->reveal(),
|
||||
$authorizationHelper->reveal()
|
||||
);
|
||||
|
||||
$tasks = $repository->findByPerson($person, null, []);
|
||||
|
||||
$this->assertGreaterThanOrEqual(0, count($tasks));
|
||||
}
|
||||
|
||||
public function testFindByAllViewable(): void
|
||||
{
|
||||
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
|
||||
$user = new User();
|
||||
$scopes = $this->scopeRepository->findAll();
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
|
||||
->willReturn([$centerA]);
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(TaskVoter::SHOW))
|
||||
->willReturn([$centerA]);
|
||||
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
|
||||
->willReturn($scopes);
|
||||
|
||||
$repository = new SingleTaskAclAwareRepository(
|
||||
$centerResolverDispatcher->reveal(),
|
||||
$this->em,
|
||||
$security->reveal(),
|
||||
$authorizationHelper->reveal()
|
||||
);
|
||||
|
||||
$tasks = $repository->findByAllViewable(null, []);
|
||||
|
||||
$this->assertGreaterThanOrEqual(0, count($tasks));
|
||||
}
|
||||
|
||||
public function testCountByAllViewable(): void
|
||||
{
|
||||
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
|
||||
$user = new User();
|
||||
$scopes = $this->scopeRepository->findAll();
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
$centerResolverDispatcher->resolveCenters(Argument::type(Person::class), Argument::any())
|
||||
->willReturn([$centerA]);
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableCenters(Argument::exact($user), Argument::exact(TaskVoter::SHOW))
|
||||
->willReturn([$centerA]);
|
||||
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::exact($centerA))
|
||||
->willReturn($scopes);
|
||||
|
||||
$repository = new SingleTaskAclAwareRepository(
|
||||
$centerResolverDispatcher->reveal(),
|
||||
$this->em,
|
||||
$security->reveal(),
|
||||
$authorizationHelper->reveal()
|
||||
);
|
||||
|
||||
$nb = $repository->countByAllViewable(null, []);
|
||||
|
||||
$this->assertGreaterThanOrEqual(0, $nb);
|
||||
}
|
||||
|
||||
public function testFindByCourse(): void
|
||||
{
|
||||
$centerA = $this->centerRepository->findOneBy(['name' => 'Center A']);
|
||||
$user = new User();
|
||||
$scopes = $this->scopeRepository->findAll();
|
||||
/** @var Person $person */
|
||||
$person = $this->em->createQuery(
|
||||
'SELECT p FROM '.Person::class.' p JOIN p.centerCurrent cc
|
||||
WHERE SIZE(p.accompanyingPeriodParticipations) > 0
|
||||
AND cc.center = :center'
|
||||
)
|
||||
->setParameter('center', $centerA)
|
||||
->setMaxResults(1)
|
||||
->getSingleResult()
|
||||
;
|
||||
$period = $person->getAccompanyingPeriodParticipations()->first()->getAccompanyingPeriod();
|
||||
|
||||
$security = $this->prophesize(Security::class);
|
||||
$security->getUser()->willReturn($user);
|
||||
|
||||
$centerResolverDispatcher = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
$centerResolverDispatcher->resolveCenters(Argument::type(AccompanyingPeriod::class), Argument::any())
|
||||
->willReturn([$centerA]);
|
||||
|
||||
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||
$authorizationHelper->getReachableScopes(Argument::exact($user), Argument::exact(TaskVoter::SHOW), Argument::any())
|
||||
->willReturn($scopes);
|
||||
|
||||
$repository = new SingleTaskAclAwareRepository(
|
||||
$centerResolverDispatcher->reveal(),
|
||||
$this->em,
|
||||
$security->reveal(),
|
||||
$authorizationHelper->reveal()
|
||||
);
|
||||
|
||||
$tasks = $repository->findByCourse($period);
|
||||
|
||||
$this->assertGreaterThanOrEqual(0, count($tasks));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user