diff --git a/.changes/unreleased/Fixed-20230621-132851.yaml b/.changes/unreleased/Fixed-20230621-132851.yaml deleted file mode 100644 index 89fb7cdd9..000000000 --- a/.changes/unreleased/Fixed-20230621-132851.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: Fixed -body: '[Accompanying period comments]: order comments from the most recent to the - oldest, in the list' -time: 2023-06-21T13:28:51.282714011+02:00 -custom: - Issue: "" diff --git a/.changes/unreleased/Fixed-20230621-135912.yaml b/.changes/unreleased/Fixed-20230621-135912.yaml deleted file mode 100644 index 676d1c21b..000000000 --- a/.changes/unreleased/Fixed-20230621-135912.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: Fixed -body: 'Api: filter social action to keep only the currently activated' -time: 2023-06-21T13:59:12.57760217+02:00 -custom: - Issue: "" diff --git a/.changes/unreleased/Fixed-20230621-141828.yaml b/.changes/unreleased/Fixed-20230621-141828.yaml deleted file mode 100644 index 2c7f94488..000000000 --- a/.changes/unreleased/Fixed-20230621-141828.yaml +++ /dev/null @@ -1,5 +0,0 @@ -kind: Fixed -body: Fix deletion and re-creation of filiation relationship -time: 2023-06-21T14:18:28.437876316+02:00 -custom: - Issue: "82" diff --git a/.changes/unreleased/Fixed-20230628-170055.yaml b/.changes/unreleased/Fixed-20230628-170055.yaml new file mode 100644 index 000000000..7f9ec3028 --- /dev/null +++ b/.changes/unreleased/Fixed-20230628-170055.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: '[export] Rename label for CurrentActionFilter (on accompanying period work) + to make precision between "ouvert" and "sans date de fin"' +time: 2023-06-28T17:00:55.206937751+02:00 +custom: + Issue: "" diff --git a/.changes/unreleased/Fixed-20230629-124412.yaml b/.changes/unreleased/Fixed-20230629-124412.yaml new file mode 100644 index 000000000..7fc3d3eb0 --- /dev/null +++ b/.changes/unreleased/Fixed-20230629-124412.yaml @@ -0,0 +1,6 @@ +kind: Fixed +body: Force the db to have either a person_location or a address_location, and avoid + to have both also internally in the entity +time: 2023-06-29T12:44:12.019663991+02:00 +custom: + Issue: "" diff --git a/.changes/unreleased/Fixed-20230629-231503.yaml b/.changes/unreleased/Fixed-20230629-231503.yaml new file mode 100644 index 000000000..e021d1fda --- /dev/null +++ b/.changes/unreleased/Fixed-20230629-231503.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: '[export] set rolling date on person age aggregator' +time: 2023-06-29T23:15:03.20841309+02:00 +custom: + Issue: "" diff --git a/.changes/unreleased/Fixed-20230630-171119.yaml b/.changes/unreleased/Fixed-20230630-171119.yaml new file mode 100644 index 000000000..f3185ace2 --- /dev/null +++ b/.changes/unreleased/Fixed-20230630-171119.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: '[export] fix list when a person locating a course is without address' +time: 2023-06-30T17:11:19.454081914+02:00 +custom: + Issue: "" diff --git a/.changes/unreleased/Fixed-20230630-171153.yaml b/.changes/unreleased/Fixed-20230630-171153.yaml new file mode 100644 index 000000000..c09bd93d0 --- /dev/null +++ b/.changes/unreleased/Fixed-20230630-171153.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: '[export] remove unused condition on course about duration participation' +time: 2023-06-30T17:11:53.076615549+02:00 +custom: + Issue: "" diff --git a/.changes/v2.2.2.md b/.changes/v2.2.2.md new file mode 100644 index 000000000..61d194b6d --- /dev/null +++ b/.changes/v2.2.2.md @@ -0,0 +1,5 @@ +## v2.2.2 - 2023-06-26 +### Fixed +* [Accompanying period comments]: order comments from the most recent to the oldest, in the list +* Api: filter social action to keep only the currently activated +* ([#82](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/82)) Fix deletion and re-creation of filiation relationship diff --git a/.changes/v2.3.0.md b/.changes/v2.3.0.md new file mode 100644 index 000000000..827a338de --- /dev/null +++ b/.changes/v2.3.0.md @@ -0,0 +1,42 @@ +## v2.3.0 - 2023-06-27 +### Feature +* ([#110](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/110)) Edit saved exports options: the saved exports options (forms, filters, aggregators) are now editable. +* ([#103](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/103)) Get an unified list of document in person and accompanying period context +* [export] Set the default date of calculation of the accompanying period's list as "today" +* Force accompanying period user history to be unique for the same period and stardate/enddate [:warning: may encounter migration issue] + + If some issue is encountered during migration, use this SQL to find the line which are in conflict, examine the problem and delete some of the concerning line +* + ```sql + -- to see the line which are in conflict with another one + SELECT o.* + FROM chill_person_accompanying_period_user_history o + JOIN chill_person_accompanying_period_user_history c ON o.id < c.id AND o.accompanyingperiod_id = c.accompanyingperiod_id + WHERE tsrange(o.startdate, o.enddate, '[)') && tsrange(c.startdate, c.enddate, '[)') + ORDER BY accompanyingperiod_id; + -- to examine line in conflict for a given accompanyingperiod_id (given by the previous query) + SELECT * FROM chill_person_accompanying_period_user_history WHERE accompanyingperiod_id = IIIIDDDD order by startdate, enddate; + ``` +* Rename label of filter in French: "parcours actif" => "parcours ouvert", and "filtrer les parcours ouverts" => "Filtrer les parcours dont la date d'ouverture" + +### Traduction francophone des principaux changements + +* Les exports enregistrés sont éditables par l'utilisateur; +* L'onglet "Document" dans les parcours et les dossiers d'usager affiche désormais les documents ajoutés à différents endroits. + + Pour les parcours, il s'agit de: + + - documents ajoutés directement dans le parcours; + - documents des échanges; + - documents des rendez-vous; + - documents des évaluations; + - documents directement ajoutés dans le dossier des usagers concernés par le parcours; + + Pour les usagers, il s'agit de: + + - documents des échanges; + - documents des parcours; + - documents des rendez-vous; + - documents des actions, des échanges, des rendez-vous, des évaluations ajoutés dans les parcours. +* Dans la liste des parcours, la date de calcul des éléments associés est "aujourd'hui" par défaut. +* Dans les exports, renommage des libellés des filtres: "parcours actif" => "parcours ouvert", et "filtrer les parcours ouverts" => "Filtrer les parcours dont la date d'ouverture" diff --git a/.changie.yaml b/.changie.yaml index ba5454ce7..8a25ed695 100644 --- a/.changie.yaml +++ b/.changie.yaml @@ -5,8 +5,11 @@ changelogPath: CHANGELOG.md versionExt: md versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}' kindFormat: '### {{.Kind}}' +# Note: it is possible to add a `.custom.Long` text manually into the yaml file produced by `changie new`. This will add a long description. changeFormat: >- - * {{ if not (eq .Custom.Issue "") }}([#{{ .Custom.Issue }}](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/{{ .Custom.Issue }})) {{ end }}{{.Body}} + * {{ if not (eq .Custom.Issue "") }}([#{{ .Custom.Issue }}](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/{{ .Custom.Issue }})) {{ end }}{{.Body}} {{ if not (eq .Custom.Long "") }} + + {{ .Custom.Long }}{{ end }} custom: - key: Issue label: Issue number (on chill-bundles repository) (optional) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3f1d75ed5..aa1eff8b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,6 +34,7 @@ variables: stages: - Composer install - Tests + - Deploy build: stage: Composer install @@ -121,3 +122,14 @@ unit_tests: paths: - bin - tests/app/vendor/ + +release: + stage: Deploy + image: registry.gitlab.com/gitlab-org/release-cli:latest + rules: + - if: $CI_COMMIT_TAG + script: + - echo "running release_job" + release: + tag_name: '$CI_COMMIT_TAG' + description: "./.changes/v$CI_COMMIT_TAG.md" diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 4b5bf98ee..31d64e600 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -13,6 +13,7 @@ $finder = PhpCsFixer\Finder::create(); $finder ->in(__DIR__.'/src') + ->in(__DIR__.'/utils') ->append([__FILE__]) ->exclude(['docs/', 'tests/app']) ->notPath('tests/app') diff --git a/CHANGELOG.md b/CHANGELOG.md index e223fa116..93ff93556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,55 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## v2.3.0 - 2023-06-27 +### Feature +* ([#110](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/110)) Edit saved exports options: the saved exports options (forms, filters, aggregators) are now editable. +* ([#103](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/103)) Get an unified list of document in person and accompanying period context +* [export] Set the default date of calculation of the accompanying period's list as "today" +* Force accompanying period user history to be unique for the same period and stardate/enddate [:warning: may encounter migration issue] + + If some issue is encountered during migration, use this SQL to find the line which are in conflict, examine the problem and delete some of the concerning line +* + ```sql + -- to see the line which are in conflict with another one + SELECT o.* + FROM chill_person_accompanying_period_user_history o + JOIN chill_person_accompanying_period_user_history c ON o.id < c.id AND o.accompanyingperiod_id = c.accompanyingperiod_id + WHERE tsrange(o.startdate, o.enddate, '[)') && tsrange(c.startdate, c.enddate, '[)') + ORDER BY accompanyingperiod_id; + -- to examine line in conflict for a given accompanyingperiod_id (given by the previous query) + SELECT * FROM chill_person_accompanying_period_user_history WHERE accompanyingperiod_id = IIIIDDDD order by startdate, enddate; + ``` +* Rename label of filter in French: "parcours actif" => "parcours ouvert", and "filtrer les parcours ouverts" => "Filtrer les parcours dont la date d'ouverture" + +### Traduction francophone des principaux changements + +* Les exports enregistrés sont éditables par l'utilisateur; +* L'onglet "Document" dans les parcours et les dossiers d'usager affiche désormais les documents ajoutés à différents endroits. + + Pour les parcours, il s'agit de: + + - documents ajoutés directement dans le parcours; + - documents des échanges; + - documents des rendez-vous; + - documents des évaluations; + - documents directement ajoutés dans le dossier des usagers concernés par le parcours; + + Pour les usagers, il s'agit de: + + - documents des échanges; + - documents des parcours; + - documents des rendez-vous; + - documents des actions, des échanges, des rendez-vous, des évaluations ajoutés dans les parcours. +* Dans la liste des parcours, la date de calcul des éléments associés est "aujourd'hui" par défaut. +* Dans les exports, renommage des libellés des filtres: "parcours actif" => "parcours ouvert", et "filtrer les parcours ouverts" => "Filtrer les parcours dont la date d'ouverture" + +## v2.2.2 - 2023-06-26 +### Fixed +* [Accompanying period comments]: order comments from the most recent to the oldest, in the list +* Api: filter social action to keep only the currently activated +* ([#82](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/82)) Fix deletion and re-creation of filiation relationship + ## v2.2.1 - 2023-06-19 ### Fixed * ([#114](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/114)) [notification on document evaluation] fix entityId and return path when adding a notification on a document in an evaluation diff --git a/composer.json b/composer.json index f6d3eb27a..a128b1b77 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,7 @@ "fakerphp/faker": "^1.13", "jangregor/phpstan-prophecy": "^1.0", "nelmio/alice": "^3.8", + "nikic/php-parser": "^4.15", "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1.2", "phpstan/phpstan": "^1.9", @@ -103,14 +104,16 @@ "Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle", "Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle", "Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle", - "Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src" + "Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src", + "Chill\\Utils\\Rector\\": "utils/rector/src" } }, "autoload-dev": { "psr-4": { "App\\": "tests/app/src/", "Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests", - "Chill\\WopiBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests" + "Chill\\WopiBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests", + "Chill\\Utils\\Rector\\Tests\\": "utils/rector/tests" } }, "config": { diff --git a/docs/source/_static/code/exports/BirthdateFilter.php b/docs/source/_static/code/exports/BirthdateFilter.php index 64c1d53a9..e25d8b42f 100644 --- a/docs/source/_static/code/exports/BirthdateFilter.php +++ b/docs/source/_static/code/exports/BirthdateFilter.php @@ -62,7 +62,6 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac { $builder->add('date_from', DateType::class, [ 'label' => 'Born after this date', - 'data' => new DateTime(), 'attr' => ['class' => 'datepicker'], 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', @@ -70,12 +69,15 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac $builder->add('date_to', DateType::class, [ 'label' => 'Born before this date', - 'data' => new DateTime(), 'attr' => ['class' => 'datepicker'], 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', ]); } + public function getFormDefaultData(): array + { + return ['date_from' => new DateTime(), 'date_to' => new DateTime()]; + } // here, we create a simple string which will describe the action of // the filter in the Response diff --git a/docs/source/_static/code/exports/CountPerson.php b/docs/source/_static/code/exports/CountPerson.php index afe19c73b..be800e52c 100644 --- a/docs/source/_static/code/exports/CountPerson.php +++ b/docs/source/_static/code/exports/CountPerson.php @@ -36,6 +36,10 @@ class CountPerson implements ExportInterface { // this export does not add any form } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 56b7c2228..62dbe0468 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,7 @@ parameters: level: 5 paths: - src/ + - utils/ tmpDir: .cache/ reportUnmatchedIgnoredErrors: false excludePaths: diff --git a/phpunit.rector.xml b/phpunit.rector.xml new file mode 100644 index 000000000..f8d9d3a11 --- /dev/null +++ b/phpunit.rector.xml @@ -0,0 +1,29 @@ + + + + + utils/rector/tests + + + + + + utils/rector/src + + + diff --git a/rector.php b/rector.php index ec9a0c684..c2e752c32 100644 --- a/rector.php +++ b/rector.php @@ -24,6 +24,9 @@ return static function (RectorConfig $rectorConfig): void { LevelSetList::UP_TO_PHP_74 ]); + // chill rules + $rectorConfig->rule(\Chill\Utils\Rector\Rector\ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector::class); + // skip some path... $rectorConfig->skip([ // make rector stuck for some files diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php index 5c6656009..c23db738e 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByActivityNumberAggregator.php @@ -40,6 +40,10 @@ class ByActivityNumberAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByCreatorAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByCreatorAggregator.php index 69149737b..917459de3 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByCreatorAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByCreatorAggregator.php @@ -52,6 +52,10 @@ class ByCreatorAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialActionAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialActionAggregator.php index 89732412d..1a75357ae 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialActionAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialActionAggregator.php @@ -57,6 +57,10 @@ class BySocialActionAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialIssueAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialIssueAggregator.php index 158e87664..9100a8c8f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialIssueAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/BySocialIssueAggregator.php @@ -57,6 +57,10 @@ class BySocialIssueAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByThirdpartyAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByThirdpartyAggregator.php index c3ca6d59c..ac05b153c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByThirdpartyAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/ByThirdpartyAggregator.php @@ -57,6 +57,10 @@ class ByThirdpartyAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/CreatorScopeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/CreatorScopeAggregator.php index 2c7ec1483..a4b5258e2 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/CreatorScopeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/CreatorScopeAggregator.php @@ -57,6 +57,10 @@ class CreatorScopeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php index b4b23dc0b..4ede5b4c4 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php @@ -29,14 +29,6 @@ class DateAggregator implements AggregatorInterface private const DEFAULT_CHOICE = 'year'; - private TranslatorInterface $translator; - - public function __construct( - TranslatorInterface $translator - ) { - $this->translator = $translator; - } - public function addRole(): ?string { return null; @@ -84,9 +76,12 @@ class DateAggregator implements AggregatorInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['frequency' => self::DEFAULT_CHOICE]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/LocationTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/LocationTypeAggregator.php index ec4ce6315..c72609e2c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/LocationTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/LocationTypeAggregator.php @@ -57,6 +57,10 @@ class LocationTypeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php index 7cd16718e..a74428b4a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php @@ -60,6 +60,10 @@ class ActivityTypeAggregator implements AggregatorInterface { // no form required for this aggregator } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php index 9bde692c6..2fab2af83 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php @@ -58,6 +58,10 @@ class ActivityUserAggregator implements AggregatorInterface { // nothing to add } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, $values, $data): Closure { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersAggregator.php index 139f2743e..e1e9f161d 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersAggregator.php @@ -56,6 +56,10 @@ class ActivityUsersAggregator implements AggregatorInterface { // nothing to add on the form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersJobAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersJobAggregator.php index 5741a0e58..721078989 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersJobAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersJobAggregator.php @@ -55,6 +55,10 @@ class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorI { // nothing to add in the form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersScopeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersScopeAggregator.php index 15da300be..d7932e9e8 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersScopeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUsersScopeAggregator.php @@ -55,6 +55,10 @@ class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\Aggregato { // nothing to add in the form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/ActivityReasonAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/ActivityReasonAggregator.php index eaccf95cb..2537f2cf6 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/ActivityReasonAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/PersonAggregators/ActivityReasonAggregator.php @@ -110,6 +110,10 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali ] ); } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php index 5f772e156..ae1dae375 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/SentReceivedAggregator.php @@ -47,6 +47,10 @@ class SentReceivedAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): callable { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php index 34771d077..6930784d3 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityDuration.php @@ -39,6 +39,10 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php index df21362cd..f1e926c64 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/AvgActivityVisitDuration.php @@ -40,6 +40,10 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac { // TODO: Implement buildForm() method. } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php index 6b7b1562d..d473a925a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/CountActivity.php @@ -39,6 +39,10 @@ class CountActivity implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php index 026e16f90..9ed6bcda2 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/ListActivity.php @@ -44,6 +44,10 @@ class ListActivity implements ListInterface, GroupedExportInterface { $this->helper->buildForm($builder); } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php index e916cab54..8adb3b77f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityDuration.php @@ -40,6 +40,10 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface { // TODO: Implement buildForm() method. } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php index 18a47289c..cc424e68b 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToACP/SumActivityVisitDuration.php @@ -40,6 +40,10 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac { // TODO: Implement buildForm() method. } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php index 4246df173..6360251b3 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/CountActivity.php @@ -35,6 +35,10 @@ class CountActivity implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php index 60110c9a8..d14111ba7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/ListActivity.php @@ -88,6 +88,10 @@ class ListActivity implements ListInterface, GroupedExportInterface ])], ]); } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php index 050034954..e68d47cd3 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/LinkedToPerson/StatActivityDuration.php @@ -53,6 +53,10 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php index c6616a4c6..4ffc3b38c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php @@ -68,6 +68,10 @@ class ActivityTypeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ByCreatorFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ByCreatorFilter.php index 322393f32..add9c7c3d 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ByCreatorFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ByCreatorFilter.php @@ -52,6 +52,10 @@ class ByCreatorFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php index d0c1b0fc7..08f6bbbc3 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php @@ -60,6 +60,10 @@ class BySocialActionFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php index bbb882a65..bd6e2ef4a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php @@ -60,6 +60,10 @@ class BySocialIssueFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/EmergencyFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/EmergencyFilter.php index b79c2ca10..807ba3903 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/EmergencyFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/EmergencyFilter.php @@ -68,9 +68,12 @@ class EmergencyFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_emergency' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php index 570f42ae0..b5dab4009 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/HasNoActivityFilter.php @@ -44,6 +44,10 @@ class HasNoActivityFilter implements FilterInterface { //no form needed } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationFilter.php index 3d69d1633..312f3a6a0 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationFilter.php @@ -46,6 +46,10 @@ class LocationFilter implements FilterInterface 'label' => 'pick location', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php index 5fe928b6c..1c3415460 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php @@ -65,6 +65,10 @@ class LocationTypeFilter implements FilterInterface //'label' => false, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/SentReceivedFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/SentReceivedFilter.php index 8daa7a781..0f2a1c7e4 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/SentReceivedFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/SentReceivedFilter.php @@ -69,9 +69,12 @@ class SentReceivedFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_sentreceived' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserFilter.php index 6350f3ace..9ae988579 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserFilter.php @@ -61,6 +61,10 @@ class UserFilter implements FilterInterface 'label' => 'Creators', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserScopeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserScopeFilter.php index 4319c100a..adb1e94f1 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserScopeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/UserScopeFilter.php @@ -71,6 +71,10 @@ class UserScopeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php index f2216c929..e582acc12 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -80,11 +80,9 @@ class ActivityDateFilter implements FilterInterface $builder ->add('date_from', PickRollingDateType::class, [ 'label' => 'Activities after this date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) ->add('date_to', PickRollingDateType::class, [ 'label' => 'Activities before this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { @@ -127,6 +125,10 @@ class ActivityDateFilter implements FilterInterface } }); } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php index b9d39c3ce..8dfcb543c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php @@ -78,6 +78,10 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter ], ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityUsersFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityUsersFilter.php index 2f6cd8462..a63ca2629 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityUsersFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityUsersFilter.php @@ -56,6 +56,10 @@ class ActivityUsersFilter implements FilterInterface 'label' => 'Users', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/ActivityReasonFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/ActivityReasonFilter.php index c55d579e4..31cfde6b6 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/ActivityReasonFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/ActivityReasonFilter.php @@ -82,6 +82,10 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt 'expanded' => false, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php index e3c85fe9c..490b5fd0c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonFilters/PersonHavingActivityBetweenDateFilter.php @@ -112,7 +112,6 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt { $builder->add('date_from', DateType::class, [ 'label' => 'Implied in an activity after this date', - 'data' => new DateTime(), 'attr' => ['class' => 'datepicker'], 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', @@ -120,7 +119,6 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt $builder->add('date_to', DateType::class, [ 'label' => 'Implied in an activity before this date', - 'data' => new DateTime(), 'attr' => ['class' => 'datepicker'], 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', @@ -130,7 +128,6 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt 'class' => ActivityReason::class, 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), 'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), - 'data' => $this->activityReasonRepository->findAll(), 'multiple' => true, 'expanded' => false, 'label' => 'Activity reasons for those activities', @@ -176,6 +173,10 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt } }); } + public function getFormDefaultData(): array + { + return ['date_from' => new DateTime(), 'date_to' => new DateTime(), 'reasons' => $this->activityReasonRepository->findAll()]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php index b52ef441c..e85b2d247 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/UsersJobFilter.php @@ -60,6 +60,10 @@ class UsersJobFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/UsersScopeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/UsersScopeFilter.php index 61b12264e..07ff509ce 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/UsersScopeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/UsersScopeFilter.php @@ -67,6 +67,10 @@ class UsersScopeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepository.php new file mode 100644 index 000000000..ce70409ba --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepository.php @@ -0,0 +1,198 @@ +buildBaseFetchQueryActivityDocumentLinkedToPersonFromPersonContext($person, $startDate, $endDate, $content); + + return $this->addFetchQueryByPersonACL($query, $person); + } + + public function buildBaseFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + $activityMetadata = $this->em->getClassMetadata(Activity::class); + + $query = new FetchQuery( + PersonActivityGenericDocProvider::KEY, + sprintf('jsonb_build_object(\'id\', stored_obj.%s, \'activity_id\', activity.%s)', $storedObjectMetadata->getSingleIdentifierColumnName(), $activityMetadata->getSingleIdentifierColumnName()), + sprintf('stored_obj.%s', $storedObjectMetadata->getColumnName('createdAt')), + sprintf('%s AS stored_obj', $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName()) + ); + + $query->addJoinClause( + 'JOIN public.activity_storedobject activity_doc ON activity_doc.storedobject_id = stored_obj.id' + ); + + $query->addJoinClause( + 'JOIN public.activity activity ON activity.id = activity_doc.activity_id' + ); + + $query->addWhereClause( + sprintf('activity.%s = ?', $activityMetadata->getSingleAssociationJoinColumnName('person')), + [$person->getId()], + [Types::INTEGER] + ); + + return $this->addWhereClauses($query, $startDate, $endDate, $content); + } + + public function buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + $activityMetadata = $this->em->getClassMetadata(Activity::class); + + $query = new FetchQuery( + AccompanyingPeriodActivityGenericDocProvider::KEY, + sprintf('jsonb_build_object(\'id\', stored_obj.%s, \'activity_id\', activity.%s)', $storedObjectMetadata->getSingleIdentifierColumnName(), $activityMetadata->getSingleIdentifierColumnName()), + sprintf('stored_obj.%s', $storedObjectMetadata->getColumnName('createdAt')), + sprintf('%s AS stored_obj', $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName()) + ); + + $query->addJoinClause( + 'JOIN public.activity_storedobject activity_doc ON activity_doc.storedobject_id = stored_obj.id' + ); + + $query->addJoinClause( + 'JOIN public.activity activity ON activity.id = activity_doc.activity_id' + ); + + // add documents of activities from parcours context + $or = []; + $orParams = []; + $orTypes = []; + foreach ($person->getAccompanyingPeriodParticipations() as $participation) { + if (!$this->security->isGranted(ActivityVoter::SEE, $participation->getAccompanyingPeriod())) { + continue; + } + + $or[] = sprintf( + '(activity.%s = ? AND stored_obj.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))', + $activityMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'), + $storedObjectMetadata->getColumnName('createdAt') + ); + $orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(), + DateTimeImmutable::createFromInterface($participation->getStartDate()), + null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())]; + $orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE]; + } + + if ([] === $or) { + $query->addWhereClause('TRUE = FALSE'); + + return $query; + } + + $query->addWhereClause(sprintf('(%s)', implode(' OR ', $or)), $orParams, $orTypes); + + return $this->addWhereClauses($query, $startDate, $endDate, $content); + } + + private function addWhereClauses(FetchQuery $query, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('stored_obj.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('stored_obj.%s < ?', $storedObjectMetadata->getColumnName('createdAt')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content and '' !== $content) { + $query->addWhereClause( + 'stored_obj.title ilike ?', + ['%' . $content . '%'], + [Types::STRING] + ); + } + + return $query; + } + + private function addFetchQueryByPersonACL(FetchQuery $fetchQuery, Person $person): FetchQuery + { + $activityMetadata = $this->em->getClassMetadata(Activity::class); + + $reachableScopes = []; + + foreach ($this->centerResolverManager->resolveCenters($person) as $center) { + $reachableScopes = [ + ...$reachableScopes, + ...$this->authorizationHelperForCurrentUser->getReachableScopes(ActivityVoter::SEE, $center) + ]; + } + + if ([] === $reachableScopes) { + $fetchQuery->addWhereClause('FALSE = TRUE'); + + return $fetchQuery; + } + + $fetchQuery->addWhereClause( + sprintf( + 'activity.%s IN (%s)', + $activityMetadata->getSingleAssociationJoinColumnName('scope'), + implode(', ', array_fill(0, count($reachableScopes), '?')) + ), + array_map(static fn (Scope $s) => $s->getId(), $reachableScopes), + array_fill(0, count($reachableScopes), Types::INTEGER) + ); + + return $fetchQuery; + } +} diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepositoryInterface.php b/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepositoryInterface.php new file mode 100644 index 000000000..9f4a9c0f8 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityDocumentACLAwareRepositoryInterface.php @@ -0,0 +1,37 @@ + +
+
+ {% if document.isPending %} +
{{ 'docgen.Doc generation is pending'|trans }}
+ {% elseif document.isFailure %} +
{{ 'docgen.Doc generation failed'|trans }}
+ {% endif %} + +
+ {% if activity.accompanyingPeriod is not null and context == 'person' %} + + {{ activity.accompanyingPeriod.id }} +   + {% endif %} +
+ + + {{ activity.type.name | localize_translatable_string }} + {% if activity.emergency %} + {{ 'Emergency'|trans|upper }} + {% endif %} + +
+
+
+ {{ document.title|chill_print_or_message("No title") }} +
+ {% if document.hasTemplate %} +
+

{{ document.template.name|localize_translatable_string }}

+
+ {% endif %} +
+ +
+
+
+ {{ document.createdAt|format_date('short') }} +
+
+
+
+ + +
+
+ {{ mmm.createdBy(document) }} +
+ + +
+ diff --git a/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/AccompanyingPeriodActivityGenericDocProvider.php b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/AccompanyingPeriodActivityGenericDocProvider.php new file mode 100644 index 000000000..334b5d2df --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/AccompanyingPeriodActivityGenericDocProvider.php @@ -0,0 +1,114 @@ +em->getClassMetadata(StoredObject::class); + $activityMetadata = $this->em->getClassMetadata(Activity::class); + + $query = new FetchQuery( + self::KEY, + sprintf("jsonb_build_object('id', doc_obj.%s, 'activity_id', activity.%s)", $storedObjectMetadata->getSingleIdentifierColumnName(), $activityMetadata->getSingleIdentifierColumnName()), + 'doc_obj.'.$storedObjectMetadata->getColumnName('createdAt'), + $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName().' AS doc_obj' + ); + + $query->addJoinClause( + 'JOIN public.activity_storedobject activity_doc ON activity_doc.storedobject_id = doc_obj.id' + ); + + $query->addJoinClause( + 'JOIN public.activity activity ON activity.id = activity_doc.activity_id' + ); + + $query->addWhereClause( + 'activity.accompanyingperiod_id = ?', + [$accompanyingPeriod->getId()], + [Types::INTEGER] + ); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('doc_obj.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('doc_obj.%s < ?', $storedObjectMetadata->getColumnName('createdAt')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content) { + $query->addWhereClause( + 'doc_obj.title ilike ?', + ['%' . $content . '%'], + [Types::STRING] + ); + } + + return $query; + } + + /** + * @param AccompanyingPeriod $accompanyingPeriod + * @return bool + */ + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return $this->security->isGranted(ActivityVoter::SEE, $accompanyingPeriod); + } + + public function isAllowedForPerson(Person $person): bool + { + return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person); + } + + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + return $this->activityDocumentACLAwareRepository + ->buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext($person, $startDate, $endDate, $content); + } +} diff --git a/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/PersonActivityGenericDocProvider.php b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/PersonActivityGenericDocProvider.php new file mode 100644 index 000000000..cf96449ab --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Providers/PersonActivityGenericDocProvider.php @@ -0,0 +1,53 @@ +personActivityDocumentACLAwareRepository->buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext( + $person, + $startDate, + $endDate, + $content + ); + } + + /** + * @param Person $person + * @return bool + */ + public function isAllowedForPerson(Person $person): bool + { + return $this->security->isGranted(ActivityVoter::SEE, $person); + } +} diff --git a/src/Bundle/ChillActivityBundle/Service/GenericDoc/Renderers/AccompanyingPeriodActivityGenericDocRenderer.php b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Renderers/AccompanyingPeriodActivityGenericDocRenderer.php new file mode 100644 index 000000000..c465dbca1 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Service/GenericDoc/Renderers/AccompanyingPeriodActivityGenericDocRenderer.php @@ -0,0 +1,52 @@ +objectRepository = $storedObjectRepository; + $this->activityRepository = $activityRepository; + } + + public function supports(GenericDocDTO $genericDocDTO, $options = []): bool + { + return $genericDocDTO->key === AccompanyingPeriodActivityGenericDocProvider::KEY || $genericDocDTO->key === PersonActivityGenericDocProvider::KEY; + } + + public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string + { + return '@ChillActivity/GenericDoc/activity_document.html.twig'; + } + + public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array + { + return [ + 'activity' => $this->activityRepository->find($genericDocDTO->identifiers['activity_id']), + 'document' => $this->objectRepository->find($genericDocDTO->identifiers['id']), + 'context' => $genericDocDTO->getContext(), + ]; + } +} diff --git a/src/Bundle/ChillActivityBundle/Tests/Repository/ActivityDocumentACLAwareRepositoryTest.php b/src/Bundle/ChillActivityBundle/Tests/Repository/ActivityDocumentACLAwareRepositoryTest.php new file mode 100644 index 000000000..ce4f318e3 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Tests/Repository/ActivityDocumentACLAwareRepositoryTest.php @@ -0,0 +1,126 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + $this->centerResolverManager = self::$container->get(CenterResolverManagerInterface::class); + $this->authorizationHelperForCurrentUser = self::$container->get(AuthorizationHelperForCurrentUserInterface::class); + $this->security = self::$container->get(Security::class); + } + + /** + * @dataProvider provideDataForPerson + */ + public function testBuildFetchQueryActivityDocumentLinkedToPersonFromPersonContext(Person $person, array $reachableScopes, bool $_unused, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $authorizationHelper = $this->prophesize(AuthorizationHelperForCurrentUserInterface::class); + $authorizationHelper->getReachableScopes(ActivityVoter::SEE, Argument::any()) + ->willReturn($reachableScopes); + + $repository = new ActivityDocumentACLAwareRepository( + $this->entityManager, + $this->centerResolverManager, + $authorizationHelper->reveal(), + $this->security + ); + + $query = $repository->buildFetchQueryActivityDocumentLinkedToPersonFromPersonContext($person, $startDate, $endDate, $content); + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) sq", $params, $types); + + self::assertIsInt($nb); + } + + /** + * @dataProvider provideDataForPerson + */ + public function testBuildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext(Person $person, array $_unused, bool $canSeePeriod, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $security = $this->prophesize(Security::class); + $security->isGranted(ActivityVoter::SEE, Argument::type(AccompanyingPeriod::class)) + ->willReturn($canSeePeriod); + + $repository = new ActivityDocumentACLAwareRepository( + $this->entityManager, + $this->centerResolverManager, + $this->authorizationHelperForCurrentUser, + $security->reveal() + ); + + $query = $repository->buildFetchQueryActivityDocumentLinkedToAccompanyingPeriodFromPersonContext($person, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) sq", $params, $types); + + self::assertIsInt($nb); + } + + public function provideDataForPerson(): iterable + { + $this->setUp(); + + if (null === $person = $this->entityManager->createQuery("SELECT p FROM " . Person::class . " p WHERE SIZE(p.accompanyingPeriodParticipations) > 0 ") + ->setMaxResults(1) + ->getSingleResult()) { + throw new \RuntimeException("no person in dtabase"); + } + + if ([] === $scopes = $this->entityManager->createQuery("SELECT s FROM " . Scope::class . " s ")->setMaxResults(5)->getResult()) { + throw new \RuntimeException("no scopes in database"); + } + + yield [$person, [], true, null, null, null]; + yield [$person, $scopes, true, null, null, null]; + yield [$person, $scopes, true, new \DateTimeImmutable("1 month ago"), null, null]; + yield [$person, $scopes, true, new \DateTimeImmutable("1 month ago"), new \DateTimeImmutable("1 week ago"), null]; + yield [$person, $scopes, true, new \DateTimeImmutable("1 month ago"), new \DateTimeImmutable("1 week ago"), "content"]; + yield [$person, $scopes, true, null, new \DateTimeImmutable("1 week ago"), "content"]; + yield [$person, [], true, new \DateTimeImmutable("1 month ago"), new \DateTimeImmutable("1 week ago"), "content"]; + } + +} diff --git a/src/Bundle/ChillActivityBundle/config/services.yaml b/src/Bundle/ChillActivityBundle/config/services.yaml index d55f86d4f..18be76ec9 100644 --- a/src/Bundle/ChillActivityBundle/config/services.yaml +++ b/src/Bundle/ChillActivityBundle/config/services.yaml @@ -38,3 +38,6 @@ services: Chill\ActivityBundle\Service\EntityInfo\: resource: '../Service/EntityInfo/' + + Chill\ActivityBundle\Service\GenericDoc\: + resource: '../Service/GenericDoc/' diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 1229494bb..c53a04f31 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -380,3 +380,8 @@ export: is sent: envoyé is received: reçu Group activity by sentreceived: Grouper les échanges par envoyé / reçu + +generic_doc: + filter: + keys: + accompanying_period_activity_document: Document des échanges des parcours diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php index 32418e3c3..8ae43534d 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByActivityTypeAggregator.php @@ -50,6 +50,10 @@ class ByActivityTypeAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserJobAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserJobAggregator.php index d2fe7c2f2..f09a704e2 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserJobAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserJobAggregator.php @@ -57,6 +57,10 @@ class ByUserJobAggregator implements AggregatorInterface { // nothing to add in the form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserScopeAggregator.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserScopeAggregator.php index 6c06ee756..3dd465db2 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserScopeAggregator.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Aggregator/ByUserScopeAggregator.php @@ -57,6 +57,10 @@ class ByUserScopeAggregator implements AggregatorInterface { // nothing to add in the form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/AvgAsideActivityDuration.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/AvgAsideActivityDuration.php index f3db629cb..2b28062f6 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/AvgAsideActivityDuration.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/AvgAsideActivityDuration.php @@ -34,6 +34,10 @@ class AvgAsideActivityDuration implements ExportInterface, GroupedExportInterfac public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php index 9204fad4b..91210f764 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/CountAsideActivity.php @@ -34,6 +34,10 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php index aee168174..b46e120b5 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php @@ -73,6 +73,10 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/SumAsideActivityDuration.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/SumAsideActivityDuration.php index af17a2591..741f129f1 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Export/SumAsideActivityDuration.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Export/SumAsideActivityDuration.php @@ -34,6 +34,10 @@ class SumAsideActivityDuration implements ExportInterface, GroupedExportInterfac public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php index 3ad8e0e93..3d389f5b3 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByActivityTypeFilter.php @@ -76,6 +76,10 @@ class ByActivityTypeFilter implements FilterInterface }, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php index 7a1b6f4dc..98a254bc4 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByDateFilter.php @@ -72,11 +72,9 @@ class ByDateFilter implements FilterInterface $builder ->add('date_from', PickRollingDateType::class, [ 'label' => 'export.filter.Aside activities after this date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) ->add('date_to', PickRollingDateType::class, [ 'label' => 'export.filter.Aside activities before this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { @@ -119,6 +117,10 @@ class ByDateFilter implements FilterInterface } }); } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserFilter.php index 795c813cd..2858d3417 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserFilter.php @@ -53,6 +53,10 @@ class ByUserFilter implements FilterInterface 'label' => 'Creators', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserJobFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserJobFilter.php index 86194b123..55f477768 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserJobFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserJobFilter.php @@ -60,6 +60,10 @@ class ByUserJobFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserScopeFilter.php b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserScopeFilter.php index 4342e11eb..8fa51866d 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserScopeFilter.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Export/Filter/ByUserScopeFilter.php @@ -67,6 +67,10 @@ class ByUserScopeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml index cc428390c..25d07bd22 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml @@ -176,11 +176,12 @@ export: agent_id: Utilisateur creator_id: Créateur main_scope: Service principal de l'utilisateur - main_center: Centre principal de l'utilisteur + main_center: Centre principal de l'utilisateur aside_activity_type: Catégorie d'activité annexe date: Date duration: Durée note: Note + id: Identifiant Exports of aside activities: Exports des activités annexes Count aside activities: Nombre d'activités annexes diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/AgentAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/AgentAggregator.php index e1de9f399..1b1b170b8 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/AgentAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/AgentAggregator.php @@ -58,6 +58,10 @@ final class AgentAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/CancelReasonAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/CancelReasonAggregator.php index 611cb6d79..a9967c470 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/CancelReasonAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/CancelReasonAggregator.php @@ -59,6 +59,10 @@ class CancelReasonAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php index 23292a5b0..51291b49e 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/JobAggregator.php @@ -58,6 +58,10 @@ final class JobAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationAggregator.php index 940000f47..952d0c5d5 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationAggregator.php @@ -52,6 +52,10 @@ final class LocationAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationTypeAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationTypeAggregator.php index 6574e3934..a9b369af0 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationTypeAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/LocationTypeAggregator.php @@ -58,6 +58,10 @@ final class LocationTypeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/MonthYearAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/MonthYearAggregator.php index 7b2a5e898..b3c2aaf19 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/MonthYearAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/MonthYearAggregator.php @@ -40,6 +40,10 @@ class MonthYearAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php index 3aff3e0d8..01874b0e2 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/ScopeAggregator.php @@ -58,6 +58,10 @@ final class ScopeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Aggregator/UrgencyAggregator.php b/src/Bundle/ChillCalendarBundle/Export/Aggregator/UrgencyAggregator.php index ad5910461..66ab8b42e 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Aggregator/UrgencyAggregator.php +++ b/src/Bundle/ChillCalendarBundle/Export/Aggregator/UrgencyAggregator.php @@ -56,6 +56,10 @@ class UrgencyAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data): Closure { diff --git a/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php b/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php index 9d3f00f99..e0391948e 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php +++ b/src/Bundle/ChillCalendarBundle/Export/Export/CountCalendars.php @@ -36,6 +36,10 @@ class CountCalendars implements ExportInterface, GroupedExportInterface { // No form necessary } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarAvgDuration.php b/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarAvgDuration.php index 14dd42d6b..dcbfb695b 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarAvgDuration.php +++ b/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarAvgDuration.php @@ -36,6 +36,10 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface { // no form needed } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarSumDuration.php b/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarSumDuration.php index 1d31bfa26..7f509a896 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarSumDuration.php +++ b/src/Bundle/ChillCalendarBundle/Export/Export/StatCalendarSumDuration.php @@ -36,6 +36,10 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface { // no form needed } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php index b58cee594..0cef89c20 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php @@ -63,6 +63,10 @@ class AgentFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php index 59019ac03..4260ecd99 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/BetweenDatesFilter.php @@ -60,12 +60,12 @@ class BetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), - ]) - ->add('date_to', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + ->add('date_from', PickRollingDateType::class, []) + ->add('date_to', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/CalendarRangeFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/CalendarRangeFilter.php index d6c38e163..5ffb7c01f 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/CalendarRangeFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/CalendarRangeFilter.php @@ -69,9 +69,12 @@ class CalendarRangeFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['hasCalendarRange' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php index 69fb24447..d02bb8e9d 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php @@ -76,6 +76,10 @@ class JobFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php b/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php index 08d9ae023..d8a40da72 100644 --- a/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php +++ b/src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php @@ -76,6 +76,10 @@ class ScopeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/chill/chill.js b/src/Bundle/ChillCalendarBundle/Resources/public/chill/chill.js new file mode 100644 index 000000000..56a8ce563 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Resources/public/chill/chill.js @@ -0,0 +1 @@ +import './scss/badge.scss'; diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/badge.scss b/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/badge.scss new file mode 100644 index 000000000..ffcda8f0f --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/badge.scss @@ -0,0 +1,25 @@ +@import '~ChillPersonAssets/chill/scss/mixins.scss'; +@import '~ChillMainAssets/module/bootstrap/shared'; + +.badge-calendar { + display: inline-block; + background-color: #f3f3f3; + + .title_label { + @include chill_badge($chill-l-gray); + } + + .title_action { + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + margin-right: 1rem; + + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + } +} + diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/calendar.scss b/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/calendar.scss index a2c0c4b89..ce54b0fa8 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/calendar.scss +++ b/src/Bundle/ChillCalendarBundle/Resources/public/chill/scss/calendar.scss @@ -17,4 +17,4 @@ span.calendarRangeItems { text-decoration: none; padding: 3px; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/GenericDoc/calendar_document.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/GenericDoc/calendar_document.html.twig new file mode 100644 index 000000000..facf5be50 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Resources/views/GenericDoc/calendar_document.html.twig @@ -0,0 +1,75 @@ +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} +{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %} +{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %} + +{% set c = document.calendar %} + +
+
+
+ {% if document.storedObject.isPending %} +
{{ 'docgen.Doc generation is pending'|trans }}
+ {% elseif document.storedObject.isFailure %} +
{{ 'docgen.Doc generation failed'|trans }}
+ {% endif %} + +
+ {% if c.accompanyingPeriod is not null and context == 'person' %} + + {{ c.accompanyingPeriod.id }} +   + {% endif %} + + + + + {{ 'Calendar'|trans }} + {% if c.endDate.diff(c.startDate).days >= 1 %} + {{ c.startDate|format_datetime('short', 'short') }} + - {{ c.endDate|format_datetime('short', 'short') }} + {% else %} + {{ c.startDate|format_datetime('short', 'short') }} + - {{ c.endDate|format_datetime('none', 'short') }} + {% endif %} + + +
+ +
+ {{ document.storedObject.title|chill_print_or_message("No title") }} +
+ {% if document.storedObject.hasTemplate %} +
+

{{ document.storedObject.template.name|localize_translatable_string }}

+
+ {% endif %} +
+ +
+
+
+ {{ document.storedObject.createdAt|format_date('short') }} +
+
+
+
+ +
+
+ {{ mmm.createdBy(document) }} +
+ + +
+
diff --git a/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProvider.php b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProvider.php new file mode 100644 index 000000000..c33ccd853 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProvider.php @@ -0,0 +1,192 @@ +em->getClassMetadata(CalendarDoc::class); + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + $calendarMetadata = $this->em->getClassMetadata(Calendar::class); + + $query = new FetchQuery( + self::KEY, + sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')), + 'cd.'.$storedObjectMetadata->getColumnName('createdAt'), + $classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd' + ); + $query->addJoinClause( + sprintf( + 'JOIN %s doc_store ON doc_store.%s = cd.%s', + $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(), + $storedObjectMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('storedObject') + ) + ); + + $query->addJoinClause( + sprintf( + 'JOIN %s calendar ON calendar.%s = cd.%s', + $calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(), + $calendarMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('calendar') + ) + ); + + $query->addWhereClause( + sprintf( + 'calendar.%s = ?', + $calendarMetadata->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]['name'] + ), + [$accompanyingPeriod->getId()], + [Types::INTEGER] + ); + + return $query; + } + + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return $this->security->isGranted(CalendarVoter::SEE, $accompanyingPeriod); + } + + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $classMetadata = $this->em->getClassMetadata(CalendarDoc::class); + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + $calendarMetadata = $this->em->getClassMetadata(Calendar::class); + + $query = new FetchQuery( + self::KEY, + sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')), + 'cd.'.$storedObjectMetadata->getColumnName('createdAt'), + $classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd' + ); + $query->addJoinClause( + sprintf( + 'JOIN %s doc_store ON doc_store.%s = cd.%s', + $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(), + $storedObjectMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('storedObject') + ) + ); + + $query->addJoinClause( + sprintf( + 'JOIN %s calendar ON calendar.%s = cd.%s', + $calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(), + $calendarMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('calendar') + ) + ); + + // get the documents associated with accompanying periods in which person participates + $or = []; + $orParams = []; + $orTypes = []; + foreach ($person->getAccompanyingPeriodParticipations() as $participation) { + if (!$this->security->isGranted(CalendarVoter::SEE, $participation->getAccompanyingPeriod())) { + continue; + } + + $or[] = sprintf( + '(calendar.%s = ? AND cd.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))', + $calendarMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'), + $storedObjectMetadata->getColumnName('createdAt') + ); + $orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(), + DateTimeImmutable::createFromInterface($participation->getStartDate()), + null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())]; + $orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE]; + } + + if ([] === $or) { + $query->addWhereClause('TRUE = FALSE'); + + return $query; + } + return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content); + } + + public function isAllowedForPerson(Person $person): bool + { + // check that the person is allowed to see an accompanying period. If yes, the + // ACL on each accompanying period will be checked when the query is build + return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person); + } + + private function addWhereClausesToQuery(FetchQuery $query, ?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?string $content): FetchQuery + { + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content) { + $query->addWhereClause( + sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')), + ['%' . $content . '%'], + [Types::STRING] + ); + } + + return $query; + } + + +} diff --git a/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/PersonCalendarGenericDocProvider.php b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/PersonCalendarGenericDocProvider.php new file mode 100644 index 000000000..f5d4b3cbb --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Providers/PersonCalendarGenericDocProvider.php @@ -0,0 +1,126 @@ +em->getClassMetadata(StoredObject::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content) { + $query->addWhereClause( + sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')), + ['%' . $content . '%'], + [Types::STRING] + ); + } + + return $query; + } + + /** + * @throws MappingException + */ + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $classMetadata = $this->em->getClassMetadata(CalendarDoc::class); + $storedObjectMetadata = $this->em->getClassMetadata(StoredObject::class); + $calendarMetadata = $this->em->getClassMetadata(Calendar::class); + + $query = new FetchQuery( + self::KEY, + sprintf("jsonb_build_object('id', cd.%s)", $classMetadata->getColumnName('id')), + 'cd.'.$storedObjectMetadata->getColumnName('createdAt'), + $classMetadata->getSchemaName().'.'.$classMetadata->getTableName().' AS cd' + ); + $query->addJoinClause( + sprintf( + 'JOIN %s doc_store ON doc_store.%s = cd.%s', + $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(), + $storedObjectMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('storedObject') + ) + ); + + $query->addJoinClause( + sprintf( + 'JOIN %s calendar ON calendar.%s = cd.%s', + $calendarMetadata->getSchemaName().'.'.$calendarMetadata->getTableName(), + $calendarMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('calendar') + ) + ); + + $query->addWhereClause( + sprintf('calendar.%s = ?', $calendarMetadata->getSingleAssociationJoinColumnName('person')), + [$person->getId()], + [Types::INTEGER] + ); + + return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content); + } + + /** + * @param Person $person + * @return bool + */ + public function isAllowedForPerson(Person $person): bool + { + return $this->security->isGranted(CalendarVoter::SEE, $person); + } +} diff --git a/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Renderers/AccompanyingPeriodCalendarGenericDocRenderer.php b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Renderers/AccompanyingPeriodCalendarGenericDocRenderer.php new file mode 100644 index 000000000..b15c091c6 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Service/GenericDoc/Renderers/AccompanyingPeriodCalendarGenericDocRenderer.php @@ -0,0 +1,46 @@ +repository = $calendarDocRepository; + } + + public function supports(GenericDocDTO $genericDocDTO, $options = []): bool + { + return $genericDocDTO->key === AccompanyingPeriodCalendarGenericDocProvider::KEY || $genericDocDTO->key === PersonCalendarGenericDocProvider::KEY; + } + + public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string + { + return '@ChillCalendar/GenericDoc/calendar_document.html.twig'; + } + + public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array + { + return [ + 'document' => $this->repository->find($genericDocDTO->identifiers['id']), + 'context' => $genericDocDTO->getContext(), + ]; + } +} diff --git a/src/Bundle/ChillCalendarBundle/chill.webpack.config.js b/src/Bundle/ChillCalendarBundle/chill.webpack.config.js index e82210087..9d45a3142 100644 --- a/src/Bundle/ChillCalendarBundle/chill.webpack.config.js +++ b/src/Bundle/ChillCalendarBundle/chill.webpack.config.js @@ -1,6 +1,8 @@ // this file loads all assets from the Chill calendar bundle module.exports = function(encore, entries) { + entries.push(__dirname + '/Resources/public/chill/chill.js'); + encore.addAliases({ ChillCalendarAssets: __dirname + '/Resources/public' }); diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml index eb02be280..c56d7835f 100644 --- a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml @@ -43,6 +43,7 @@ crud: title_edit: Modifier le motif d'annulation chill_calendar: + Document: Document d'un rendez-vous form: The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement. Create for referrer: Créer pour le référent @@ -65,6 +66,7 @@ chill_calendar: Document outdated: La date et l'heure du rendez-vous ont été modifiés après la création du document + remote_ms_graph: freebusy_statuses: busy: Occupé @@ -145,3 +147,9 @@ CHILL_CALENDAR_CALENDAR_EDIT: Modifier les rendez-vous CHILL_CALENDAR_CALENDAR_DELETE: Supprimer les rendez-vous CHILL_CALENDAR_CALENDAR_SEE: Voir les rendez-vous + +generic_doc: + filter: + keys: + accompanying_period_calendar_document: Document des rendez-vous des parcours + person_calendar_document: Document des rendez-vous de l'usager diff --git a/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php b/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php index 81c71f45f..8dcbe72c3 100644 --- a/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php +++ b/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php @@ -11,8 +11,21 @@ declare(strict_types=1); namespace Chill\DocStoreBundle; +use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface; +use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface; +use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; class ChillDocStoreBundle extends Bundle { + public function build(ContainerBuilder $container) + { + $container->registerForAutoconfiguration(GenericDocForAccompanyingPeriodProviderInterface::class) + ->addTag('chill_doc_store.generic_doc_accompanying_period_provider'); + $container->registerForAutoconfiguration(GenericDocForPersonProviderInterface::class) + ->addTag('chill_doc_store.generic_doc_person_provider'); + $container->registerForAutoconfiguration(GenericDocRendererInterface::class) + ->addTag('chill_doc_store.generic_doc_renderer'); + } } diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php index 1bc3db221..384eeb510 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php @@ -39,10 +39,6 @@ class DocumentAccompanyingCourseController extends AbstractController protected TranslatorInterface $translator; - private AccompanyingCourseDocumentRepository $courseRepository; - - private PaginatorFactory $paginatorFactory; - /** * DocumentAccompanyingCourseController constructor. */ @@ -50,14 +46,10 @@ class DocumentAccompanyingCourseController extends AbstractController TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper, - PaginatorFactory $paginatorFactory, - AccompanyingCourseDocumentRepository $courseRepository ) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; - $this->paginatorFactory = $paginatorFactory; - $this->courseRepository = $courseRepository; } /** @@ -82,7 +74,7 @@ class DocumentAccompanyingCourseController extends AbstractController return $this->redirect($request->query->get('returnPath')); } - return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]); + return $this->redirectToRoute('chill_docstore_generic-doc_by-period_index', ['id' => $course->getId()]); } return $this->render( @@ -136,40 +128,6 @@ class DocumentAccompanyingCourseController extends AbstractController ); } - /** - * @Route("/", name="accompanying_course_document_index", methods="GET") - */ - public function index(AccompanyingPeriod $course): Response - { - $em = $this->getDoctrine()->getManager(); - - if (null === $course) { - throw $this->createNotFoundException('Accompanying period not found'); - } - - $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE, $course); - - $total = $this->courseRepository->countByCourse($course); - $pagination = $this->paginatorFactory->create($total); - - $documents = $this->courseRepository - ->findBy( - ['course' => $course], - ['date' => 'DESC', 'id' => 'DESC'], - $pagination->getItemsPerPage(), - $pagination->getCurrentPageFirstItemNumber() - ); - - return $this->render( - 'ChillDocStoreBundle:AccompanyingCourseDocument:index.html.twig', - [ - 'documents' => $documents, - 'accompanyingCourse' => $course, - 'pagination' => $pagination, - ] - ); - } - /** * @Route("/new", name="accompanying_course_document_new", methods="GET|POST") */ @@ -202,7 +160,7 @@ class DocumentAccompanyingCourseController extends AbstractController $this->addFlash('success', $this->translator->trans('The document is successfully registered')); - return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]); + return $this->redirectToRoute('chill_docstore_generic-doc_by-period_index', ['id' => $course->getId()]); } if ($form->isSubmitted() && !$form->isValid()) { diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php index 6fcb6a8e5..20e8e9b03 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php @@ -45,10 +45,6 @@ class DocumentPersonController extends AbstractController protected TranslatorInterface $translator; - private PaginatorFactory $paginatorFactory; - - private PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository; - /** * DocumentPersonController constructor. */ @@ -56,14 +52,10 @@ class DocumentPersonController extends AbstractController TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper, - PaginatorFactory $paginatorFactory, - PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository ) { $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; - $this->paginatorFactory = $paginatorFactory; - $this->personDocumentACLAwareRepository = $personDocumentACLAwareRepository; } /** @@ -88,7 +80,7 @@ class DocumentPersonController extends AbstractController return $this->redirect($request->query->get('returnPath')); } - return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]); + return $this->redirectToRoute('chill_docstore_generic-doc_by-person_index', ['id' => $person->getId()]); } return $this->render( @@ -160,45 +152,6 @@ class DocumentPersonController extends AbstractController ); } - /** - * @Route("/", name="person_document_index", methods="GET") - */ - public function index(Person $person): Response - { - $em = $this->getDoctrine()->getManager(); - - if (null === $person) { - throw $this->createNotFoundException('Person not found'); - } - - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - - $total = $this->personDocumentACLAwareRepository->countByPerson($person); - $pagination = $this->paginatorFactory->create($total); - - $documents = $this->personDocumentACLAwareRepository->findByPerson( - $person, - ['date' => 'DESC', 'id' => 'DESC'], - $pagination->getItemsPerPage(), - $pagination->getCurrentPageFirstItemNumber() - ); - - $event = new PrivacyEvent($person, [ - 'element_class' => PersonDocument::class, - 'action' => 'index', - ]); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render( - 'ChillDocStoreBundle:PersonDocument:index.html.twig', - [ - 'documents' => $documents, - 'person' => $person, - 'pagination' => $pagination, - ] - ); - } - /** * @Route("/new", name="person_document_new", methods="GET|POST") */ @@ -233,7 +186,7 @@ class DocumentPersonController extends AbstractController $this->addFlash('success', $this->translator->trans('The document is successfully registered')); - return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]); + return $this->redirectToRoute('chill_docstore_generic-doc_by-person_index', ['id' => $person->getId()]); } if ($form->isSubmitted() && !$form->isValid()) { diff --git a/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForAccompanyingPeriodController.php b/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForAccompanyingPeriodController.php new file mode 100644 index 000000000..70c41db50 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForAccompanyingPeriodController.php @@ -0,0 +1,98 @@ +security->isGranted(AccompanyingCourseDocumentVoter::SEE, $accompanyingPeriod)) { + throw new AccessDeniedHttpException("not allowed to see the documents for accompanying period"); + } + + $filterBuilder = $this->filterOrderHelperFactory + ->create(self::class) + ->addSearchBox() + ->addDateRange('dateRange', 'generic_doc.filter.date-range'); + + if ([] !== $places = $this->manager->placesForAccompanyingPeriod($accompanyingPeriod)) { + $filterBuilder->addCheckbox('places', $places, [], array_map( + static fn (string $k) => 'generic_doc.filter.keys.' . $k, + $places + )); + } + + $filter = $filterBuilder + ->build(); + + ['to' => $endDate, 'from' => $startDate ] = $filter->getDateRangeData('dateRange'); + $content = $filter->getQueryString(); + + $nb = $this->manager->countDocForAccompanyingPeriod( + $accompanyingPeriod, + $startDate, + $endDate, + $content, + $filter->hasCheckBox('places') ? array_values($filter->getCheckboxData('places')) : [] + ); + $paginator = $this->paginator->create($nb); + + $documents = $this->manager->findDocForAccompanyingPeriod( + $accompanyingPeriod, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage(), + $startDate, + $endDate, + $content, + $filter->hasCheckBox('places') ? array_values($filter->getCheckboxData('places')) : [] + ); + + return new Response($this->twig->render( + '@ChillDocStore/GenericDoc/accompanying_period_list.html.twig', + [ + 'accompanyingCourse' => $accompanyingPeriod, + 'pagination' => $paginator, + 'documents' => iterator_to_array($documents), + 'filter' => $filter, + ] + )); + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForPerson.php b/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForPerson.php new file mode 100644 index 000000000..3484e0904 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Controller/GenericDocForPerson.php @@ -0,0 +1,95 @@ +security->isGranted(PersonDocumentVoter::SEE, $person)) { + throw new AccessDeniedHttpException("not allowed to see the documents for person"); + } + + $filterBuilder = $this->filterOrderHelperFactory + ->create(self::class) + ->addSearchBox() + ->addDateRange('dateRange', 'generic_doc.filter.date-range'); + + if ([] !== $places = $this->manager->placesForPerson($person)) { + $filterBuilder->addCheckbox('places', $places, [], array_map( + static fn (string $k) => 'generic_doc.filter.keys.' . $k, + $places + )); + } + + $filter = $filterBuilder + ->build(); + + ['to' => $endDate, 'from' => $startDate ] = $filter->getDateRangeData('dateRange'); + $content = $filter->getQueryString(); + + $nb = $this->manager->countDocForPerson( + $person, + $startDate, + $endDate, + $content, + $filter->hasCheckBox('places') ? array_values($filter->getCheckboxData('places')) : [] + ); + $paginator = $this->paginator->create($nb); + + $documents = $this->manager->findDocForPerson( + $person, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage(), + $startDate, + $endDate, + $content, + $filter->hasCheckBox('places') ? array_values($filter->getCheckboxData('places')) : [] + ); + + return new Response($this->twig->render( + '@ChillDocStore/GenericDoc/person_list.html.twig', + [ + 'person' => $person, + 'pagination' => $paginator, + 'documents' => iterator_to_array($documents), + 'filter' => $filter, + ] + )); + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQuery.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQuery.php new file mode 100644 index 000000000..30e07a841 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQuery.php @@ -0,0 +1,233 @@ + + */ + private array $joins = []; + + /** + * @var list> + */ + private array $joinParams = []; + + /** + * @var array> + */ + private array $joinTypes = []; + + /** + * @var array + */ + private array $wheres = []; + + /** + * @var array> + */ + private array $whereParams = []; + + /** + * @var array> + */ + private array $whereTypes = []; + + public function __construct( + private readonly string $selectKeyString, + private readonly string $selectIdentifierJsonB, + private readonly string $selectDate, + private string $from = '', + private array $selectIdentifierParams = [], + private array $selectIdentifierTypes = [], + private array $selectDateParams = [], + private array $selectDateTypes = [], + ) { + } + + public function addJoinClause(string $sql, array $params = [], array $types = []): int + { + $this->joins[] = $sql; + $this->joinParams[] = $params; + $this->joinTypes[] = $types; + + return count($this->joins) - 1; + } + + public function addWhereClause(string $sql, array $params = [], array $types = []): int + { + $this->wheres[] = $sql; + $this->whereParams[] = $params; + $this->whereTypes[] = $types; + + return count($this->wheres) - 1; + } + + public function removeWhereClause(int $index): void + { + if (!array_key_exists($index, $this->wheres)) { + throw new \UnexpectedValueException("this index does not exists"); + } + + unset($this->wheres[$index], $this->whereParams[$index], $this->whereTypes[$index]); + + } + + public function removeJoinClause(int $index): void + { + if (!array_key_exists($index, $this->joins)) { + throw new \UnexpectedValueException("this index does not exists"); + } + + unset($this->joins[$index], $this->joinParams[$index], $this->joinTypes[$index]); + + } + + public function getSelectKeyString(): string + { + return $this->selectKeyString; + } + + public function getSelectIdentifierJsonB(): string + { + return $this->selectIdentifierJsonB; + } + + /** + * @inheritDoc + */ + public function getSelectIdentifierParams(): array + { + return $this->selectIdentifierParams; + } + + public function getSelectIdentifiersTypes(): array + { + return $this->selectIdentifierTypes; + } + + public function getSelectDate(): string + { + return $this->selectDate; + } + + public function getSelectDateTypes(): array + { + return $this->selectDateTypes; + } + + /** + * @inheritDoc + */ + public function getSelectDateParams(): array + { + return $this->selectDateParams; + } + + public function getFromQuery(): string + { + return $this->from . " " . implode(' ', $this->joins); + } + + /** + * @inheritDoc + */ + public function getFromQueryParams(): array + { + $result = []; + + foreach ($this->joinParams as $params) { + $result = [...$result, ...$params]; + } + + return $result; + } + + public function getFromQueryTypes(): array + { + $result = []; + + foreach ($this->joinTypes as $types) { + $result = [...$result, ...$types]; + } + + return $result; + } + + public function getWhereQuery(): string + { + return implode(' AND ', $this->wheres); + } + + /** + * @inheritDoc + */ + public function getWhereQueryParams(): array + { + $result = []; + + foreach ($this->whereParams as $params) { + $result = [...$result, ...$params]; + } + + return $result; + } + + public function getWhereQueryTypes(): array + { + $result = []; + + foreach ($this->whereTypes as $types) { + $result = [...$result, ...$types]; + } + + return $result; + } + + public function setSelectIdentifierParams(array $selectIdentifierParams): self + { + $this->selectIdentifierParams = $selectIdentifierParams; + + return $this; + } + + public function setSelectDateParams(array $selectDateParams): self + { + $this->selectDateParams = $selectDateParams; + + return $this; + } + + public function setFrom(string $from): self + { + $this->from = $from; + + return $this; + } + + public function setSelectIdentifierTypes(array $selectIdentifierTypes): self + { + $this->selectIdentifierTypes = $selectIdentifierTypes; + + return $this; + } + + public function setSelectDateTypes(array $selectDateTypes): self + { + $this->selectDateTypes = $selectDateTypes; + + return $this; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryInterface.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryInterface.php new file mode 100644 index 000000000..e46795457 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryInterface.php @@ -0,0 +1,67 @@ + + */ + public function getSelectIdentifierParams(): array; + + /** + * @return list + */ + public function getSelectIdentifiersTypes(): array; + + public function getSelectDate(): string; + + /** + * @return list + */ + public function getSelectDateParams(): array; + + /** + * @return list + */ + public function getSelectDateTypes(): array; + + public function getFromQuery(): string; + + /** + * @return list + */ + public function getFromQueryParams(): array; + + /** + * @return list + */ + public function getFromQueryTypes(): array; + + public function getWhereQuery(): string; + + /** + * @return list + */ + public function getWhereQueryParams(): array; + + /** + * @return list + */ + public function getWhereQueryTypes(): array; +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryToSqlBuilder.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryToSqlBuilder.php new file mode 100644 index 000000000..2c0c59cff --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/FetchQueryToSqlBuilder.php @@ -0,0 +1,57 @@ +, types: list} + */ + public function toSql(FetchQueryInterface $query): array + { + $sql = strtr(self::SQL, [ + '{{ key }}' => $query->getSelectKeyString(), + '{{ identifiers }}' => $query->getSelectIdentifierJsonB(), + '{{ date }}' => $query->getSelectDate(), + '{{ from }}' => $query->getFromQuery(), + '{{ where }}' => '' === ($w = $query->getWhereQuery()) ? '' : 'WHERE ' . $w, + ]); + + $params = [ + ...$query->getSelectIdentifierParams(), + ...$query->getSelectDateParams(), + ...$query->getFromQueryParams(), + ...$query->getWhereQueryParams() + ]; + + $types = [ + ...$query->getSelectIdentifiersTypes(), + ...$query->getSelectDateTypes(), + ...$query->getFromQueryTypes(), + ...$query->getWhereQueryTypes(), + ]; + + return ['sql' => $sql, 'params' => $params, 'types' => $types]; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocDTO.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocDTO.php new file mode 100644 index 000000000..fe9bf7e4f --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocDTO.php @@ -0,0 +1,31 @@ +linked instanceof AccompanyingPeriod ? 'accompanying-period' : 'person'; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocForAccompanyingPeriodProviderInterface.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocForAccompanyingPeriodProviderInterface.php new file mode 100644 index 000000000..0d3cb1c32 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/GenericDocForAccompanyingPeriodProviderInterface.php @@ -0,0 +1,31 @@ + + */ + private iterable $providersForAccompanyingPeriod, + + /** + * @var iterable + */ + private iterable $providersForPerson, + private Connection $connection, + ) { + $this->builder = new FetchQueryToSqlBuilder(); + } + + /** + * @param list $places + * @throws Exception + */ + public function countDocForAccompanyingPeriod( + AccompanyingPeriod $accompanyingPeriod, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null, + array $places = [] + ): int { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($accompanyingPeriod, $startDate, $endDate, $content, $places); + + return $this->countDoc($sql, $params, $types); + } + + private function countDoc(string $sql, array $params, array $types): int + { + if ($sql === '') { + return 0; + } + + $countSql = "SELECT count(*) AS c FROM ({$sql}) AS sq"; + $result = $this->connection->executeQuery($countSql, $params, $types); + + $number = $result->fetchOne(); + + if (false === $number) { + throw new \UnexpectedValueException("number of documents failed to load"); + } + + return $number; + } + + public function countDocForPerson( + Person $person, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null, + array $places = [] + ): int { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($person, $startDate, $endDate, $content, $places); + + return $this->countDoc($sql, $params, $types); + } + + /** + * @param list $places places to search. When empty, search in all places + * @return iterable + * @throws Exception + */ + public function findDocForAccompanyingPeriod( + AccompanyingPeriod $accompanyingPeriod, + int $offset = 0, + int $limit = 20, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null, + array $places = [] + ): iterable { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($accompanyingPeriod, $startDate, $endDate, $content, $places); + + return $this->findDocs($accompanyingPeriod, $sql, $params, $types, $offset, $limit); + } + + /** + * @throws \JsonException + * @throws Exception + */ + private function findDocs(AccompanyingPeriod|Person $linked, string $sql, array $params, array $types, int $offset, int $limit): iterable + { + if ($sql === '') { + return []; + } + + $runSql = "{$sql} ORDER BY doc_date DESC LIMIT ? OFFSET ?"; + $runParams = [...$params, ...[$limit, $offset]]; + $runTypes = [...$types, ...[Types::INTEGER, Types::INTEGER]]; + + foreach ($this->connection->iterateAssociative($runSql, $runParams, $runTypes) as $row) { + yield new GenericDocDTO( + $row['key'], + json_decode($row['identifiers'], true, 512, JSON_THROW_ON_ERROR), + new \DateTimeImmutable($row['doc_date']), + $linked, + ); + } + } + + /** + * @param list $places places to search. When empty, search in all places + * @return iterable + */ + public function findDocForPerson( + Person $person, + int $offset = 0, + int $limit = 20, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null, + array $places = [] + ): iterable { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($person, $startDate, $endDate, $content, $places); + + return $this->findDocs($person, $sql, $params, $types, $offset, $limit); + } + + public function placesForPerson(Person $person): array + { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($person); + + return $this->places($sql, $params, $types); + } + + public function placesForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): array + { + ['sql' => $sql, 'params' => $params, 'types' => $types] = $this->buildUnionQuery($accompanyingPeriod); + + return $this->places($sql, $params, $types); + } + + private function places(string $sql, array $params, array $types): array + { + if ($sql === '') { + return []; + } + + $runSql = "SELECT DISTINCT key FROM ({$sql}) AS sq ORDER BY key"; + + $keys = []; + + foreach ($this->connection->iterateAssociative($runSql, $params, $types) as $k) { + $keys[] = $k['key']; + } + + return $keys; + } + + /** + * @param list $places places to search. When empty, search in all places + */ + private function buildUnionQuery( + AccompanyingPeriod|Person $linked, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null, + array $places = [], + ): array { + $queries = []; + + if ($linked instanceof AccompanyingPeriod) { + foreach ($this->providersForAccompanyingPeriod as $provider) { + if (!$provider->isAllowedForAccompanyingPeriod($linked)) { + continue; + } + $queries[] = $provider->buildFetchQueryForAccompanyingPeriod($linked, $startDate, $endDate, $content); + } + } else { + foreach ($this->providersForPerson as $provider) { + if (!$provider->isAllowedForPerson($linked)) { + continue; + } + $queries[] = $provider->buildFetchQueryForPerson($linked, $startDate, $endDate, $content); + } + } + $sql = []; + $params = []; + $types = []; + + foreach ($queries as $query) { + if ([] !== $places and !in_array($query->getSelectKeyString(), $places, true)) { + continue; + } + + ['sql' => $q, 'params' => $p, 'types' => $t ] = $this->builder->toSql($query); + + $sql[] = $q; + $params = [...$params, ...$p]; + $types = [...$types, ...$t]; + } + + return ['sql' => implode(' UNION ', $sql), 'params' => $params, 'types' => $types]; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProvider.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProvider.php new file mode 100644 index 000000000..fd36f7976 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProvider.php @@ -0,0 +1,147 @@ +entityManager->getClassMetadata(AccompanyingCourseDocument::class); + + $query = new FetchQuery( + self::KEY, + sprintf('jsonb_build_object(\'id\', %s)', $classMetadata->getIdentifierColumnNames()[0]), + $classMetadata->getColumnName('date'), + $classMetadata->getSchemaName() . '.' . $classMetadata->getTableName() + ); + + $query->addWhereClause( + sprintf('%s = ?', $classMetadata->getSingleAssociationJoinColumnName('course')), + [$accompanyingPeriod->getId()], + [Types::INTEGER] + ); + + return $this->addWhereClause($query, $startDate, $endDate, $content); + } + + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return $this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $accompanyingPeriod); + } + + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class); + + $query = new FetchQuery( + self::KEY, + sprintf('jsonb_build_object(\'id\', %s)', $classMetadata->getIdentifierColumnNames()[0]), + $classMetadata->getColumnName('date'), + $classMetadata->getSchemaName() . '.' . $classMetadata->getTableName() . ' AS acc_course_document' + ); + + $atLeastOne = false; + $or = []; + $orParams = []; + $orTypes = []; + + foreach ($person->getAccompanyingPeriodParticipations() as $participation) { + if (!$this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $participation->getAccompanyingPeriod())) { + continue; + } + + $atLeastOne = true; + + $or[] = sprintf( + "(acc_course_document.%s = ? AND acc_course_document.%s BETWEEN ? AND COALESCE(?, 'infinity'::date))", + $classMetadata->getSingleAssociationJoinColumnName('course'), + $classMetadata->getColumnName('date') + ); + $orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(), $participation->getStartDate(), $participation->getEndDate()]; + $orTypes = [...$orTypes, Types::INTEGER, Types::DATE_MUTABLE, Types::DATE_MUTABLE]; + } + + if (!$atLeastOne) { + // there aren't any period allowed to be seen. Add an unreachable condition + $query->addWhereClause('TRUE = FALSE'); + + return $query; + } + + $query->addWhereClause('(' . implode(' OR ', $or) . ')', $orParams, $orTypes); + + return $this->addWhereClause($query, $startDate, $endDate, $content); + } + + public function isAllowedForPerson(Person $person): bool + { + return $this->security->isGranted(AccompanyingPeriodVoter::SEE, $person); + } + + private function addWhereClause(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('? <= %s', $classMetadata->getColumnName('date')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('? >= %s', $classMetadata->getColumnName('date')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content and '' !== $content) { + $query->addWhereClause( + sprintf( + '(%s ilike ? OR %s ilike ?)', + $classMetadata->getColumnName('title'), + $classMetadata->getColumnName('description') + ), + ['%' . $content . '%', '%' . $content . '%'], + [Types::STRING, Types::STRING] + ); + } + + return $query; + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/PersonDocumentGenericDocProvider.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/PersonDocumentGenericDocProvider.php new file mode 100644 index 000000000..613f8d758 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Providers/PersonDocumentGenericDocProvider.php @@ -0,0 +1,65 @@ +personDocumentACLAwareRepository->buildFetchQueryForPerson( + $person, + $startDate, + $endDate, + $content + ); + } + + public function isAllowedForPerson(Person $person): bool + { + return $this->security->isGranted(PersonDocumentVoter::SEE, $person); + } + + public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + return $this->personDocumentACLAwareRepository->buildFetchQueryForAccompanyingPeriod($accompanyingPeriod, $startDate, $endDate, $content); + } + + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + // we assume that the user is allowed to see at least one person of the course + // this will be double checked when running the query + return true; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Renderer/AccompanyingCourseDocumentGenericDocRenderer.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Renderer/AccompanyingCourseDocumentGenericDocRenderer.php new file mode 100644 index 000000000..c32620030 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Renderer/AccompanyingCourseDocumentGenericDocRenderer.php @@ -0,0 +1,59 @@ +key === AccompanyingCourseDocumentGenericDocProvider::KEY + || $genericDocDTO->key === PersonDocumentGenericDocProvider::KEY; + } + + public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string + { + return '@ChillDocStore/List/list_item.html.twig'; + } + + public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array + { + if (AccompanyingCourseDocumentGenericDocProvider::KEY === $genericDocDTO->key) { + return [ + 'document' => $doc = $this->accompanyingCourseDocumentRepository->find($genericDocDTO->identifiers['id']), + 'accompanyingCourse' => $doc->getCourse(), + 'options' => $options, + 'context' => $genericDocDTO->getContext(), + ]; + } + // this is a person + return [ + 'document' => $doc = $this->personDocumentRepository->find($genericDocDTO->identifiers['id']), + 'person' => $doc->getPerson(), + 'options' => $options, + 'context' => $genericDocDTO->getContext(), + ]; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtension.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtension.php new file mode 100644 index 000000000..308d85cd7 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtension.php @@ -0,0 +1,28 @@ + true, + 'is_safe' => ['html'], + ]) + ]; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtensionRuntime.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtensionRuntime.php new file mode 100644 index 000000000..2dee0ed0b --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocExtensionRuntime.php @@ -0,0 +1,50 @@ + + */ + private iterable $renderers, + ) { + } + + /** + * @throws RuntimeError + * @throws SyntaxError + * @throws LoaderError + */ + public function renderGenericDoc(Environment $twig, GenericDocDTO $genericDocDTO, array $options = []): string + { + foreach ($this->renderers as $renderer) { + if ($renderer->supports($genericDocDTO)) { + return $twig->render( + $renderer->getTemplate($genericDocDTO, $options), + $renderer->getTemplateData($genericDocDTO, $options), + ); + } + } + + throw new \LogicException("no renderer found"); + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocRendererInterface.php b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocRendererInterface.php new file mode 100644 index 000000000..940001f4a --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/GenericDoc/Twig/GenericDocRendererInterface.php @@ -0,0 +1,24 @@ +security->isGranted(AccompanyingCourseDocumentVoter::SEE, $course)) { $menu->addChild($this->translator->trans('Documents'), [ - 'route' => 'accompanying_course_document_index', + 'route' => 'chill_docstore_generic-doc_by-period_index', 'routeParameters' => [ - 'course' => $course->getId(), + 'id' => $course->getId(), ], ]) ->setExtras([ @@ -80,9 +80,9 @@ final class MenuBuilder implements LocalMenuBuilderInterface if ($this->security->isGranted(PersonDocumentVoter::SEE, $person)) { $menu->addChild($this->translator->trans('Documents'), [ - 'route' => 'person_document_index', + 'route' => 'chill_docstore_generic-doc_by-person_index', 'routeParameters' => [ - 'person' => $person->getId(), + 'id' => $person->getId(), ], ]) ->setExtras([ diff --git a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php index 23dcc4e0b..26a42b894 100644 --- a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php +++ b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php @@ -12,30 +12,33 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Repository; use Chill\DocStoreBundle\Entity\PersonDocument; +use Chill\DocStoreBundle\GenericDoc\FetchQuery; +use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface; +use Chill\DocStoreBundle\GenericDoc\Providers\PersonDocumentGenericDocProvider; use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; +use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface; +use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person; +use DateTimeImmutable; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Security\Core\Security; -class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareRepositoryInterface +final readonly class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareRepositoryInterface { - private AuthorizationHelperInterface $authorizationHelper; - - private CenterResolverDispatcher $centerResolverDispatcher; - - private EntityManagerInterface $em; - - private Security $security; - - public function __construct(EntityManagerInterface $em, AuthorizationHelperInterface $authorizationHelper, CenterResolverDispatcher $centerResolverDispatcher, Security $security) - { - $this->em = $em; - $this->authorizationHelper = $authorizationHelper; - $this->centerResolverDispatcher = $centerResolverDispatcher; - $this->security = $security; + public function __construct( + private EntityManagerInterface $em, + private CenterResolverManagerInterface $centerResolverManager, + private AuthorizationHelperForCurrentUserInterface $authorizationHelperForCurrentUser, + private Security $security, + ) { } public function buildQueryByPerson(Person $person): QueryBuilder @@ -49,6 +52,128 @@ class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareReposito return $qb; } + + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface + { + $query = $this->buildBaseFetchQueryForPerson($person, $startDate, $endDate, $content); + + return $this->addFetchQueryByPersonACL($query, $person); + } + + public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $period, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQueryInterface + { + $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); + $participationMetadata = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); + + $query = new FetchQuery( + PersonDocumentGenericDocProvider::KEY, + sprintf('jsonb_build_object(\'id\', person_document.%s)', $personDocMetadata->getSingleIdentifierColumnName()), + sprintf('person_document.%s', $personDocMetadata->getColumnName('date')), + sprintf('%s AS person_document', $personDocMetadata->getSchemaName().'.'.$personDocMetadata->getTableName()) + ); + + $query->addJoinClause( + sprintf( + 'JOIN %s AS participation ON participation.%s = person_document.%s '. + 'AND person_document.%s BETWEEN participation.%s AND COALESCE(participation.%s, \'infinity\'::date)', + $participationMetadata->getTableName(), + $participationMetadata->getSingleAssociationJoinColumnName('person'), + $personDocMetadata->getSingleAssociationJoinColumnName('person'), + $personDocMetadata->getColumnName('date'), + $participationMetadata->getColumnName('startDate'), + $participationMetadata->getColumnName('endDate') + ) + ); + + $query->addWhereClause( + sprintf('participation.%s = ?', $participationMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod')), + [$period->getId()], + [Types::INTEGER] + ); + + // can we see the document for this person ? + $orPersonId = []; + foreach ($period->getParticipations() as $participation) { + if (!$this->security->isGranted(PersonDocumentVoter::SEE, $participation->getPerson())) { + continue; + } + $orPersonId[] = $participation->getPerson()->getId(); + + } + + if ([] === $orPersonId) { + $query->addWhereClause('FALSE = TRUE'); + + return $query; + } + + $query->addWhereClause( + sprintf( + 'participation.%s IN (%s)', + $participationMetadata->getSingleAssociationJoinColumnName('person'), + implode(', ', array_fill(0, count($orPersonId), '?')) + ), + $orPersonId, + array_fill(0, count($orPersonId), Types::INTEGER) + ); + + return $this->addFilterClauses($query, $startDate, $endDate, $content); + } + + public function buildBaseFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); + + $query = new FetchQuery( + PersonDocumentGenericDocProvider::KEY, + sprintf('jsonb_build_object(\'id\', person_document.%s)', $personDocMetadata->getSingleIdentifierColumnName()), + sprintf('person_document.%s', $personDocMetadata->getColumnName('date')), + sprintf('%s AS person_document', $personDocMetadata->getSchemaName().'.'.$personDocMetadata->getTableName()) + ); + + $query->addWhereClause( + sprintf('person_document.%s = ?', $personDocMetadata->getSingleAssociationJoinColumnName('person')), + [$person->getId()], + [Types::INTEGER] + ); + + return $this->addFilterClauses($query, $startDate, $endDate, $content); + } + + private function addFilterClauses(FetchQuery $query, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('? <= %s', $personDocMetadata->getColumnName('date')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('? >= %s', $personDocMetadata->getColumnName('date')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content and '' !== $content) { + $query->addWhereClause( + sprintf( + '(%s ilike ? OR %s ilike ?)', + $personDocMetadata->getColumnName('title'), + $personDocMetadata->getColumnName('description') + ), + ['%' . $content . '%', '%' . $content . '%'], + [Types::STRING, Types::STRING] + ); + } + return $query; + } + public function countByPerson(Person $person): int { $qb = $this->buildQueryByPerson($person)->select('COUNT(d)'); @@ -75,16 +200,58 @@ class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareReposito private function addACL(QueryBuilder $qb, Person $person): void { - $center = $this->centerResolverDispatcher->resolveCenter($person); + $reachableScopes = []; - $reachableScopes = $this->authorizationHelper - ->getReachableScopes( - $this->security->getUser(), - PersonDocumentVoter::SEE, - $center - ); + foreach ($this->centerResolverManager->resolveCenters($person) as $center) { + $reachableScopes = [ + ...$reachableScopes, + ...$this->authorizationHelperForCurrentUser + ->getReachableScopes( + PersonDocumentVoter::SEE, + $center + ) + ]; + } + + if ([] === $reachableScopes) { + $qb->andWhere("'FALSE' = 'TRUE'"); + + return; + } $qb->andWhere($qb->expr()->in('d.scope', ':scopes')) ->setParameter('scopes', $reachableScopes); } + + private function addFetchQueryByPersonACL(FetchQuery $fetchQuery, Person $person): FetchQuery + { + $personDocMetadata = $this->em->getClassMetadata(PersonDocument::class); + + $reachableScopes = []; + + foreach ($this->centerResolverManager->resolveCenters($person) as $center) { + $reachableScopes = [ + ...$reachableScopes, + ...$this->authorizationHelperForCurrentUser->getReachableScopes(PersonDocumentVoter::SEE, $center) + ]; + } + + if ([] === $reachableScopes) { + $fetchQuery->addWhereClause('FALSE = TRUE'); + + return $fetchQuery; + } + + $fetchQuery->addWhereClause( + sprintf( + 'person_document.%s IN (%s)', + $personDocMetadata->getSingleAssociationJoinColumnName('scope'), + implode(', ', array_fill(0, count($reachableScopes), '?')) + ), + array_map(static fn (Scope $s) => $s->getId(), $reachableScopes), + array_fill(0, count($reachableScopes), Types::INTEGER) + ); + + return $fetchQuery; + } } diff --git a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php index 6c4bd2e9a..f1bc70812 100644 --- a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepositoryInterface.php @@ -11,11 +11,33 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Repository; +use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; interface PersonDocumentACLAwareRepositoryInterface { + /** + * @deprecated use fetch query for listing and counting person documents + */ public function countByPerson(Person $person): int; + /** + * @deprecated use fetch query for listing and counting person documents + */ public function findByPerson(Person $person, array $orderBy = [], int $limit = 20, int $offset = 0): array; + + public function buildFetchQueryForPerson( + Person $person, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null + ): FetchQueryInterface; + + public function buildFetchQueryForAccompanyingPeriod( + AccompanyingPeriod $period, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null + ): FetchQueryInterface; } diff --git a/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentRepository.php new file mode 100644 index 000000000..40afdc220 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentRepository.php @@ -0,0 +1,57 @@ + + */ +readonly class PersonDocumentRepository implements ObjectRepository +{ + private EntityRepository $repository; + + public function __construct( + private EntityManagerInterface $entityManager + ) { + $this->repository = $this->entityManager->getRepository($this->getClassName()); + } + + public function find($id): ?PersonDocument + { + return $this->repository->find($id); + } + + public function findAll() + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?PersonDocument + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return PersonDocument::class; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/delete.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/delete.html.twig index c9bb608cf..d6f23d09d 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/delete.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/delete.html.twig @@ -31,8 +31,8 @@ 'title' : 'Delete document ?'|trans, 'display_content' : block('docdescription'), 'confirm_question' : 'Are you sure you want to remove this document ?'|trans, - 'cancel_route' : 'accompanying_course_document_index', - 'cancel_parameters' : {'course' : accompanyingCourse.id, 'id': document.id}, + 'cancel_route' : 'chill_docstore_generic-doc_by-period_index', + 'cancel_parameters' : {'id' : accompanyingCourse.id}, 'form' : delete_form } ) }} {% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/edit.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/edit.html.twig index 0ca5661fc..326814502 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/edit.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/edit.html.twig @@ -21,7 +21,7 @@ diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig deleted file mode 100644 index 7a013260c..000000000 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} - -{% set activeRouteKey = '' %} - -{% block title %} - {{ 'Documents' }} -{% endblock %} - -{% block js %} - {{ parent() }} - {{ encore_entry_script_tags('mod_docgen_picktemplate') }} - {{ encore_entry_script_tags('mod_entity_workflow_pick') }} - {{ encore_entry_script_tags('mod_document_action_buttons_group') }} -{% endblock %} - -{% block css %} - {{ parent() }} - {{ encore_entry_link_tags('mod_docgen_picktemplate') }} - {{ encore_entry_link_tags('mod_entity_workflow_pick') }} - {{ encore_entry_link_tags('mod_document_action_buttons_group') }} -{% endblock %} - -{% block content %} -
-

{{ 'Documents' }}

- - {% if documents|length == 0 %} -

{{ 'No documents'|trans }}

- {% else %} -
- {% for document in documents %} - {% include '@ChillDocStore/List/list_item.html.twig' %} - {% endfor %} -
- {% endif %} - - {{ chill_pagination(pagination) }} - -
- - {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %} - - {% endif %} - -
-{% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/new.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/new.html.twig index 01be1a5d7..3fb692c78 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/new.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/new.html.twig @@ -25,7 +25,7 @@
  • - + {{ 'Back to the list' | trans }}
  • diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/show.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/show.html.twig index 3c62451a9..9590dbb78 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/show.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/show.html.twig @@ -46,7 +46,7 @@
    • - + {{ 'Back to the list' | trans }}
    • diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/accompanying_period_list.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/accompanying_period_list.html.twig new file mode 100644 index 000000000..b22c7d00f --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/accompanying_period_list.html.twig @@ -0,0 +1,54 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %} + {{ 'Documents' }} +{% endblock %} + +{% block js %} + {{ parent() }} + {{ encore_entry_script_tags('mod_docgen_picktemplate') }} + {{ encore_entry_script_tags('mod_entity_workflow_pick') }} + {{ encore_entry_script_tags('mod_document_action_buttons_group') }} +{% endblock %} + +{% block css %} + {{ parent() }} + {{ encore_entry_script_tags('mod_docgen_picktemplate') }} + {{ encore_entry_link_tags('mod_entity_workflow_pick') }} + {{ encore_entry_link_tags('mod_document_action_buttons_group') }} +{% endblock %} + +{% block content %} +
      +

      {{ 'Documents' }}

      + + {{ filter|chill_render_filter_order_helper }} + + {% if documents|length == 0 %} +

      {{ 'No documents'|trans }}

      + {% else %} +
      + {% for document in documents %} + {{ document|chill_generic_doc_render }} + {% endfor %} +
      + {% endif %} + + {{ chill_pagination(pagination) }} + +
      + + {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %} + + {% endif %} + +
      +{% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/person_list.html.twig similarity index 95% rename from src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig rename to src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/person_list.html.twig index 8d201605e..a4aa4fbbc 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/index.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/GenericDoc/person_list.html.twig @@ -44,12 +44,14 @@

      {{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}

      + {{ filter|chill_render_filter_order_helper }} + {% if documents|length == 0 %}

      {{ 'No documents'|trans }}

      {% else %}
      {% for document in documents %} - {% include 'ChillDocStoreBundle:List:list_item.html.twig' %} + {{ document|chill_generic_doc_render }} {% endfor %}
      {% endif %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig index 8dea4bbe7..58504b095 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig @@ -10,8 +10,23 @@ {% elseif document.object.isFailure %}
      {{ 'docgen.Doc generation failed'|trans }}
      {% endif %} + + {% if context == 'person' and accompanyingCourse is defined %} +
      + + {{ accompanyingCourse.id }} +   +
      + {% elseif context == 'accompanying-period' and person is defined %} +
      + + {{ 'Document from person %name%'|trans({ '%name%': document.person|chill_entity_render_string }) }} +   +
      + + {% endif %}
      - {{ document.title }} + {{ document.title|chill_print_or_message("No title") }}
      {% if document.object.type is not empty %}
      diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/delete.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/delete.html.twig index bfdd87dc3..41c229faa 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/delete.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/delete.html.twig @@ -36,8 +36,8 @@ 'title' : 'Delete document ?'|trans, 'display_content' : block('docdescription'), 'confirm_question' : 'Are you sure you want to remove this document ?'|trans, - 'cancel_route' : 'person_document_index', - 'cancel_parameters' : {'person' : person.id, 'id': document.id}, + 'cancel_route' : 'chill_docstore_generic-doc_by-person_index', + 'cancel_parameters' : {'id' : person.id}, 'form' : delete_form } ) }} {% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig index 416a35e35..17ce9d774 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/edit.html.twig @@ -38,7 +38,7 @@
      • - + {{ 'Back to the list' | trans }}
      • diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/new.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/new.html.twig index 3187714a6..faf8895e7 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/new.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/new.html.twig @@ -42,7 +42,7 @@
        • - + {{ 'Back to the list' | trans }}
        • diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig index c276e067e..1c0aa5e64 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/PersonDocument/show.html.twig @@ -63,7 +63,7 @@
          • - + {{ 'Back to the list' | trans }}
          • diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/FetchQueryToSqlBuilderTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/FetchQueryToSqlBuilderTest.php new file mode 100644 index 000000000..02be9460f --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/FetchQueryToSqlBuilderTest.php @@ -0,0 +1,89 @@ +addJoinClause('LEFT JOIN other b ON a.id = b.foreign_id', ['foo'], [Types::STRING]); + $index = $query->addJoinClause('LEFT JOIN other c ON a.id = c.foreign_id', ['bar'], [Types::STRING]); + $query->addJoinClause('LEFT JOIN other d ON a.id = d.foreign_id', ['bar_baz'], [Types::STRING]); + $query->removeJoinClause($index); + $query->addWhereClause('b.item = ?', ['baz'], [Types::STRING]); + $index = $query->addWhereClause('b.cancel', [ 'foz'], [Types::STRING]); + $query->removeWhereClause($index); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $filteredSql = + implode(" ", array_filter( + explode(" ", str_replace("\n", "", $sql)), + fn (string $tok) => $tok !== "" + )) + ; + + self::assertEquals( + "SELECT 'test' AS key, jsonb_build_object('id', a.column) AS identifiers, ". + "a.datecolumn::date AS doc_date FROM my_table a LEFT JOIN other b ON a.id = b.foreign_id LEFT JOIN other d ON a.id = d.foreign_id WHERE b.item = ?", + $filteredSql + ); + self::assertEquals(['foo', 'bar_baz', 'baz'], $params); + self::assertEquals([Types::STRING, Types::STRING, Types::STRING], $types); + + + + } + + public function testToSqlWithoutWhere(): void + { + $query = new FetchQuery( + 'test', + 'jsonb_build_object(\'id\', a.column)', + 'a.datecolumn', + 'my_table a' + ); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $filteredSql = + implode(" ", array_filter( + explode(" ", str_replace("\n", "", $sql)), + fn (string $tok) => $tok !== "" + )) + ; + + self::assertEquals( + "SELECT 'test' AS key, jsonb_build_object('id', a.column) AS identifiers, ". + "a.datecolumn::date AS doc_date FROM my_table a", + $filteredSql + ); + self::assertEquals([], $params); + self::assertEquals([], $types); + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php new file mode 100644 index 000000000..f59779374 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php @@ -0,0 +1,217 @@ +em = self::$container->get(EntityManagerInterface::class); + $this->connection = self::$container->get(Connection::class); + } + + public function testCountByAccompanyingPeriod(): void + { + $period = $this->em->createQuery('SELECT a FROM '.AccompanyingPeriod::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \UnexpectedValueException("period not found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + $nb = $manager->countDocForAccompanyingPeriod($period); + + self::assertIsInt($nb); + } + + public function testCountByPerson(): void + { + $person = $this->em->createQuery('SELECT a FROM '.Person::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \UnexpectedValueException("person found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + $nb = $manager->countDocForPerson($person); + + self::assertIsInt($nb); + } + + public function testFindDocByAccompanyingPeriod(): void + { + $period = $this->em->createQuery('SELECT a FROM '.AccompanyingPeriod::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \UnexpectedValueException("period not found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + foreach ($manager->findDocForAccompanyingPeriod($period) as $doc) { + self::assertInstanceOf(GenericDocDTO::class, $doc); + } + } + + public function testFindDocByPerson(): void + { + $person = $this->em->createQuery('SELECT a FROM '.Person::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \UnexpectedValueException("person not found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + foreach ($manager->findDocForPerson($person) as $doc) { + self::assertInstanceOf(GenericDocDTO::class, $doc); + } + } + + public function testPlacesForPerson(): void + { + $person = $this->em->createQuery('SELECT a FROM '.Person::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \UnexpectedValueException("person not found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + $places = $manager->placesForPerson($person); + + self::assertEquals(['dummy_person_doc'], $places); + } + + public function testPlacesForAccompanyingPeriod(): void + { + $period = $this->em->createQuery('SELECT a FROM '.AccompanyingPeriod::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \UnexpectedValueException("period not found"); + } + + $manager = new Manager( + [new SimpleGenericDocAccompanyingPeriodProvider()], + [new SimpleGenericDocPersonProvider()], + $this->connection, + ); + + $places = $manager->placesForAccompanyingPeriod($period); + + self::assertEquals(['accompanying_course_document_dummy'], $places); + } +} + +final readonly class SimpleGenericDocAccompanyingPeriodProvider implements GenericDocForAccompanyingPeriodProviderInterface +{ + public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $query = new FetchQuery( + 'accompanying_course_document_dummy', + sprintf('jsonb_build_object(\'id\', %s)', 'id'), + 'd', + '(VALUES (1, \'2023-05-01\'::date), (2, \'2023-05-01\'::date)) AS sq (id, d)', + ); + + $query->addWhereClause('d > ?', [new \DateTimeImmutable('2023-01-01')], [Types::DATE_IMMUTABLE]); + + return $query; + } + + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return true; + } +} + +final readonly class SimpleGenericDocPersonProvider implements GenericDocForPersonProviderInterface +{ + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $query = new FetchQuery( + 'dummy_person_doc', + sprintf('jsonb_build_object(\'id\', %s)', 'id'), + 'd', + '(VALUES (1, \'2023-05-01\'::date), (2, \'2023-05-01\'::date)) AS sq (id, d)', + ); + + $query->addWhereClause('d > ?', [new \DateTimeImmutable('2023-01-01')], [Types::DATE_IMMUTABLE]); + + return $query; + } + + public function isAllowedForPerson(Person $person): bool + { + return true; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php new file mode 100644 index 000000000..79ced9258 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php @@ -0,0 +1,79 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + /** + * @dataProvider provideSearchArguments + */ + public function testWithoutAnyArgument(?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content = null): void + { + $period = $this->entityManager->createQuery('SELECT a FROM '.AccompanyingPeriod::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \UnexpectedValueException("period not found"); + } + + $security = $this->prophesize(Security::class); + $security->isGranted(AccompanyingCourseDocumentVoter::SEE, $period) + ->willReturn(true); + + $provider = new AccompanyingCourseDocumentGenericDocProvider( + $security->reveal(), + $this->entityManager + ); + + $query = $provider->buildFetchQueryForAccompanyingPeriod($period, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->executeQuery('SELECT COUNT(*) FROM ('.$sql.') AS sq', $params, $types) + ->fetchOne(); + + self::assertIsInt($nb); + } + + public function provideSearchArguments(): iterable + { + yield [null, null, null]; + yield [new \DateTimeImmutable('1 month ago'), null, null]; + yield [new \DateTimeImmutable('1 month ago'), new \DateTimeImmutable('now'), null]; + yield [null, null, 'test']; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php new file mode 100644 index 000000000..577357820 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php @@ -0,0 +1,84 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + $this->personDocumentACLAwareRepository = self::$container->get(PersonDocumentACLAwareRepositoryInterface::class); + } + + /** + * @dataProvider provideDataBuildFetchQueryForPerson + * @throws \Doctrine\DBAL\Exception + * @throws \Doctrine\ORM\NoResultException + * @throws \Doctrine\ORM\NonUniqueResultException + */ + public function testBuildFetchQueryForPerson(?DateTimeImmutable $startDate, ?DateTimeImmutable $endDate, ?string $content): void + { + $security = $this->prophesize(Security::class); + $person = $this->entityManager->createQuery('SELECT a FROM '.Person::class.' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \UnexpectedValueException("person found"); + } + + $provider = new PersonDocumentGenericDocProvider( + $security->reveal(), + $this->personDocumentACLAwareRepository + ); + + $query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection() + ->fetchOne("SELECT COUNT(*) AS nb FROM (${sql}) AS sq", $params, $types); + + self::assertIsInt($nb, "Test that the query is syntactically correct"); + } + + public function provideDataBuildFetchQueryForPerson(): iterable + { + yield [null, null, null]; + yield [new DateTimeImmutable('1 year ago'), null, null]; + yield [null, new DateTimeImmutable('1 year ago'), null]; + yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), null]; + yield [null, null, 'test']; + yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test']; + } +} diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Repository/PersonDocumentACLAwareRepositoryTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Repository/PersonDocumentACLAwareRepositoryTest.php new file mode 100644 index 000000000..fd611042c --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Tests/Repository/PersonDocumentACLAwareRepositoryTest.php @@ -0,0 +1,158 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + $this->scopeRepository = self::$container->get(ScopeRepositoryInterface::class); + } + + /** + * @dataProvider provideDataBuildFetchQueryForPerson + * @throws \Doctrine\DBAL\Exception + * @throws \Doctrine\ORM\NoResultException + * @throws \Doctrine\ORM\NonUniqueResultException + */ + public function testBuildFetchQueryForPerson(?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null): void + { + $centerManager = $this->prophesize(CenterResolverManagerInterface::class); + $centerManager->resolveCenters(Argument::type(Person::class)) + ->willReturn([new Center()]); + + $scopes = $this->scopeRepository->findAll(); + $authorizationHelper = $this->prophesize(AuthorizationHelperForCurrentUserInterface::class); + $authorizationHelper->getReachableScopes(PersonDocumentVoter::SEE, Argument::any())->willReturn($scopes); + + $repository = new PersonDocumentACLAwareRepository( + $this->entityManager, + $centerManager->reveal(), + $authorizationHelper->reveal(), + $this->prophesize(Security::class)->reveal() + ); + + $person = $this->entityManager->createQuery("SELECT p FROM " . Person::class . " p") + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $person) { + throw new \RuntimeException("person not exists in database"); + } + + $query = $repository->buildFetchQueryForPerson($person, $startDate, $endDate, $content); + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection() + ->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb, "test that the query could be executed"); + } + + /** + * @dataProvider provideDateForFetchQueryForAccompanyingPeriod + */ + public function testBuildFetchQueryForAccompanyingPeriod( + AccompanyingPeriod $period, + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null + ): void { + $centerManager = $this->prophesize(CenterResolverManagerInterface::class); + $centerManager->resolveCenters(Argument::type(Person::class)) + ->willReturn([new Center()]); + + $scopes = $this->scopeRepository->findAll(); + $authorizationHelper = $this->prophesize(AuthorizationHelperForCurrentUserInterface::class); + $authorizationHelper->getReachableScopes(PersonDocumentVoter::SEE, Argument::any())->willReturn($scopes); + + $security = $this->prophesize(Security::class); + $security->isGranted(PersonDocumentVoter::SEE, Argument::type(Person::class))->willReturn(true); + + $repository = new PersonDocumentACLAwareRepository( + $this->entityManager, + $centerManager->reveal(), + $authorizationHelper->reveal(), + $security->reveal() + ); + + $query = $repository->buildFetchQueryForAccompanyingPeriod($period, $startDate, $endDate, $content); + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection() + ->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb, "test that the query could be executed"); + } + + public function provideDateForFetchQueryForAccompanyingPeriod(): iterable + { + $this->setUp(); + + if (null === $period = $this->entityManager->createQuery( + "SELECT p FROM " . AccompanyingPeriod::class . " p WHERE SIZE(p.participations) > 0" + ) + ->setMaxResults(1)->getSingleResult()) { + throw new \RuntimeException("no course found"); + } + + yield [$period, null, null, null]; + yield [$period, new DateTimeImmutable('1 year ago'), null, null]; + yield [$period, null, new DateTimeImmutable('1 year ago'), null]; + yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), null]; + yield [$period, null, null, 'test']; + yield [$period, new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test']; + + } + + public function provideDataBuildFetchQueryForPerson(): iterable + { + yield [null, null, null]; + yield [new DateTimeImmutable('1 year ago'), null, null]; + yield [null, new DateTimeImmutable('1 year ago'), null]; + yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), null]; + yield [null, null, 'test']; + yield [new DateTimeImmutable('2 years ago'), new DateTimeImmutable('1 year ago'), 'test']; + } + +} diff --git a/src/Bundle/ChillDocStoreBundle/config/services.yaml b/src/Bundle/ChillDocStoreBundle/config/services.yaml index 860495677..04fc3ace3 100644 --- a/src/Bundle/ChillDocStoreBundle/config/services.yaml +++ b/src/Bundle/ChillDocStoreBundle/config/services.yaml @@ -2,46 +2,72 @@ parameters: # cl_chill_person.example.class: Chill\PersonBundle\Example services: - Chill\DocStoreBundle\Repository\: - autowire: true - autoconfigure: true - resource: "../Repository/" + Chill\DocStoreBundle\Repository\: + autowire: true + autoconfigure: true + resource: "../Repository/" - Chill\DocStoreBundle\Form\DocumentCategoryType: - class: Chill\DocStoreBundle\Form\DocumentCategoryType - arguments: ["%kernel.bundles%"] - tags: - - { name: form.type } + Chill\DocStoreBundle\Form\DocumentCategoryType: + class: Chill\DocStoreBundle\Form\DocumentCategoryType + arguments: [ "%kernel.bundles%" ] + tags: + - { name: form.type } - Chill\DocStoreBundle\Form\PersonDocumentType: - class: Chill\DocStoreBundle\Form\PersonDocumentType - autowire: true - autoconfigure: true - # arguments: - # - "@chill.main.helper.translatable_string" - tags: - - { name: form.type, alias: chill_docstorebundle_form_document } + Chill\DocStoreBundle\Form\PersonDocumentType: + class: Chill\DocStoreBundle\Form\PersonDocumentType + autowire: true + autoconfigure: true + # arguments: + # - "@chill.main.helper.translatable_string" + tags: + - { name: form.type, alias: chill_docstorebundle_form_document } - Chill\DocStoreBundle\Security\Authorization\: - resource: "./../Security/Authorization" - autowire: true - autoconfigure: true - tags: - - { name: chill.role } + Chill\DocStoreBundle\Security\Authorization\: + resource: "./../Security/Authorization" + autowire: true + autoconfigure: true + tags: + - { name: chill.role } - Chill\DocStoreBundle\Workflow\: - resource: './../Workflow/' - autoconfigure: true - autowire: true + Chill\DocStoreBundle\Workflow\: + resource: './../Workflow/' + autoconfigure: true + autowire: true - Chill\DocStoreBundle\Serializer\Normalizer\: - autowire: true - resource: '../Serializer/Normalizer/' - tags: - - { name: 'serializer.normalizer', priority: 16 } + Chill\DocStoreBundle\Serializer\Normalizer\: + autowire: true + resource: '../Serializer/Normalizer/' + tags: + - { name: 'serializer.normalizer', priority: 16 } - Chill\DocStoreBundle\Service\: - autowire: true - autoconfigure: true - resource: '../Service/' + Chill\DocStoreBundle\Service\: + autowire: true + autoconfigure: true + resource: '../Service/' + Chill\DocStoreBundle\GenericDoc\Manager: + autowire: true + autoconfigure: true + arguments: + $providersForAccompanyingPeriod: !tagged_iterator chill_doc_store.generic_doc_accompanying_period_provider + $providersForPerson: !tagged_iterator chill_doc_store.generic_doc_person_provider + + Chill\DocStoreBundle\GenericDoc\Twig\GenericDocExtension: + autoconfigure: true + autowire: true + + Chill\DocStoreBundle\GenericDoc\Twig\GenericDocExtensionRuntime: + autoconfigure: true + autowire: true + arguments: + $renderers: !tagged_iterator chill_doc_store.generic_doc_renderer + + Chill\DocStoreBundle\GenericDoc\Providers\: + autowire: true + autoconfigure: true + resource: '../GenericDoc/Providers/' + + Chill\DocStoreBundle\GenericDoc\Renderer\: + autowire: true + autoconfigure: true + resource: '../GenericDoc/Renderer/' diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml index 0f8124d41..ffabdaa59 100644 --- a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml @@ -18,11 +18,19 @@ No document found: Aucun document trouvé The document is successfully registered: Le document est enregistré The document is successfully updated: Le document est mis à jour Any description: Aucune description +Document from person %name%: Document de l'usager %name% See the document: Voir le document document: Any title: Aucun titre +generic_doc: + filter: + keys: + accompanying_course_document: Document du parcours + person_document: Documents de l'usager + date-range: Date du document + # delete Delete document ?: Supprimer le document ? Are you sure you want to remove this document ?: Êtes-vous sûr·e de vouloir supprimer ce document ? diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 6c4ea0269..e8ee9b97b 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -13,12 +13,16 @@ namespace Chill\MainBundle\Controller; use Chill\MainBundle\Entity\SavedExport; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Export\DirectExportInterface; +use Chill\MainBundle\Export\ExportFormHelper; +use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Form\SavedExportType; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\FormatterType; use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Redis\ChillRedis; +use Chill\MainBundle\Repository\SavedExportRepositoryInterface; use Chill\MainBundle\Security\Authorization\SavedExportVoter; use Doctrine\ORM\EntityManagerInterface; use LogicException; @@ -36,6 +40,7 @@ use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; use function count; use function serialize; @@ -86,7 +91,10 @@ class ExportController extends AbstractController LoggerInterface $logger, SessionInterface $session, TranslatorInterface $translator, - EntityManagerInterface $entityManager + EntityManagerInterface $entityManager, + private readonly ExportFormHelper $exportFormHelper, + private readonly SavedExportRepositoryInterface $savedExportRepository, + private readonly Security $security, ) { $this->entityManager = $entityManager; $this->redis = $chillRedis; @@ -101,12 +109,11 @@ class ExportController extends AbstractController { /** @var \Chill\MainBundle\Export\ExportManager $exportManager */ $exportManager = $this->exportManager; - $export = $exportManager->getExport($alias); - $key = $request->query->get('key', null); + $savedExport = $this->getSavedExportFromRequest($request); - [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key); + [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key, $savedExport); $formatterAlias = $exportManager->getFormatterAlias($dataExport['export']); @@ -120,6 +127,7 @@ class ExportController extends AbstractController 'alias' => $alias, 'export' => $export, 'export_group' => $this->getExportGroup($export), + 'saved_export' => $savedExport, ]; if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) { @@ -144,8 +152,9 @@ class ExportController extends AbstractController /** @var \Chill\MainBundle\Export\ExportManager $exportManager */ $exportManager = $this->exportManager; $key = $request->query->get('key', null); + $savedExport = $this->getSavedExportFromRequest($request); - [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key); + [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key, $savedExport); return $exportManager->generate( $alias, @@ -204,12 +213,8 @@ class ExportController extends AbstractController * 3. 'generate': gather data from session from the previous steps, and * make a redirection to the "generate" action with data in query (HTTP GET) * - * @param string $request - * @param Request $alias - * - * @return \Symfony\Component\HttpFoundation\Response */ - public function newAction(Request $request, $alias) + public function newAction(Request $request, string $alias): Response { // first check for ACL $exportManager = $this->exportManager; @@ -219,26 +224,50 @@ class ExportController extends AbstractController throw $this->createAccessDeniedException('The user does not have access to this export'); } + $savedExport = $this->getSavedExportFromRequest($request); + $step = $request->query->getAlpha('step', 'centers'); switch ($step) { case 'centers': - return $this->selectCentersStep($request, $export, $alias); + return $this->selectCentersStep($request, $export, $alias, $savedExport); case 'export': - return $this->exportFormStep($request, $export, $alias); + return $this->exportFormStep($request, $export, $alias, $savedExport); case 'formatter': - return $this->formatterFormStep($request, $export, $alias); + return $this->formatterFormStep($request, $export, $alias, $savedExport); case 'generate': - return $this->forwardToGenerate($request, $export, $alias); + return $this->forwardToGenerate($request, $export, $alias, $savedExport); default: throw $this->createNotFoundException("The given step '{$step}' is invalid"); } } + /** + * @Route("/{_locale}/export/saved/update-from-key/{id}/{key}", name="chill_main_export_saved_edit_options_from_key") + */ + public function editSavedExportOptionsFromKey(SavedExport $savedExport, string $key): Response + { + $this->denyAccessUnlessGranted('ROLE_USER'); + $user = $this->getUser(); + + if (!$user instanceof User) { + throw new AccessDeniedHttpException(); + } + + $data = $this->rebuildRawData($key); + + $savedExport + ->setOptions($data); + + $this->entityManager->flush(); + + return $this->redirectToRoute('chill_main_export_saved_edit', ['id' => $savedExport->getId()]); + } + /** * @Route("/{_locale}/export/save-from-key/{alias}/{key}", name="chill_main_export_save_from_key") */ @@ -282,45 +311,55 @@ class ExportController extends AbstractController /** * create a form to show on different steps. * - * @param string $alias * @param array $data the data from previous step. Required for steps 'formatter' and 'generate_formatter' - * @param mixed $step */ - protected function createCreateFormExport($alias, $step, $data = []): FormInterface + protected function createCreateFormExport(string $alias, string $step, array $data, ?SavedExport $savedExport): FormInterface { /** @var \Chill\MainBundle\Export\ExportManager $exportManager */ $exportManager = $this->exportManager; $isGenerate = strpos($step, 'generate_') === 0; - $builder = $this->formFactory - ->createNamedBuilder(null, FormType::class, [], [ - 'method' => $isGenerate ? 'GET' : 'POST', - 'csrf_protection' => $isGenerate ? false : true, - ]); + $options = match ($step) { + 'export', 'generate_export' => [ + 'export_alias' => $alias, + 'picked_centers' => $exportManager->getPickedCenters($data['centers']) + ], + 'formatter', 'generate_formatter' => [ + 'export_alias' => $alias, + 'formatter_alias' => $exportManager->getFormatterAlias($data['export']), + 'aggregator_aliases' => $exportManager->getUsedAggregatorsAliases($data['export']), + ], + default => [ + 'export_alias' => $alias, + ], + }; - // TODO: add a condition to be able to select a regroupment of centers? + $defaultFormData = match ($savedExport) { + null => $this->exportFormHelper->getDefaultData($step, $exportManager->getExport($alias), $options), + default => $this->exportFormHelper->savedExportDataToFormData($savedExport, $step, $options), + }; + + $builder = $this->formFactory + ->createNamedBuilder( + null, + FormType::class, + $defaultFormData, + [ + 'method' => $isGenerate ? 'GET' : 'POST', + 'csrf_protection' => !$isGenerate, + ] + ); if ('centers' === $step || 'generate_centers' === $step) { - $builder->add('centers', PickCenterType::class, [ - 'export_alias' => $alias, - ]); + $builder->add('centers', PickCenterType::class, $options); } if ('export' === $step || 'generate_export' === $step) { - $builder->add('export', ExportType::class, [ - 'export_alias' => $alias, - 'picked_centers' => $exportManager->getPickedCenters($data['centers']), - ]); + $builder->add('export', ExportType::class, $options); } if ('formatter' === $step || 'generate_formatter' === $step) { - $builder->add('formatter', FormatterType::class, [ - 'formatter_alias' => $exportManager - ->getFormatterAlias($data['export']), - 'export_alias' => $alias, - 'aggregator_aliases' => $exportManager - ->getUsedAggregatorsAliases($data['export']), - ]); + $builder->add('formatter', FormatterType::class, $options); } $builder->add('submit', SubmitType::class, [ @@ -335,13 +374,8 @@ class ExportController extends AbstractController * * When the method is POST, the form is stored if valid, and a redirection * is done to next step. - * - * @param string $alias - * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export - * - * @return \Symfony\Component\HttpFoundation\Response */ - protected function exportFormStep(Request $request, $export, $alias) + private function exportFormStep(Request $request, DirectExportInterface|ExportInterface $export, string $alias, ?SavedExport $savedExport = null): Response { $exportManager = $this->exportManager; @@ -357,7 +391,7 @@ class ExportController extends AbstractController $export = $exportManager->getExport($alias); - $form = $this->createCreateFormExport($alias, 'export', $data); + $form = $this->createCreateFormExport($alias, 'export', $data, $savedExport); if ($request->getMethod() === 'POST') { $form->handleRequest($request); @@ -379,6 +413,7 @@ class ExportController extends AbstractController $this->generateUrl('chill_main_export_new', [ 'step' => $this->getNextStep('export', $export), 'alias' => $alias, + 'from_saved' => $request->get('from_saved', '') ]) ); } @@ -399,13 +434,8 @@ class ExportController extends AbstractController * * If the form is posted and valid, store the data in session and * redirect to the next step. - * - * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export - * @param string $alias - * - * @return \Symfony\Component\HttpFoundation\Response */ - protected function formatterFormStep(Request $request, $export, $alias) + private function formatterFormStep(Request $request, DirectExportInterface|ExportInterface $export, string $alias, ?SavedExport $savedExport = null): Response { // check we have data from the previous step (export step) $data = $this->session->get('export_step', null); @@ -417,7 +447,7 @@ class ExportController extends AbstractController ]); } - $form = $this->createCreateFormExport($alias, 'formatter', $data); + $form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport); if ($request->getMethod() === 'POST') { $form->handleRequest($request); @@ -436,6 +466,7 @@ class ExportController extends AbstractController [ 'alias' => $alias, 'step' => $this->getNextStep('formatter', $export), + 'from_saved' => $request->get('from_saved', ''), ] )); } @@ -462,7 +493,7 @@ class ExportController extends AbstractController * * @return \Symfony\Component\HttpFoundation\RedirectResponse */ - protected function forwardToGenerate(Request $request, $export, $alias) + private function forwardToGenerate(Request $request, $export, $alias, ?SavedExport $savedExport) { $dataCenters = $this->session->get('centers_step_raw', null); $dataFormatter = $this->session->get('formatter_step_raw', null); @@ -470,7 +501,9 @@ class ExportController extends AbstractController if (null === $dataFormatter && $export instanceof \Chill\MainBundle\Export\ExportInterface) { return $this->redirectToRoute('chill_main_export_new', [ - 'alias' => $alias, 'step' => $this->getNextStep('generate', $export, true), + 'alias' => $alias, + 'step' => $this->getNextStep('generate', $export, true), + 'from_saved' => $savedExport?->getId() ?? '', ]); } @@ -491,20 +524,24 @@ class ExportController extends AbstractController $this->session->remove('formatter_step_raw'); $this->session->remove('formatter_step'); - return $this->redirectToRoute('chill_main_export_download', ['key' => $key, 'alias' => $alias]); + return $this->redirectToRoute('chill_main_export_download', [ + 'key' => $key, + 'alias' => $alias, + 'from_saved' => $savedExport?->getId(), + ]); } - protected function rebuildData($key) + private function rebuildData($key, ?SavedExport $savedExport) { $rawData = $this->rebuildRawData($key); $alias = $rawData['alias']; - $formCenters = $this->createCreateFormExport($alias, 'generate_centers'); + $formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], $savedExport); $formCenters->submit($rawData['centers']); $dataCenters = $formCenters->getData(); - $formExport = $this->createCreateFormExport($alias, 'generate_export', $dataCenters); + $formExport = $this->createCreateFormExport($alias, 'generate_export', $dataCenters, $savedExport); $formExport->submit($rawData['export']); $dataExport = $formExport->getData(); @@ -512,7 +549,8 @@ class ExportController extends AbstractController $formFormatter = $this->createCreateFormExport( $alias, 'generate_formatter', - $dataExport + $dataExport, + $savedExport ); $formFormatter->submit($rawData['formatter']); $dataFormatter = $formFormatter->getData(); @@ -527,12 +565,12 @@ class ExportController extends AbstractController * * @return Response */ - protected function selectCentersStep(Request $request, $export, $alias) + private function selectCentersStep(Request $request, $export, $alias, ?SavedExport $savedExport = null) { /** @var \Chill\MainBundle\Export\ExportManager $exportManager */ $exportManager = $this->exportManager; - $form = $this->createCreateFormExport($alias, 'centers'); + $form = $this->createCreateFormExport($alias, 'centers', [], $savedExport); if ($request->getMethod() === 'POST') { $form->handleRequest($request); @@ -564,6 +602,7 @@ class ExportController extends AbstractController return $this->redirectToRoute('chill_main_export_new', [ 'step' => $this->getNextStep('centers', $export), 'alias' => $alias, + 'from_saved' => $request->get('from_saved', ''), ]); } } @@ -670,4 +709,18 @@ class ExportController extends AbstractController return $rawData; } + + private function getSavedExportFromRequest(Request $request): ?SavedExport + { + $savedExport = match ($savedExportId = $request->query->get('from_saved', '')) { + '' => null, + default => $this->savedExportRepository->find($savedExportId), + }; + + if (null !== $savedExport && !$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) { + throw new AccessDeniedHttpException("saved export edition not allowed"); + } + + return $savedExport; + } } diff --git a/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php b/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php index 850d29838..8d805f612 100644 --- a/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php +++ b/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; use Closure; +use Symfony\Component\Form\FormBuilderInterface; /** * Interface for Aggregators. @@ -21,6 +22,16 @@ use Closure; */ interface AggregatorInterface extends ModifierInterface { + /** + * Add a form to collect data from the user. + */ + public function buildForm(FormBuilderInterface $builder); + + /** + * Get the default data, that can be use as "data" for the form + */ + public function getFormDefaultData(): array; + /** * get a callable which will be able to transform the results into * viewable and understable string. diff --git a/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php b/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php index 9703a42de..5bad5bb42 100644 --- a/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php +++ b/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php @@ -11,10 +11,21 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\Response; interface DirectExportInterface extends ExportElementInterface { + /** + * Add a form to collect data from the user. + */ + public function buildForm(FormBuilderInterface $builder); + + /** + * Get the default data, that can be use as "data" for the form + */ + public function getFormDefaultData(): array; + /** * Generate the export. */ diff --git a/src/Bundle/ChillMainBundle/Export/ExportElementInterface.php b/src/Bundle/ChillMainBundle/Export/ExportElementInterface.php index 3b0402f42..b8cca4ed0 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportElementInterface.php +++ b/src/Bundle/ChillMainBundle/Export/ExportElementInterface.php @@ -19,11 +19,6 @@ use Symfony\Component\Form\FormBuilderInterface; */ interface ExportElementInterface { - /** - * Add a form to collect data from the user. - */ - public function buildForm(FormBuilderInterface $builder); - /** * get a title, which will be used in UI (and translated). * diff --git a/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php b/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php new file mode 100644 index 000000000..5271fb223 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php @@ -0,0 +1,171 @@ + ['centers' => $this->authorizationHelper->getReachableCenters($export->requiredRole())], + 'export', 'generate_export' => ['export' => $this->getDefaultDataStepExport($export, $options)], + 'formatter', 'generate_formatter' => ['formatter' => $this->getDefaultDataStepFormatter($options)], + default => throw new \LogicException("step not allowed : " . $step), + }; + } + + private function getDefaultDataStepFormatter(array $options): array + { + $formatter = $this->exportManager->getFormatter($options['formatter_alias']); + + return $formatter->getFormDefaultData($options['aggregator_aliases']); + } + + private function getDefaultDataStepExport(ExportInterface|DirectExportInterface $export, array $options): array + { + $data = [ + ExportType::EXPORT_KEY => $export->getFormDefaultData(), + ExportType::FILTER_KEY => [], + ExportType::AGGREGATOR_KEY => [], + ExportType::PICK_FORMATTER_KEY => [], + ]; + + $filters = $this->exportManager->getFiltersApplyingOn($export, $options['picked_centers']); + foreach ($filters as $alias => $filter) { + $data[ExportType::FILTER_KEY][$alias] = [ + FilterType::ENABLED_FIELD => false, + 'form' => $filter->getFormDefaultData() + ]; + } + + $aggregators = $this->exportManager + ->getAggregatorsApplyingOn($export, $options['picked_centers']); + foreach ($aggregators as $alias => $aggregator) { + $data[ExportType::AGGREGATOR_KEY][$alias] = [ + 'enabled' => false, + 'form' => $aggregator->getFormDefaultData(), + ]; + } + + if ($export instanceof ExportInterface) { + $allowedFormatters = $this->exportManager + ->getFormattersByTypes($export->getAllowedFormattersTypes()); + $choices = []; + foreach (array_keys(iterator_to_array($allowedFormatters)) as $alias) { + $choices[] = $alias; + } + + $data[ExportType::PICK_FORMATTER_KEY]['alias'] = match (count($choices)) { + 1 => $choices[0], + default => null, + }; + } else { + unset($data[ExportType::PICK_FORMATTER_KEY]); + } + + return $data; + } + + public function savedExportDataToFormData( + SavedExport $savedExport, + string $step, + array $formOptions = [], + ): array { + return match ($step) { + 'centers', 'generate_centers' => $this->savedExportDataToFormDataStepCenter($savedExport), + 'export', 'generate_export' => $this->savedExportDataToFormDataStepExport($savedExport, $formOptions), + 'formatter', 'generate_formatter' => $this->savedExportDataToFormDataStepFormatter($savedExport, $formOptions), + default => throw new \LogicException("this step is not allowed: " . $step), + }; + } + + private function savedExportDataToFormDataStepCenter( + SavedExport $savedExport, + ): array { + $builder = $this->formFactory + ->createBuilder( + FormType::class, + [], + [ + 'csrf_protection' => false, + ] + ); + + $builder->add('centers', PickCenterType::class, [ + 'export_alias' => $savedExport->getExportAlias(), + ]); + $form = $builder->getForm(); + $form->submit($savedExport->getOptions()['centers']); + + return $form->getData(); + } + + private function savedExportDataToFormDataStepExport( + SavedExport $savedExport, + array $formOptions + ): array { + $builder = $this->formFactory + ->createBuilder( + FormType::class, + [], + [ + 'csrf_protection' => false, + ] + ); + + $builder->add('export', ExportType::class, [ + 'export_alias' => $savedExport->getExportAlias(), ...$formOptions + ]); + $form = $builder->getForm(); + $form->submit($savedExport->getOptions()['export']); + + return $form->getData(); + } + + private function savedExportDataToFormDataStepFormatter( + SavedExport $savedExport, + array $formOptions + ): array { + $builder = $this->formFactory + ->createBuilder( + FormType::class, + [], + [ + 'csrf_protection' => false, + ] + ); + + $builder->add('formatter', FormatterType::class, [ + 'export_alias' => $savedExport->getExportAlias(), ...$formOptions + ]); + $form = $builder->getForm(); + $form->submit($savedExport->getOptions()['formatter']); + + return $form->getData(); + } +} diff --git a/src/Bundle/ChillMainBundle/Export/ExportInterface.php b/src/Bundle/ChillMainBundle/Export/ExportInterface.php index d4e456ca6..f357a9fdb 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportInterface.php +++ b/src/Bundle/ChillMainBundle/Export/ExportInterface.php @@ -13,6 +13,7 @@ namespace Chill\MainBundle\Export; use Doctrine\ORM\NativeQuery; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; /** * Interface for Export. @@ -28,6 +29,16 @@ use Doctrine\ORM\QueryBuilder; */ interface ExportInterface extends ExportElementInterface { + /** + * Add a form to collect data from the user. + */ + public function buildForm(FormBuilderInterface $builder); + + /** + * Get the default data, that can be use as "data" for the form + */ + public function getFormDefaultData(): array; + /** * Return which formatter type is allowed for this report. * diff --git a/src/Bundle/ChillMainBundle/Export/ExportManager.php b/src/Bundle/ChillMainBundle/Export/ExportManager.php index f39926083..3f9c839a5 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -12,7 +12,6 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; use Chill\MainBundle\Form\Type\Export\ExportType; -use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Doctrine\ORM\QueryBuilder; use Generator; @@ -114,8 +113,12 @@ class ExportManager * * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias */ - public function &getFiltersApplyingOn(ExportInterface $export, ?array $centers = null) + public function &getFiltersApplyingOn(ExportInterface|DirectExportInterface $export, ?array $centers = null): iterable { + if ($export instanceof DirectExportInterface) { + return; + } + foreach ($this->filters as $alias => $filter) { if ( in_array($filter->applyOn(), $export->supportsModifiers(), true) @@ -131,11 +134,11 @@ class ExportManager * * @internal This class check the interface implemented by export, and, if ´ListInterface´ is used, return an empty array * - * @return AggregatorInterface[] a \Generator that contains aggretagors. The key is the filter's alias + * @return null|iterable a \Generator that contains aggretagors. The key is the filter's alias */ - public function &getAggregatorsApplyingOn(ExportInterface $export, ?array $centers = null) + public function &getAggregatorsApplyingOn(ExportInterface|DirectExportInterface $export, ?array $centers = null): ?iterable { - if ($export instanceof ListInterface) { + if ($export instanceof ListInterface || $export instanceof DirectExportInterface) { return; } @@ -149,7 +152,7 @@ class ExportManager } } - public function addExportElementsProvider(ExportElementsProviderInterface $provider, $prefix) + public function addExportElementsProvider(ExportElementsProviderInterface $provider, string $prefix): void { foreach ($provider->getExportElements() as $suffix => $element) { $alias = $prefix . '_' . $suffix; @@ -173,23 +176,16 @@ class ExportManager * add a formatter. * * @internal used by DI - * - * @param string $alias */ - public function addFormatter(FormatterInterface $formatter, $alias) + public function addFormatter(FormatterInterface $formatter, string $alias) { $this->formatters[$alias] = $formatter; } /** * Generate a response which contains the requested data. - * - * @param string $exportAlias - * @param mixed[] $data - * - * @return Response */ - public function generate($exportAlias, array $pickedCentersData, array $data, array $formatterData) + public function generate(string $exportAlias, array $pickedCentersData, array $data, array $formatterData): Response { $export = $this->getExport($exportAlias); $centers = $this->getPickedCenters($pickedCentersData); @@ -288,7 +284,11 @@ class ExportManager return $this->aggregators[$alias]; } - public function getAggregators(array $aliases) + /** + * @param array $aliases + * @return iterable + */ + public function getAggregators(array $aliases): iterable { foreach ($aliases as $alias) { yield $alias => $this->getAggregator($alias); @@ -296,9 +296,11 @@ class ExportManager } /** - * @return string[] the existing type for known exports + * Get the types for known exports + * + * @return list the existing type for known exports */ - public function getExistingExportsTypes() + public function getExistingExportsTypes(): array { $existingTypes = []; @@ -317,10 +319,8 @@ class ExportManager * @param string $alias * * @throws RuntimeException - * - * @return ExportInterface */ - public function getExport($alias) + public function getExport($alias): ExportInterface|DirectExportInterface { if (!array_key_exists($alias, $this->exports)) { throw new RuntimeException("The export with alias {$alias} is not known."); @@ -334,9 +334,9 @@ class ExportManager * * @param bool $whereUserIsGranted if true (default), restrict to user which are granted the right to execute the export * - * @return ExportInterface[] an array where export's alias are keys + * @return iterable an array where export's alias are keys */ - public function getExports($whereUserIsGranted = true) + public function getExports($whereUserIsGranted = true): iterable { foreach ($this->exports as $alias => $export) { if ($whereUserIsGranted) { @@ -354,9 +354,9 @@ class ExportManager * * @param bool $whereUserIsGranted * - * @return array where keys are the groups's name and value is an array of exports + * @return array> where keys are the groups's name and value is an array of exports */ - public function getExportsGrouped($whereUserIsGranted = true): array + public function getExportsGrouped(bool $whereUserIsGranted = true): array { $groups = ['_' => []]; @@ -375,10 +375,8 @@ class ExportManager * @param string $alias * * @throws RuntimeException if the filter is not known - * - * @return FilterInterface */ - public function getFilter($alias) + public function getFilter(string $alias): FilterInterface { if (!array_key_exists($alias, $this->filters)) { throw new RuntimeException("The filter with alias {$alias} is not known."); @@ -390,16 +388,17 @@ class ExportManager /** * get all filters. * - * @param Generator $aliases + * @param array $aliases + * @return iterable $aliases */ - public function getFilters(array $aliases) + public function getFilters(array $aliases): iterable { foreach ($aliases as $alias) { yield $alias => $this->getFilter($alias); } } - public function getFormatter($alias) + public function getFormatter(string $alias): FormatterInterface { if (!array_key_exists($alias, $this->formatters)) { throw new RuntimeException("The formatter with alias {$alias} is not known."); @@ -414,7 +413,7 @@ class ExportManager * @param array $data the data from the export form * @string the formatter alias|null */ - public function getFormatterAlias(array $data) + public function getFormatterAlias(array $data): ?string { if (array_key_exists(ExportType::PICK_FORMATTER_KEY, $data)) { return $data[ExportType::PICK_FORMATTER_KEY]['alias']; @@ -426,9 +425,9 @@ class ExportManager /** * Get all formatters which supports one of the given types. * - * @return Generator + * @return iterable */ - public function getFormattersByTypes(array $types) + public function getFormattersByTypes(array $types): iterable { foreach ($this->formatters as $alias => $formatter) { if (in_array($formatter->getType(), $types, true)) { @@ -445,7 +444,7 @@ class ExportManager * * @return \Chill\MainBundle\Entity\Center[] the picked center */ - public function getPickedCenters(array $data) + public function getPickedCenters(array $data): array { return $data; } @@ -455,9 +454,9 @@ class ExportManager * * @param array $data the data from the export form * - * @return string[] + * @return list */ - public function getUsedAggregatorsAliases(array $data) + public function getUsedAggregatorsAliases(array $data): array { $aggregators = $this->retrieveUsedAggregators($data[ExportType::AGGREGATOR_KEY]); @@ -471,9 +470,8 @@ class ExportManager * @param \Chill\MainBundle\Export\ExportElementInterface $element * @param DirectExportInterface|ExportInterface $export * - * @return bool */ - public function isGrantedForElement(ExportElementInterface $element, ?ExportElementInterface $export = null, ?array $centers = null) + public function isGrantedForElement(ExportElementInterface $element, ?ExportElementInterface $export = null, ?array $centers = null): bool { if ($element instanceof ExportInterface || $element instanceof DirectExportInterface) { $role = $element->requiredRole(); @@ -548,13 +546,12 @@ class ExportManager * Check for acl. If an user is not authorized to see an aggregator, throw an * UnauthorizedException. * - * @param type $data * @throw UnauthorizedHttpException if the user is not authorized */ private function handleAggregators( ExportInterface $export, QueryBuilder $qb, - $data, + array $data, array $center ) { $aggregators = $this->retrieveUsedAggregators($data); @@ -600,9 +597,9 @@ class ExportManager /** * @param mixed $data * - * @return AggregatorInterface[] + * @return iterable */ - private function retrieveUsedAggregators($data) + private function retrieveUsedAggregators($data): iterable { if (null === $data) { return []; diff --git a/src/Bundle/ChillMainBundle/Export/FilterInterface.php b/src/Bundle/ChillMainBundle/Export/FilterInterface.php index 5e398c30d..7db850108 100644 --- a/src/Bundle/ChillMainBundle/Export/FilterInterface.php +++ b/src/Bundle/ChillMainBundle/Export/FilterInterface.php @@ -11,6 +11,8 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; +use Symfony\Component\Form\FormBuilderInterface; + /** * Interface for filters. * @@ -23,6 +25,16 @@ interface FilterInterface extends ModifierInterface { public const STRING_FORMAT = 'string'; + /** + * Add a form to collect data from the user. + */ + public function buildForm(FormBuilderInterface $builder); + + /** + * Get the default data, that can be use as "data" for the form + */ + public function getFormDefaultData(): array; + /** * Describe the filtering action. * diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php index c8b20a88b..0e4114849 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php @@ -86,6 +86,11 @@ class CSVFormatter implements FormatterInterface } } + public function getFormDefaultData(array $aggregatorAliases): array + { + return []; + } + public function gatherFiltersDescriptions() { $descriptions = []; diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php index b84c80118..d11aea068 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php @@ -85,10 +85,14 @@ class CSVListFormatter implements FormatterInterface 'expanded' => true, 'multiple' => false, 'label' => 'Add a number on first column', - 'data' => true, ]); } + public function getFormDefaultData(array $aggregatorAliases): array + { + return ['numerotation' => true]; + } + public function getName() { return 'CSV vertical list'; diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php index 63d691443..ae4d3629f 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php @@ -84,6 +84,11 @@ class CSVPivotedListFormatter implements FormatterInterface ]); } + public function getFormDefaultData(array $aggregatorAliases): array + { + return ['numerotation' => true]; + } + public function getName() { return 'CSV horizontal list'; diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php index dc09c55a1..6a4b38e84 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php @@ -173,7 +173,19 @@ class SpreadSheetFormatter implements FormatterInterface } } - public function getName() + public function getFormDefaultData(array $aggregatorAliases): array + { + $data = ['format' => 'xlsx']; + + $aggregators = iterator_to_array($this->exportManager->getAggregators($aggregatorAliases)); + foreach (array_keys($aggregators) as $index => $alias) { + $data[$alias] = ['order' => $index + 1]; + } + + return $data; + } + + public function getName(): string { return 'SpreadSheet (xlsx, ods)'; } @@ -185,7 +197,7 @@ class SpreadSheetFormatter implements FormatterInterface array $exportData, array $filtersData, array $aggregatorsData - ) { + ): Response { // store all data when the process is initiated $this->result = $result; $this->formatterData = $formatterData; @@ -574,10 +586,8 @@ class SpreadSheetFormatter implements FormatterInterface * * This form allow to choose the aggregator position (row or column) and * the ordering - * - * @param string $nbAggregators */ - private function appendAggregatorForm(FormBuilderInterface $builder, $nbAggregators) + private function appendAggregatorForm(FormBuilderInterface $builder, int $nbAggregators): void { $builder->add('order', ChoiceType::class, [ 'choices' => array_combine( diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php index 0e5e339ea..b82ab8f61 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php @@ -104,10 +104,14 @@ class SpreadsheetListFormatter implements FormatterInterface 'expanded' => true, 'multiple' => false, 'label' => 'Add a number on first column', - 'data' => true, ]); } + public function getFormDefaultData(array $aggregatorAliases): array + { + return ['numerotation' => true, 'format' => 'xlsx']; + } + public function getName() { return 'Spreadsheet list formatter (.xlsx, .ods)'; diff --git a/src/Bundle/ChillMainBundle/Export/FormatterInterface.php b/src/Bundle/ChillMainBundle/Export/FormatterInterface.php index 1f9df225a..e939c47f2 100644 --- a/src/Bundle/ChillMainBundle/Export/FormatterInterface.php +++ b/src/Bundle/ChillMainBundle/Export/FormatterInterface.php @@ -34,6 +34,11 @@ interface FormatterInterface array $aggregatorAliases ); + /** + * get the default data for the form build by buildForm + */ + public function getFormDefaultData(array $aggregatorAliases): array; + public function getName(); /** diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php index 01303bfbb..d4dc4719d 100644 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php @@ -20,35 +20,23 @@ use Symfony\Component\Form\FormInterface; use function array_key_exists; use function count; -class ExportPickCenterDataMapper implements DataMapperInterface +final readonly class ExportPickCenterDataMapper implements DataMapperInterface { - protected RegroupmentRepository $regroupmentRepository; - - public function mapDataToForms($data, $forms): void + public function mapDataToForms($viewData, $forms): void { - if (null === $data) { + if (null === $viewData) { return; } /** @var array $form */ $form = iterator_to_array($forms); - $pickedRegroupment = []; + $form['center']->setData($viewData); - foreach ($this->regroupmentRepository->findAll() as $regroupment) { - /** @phpstan-ignore-next-line */ - [$contained, $notContained] = $regroupment->getCenters()->partition(static fn (Center $center): bool => false); - - if (0 === count($notContained)) { - $pickedRegroupment[] = $regroupment; - } - } - - $form['regroupment']->setData($pickedRegroupment); - $form['centers']->setData($data); + // NOTE: we do not map back the regroupments } - public function mapFormsToData($forms, &$data): void + public function mapFormsToData($forms, &$viewData): void { /** @var array $forms */ $forms = iterator_to_array($forms); @@ -68,6 +56,6 @@ class ExportPickCenterDataMapper implements DataMapperInterface } } - $data = array_values($centers); + $viewData = array_values($centers); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php index eff303573..1ea01d5f8 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php @@ -32,7 +32,6 @@ class AggregatorType extends AbstractType ->add('enabled', CheckboxType::class, [ 'value' => true, 'required' => false, - 'data' => false, ]); $filterFormBuilder = $builder->create('form', FormType::class, [ diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php index 153f8946b..7994881d5 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php @@ -33,7 +33,6 @@ class FilterType extends AbstractType $builder ->add(self::ENABLED_FIELD, CheckboxType::class, [ 'value' => true, - 'data' => false, 'required' => false, ]); diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php index c89907cf3..c51676b32 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php @@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Regroupment; use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Form\DataMapper\ExportPickCenterDataMapper; use Chill\MainBundle\Repository\RegroupmentRepository; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; @@ -33,22 +34,18 @@ final class PickCenterType extends AbstractType { public const CENTERS_IDENTIFIERS = 'c'; - private AuthorizationHelperInterface $authorizationHelper; + private AuthorizationHelperForCurrentUserInterface $authorizationHelper; private ExportManager $exportManager; private RegroupmentRepository $regroupmentRepository; - private UserInterface $user; - public function __construct( - TokenStorageInterface $tokenStorage, ExportManager $exportManager, RegroupmentRepository $regroupmentRepository, - AuthorizationHelperInterface $authorizationHelper + AuthorizationHelperForCurrentUserInterface $authorizationHelper ) { $this->exportManager = $exportManager; - $this->user = $tokenStorage->getToken()->getUser(); $this->authorizationHelper = $authorizationHelper; $this->regroupmentRepository = $regroupmentRepository; } @@ -57,18 +54,19 @@ final class PickCenterType extends AbstractType { $export = $this->exportManager->getExport($options['export_alias']); $centers = $this->authorizationHelper->getReachableCenters( - $this->user, $export->requiredRole() ); + // order alphabetically + usort($centers, fn (Center $a, Center $b) => $a->getCenter() <=> $b->getName()); + $builder->add('center', EntityType::class, [ 'class' => Center::class, - 'label' => 'center', 'choices' => $centers, + 'label' => 'center', 'multiple' => true, 'expanded' => true, 'choice_label' => static fn (Center $c) => $c->getName(), - 'data' => $centers, ]); if (count($this->regroupmentRepository->findAllActive()) > 0) { diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php index ce442231e..b3253ec42 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php @@ -47,8 +47,6 @@ class PickFormatterType extends AbstractType 'multiple' => false, 'placeholder' => 'Choose a format', ]); - - //$builder->get('type')->addModelTransformer($transformer); } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig index 1e69c5a49..bd7dbf7e9 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/download.html.twig @@ -1,5 +1,5 @@ {# - * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, / * * This program is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ {% extends "@ChillMain/layout.html.twig" %} {% block title "Download export"|trans ~ export.title|trans %} - + {% block js %} {% endblock %} - + {% block content %}
            - + {{ include('@ChillMain/Export/_breadcrumb.html.twig') }} - +

            {{ export.title|trans }}

            {{ "Download export"|trans }}

            - +
            {{ 'Back to the list'|trans }} {% if not app.request.query.has('prevent_save') %} + {% if saved_export is null %}
          • {{ 'Save'|trans }}
          • + {% else %} +
          • + +
          • + {% endif %} {% endif %}
      -{% endblock content %} \ No newline at end of file +{% endblock content %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig index fd0cda2a7..7e0517e31 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/index.html.twig @@ -22,18 +22,28 @@

      {{ s.export.title|trans }}

      {{ s.saved.title }}

      - +
      {{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
      - +
      {{ s.saved.description|chill_markdown_to_html }}
      - +
      @@ -54,13 +64,13 @@

      {{ s.export.title|trans }}

      {{ s.saved.title }}

      - +
      {{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}
      - +
      {{ s.saved.description|chill_markdown_to_html }}
      - +
      • diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php index 28cc8e331..8f18f9102 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -136,6 +136,11 @@ class FilterOrderHelper return $this->checkboxes; } + public function hasCheckBox(string $name): bool + { + return array_key_exists($name, $this->checkboxes); + } + /** * @return array */ diff --git a/src/Bundle/ChillMainBundle/config/services/export.yaml b/src/Bundle/ChillMainBundle/config/services/export.yaml index ea7328839..b0dbf934d 100644 --- a/src/Bundle/ChillMainBundle/config/services/export.yaml +++ b/src/Bundle/ChillMainBundle/config/services/export.yaml @@ -6,6 +6,8 @@ services: Chill\MainBundle\Export\Helper\: resource: '../../Export/Helper' + Chill\MainBundle\Export\ExportFormHelper: ~ + chill.main.export_element_validator: class: Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraintValidator tags: diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 78de523c4..6a6136a41 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -42,6 +42,7 @@ by_user: "par " lifecycleUpdate: Evenements de création et mise à jour address_fields: Données liées à l'adresse Datas: Données +No title: Aucun titre inactive: inactif @@ -598,7 +599,10 @@ saved_export: Export is deleted: L'export est supprimé Saved export is saved!: L'export est enregistré Created on %date%: Créé le %date% - + update_title_and_description: Modifier le titre et la description + update_filters_aggregators_and_execute: Modifier les filtres et regroupements et télécharger + execute: Télécharger + Update existing: Mettre à jour le rapport enregistré existant absence: # single letter for absence diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index accf39db5..07e1bafe4 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -271,6 +271,7 @@ class AccompanyingPeriod implements * cascade={"persist", "refresh", "remove", "merge", "detach"}) * @Groups({"read", "docgen:read"}) * @ParticipationOverlap(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) + * @var Collection */ private Collection $participations; @@ -785,7 +786,7 @@ class AccompanyingPeriod implements } /** - * @return Collection|AccompanyingPeriodLocationHistory[] + * @return Collection */ public function getLocationHistories(): Collection { @@ -796,6 +797,7 @@ class AccompanyingPeriod implements * Get where the location is. * * @Groups({"read"}) + * @return 'person'|'address'|'none' */ public function getLocationStatus(): string { @@ -873,6 +875,7 @@ class AccompanyingPeriod implements /** * Get Participations Collection. + * @return Collection */ public function getParticipations(): Collection { @@ -1207,6 +1210,7 @@ class AccompanyingPeriod implements $this->addressLocation = $addressLocation; if (null !== $addressLocation) { + $this->setPersonLocation(null); $locationHistory = new AccompanyingPeriodLocationHistory(); $locationHistory ->setStartDate(new DateTimeImmutable('now')) @@ -1325,6 +1329,7 @@ class AccompanyingPeriod implements $this->personLocation = $person; if (null !== $person) { + $this->setAddressLocation(null); $locationHistory = new AccompanyingPeriodLocationHistory(); $locationHistory ->setStartDate(new DateTimeImmutable('now')) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/AdministrativeLocationAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/AdministrativeLocationAggregator.php index 96deac574..56fdc07d7 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/AdministrativeLocationAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/AdministrativeLocationAggregator.php @@ -57,6 +57,10 @@ class AdministrativeLocationAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php index 2dffccbbb..104b934ca 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ByActionNumberAggregator.php @@ -39,6 +39,10 @@ class ByActionNumberAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingMotiveAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingMotiveAggregator.php index 342958361..73cfdc7b9 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingMotiveAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ClosingMotiveAggregator.php @@ -52,6 +52,10 @@ class ClosingMotiveAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ConfidentialAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ConfidentialAggregator.php index e9b9e28fa..4ad18030e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ConfidentialAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ConfidentialAggregator.php @@ -48,6 +48,10 @@ class ConfidentialAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php index c336a8887..5a060bcd7 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/CreatorJobAggregator.php @@ -57,6 +57,10 @@ class CreatorJobAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php index 0dc66e81e..581c7d6e5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/DurationAggregator.php @@ -84,6 +84,10 @@ final class DurationAggregator implements AggregatorInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EmergencyAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EmergencyAggregator.php index 02f9f5cd9..4429c7b62 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EmergencyAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EmergencyAggregator.php @@ -48,6 +48,10 @@ class EmergencyAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EvaluationAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EvaluationAggregator.php index b6436efc0..119fa50b7 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EvaluationAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/EvaluationAggregator.php @@ -61,6 +61,10 @@ final class EvaluationAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php index d001cbef7..a83634830 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/GeographicalUnitStatAggregator.php @@ -121,7 +121,6 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('level', EntityType::class, [ 'label' => 'Geographical layer', @@ -133,6 +132,10 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/IntensityAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/IntensityAggregator.php index a3618f40f..ac55d7734 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/IntensityAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/IntensityAggregator.php @@ -48,6 +48,10 @@ class IntensityAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php index 37d0c7b20..1d01920d5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/OriginAggregator.php @@ -59,6 +59,10 @@ final class OriginAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php index a09097fd2..7b826600a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerAggregator.php @@ -81,11 +81,14 @@ final class ReferrerAggregator implements AggregatorInterface { $builder ->add('date_calc', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.aggregator.course.by_referrer.Computation date for referrer', 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php index ccbd21da1..adfd9b489 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ReferrerScopeAggregator.php @@ -88,11 +88,14 @@ class ReferrerScopeAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { $builder->add('date_calc', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.aggregator.course.by_user_scope.Computation date for referrer', 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/RequestorAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/RequestorAggregator.php index 7b5cf0edd..3baf9bd33 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/RequestorAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/RequestorAggregator.php @@ -69,6 +69,10 @@ final class RequestorAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ScopeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ScopeAggregator.php index 8f34661bb..253727c89 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ScopeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/ScopeAggregator.php @@ -57,6 +57,10 @@ final class ScopeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialActionAggregator.php index 3bdd6549e..b82b47ad0 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialActionAggregator.php @@ -58,6 +58,10 @@ final class SocialActionAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialIssueAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialIssueAggregator.php index 12fa5a454..29fcba4a2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialIssueAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/SocialIssueAggregator.php @@ -58,6 +58,10 @@ final class SocialIssueAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php index 85cfc3190..7632f72f0 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/StepAggregator.php @@ -76,9 +76,11 @@ final class StepAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + $builder->add('on_date', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['on_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getLabels($key, array $values, $data) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/UserJobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/UserJobAggregator.php index a8acdcf12..13d1e3f83 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/UserJobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AccompanyingCourseAggregators/UserJobAggregator.php @@ -57,6 +57,10 @@ final class UserJobAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php index 2f4275c49..cb66fa600 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByEndDateAggregator.php @@ -75,9 +75,12 @@ class ByEndDateAggregator implements AggregatorInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['frequency' => self::DEFAULT_CHOICE]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php index 9283fd9dc..af6dfc465 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByMaxDateAggregator.php @@ -75,9 +75,12 @@ class ByMaxDateAggregator implements AggregatorInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['frequency' => self::DEFAULT_CHOICE]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php index cd183b25e..87a6a672b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/ByStartDateAggregator.php @@ -75,9 +75,12 @@ class ByStartDateAggregator implements AggregatorInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['frequency' => self::DEFAULT_CHOICE]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/EvaluationTypeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/EvaluationTypeAggregator.php index 0c13611cb..a48ed763d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/EvaluationTypeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/EvaluationTypeAggregator.php @@ -52,6 +52,10 @@ class EvaluationTypeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php index e33bb326f..e710949fd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/EvaluationAggregators/HavingEndDateAggregator.php @@ -48,6 +48,10 @@ class HavingEndDateAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php index 0c9bc623f..1c5b3dc2c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/ChildrenNumberAggregator.php @@ -72,9 +72,11 @@ class ChildrenNumberAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + $builder->add('on_date', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['on_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getLabels($key, array $values, $data) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php index 52bcd88e5..62fc20173 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/HouseholdAggregators/CompositionAggregator.php @@ -77,9 +77,11 @@ class CompositionAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('on_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + $builder->add('on_date', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['on_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getLabels($key, array $values, $data) diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php index 365a73704..e3d364fa2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php @@ -13,20 +13,18 @@ namespace Chill\PersonBundle\Export\Aggregator\PersonAggregators; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use DateTime; +use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; +use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Contracts\Translation\TranslatorInterface; -final class AgeAggregator implements AggregatorInterface, ExportElementValidatedInterface +final readonly class AgeAggregator implements AggregatorInterface, ExportElementValidatedInterface { - private TranslatorInterface $translator; - - public function __construct(TranslatorInterface $translator) - { - $this->translator = $translator; + public function __construct( + private RollingDateConverterInterface $rollingDateConverter, + ) { } public function addRole(): ?string @@ -37,7 +35,7 @@ final class AgeAggregator implements AggregatorInterface, ExportElementValidated public function alterQuery(QueryBuilder $qb, $data) { $qb->addSelect('DATE_DIFF(:date_age_calculation, person.birthdate)/365 as person_age'); - $qb->setParameter('date_age_calculation', $data['date_age_calculation']); + $qb->setParameter('date_age_calculation', $this->rollingDateConverter->convert($data['date_age_calculation'])); $qb->addGroupBy('person_age'); } @@ -48,14 +46,14 @@ final class AgeAggregator implements AggregatorInterface, ExportElementValidated public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_age_calculation', DateType::class, [ + $builder->add('date_age_calculation', PickRollingDateType::class, [ 'label' => 'Calculate age in relation to this date', - 'data' => new DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy', ]); } + public function getFormDefaultData(): array + { + return ['date_age_calculation' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { @@ -64,11 +62,7 @@ final class AgeAggregator implements AggregatorInterface, ExportElementValidated return 'Age'; } - if (null === $value) { - return $this->translator->trans('without data'); - } - - return $value; + return $value ?? ''; }; } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php index 80f0faa17..16b62c2b5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/ByHouseholdCompositionAggregator.php @@ -94,9 +94,12 @@ class ByHouseholdCompositionAggregator implements AggregatorInterface { $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'export.aggregator.person.by_household_composition.Calc date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/CountryOfBirthAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/CountryOfBirthAggregator.php index 3d785b586..90882245e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/CountryOfBirthAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/CountryOfBirthAggregator.php @@ -108,6 +108,10 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme 'multiple' => false, ]); } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GenderAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GenderAggregator.php index f76420047..dbe3d19d3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GenderAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GenderAggregator.php @@ -48,6 +48,10 @@ final class GenderAggregator implements AggregatorInterface public function buildForm(FormBuilderInterface $builder) { } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php index 5d73c1fdd..a72d91db2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/GeographicalUnitAggregator.php @@ -93,7 +93,6 @@ class GeographicalUnitAggregator implements AggregatorInterface ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Address valid at this date', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('level', EntityType::class, [ 'label' => 'Geographical layer', @@ -105,6 +104,10 @@ class GeographicalUnitAggregator implements AggregatorInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public static function getDefaultAlias(): string { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php index 107634803..63d84d4da 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/HouseholdPositionAggregator.php @@ -90,9 +90,12 @@ final class HouseholdPositionAggregator implements AggregatorInterface, ExportEl { $builder->add('date_position', PickRollingDateType::class, [ 'label' => 'Household position in relation to this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_position' => new RollingDate(RollingDate::T_TODAY)]; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/MaritalStatusAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/MaritalStatusAggregator.php index 08bde4bda..508efd3ad 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/MaritalStatusAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/MaritalStatusAggregator.php @@ -56,6 +56,11 @@ final class MaritalStatusAggregator implements AggregatorInterface // no form } + public function getFormDefaultData(): array + { + return []; + } + public function getLabels($key, array $values, $data) { return function ($value): string { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/NationalityAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/NationalityAggregator.php index d7c4097af..57721f55c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/NationalityAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/NationalityAggregator.php @@ -103,6 +103,13 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV ]); } + public function getFormDefaultData(): array + { + return [ + 'group_by_level' => 'country', + ]; + } + public function getLabels($key, array $values, $data) { $labels = []; diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php index c1fccb968..66c87d94f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ActionTypeAggregator.php @@ -75,6 +75,10 @@ final class ActionTypeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php index 58fcb2874..539c9f286 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/CurrentActionAggregator.php @@ -51,6 +51,10 @@ class CurrentActionAggregator implements AggregatorInterface { // No form needed } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php index 8cc6a25da..4c0e8b393 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalAggregator.php @@ -55,6 +55,10 @@ final class GoalAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php index 17b263d7e..c99ee85ea 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/GoalResultAggregator.php @@ -68,6 +68,10 @@ class GoalResultAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/JobAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/JobAggregator.php index cbf07091f..8271c90e3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/JobAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/JobAggregator.php @@ -57,6 +57,10 @@ final class JobAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ReferrerAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ReferrerAggregator.php index 0fe53b707..047504224 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ReferrerAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ReferrerAggregator.php @@ -57,6 +57,10 @@ final class ReferrerAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php index 2e46673da..3cce7b283 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ResultAggregator.php @@ -55,6 +55,10 @@ final class ResultAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ScopeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ScopeAggregator.php index 243263b83..0828b5d0d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ScopeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/SocialWorkAggregators/ScopeAggregator.php @@ -57,6 +57,10 @@ final class ScopeAggregator implements AggregatorInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function getLabels($key, array $values, $data) { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php index 978f88a10..58ef24e42 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingCourse.php @@ -39,6 +39,10 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface { // Nothing to add here } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { @@ -97,7 +101,6 @@ class CountAccompanyingCourse implements ExportInterface, GroupedExportInterface ->andWhere('acp.step != :count_acp_step') ->leftJoin('acp.participations', 'acppart') ->leftJoin('acppart.person', 'person') - ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php index 122ee14d9..cf9feb3af 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountAccompanyingPeriodWork.php @@ -38,6 +38,10 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter { // No form necessary? } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { @@ -97,7 +101,6 @@ class CountAccompanyingPeriodWork implements ExportInterface, GroupedExportInter ->join('acpw.accompanyingPeriod', 'acp') ->join('acp.participations', 'acppart') ->join('acppart.person', 'person') - ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php index 1613b63d3..d9795e3ba 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountEvaluation.php @@ -37,6 +37,10 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface { // TODO: Implement buildForm() method. } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { @@ -97,7 +101,6 @@ class CountEvaluation implements ExportInterface, GroupedExportInterface ->join('acpw.accompanyingPeriod', 'acp') ->join('acp.participations', 'acppart') ->join('acppart.person', 'person') - ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') ->andWhere( $qb->expr()->exists( 'SELECT 1 FROM ' . PersonCenterHistory::class . ' acl_count_person_history WHERE acl_count_person_history.person = person diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php index 0b693b9d8..05e32fde6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountHousehold.php @@ -46,11 +46,14 @@ class CountHousehold implements ExportInterface, GroupedExportInterface { $builder ->add('calc_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => self::TR_PREFIX . 'Date of calculation of household members', 'required' => false, ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index 60429ae55..c1800395c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -38,6 +38,11 @@ class CountPerson implements ExportInterface, GroupedExportInterface // No form necessary } + public function getFormDefaultData(): array + { + return []; + } + public function getAllowedFormattersTypes() { return [FormatterInterface::TYPE_TABULAR]; @@ -115,9 +120,9 @@ class CountPerson implements ExportInterface, GroupedExportInterface public function supportsModifiers() { return [ - Declarations::PERSON_TYPE, - Declarations::PERSON_IMPLIED_IN, - //Declarations::ACP_TYPE + 'abcde', + //Declarations::PERSON_TYPE, + //Declarations::PERSON_IMPLIED_IN, ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php index e52cc83b1..ae7238d4e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPersonWithAccompanyingCourse.php @@ -39,6 +39,10 @@ class CountPersonWithAccompanyingCourse implements ExportInterface, GroupedExpor { // TODO: Implement buildForm() method. } + public function getFormDefaultData(): array + { + return []; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php index 0647460dd..af66ab312 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php @@ -20,6 +20,7 @@ use Chill\MainBundle\Export\Helper\ExportAddressHelper; use Chill\MainBundle\Export\Helper\UserHelper; use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Form\Type\PickRollingDateType; +use Chill\MainBundle\Service\RollingDate\RollingDate; use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; @@ -144,6 +145,12 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface 'required' => true, ]); } + public function getFormDefaultData(): array + { + return [ + 'calc_date' => new RollingDate(RollingDate::T_TODAY) + ]; + } public function getAllowedFormattersTypes() { @@ -409,15 +416,11 @@ class ListAccompanyingPeriod implements ListInterface, GroupedExportInterface ) ) ) - ->leftJoin(PersonHouseholdAddress::class, 'personAddress', Join::WITH, 'locationHistory.personLocation = personAddress.person') - ->andWhere( - $qb->expr()->orX( - $qb->expr()->isNull('personAddress'), - $qb->expr()->andX( - $qb->expr()->lte('personAddress.validFrom', ':calcDate'), - $qb->expr()->orX($qb->expr()->isNull('personAddress.validTo'), $qb->expr()->gt('personAddress.validTo', ':calcDate')) - ) - ) + ->leftJoin( + PersonHouseholdAddress::class, + 'personAddress', + Join::WITH, + 'locationHistory.personLocation = personAddress.person AND (personAddress.validFrom <= :calcDate AND (personAddress.validTo IS NULL OR personAddress.validTo > :calcDate))' ) ->leftJoin(Address::class, 'acp_address', Join::WITH, 'COALESCE(IDENTITY(locationHistory.addressLocation), IDENTITY(personAddress.address)) = acp_address.id'); diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php index 00fa8adb1..c437454c2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriodWork.php @@ -135,9 +135,12 @@ class ListAccompanyingPeriodWork implements ListInterface, GroupedExportInterfac 'label' => 'export.list.acpw.Date of calculation for associated elements', 'help' => 'export.list.acpw.help_description', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php b/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php index f0985436b..c3e273733 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListEvaluation.php @@ -123,9 +123,12 @@ class ListEvaluation implements ListInterface, GroupedExportInterface 'label' => 'export.list.eval.Date of calculation for associated elements', 'help' => 'export.list.eval.help_description', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php index 8894d145d..4dcc89495 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php @@ -75,10 +75,13 @@ class ListHouseholdInPeriod implements ListInterface, GroupedExportInterface ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.list.household.Date of calculation for associated elements', 'help' => 'export.list.household.help_description', - 'data' => new RollingDate(RollingDate::T_TODAY), 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index 8145fd658..467bc02ea 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -107,17 +107,27 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou } }, ])], - 'data' => array_values($choices), ]); // add a date field for addresses $builder->add('address_date', ChillDateType::class, [ 'label' => 'Data valid at this date', 'help' => 'Data regarding center, addresses, and so on will be computed at this date', - 'data' => new DateTimeImmutable(), 'input' => 'datetime_immutable', ]); } + public function getFormDefaultData(): array + { + $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); + + foreach ($this->getCustomFields() as $cf) { + $choices[$this->translatableStringHelper->localize($cf->getName())] + = + $cf->getSlug(); + } + + return ['fields' => array_values($choices), 'address_date' => new DateTimeImmutable()]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php index e40ffccce..e7c105604 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php @@ -74,9 +74,12 @@ class ListPersonDuplicate implements DirectExportInterface, ExportElementValidat { $builder->add('precision', NumberType::class, [ 'label' => 'Precision', - 'data' => self::PRECISION_DEFAULT_VALUE, ]); } + public function getFormDefaultData(): array + { + return ['precision' => self::PRECISION_DEFAULT_VALUE]; + } public function generate(array $acl, array $data = []): Response { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php index 7cb066e87..370046232 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonWithAccompanyingPeriod.php @@ -57,7 +57,6 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac { $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); - // Add a checkbox to select fields $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, @@ -80,17 +79,20 @@ class ListPersonWithAccompanyingPeriod implements ExportElementValidatedInterfac } }, ])], - 'data' => array_values($choices), ]); - // add a date field for addresses $builder->add('address_date', ChillDateType::class, [ 'label' => 'Data valid at this date', 'help' => 'Data regarding center, addresses, and so on will be computed at this date', - 'data' => new DateTimeImmutable(), 'input' => 'datetime_immutable', ]); } + public function getFormDefaultData(): array + { + $choices = array_combine(ListPersonHelper::FIELDS, ListPersonHelper::FIELDS); + + return ['fields' => array_values($choices), 'address_date' => new DateTimeImmutable()]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php index 31ca41cbb..66b47131d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/StatAccompanyingCourseDuration.php @@ -41,9 +41,12 @@ class StatAccompanyingCourseDuration implements ExportInterface, GroupedExportIn { $builder->add('closingdate', ChillDateType::class, [ 'label' => 'Closingdate to apply', - 'data' => new DateTime('now'), ]); } + public function getFormDefaultData(): array + { + return ['closingdate' => new DateTime('now')]; + } public function getAllowedFormattersTypes(): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php index 3fa8d711f..fcb4d67fb 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOnDateFilter.php @@ -67,9 +67,11 @@ class ActiveOnDateFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('on_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + ->add('on_date', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['on_date' => new RollingDate(RollingDate::T_TODAY)]; } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php index f713e8a97..ae21dc724 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ActiveOneDayBetweenDatesFilter.php @@ -56,12 +56,12 @@ class ActiveOneDayBetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), - ]) - ->add('date_to', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + ->add('date_from', PickRollingDateType::class, []) + ->add('date_to', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php index c74e309b2..aa1abb36e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php @@ -53,6 +53,10 @@ class AdministrativeLocationFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ClosingMotiveFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ClosingMotiveFilter.php index e57370f30..153b2ecbd 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ClosingMotiveFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ClosingMotiveFilter.php @@ -64,6 +64,10 @@ class ClosingMotiveFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ConfidentialFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ConfidentialFilter.php index 8fcd874fe..8811b9930 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ConfidentialFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ConfidentialFilter.php @@ -22,11 +22,11 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ConfidentialFilter implements FilterInterface { private const CHOICES = [ - 'is not confidential' => false, - 'is confidential' => true, + 'is not confidential' => 'false', + 'is confidential' => 'true', ]; - private const DEFAULT_CHOICE = false; + private const DEFAULT_CHOICE = 'false'; private TranslatorInterface $translator; @@ -67,9 +67,12 @@ class ConfidentialFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_confidentials' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php index b13947e60..8a8a24013 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorFilter.php @@ -50,6 +50,10 @@ class CreatorFilter implements FilterInterface 'label' => false, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php index f585cfafb..5faeb850f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/CreatorJobFilter.php @@ -69,6 +69,10 @@ class CreatorJobFilter implements FilterInterface 'label' => 'Job', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EmergencyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EmergencyFilter.php index afdb717f0..f9d45c9d7 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EmergencyFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EmergencyFilter.php @@ -22,11 +22,11 @@ use Symfony\Contracts\Translation\TranslatorInterface; class EmergencyFilter implements FilterInterface { private const CHOICES = [ - 'is emergency' => true, - 'is not emergency' => false, + 'is emergency' => 'true', + 'is not emergency' => 'false', ]; - private const DEFAULT_CHOICE = false; + private const DEFAULT_CHOICE = 'false'; private TranslatorInterface $translator; @@ -67,9 +67,12 @@ class EmergencyFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_emergency' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EvaluationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EvaluationFilter.php index ab7f4257e..a6fb3583d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EvaluationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/EvaluationFilter.php @@ -75,6 +75,10 @@ class EvaluationFilter implements FilterInterface 'attr' => ['class' => 'select2'], ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php index d35565c80..a20cfc08f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/GeographicalUnitStatFilter.php @@ -100,7 +100,6 @@ class GeographicalUnitStatFilter implements FilterInterface ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', @@ -114,6 +113,10 @@ class GeographicalUnitStatFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php index 54c28d027..4820116c0 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoActionFilter.php @@ -38,6 +38,10 @@ class HasNoActionFilter implements FilterInterface { // no form } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php index 4c682a56a..6d01ea7c2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasNoReferrerFilter.php @@ -65,9 +65,12 @@ class HasNoReferrerFilter implements FilterInterface $builder ->add('calc_date', PickRollingDateType::class, [ 'label' => 'Has no referrer on this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php index 615ace4c6..ec3b4e417 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HasTemporaryLocationFilter.php @@ -92,9 +92,12 @@ class HasTemporaryLocationFilter implements FilterInterface ]) ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.filter.course.having_temporarily.Calculation date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HavingAnAccompanyingPeriodInfoWithinDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HavingAnAccompanyingPeriodInfoWithinDatesFilter.php index 7069a1d80..d50622502 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HavingAnAccompanyingPeriodInfoWithinDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/HavingAnAccompanyingPeriodInfoWithinDatesFilter.php @@ -38,13 +38,14 @@ final readonly class HavingAnAccompanyingPeriodInfoWithinDatesFilter implements $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'export.filter.course.having_info_within_interval.start_date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'export.filter.course.having_info_within_interval.end_date', - 'data' => new RollingDate(RollingDate::T_TODAY), - ]) - ; + ]); + } + public function getFormDefaultData(): array + { + return ['start_date' => new RollingDate(RollingDate::T_TODAY), 'end_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/IntensityFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/IntensityFilter.php index b0c2205a0..1fd05d2b4 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/IntensityFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/IntensityFilter.php @@ -67,9 +67,12 @@ class IntensityFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_intensities' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php index 07ca1de75..e9413083f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OpenBetweenDatesFilter.php @@ -54,12 +54,12 @@ class OpenBetweenDatesFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date_from', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_MONTH_PREVIOUS_START), - ]) - ->add('date_to', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + ->add('date_from', PickRollingDateType::class, []) + ->add('date_to', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_MONTH_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OriginFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OriginFilter.php index 00febc640..8395c79f8 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OriginFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/OriginFilter.php @@ -64,6 +64,10 @@ class OriginFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php index 2a3e5d17e..f0bf65d49 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/ReferrerFilter.php @@ -77,11 +77,14 @@ class ReferrerFilter implements FilterInterface 'multiple' => true, ]) ->add('date_calc', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_referrer.Computation date for referrer', 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/RequestorFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/RequestorFilter.php index 3295a5b57..614889c27 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/RequestorFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/RequestorFilter.php @@ -126,9 +126,12 @@ final class RequestorFilter implements FilterInterface 'multiple' => false, 'expanded' => true, 'empty_data' => self::DEFAULT_CHOICE, - 'data' => self::DEFAULT_CHOICE, ]); } + public function getFormDefaultData(): array + { + return ['accepted_choices' => self::DEFAULT_CHOICE]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php index bc1f368da..0c14ba73a 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php @@ -70,6 +70,10 @@ class SocialActionFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php index 917e129bf..a793bc548 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php @@ -69,6 +69,10 @@ class SocialIssueFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php index 05d84d7b2..e7685fe4d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserJobFilter.php @@ -96,11 +96,14 @@ class UserJobFilter implements FilterInterface 'label' => 'Job', ]) ->add('date_calc', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_user_scope.Computation date for referrer', 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php index bbffa4bca..7c8d84499 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserScopeFilter.php @@ -100,11 +100,14 @@ class UserScopeFilter implements FilterInterface 'expanded' => true, ]) ->add('date_calc', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), 'label' => 'export.filter.course.by_user_scope.Computation date for referrer', 'required' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php index 586bb645d..d078443af 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/UserWorkingOnCourseFilter.php @@ -42,6 +42,10 @@ readonly class UserWorkingOnCourseFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function getTitle(): string { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php index de86604e6..4c019cc73 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByEndDateFilter.php @@ -57,13 +57,15 @@ class ByEndDateFilter implements FilterInterface $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['start_date' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'end_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php index 27518599c..ea221e87b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/ByStartDateFilter.php @@ -57,13 +57,15 @@ class ByStartDateFilter implements FilterInterface $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'start period date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'end period date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['start_date' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'end_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php index 140f6c3cb..8841c7b9e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/CurrentEvaluationsFilter.php @@ -37,6 +37,10 @@ class CurrentEvaluationsFilter implements FilterInterface { //no form needed } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/EvaluationTypeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/EvaluationTypeFilter.php index 6a0c71d55..77bae1b56 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/EvaluationTypeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/EvaluationTypeFilter.php @@ -64,6 +64,10 @@ final class EvaluationTypeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/MaxDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/MaxDateFilter.php index 4a65452a1..daa7d1954 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/MaxDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/EvaluationFilters/MaxDateFilter.php @@ -61,6 +61,10 @@ class MaxDateFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php index 22761c158..3a2cb5337 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/HouseholdFilters/CompositionFilter.php @@ -84,9 +84,11 @@ class CompositionFilter implements FilterInterface 'multiple' => true, 'expanded' => true, ]) - ->add('on_date', PickRollingDateType::class, [ - 'data' => new RollingDate(RollingDate::T_TODAY), - ]); + ->add('on_date', PickRollingDateType::class, []); + } + public function getFormDefaultData(): array + { + return ['on_date' => new RollingDate(RollingDate::T_TODAY)]; } public function describeAction($data, $format = 'string'): array diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php index 7580a37a3..5588d8c15 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AddressRefStatusFilter.php @@ -76,17 +76,19 @@ class AddressRefStatusFilter implements \Chill\MainBundle\Export\FilterInterface ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute address at date', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('ref_statuses', ChoiceType::class, [ 'label' => 'export.filter.person.by_address_ref_status.Status', 'choices' => [Address::ADDR_REFERENCE_STATUS_TO_REVIEW, Address::ADDR_REFERENCE_STATUS_REVIEWED, Address::ADDR_REFERENCE_STATUS_MATCH], 'choice_label' => fn (string $item) => 'export.filter.person.by_address_ref_status.'.$item, 'multiple' => true, - 'expanded' => true, - 'data' => [Address::ADDR_REFERENCE_STATUS_TO_REVIEW] + 'expanded' => true ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY), 'ref_statuses' => [Address::ADDR_REFERENCE_STATUS_TO_REVIEW]]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php index c05f97ca8..f06e42c1f 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/AgeFilter.php @@ -92,6 +92,15 @@ class AgeFilter implements ExportElementValidatedInterface, FilterInterface ]); } + public function getFormDefaultData(): array + { + return [ + 'min_age' => 0, + 'max_age' => 120, + 'date_calc' => new RollingDate(RollingDate::T_TODAY), + ]; + } + public function describeAction($data, $format = 'string') { return ['Filtered by person\'s age: ' diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php index 7ae22ddd8..9a0478b6c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/BirthdateFilter.php @@ -71,14 +71,16 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac { $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Born after this date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Born before this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php index 9b59549f1..749897a53 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ByHouseholdCompositionFilter.php @@ -86,9 +86,12 @@ class ByHouseholdCompositionFilter implements FilterInterface ]) ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.filter.person.by_composition.Date calc', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php index 384d6698a..8b2444ca2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeadOrAliveFilter.php @@ -102,9 +102,12 @@ class DeadOrAliveFilter implements FilterInterface $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Filter in relation to this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php index 0ac4b3173..7805331a5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/DeathdateFilter.php @@ -72,14 +72,16 @@ class DeathdateFilter implements ExportElementValidatedInterface, FilterInterfac { $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Death after this date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Deathdate before', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GenderFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GenderFilter.php index 739945b98..182006bbc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GenderFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GenderFilter.php @@ -89,6 +89,10 @@ class GenderFilter implements 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php index 79f5cb2d4..ab9bb08ab 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/GeographicalUnitFilter.php @@ -91,7 +91,6 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface ->add('date_calc', PickRollingDateType::class, [ 'label' => 'Compute geographical location at date', 'required' => true, - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('units', ChoiceType::class, [ 'label' => 'Geographical unit', @@ -105,6 +104,10 @@ class GeographicalUnitFilter implements \Chill\MainBundle\Export\FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/MaritalStatusFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/MaritalStatusFilter.php index 47a75871c..021c22fc6 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/MaritalStatusFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/MaritalStatusFilter.php @@ -56,6 +56,10 @@ class MaritalStatusFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/NationalityFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/NationalityFilter.php index b1d77d60e..e5102128b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/NationalityFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/NationalityFilter.php @@ -67,6 +67,10 @@ class NationalityFilter implements 'placeholder' => 'Choose countries', ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php index 21bb40947..8f22750a5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtThirdpartyFilter.php @@ -107,9 +107,12 @@ class ResidentialAddressAtThirdpartyFilter implements FilterInterface $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Date during which residential address was valid', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php index bd55c5b80..62b142420 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/ResidentialAddressAtUserFilter.php @@ -82,9 +82,12 @@ class ResidentialAddressAtUserFilter implements FilterInterface { $builder->add('date_calc', PickRollingDateType::class, [ 'label' => 'Date during which residential address was valid', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_calc' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php index c4644fc11..9f5ed90b5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/PersonFilters/WithoutHouseholdComposition.php @@ -66,9 +66,12 @@ class WithoutHouseholdComposition implements FilterInterface $builder ->add('calc_date', PickRollingDateType::class, [ 'label' => 'export.filter.person.by_no_composition.Date calc', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['calc_date' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php index b13c49e9a..e78b1d021 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkEndDateBetweenDateFilter.php @@ -32,17 +32,18 @@ final readonly class AccompanyingPeriodWorkEndDateBetweenDateFilter implements F $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'export.filter.work.end_between_dates.start_date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'export.filter.work.end_between_dates.end_date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('keep_null', CheckboxType::class, [ 'label' => 'export.filter.work.end_between_dates.keep_null', 'help' => 'export.filter.work.end_between_dates.keep_null_help', - ]) - ; + ]); + } + public function getFormDefaultData(): array + { + return ['start_date' => new RollingDate(RollingDate::T_TODAY), 'end_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkStartDateBetweenDateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkStartDateBetweenDateFilter.php index e9526a9a5..947e6c57c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkStartDateBetweenDateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/AccompanyingPeriodWorkStartDateBetweenDateFilter.php @@ -32,17 +32,18 @@ final readonly class AccompanyingPeriodWorkStartDateBetweenDateFilter implements $builder ->add('start_date', PickRollingDateType::class, [ 'label' => 'export.filter.work.start_between_dates.start_date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('end_date', PickRollingDateType::class, [ 'label' => 'export.filter.work.start_between_dates.end_date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]) ->add('keep_null', CheckboxType::class, [ 'label' => 'export.filter.work.start_between_dates.keep_null', 'help' => 'export.filter.work.start_between_dates.keep_null_help', - ]) - ; + ]); + } + public function getFormDefaultData(): array + { + return ['start_date' => new RollingDate(RollingDate::T_TODAY), 'end_date' => new RollingDate(RollingDate::T_TODAY)]; } public function getTitle(): string diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php index cbdb64d8d..09551a3c5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/CurrentActionFilter.php @@ -37,14 +37,18 @@ class CurrentActionFilter implements FilterInterface { //no form } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { - return ['Filtered by current action']; + return ['Filtered actions without end date']; } public function getTitle(): string { - return 'Filter by current actions'; + return 'Filter actions without end date'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/JobFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/JobFilter.php index 144bf3260..265c8e24d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/JobFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/JobFilter.php @@ -76,6 +76,10 @@ class JobFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ReferrerFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ReferrerFilter.php index 8d0da32fb..bddcfbf9b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ReferrerFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ReferrerFilter.php @@ -57,6 +57,10 @@ class ReferrerFilter implements FilterInterface 'multiple' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string'): array { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ScopeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ScopeFilter.php index 315025722..737759c3e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ScopeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/ScopeFilter.php @@ -76,6 +76,10 @@ class ScopeFilter implements FilterInterface 'expanded' => true, ]); } + public function getFormDefaultData(): array + { + return []; + } public function describeAction($data, $format = 'string') { diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php index 11fd0ed9d..e97834319 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/SocialWorkFilters/SocialWorkTypeFilter.php @@ -111,6 +111,11 @@ class SocialWorkTypeFilter implements FilterInterface ); } + public function getFormDefaultData(): array + { + return ['action_type' => [], 'goal' => [], 'result' => []]; + } + public function describeAction($data, $format = 'string'): array { $actionTypes = []; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/chill/scss/accompanying_period_work.scss b/src/Bundle/ChillPersonBundle/Resources/public/chill/scss/accompanying_period_work.scss index a12f1554c..e82029a1f 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/chill/scss/accompanying_period_work.scss +++ b/src/Bundle/ChillPersonBundle/Resources/public/chill/scss/accompanying_period_work.scss @@ -1,3 +1,25 @@ +.badge-accompanying-work-type { + display: inline-block; + background-color: #f3f3f3; + + .title_label { + @include chill_badge(#e2793d); + } + + .title_action { + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + margin-right: 1rem; + + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + } +} + /// AccompanyingCourse Work Pages div.accompanying-course-work { diff --git a/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig new file mode 100644 index 000000000..ae54d077b --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig @@ -0,0 +1,76 @@ +{% import "@ChillDocStore/Macro/macro.html.twig" as m %} +{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %} +{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %} + +{% set w = document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork %} + +
        +
        +
        + {% if document.storedObject.isPending %} +
        {{ 'docgen.Doc generation is pending'|trans }}
        + {% elseif document.storedObject.isFailure %} +
        {{ 'docgen.Doc generation failed'|trans }}
        + {% endif %} +
        + {% if context == 'person' %} + + {{ w.accompanyingPeriod.id }} +   + {% endif %} +
        + + {{ w.socialAction|chill_entity_render_string }} > {{ document.accompanyingPeriodWorkEvaluation.evaluation.title|localize_translatable_string }} +
        +
        +
        + {{ document.title|chill_print_or_message("No title") }} +
        + {% if document.storedObject.type is not empty %} +
        + {{ mm.mimeIcon(document.storedObject.type) }} +
        + {% endif %} + {% if document.storedObject.hasTemplate %} +
        +

        {{ document.storedObject.template.name|localize_translatable_string }}

        +
        + {% endif %} +
        + +
        +
        +
        + {{ document.storedObject.createdAt|format_date('short') }} +
        +
        +
        +
        + +
        +
        + {{ mmm.createdBy(document) }} +
        +
          +
        • + {{ chill_entity_workflow_list('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument', document.id) }} +
        • + {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_EVALUATION_DOCUMENT_SHOW', document) %} +
        • + {{ document.storedObject|chill_document_button_group(document.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork)) }} +
        • + {% endif %} + {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE', w)%} +
        • + +
        • + {% endif %} + {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %} +
        • + +
        • + {% endif %} +
        + +
        +
        diff --git a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php new file mode 100644 index 000000000..f8b99a048 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php @@ -0,0 +1,165 @@ +entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWork::class); + $query = $this->buildBaseQuery(); + + $query->addWhereClause( + sprintf('action.%s = ?', $accompanyingPeriodWorkMetadata->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]['name']), + [$accompanyingPeriod->getId()], + [Types::INTEGER] + ); + + return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content); + } + + public function isAllowedForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool + { + return $this->security->isGranted(AccompanyingPeriodWorkVoter::SEE, $accompanyingPeriod); + } + + private function addWhereClausesToQuery(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery + { + $classMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument::class); + $storedObjectMetadata = $this->entityManager->getClassMetadata(StoredObject::class); + + if (null !== $startDate) { + $query->addWhereClause( + sprintf('doc_store.%s >= ?', $storedObjectMetadata->getColumnName('createdAt')), + [$startDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $endDate) { + $query->addWhereClause( + sprintf('doc_store.%s < ?', $storedObjectMetadata->getColumnName('createdAt')), + [$endDate], + [Types::DATE_IMMUTABLE] + ); + } + + if (null !== $content) { + $query->addWhereClause( + sprintf('apwed.%s ilike ?', $classMetadata->getColumnName('title')), + ['%' . $content . '%'], + [Types::STRING] + ); + } + + return $query; + } + + public function buildFetchQueryForPerson(Person $person, ?DateTimeImmutable $startDate = null, ?DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface + { + $storedObjectMetadata = $this->entityManager->getClassMetadata(StoredObject::class); + $accompanyingPeriodWorkMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWork::class); + $query = $this->buildBaseQuery(); + + // we loop over each accompanying period participation, to check of the user is allowed to see them + $or = []; + $orParams = []; + $orTypes = []; + foreach ($person->getAccompanyingPeriodParticipations() as $participation) { + if (!$this->security->isGranted(AccompanyingPeriodWorkVoter::SEE, $participation->getAccompanyingPeriod())) { + continue; + } + + $or[] = sprintf( + '(action.%s = ? AND apwed.%s BETWEEN ?::date AND COALESCE(?::date, \'infinity\'::date))', + $accompanyingPeriodWorkMetadata->getSingleAssociationJoinColumnName('accompanyingPeriod'), + $storedObjectMetadata->getColumnName('createdAt') + ); + $orParams = [...$orParams, $participation->getAccompanyingPeriod()->getId(), + DateTimeImmutable::createFromInterface($participation->getStartDate()), + null === $participation->getEndDate() ? null : DateTimeImmutable::createFromInterface($participation->getEndDate())]; + $orTypes = [...$orTypes, Types::INTEGER, Types::DATE_IMMUTABLE, Types::DATE_IMMUTABLE]; + } + + if ([] === $or) { + $query->addWhereClause('TRUE = FALSE'); + + return $query; + } + + $query->addWhereClause(sprintf('(%s)', implode(' OR ', $or)), $orParams, $orTypes); + + return $this->addWhereClausesToQuery($query, $startDate, $endDate, $content); + } + + public function isAllowedForPerson(Person $person): bool + { + // this will be filtered during query + return true; + } + + private function buildBaseQuery(): FetchQuery + { + $classMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument::class); + $storedObjectMetadata = $this->entityManager->getClassMetadata(StoredObject::class); + $evaluationMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWorkEvaluation::class); + $accompanyingPeriodWorkMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWork::class); + + $query = new FetchQuery( + self::KEY, + sprintf("jsonb_build_object('id', apwed.%s)", $classMetadata->getColumnName('id')), + sprintf('apwed.'.$storedObjectMetadata->getColumnName('createdAt')), + $classMetadata->getTableName().' AS apwed' + ); + $query->addJoinClause(sprintf( + 'JOIN %s doc_store ON doc_store.%s = apwed.%s', + $storedObjectMetadata->getSchemaName().'.'.$storedObjectMetadata->getTableName(), + $storedObjectMetadata->getColumnName('id'), + $classMetadata->getSingleAssociationJoinColumnName('storedObject') + )); + $query->addJoinClause(sprintf( + 'JOIN %s evaluation ON apwed.%s = evaluation.%s', + $evaluationMetadata->getTableName(), + $classMetadata->getAssociationMapping('accompanyingPeriodWorkEvaluation')['joinColumns'][0]['name'], + $evaluationMetadata->getColumnName('id') + )); + $query->addJoinClause(sprintf( + 'JOIN %s action ON evaluation.%s = action.%s', + $accompanyingPeriodWorkMetadata->getTableName(), + $evaluationMetadata->getAssociationMapping('accompanyingPeriodWork')['joinColumns'][0]['name'], + $accompanyingPeriodWorkMetadata->getColumnName('id') + )); + + return $query; + } +} diff --git a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php new file mode 100644 index 000000000..9810fe7a1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php @@ -0,0 +1,44 @@ +key === AccompanyingPeriodWorkEvaluationGenericDocProvider::KEY; + } + + public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string + { + return '@ChillPerson/GenericDoc/evaluation_document.html.twig'; + } + + public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array + { + return [ + 'document' => $this->accompanyingPeriodWorkEvaluationDocumentRepository->find($genericDocDTO->identifiers['id']), + 'context' => $genericDocDTO->getContext(), + ]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php index 0a9c22df1..bb7e2e80a 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php @@ -138,12 +138,14 @@ final class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $this->assertCount(1, $period->getLocationHistories()); $this->assertSame($address, $period->getLocationHistories()->first()->getAddressLocation()); + $this->assertNull($period->getLocationHistories()->first()->getPersonLocation()); $period->setPersonLocation($person); $period->setAddressLocation(null); $this->assertCount(2, $period->getLocationHistories()); $this->assertSame($person, $period->getLocationHistories()->last()->getPersonLocation()); + $this->assertNull($period->getLocationHistories()->last()->getAddressLocation()); $period->setAddressLocation($address); $period->setPersonLocation(null); @@ -172,6 +174,27 @@ final class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase } while ($iterator->valid()); } + + public function testHistoryLocationNotHavingBothAtStart() + { + $period = new AccompanyingPeriod(); + $person = new Person(); + $address = new Address(); + + $period->setAddressLocation($address); + $period->setPersonLocation($person); + + $period->setStep(AccompanyingPeriod::STEP_CONFIRMED); + + $this->assertCount(1, $period->getLocationHistories()); + + self::assertNull($period->getAddressLocation()); + self::assertNull($period->getLocationHistories()->first()->getAddressLocation()); + self::assertSame($person, $period->getLocationHistories()->first()->getPersonLocation()); + self::assertSame($person, $period->getPersonLocation()); + self::assertEquals('person', $period->getLocationStatus()); + } + public function testIsClosed() { $period = new AccompanyingPeriod(new DateTime()); diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php new file mode 100644 index 000000000..8aff23673 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php @@ -0,0 +1,134 @@ +security = self::$container->get(Security::class); + $this->entityManager = self::$container->get(EntityManagerInterface::class); + } + + /** + * @dataProvider provideDataForAccompanyingPeriod + */ + public function testBuildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $provider = new AccompanyingPeriodCalendarGenericDocProvider($this->security, $this->entityManager); + + $query = $provider->buildFetchQueryForAccompanyingPeriod($accompanyingPeriod, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb); + } + + /** + * @dataProvider provideDataForPerson + */ + public function testBuildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $security = $this->prophesize(Security::class); + $security->isGranted(CalendarVoter::SEE, Argument::any())->willReturn(true); + + $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager); + + $query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb); + self::assertStringNotContainsStringIgnoringCase('FALSE = TRUE', $sql); + self::assertStringNotContainsStringIgnoringCase('TRUE = FALSE', $sql); + } + + /** + * @dataProvider provideDataForPerson + */ + public function testBuildFetchQueryForPersonWithoutAnyRight(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $security = $this->prophesize(Security::class); + $security->isGranted(CalendarVoter::SEE, Argument::any())->willReturn(false); + + $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager); + + $query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb); + self::assertStringContainsStringIgnoringCase('TRUE = FALSE', $sql); + } + + public function provideDataForPerson(): iterable + { + $this->setUp(); + + if (null === $person = $this->entityManager->createQuery("SELECT p FROM " . Person::class . " p WHERE SIZE(p.accompanyingPeriodParticipations) > 0") + ->setMaxResults(1)->getSingleResult()) { + throw new \RuntimeException("There is no person"); + } + + yield [$person, null, null, null]; + yield [$person, new \DateTimeImmutable("1 year ago"), null, null]; + yield [$person, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), null]; + yield [$person, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), "text"]; + yield [$person, null, null, "text"]; + yield [$person, null, new \DateTimeImmutable("6 month ago"), null]; + } + + public function provideDataForAccompanyingPeriod(): iterable + { + $this->setUp(); + + if (null === $period = $this->entityManager->createQuery("SELECT p FROM " . AccompanyingPeriod::class . " p ") + ->setMaxResults(1)->getSingleResult()) { + throw new \RuntimeException("There is no accompanying period"); + } + + yield [$period, null, null, null]; + yield [$period, new \DateTimeImmutable("1 year ago"), null, null]; + yield [$period, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), null]; + yield [$period, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), "text"]; + yield [$period, null, null, "text"]; + yield [$period, null, new \DateTimeImmutable("6 month ago"), null]; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php new file mode 100644 index 000000000..c9ed96581 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php @@ -0,0 +1,79 @@ +entityManager = self::$container->get(EntityManagerInterface::class); + } + + /** + * @dataProvider provideSearchArguments + */ + public function testBuildFetchQueryForAccompanyingPeriod( + ?\DateTimeImmutable $startDate = null, + ?\DateTimeImmutable $endDate = null, + ?string $content = null + ): void { + $period = $this->entityManager->createQuery("SELECT a FROM " . AccompanyingPeriod::class . ' a') + ->setMaxResults(1) + ->getSingleResult(); + + if (null === $period) { + throw new \RuntimeException('no accompanying period in databasee'); + } + + $security = $this->prophesize(Security::class); + + $provider = new AccompanyingPeriodWorkEvaluationGenericDocProvider( + $security->reveal(), + $this->entityManager + ); + + $query = $provider->buildFetchQueryForAccompanyingPeriod($period, $startDate, $endDate, $content); + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->executeQuery( + 'SELECT COUNT(*) FROM ('.$sql.') AS sq', + $params, + $types + )->fetchOne(); + + self::assertIsInt($nb, "Test that there are no errors"); + } + + public function provideSearchArguments(): iterable + { + yield [null, null, null]; + yield [new \DateTimeImmutable('1 month ago'), null, null]; + yield [new \DateTimeImmutable('1 month ago'), new \DateTimeImmutable('now'), null]; + yield [null, null, 'test']; + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/PersonCalendarGenericDocProviderTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/PersonCalendarGenericDocProviderTest.php new file mode 100644 index 000000000..dbad052ca --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/PersonCalendarGenericDocProviderTest.php @@ -0,0 +1,70 @@ +security = self::$container->get(Security::class); + $this->entityManager = self::$container->get(EntityManagerInterface::class); + } + + /** + * @dataProvider provideDataForPerson + */ + public function testBuildFetchQueryForPerson(Person $person, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void + { + $provider = new PersonCalendarGenericDocProvider($this->security, $this->entityManager); + + $query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content); + + ['sql' => $sql, 'params' => $params, 'types' => $types] = (new FetchQueryToSqlBuilder())->toSql($query); + + $nb = $this->entityManager->getConnection()->fetchOne("SELECT COUNT(*) FROM ({$sql}) AS sq", $params, $types); + + self::assertIsInt($nb); + } + + public function provideDataForPerson(): iterable + { + $this->setUp(); + + if (null === $person = $this->entityManager->createQuery("SELECT p FROM " . Person::class . " p ") + ->setMaxResults(1)->getSingleResult()) { + throw new \RuntimeException("There is no person"); + } + + yield [$person, null, null, null]; + yield [$person, new \DateTimeImmutable("1 year ago"), null, null]; + yield [$person, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), null]; + yield [$person, new \DateTimeImmutable("1 year ago"), new \DateTimeImmutable("6 month ago"), "text"]; + yield [$person, null, null, "text"]; + yield [$person, null, new \DateTimeImmutable("6 month ago"), null]; + } +} diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20230627130331.php b/src/Bundle/ChillPersonBundle/migrations/Version20230627130331.php new file mode 100644 index 000000000..63f160997 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20230627130331.php @@ -0,0 +1,36 @@ +addSql('ALTER TABLE chill_person_accompanying_period_user_history + ADD CONSTRAINT acc_period_user_history_not_overlaps + EXCLUDE USING GIST (accompanyingperiod_id with =, tsrange(startdate, enddate) with &&) + DEFERRABLE INITIALLY DEFERRED'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_accompanying_period_user_history DROP CONSTRAINT acc_period_user_history_not_overlaps'); + } +} diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20230628152138.php b/src/Bundle/ChillPersonBundle/migrations/Version20230628152138.php new file mode 100644 index 000000000..240b99dbf --- /dev/null +++ b/src/Bundle/ChillPersonBundle/migrations/Version20230628152138.php @@ -0,0 +1,45 @@ +addSql('UPDATE chill_person_accompanying_period SET addresslocation_id = NULL + where personlocation_id IS NOT NULL AND addresslocation_id IS NOT NULL'); + $this->addSql('INSERT INTO chill_person_accompanying_period_location_history + (id, period_id, startdate, enddate, createdat, personlocation_id, addresslocation_id, createdby_id) + SELECT nextval(\'chill_person_accompanying_period_location_history_id_seq\'), period_id, startdate, startdate, now(), null, addresslocation_id, null + FROM chill_person_accompanying_period_location_history + WHERE personlocation_id IS NOT NULL AND addresslocation_id IS NOT NULL + '); + $this->addSql('UPDATE chill_person_accompanying_period_location_history SET addresslocation_id = NULL WHERE addresslocation_id IS NOT NULL AND personlocation_id IS NOT NULL'); + + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT location_check CHECK (personlocation_id IS NULL OR addresslocation_id IS NULL)'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_location_history ADD CONSTRAINT location_check CHECK (personlocation_id IS NULL OR addresslocation_id IS NULL)'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT location_check'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_location_history DROP CONSTRAINT location_check'); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index bdb93afc0..01383c050 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -555,22 +555,22 @@ is regular: le parcours est régulier Intensity: Intensité Group by intensity: Grouper les parcours par intensité -Filter by active on date: Filtrer les parcours actifs à une date -On date: Actifs à cette date -"Filtered by actives courses: active on %ondate%": "Filtrer les parcours actifs: actifs le %ondate%" +Filter by active on date: Filtrer les parcours ouverts à une date +On date: A l'état ouvert à cette date +"Filtered by actives courses: active on %ondate%": "Filtrer les parcours ouverts: actifs le %ondate%" -Filter by active at least one day between dates: Filtrer les parcours actifs au moins un jour dans la période -"Filtered by actives courses: at least one day between %datefrom% and %dateto%": "Filtrer les parcours actifs: au moins un jour entre le %datefrom% et le %dateto%" +Filter by active at least one day between dates: Filtrer les parcours ouverts au moins un jour dans la période +"Filtered by actives courses: at least one day between %datefrom% and %dateto%": "Filtrer les parcours ouverts: au moins un jour entre le %datefrom% et le %dateto%" Filter by referrers: Filtrer les parcours par référent Accepted referrers: Référents "Filtered by referrer: only %referrers%": "Filtré par référent: uniquement %referrers%" Group by referrers: Grouper les parcours par référent -Filter by opened between dates: Filtrer les parcours ouverts entre deux dates +Filter by opened between dates: Filtrer les parcours dont la date d'ouverture est comprise entre deux dates Date from: Date de début Date to: Date de fin -"Filtered by opening dates: between %datefrom% and %dateto%": "Filtrer les parcours ouverts entre deux dates: entre le %datefrom% et le %dateto%" +"Filtered by opening dates: between %datefrom% and %dateto%": "Filtrer les parcours dont la date d'ouverture est comprise entre le %datefrom% et le %dateto%" Filter by temporary location: Filtrer les parcours avec une localisation temporaire Filter by which has no referrer: Filtrer les parcours sans référent @@ -585,8 +585,8 @@ Filter by creator job: Filtrer les parcours par métier du créateur 'Filtered by creator job: only %jobs%': 'Filtré par métier du créateur: uniquement %jobs%' Group by creator job: Grouper les parcours par métier du créateur -Filter by current actions: Filtrer les actions en cours -Filtered by current action: 'Filtré: uniquement les actions en cours (sans date de fin)' +Filter actions without end date: Filtre les actions sans date de fin (ouvertes) +Filtered actions without end date: 'Filtré: uniquement les actions sans date de fin (ouvertes)' Filter by start date evaluations: Filtrer les évaluations par date de début Filter by end date evaluations: Filtrer les évaluations par date de fin start period date: Date de début de la période @@ -1137,7 +1137,7 @@ export: createdAt: Créé le updatedAt: Dernière mise à jour le acpOrigin: Origine du parcours - origin: Origine du parcourse + origin: Origine du parcours acpClosingMotive: Motif de fermeture acpJob: Métier du parcours createdBy: Créé par @@ -1236,3 +1236,8 @@ social_action: social_issue: and children: et dérivés + +generic_doc: + filter: + keys: + accompanying_period_work_evaluation_document: Document des actions d'accompagnement diff --git a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php index 9adae0097..9d99b7e62 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php @@ -94,7 +94,6 @@ class ReportList implements ExportElementValidatedInterface, ListInterface $cf->getSlug(); } - // Add a checkbox to select fields $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, @@ -134,14 +133,16 @@ class ReportList implements ExportElementValidatedInterface, ListInterface ])], ]); - // add a date field for addresses $builder->add('address_date', ChillDateType::class, [ 'label' => 'Address valid at this date', - 'data' => new DateTime(), 'required' => false, 'block_name' => 'list_export_form_address_date', ]); } + public function getFormDefaultData(): array + { + return ['address_date' => new DateTime()]; + } public function getAllowedFormattersTypes() { diff --git a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php index 79bad4f52..cb8e7d1d0 100644 --- a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php +++ b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php @@ -67,14 +67,16 @@ class ReportDateFilter implements FilterInterface { $builder->add('date_from', PickRollingDateType::class, [ 'label' => 'Report is after this date', - 'data' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), ]); $builder->add('date_to', PickRollingDateType::class, [ 'label' => 'Report is before this date', - 'data' => new RollingDate(RollingDate::T_TODAY), ]); } + public function getFormDefaultData(): array + { + return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)]; + } public function describeAction($data, $format = 'string') { diff --git a/utils/rector/src/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector.php b/utils/rector/src/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector.php new file mode 100644 index 000000000..4718aedac --- /dev/null +++ b/utils/rector/src/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector.php @@ -0,0 +1,273 @@ +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + 'data' => new RollingDate(RollingDate::T_TODAY) + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + 'data' => 'Castor' + ]); + } +} +PHP, +<<add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + 'data' => new RollingDate(RollingDate::T_TODAY) + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + 'data' => 'Castor' + ]); + } + public function getFormDefaultData(): array + { + return ['foo' => new RollingDate(RollingDate::T_TODAY), 'baz' => 'Castor']; + } +} +PHP */ + ] + ); + } + + public function getNodeTypes(): array + { + return [Node\Stmt\Class_::class]; + } + + public function refactor(Node $node): ?Node + { + if (!$node instanceof Node\Stmt\Class_) { + return null; + } + + if ( + !$this->classAnalyzer->hasImplements($node, FilterInterface::class) + && !$this->classAnalyzer->hasImplements($node, AggregatorInterface::class) + && !$this->classAnalyzer->hasImplements($node, ExportInterface::class) + && !$this->classAnalyzer->hasImplements($node, DirectExportInterface::class) + && !$this->classAnalyzer->hasImplements($node, ListInterface::class) + ) { + return null; + } + + $buildFormStmtIndex = null; + $hasGetFormDefaultDataMethod = false; + foreach ($node->stmts as $k => $stmt) { + if (!$stmt instanceof Node\Stmt\ClassMethod) { + continue; + } + + if ('buildForm' === $stmt->name->name) { + $buildFormStmtIndex = $k; + } + + if ('getFormDefaultData' === $stmt->name->name) { + $hasGetFormDefaultDataMethod = true; + } + } + + if ($hasGetFormDefaultDataMethod || null === $buildFormStmtIndex) { + return null; + } + + $stmtBefore = array_slice($node->stmts, 0, $buildFormStmtIndex, false); + $stmtAfter = array_slice($node->stmts, $buildFormStmtIndex + 1); + + // lines to satisfay phpstan parser + if (!$node->stmts[$buildFormStmtIndex] instanceof Node\Stmt\ClassMethod) { + throw new \LogicException(); + } + + ['build_form_method' => $buildFormMethod, 'empty_to_replace' => $emptyToReplace] + = $this->filterBuildFormMethod($node->stmts[$buildFormStmtIndex], $node); + + $node->stmts = [ + ...$stmtBefore, + $buildFormMethod, + $this->makeGetFormDefaultData($node->stmts[$buildFormStmtIndex], $emptyToReplace), + ...$stmtAfter, + ]; + + return $node; + } + + private function makeGetFormDefaultData(Node\Stmt\ClassMethod $buildFormMethod, array $emptyToReplace): Node\Stmt\ClassMethod + { + $method = new Node\Stmt\ClassMethod('getFormDefaultData'); + $method->flags = Node\Stmt\Class_::MODIFIER_PUBLIC; + $method->returnType = new Node\Identifier('array'); + + $data = new Node\Expr\Array_([]); + + foreach ($emptyToReplace as $key => $value) { + $item = new Node\Expr\ArrayItem($value, new Node\Scalar\String_($key)); + $data->items[] = $item; + } + + $method->stmts[] = new Node\Stmt\Return_($data); + + return $method; + } + + /** + * @param Node\Stmt\ClassMethod $buildFormMethod + * @return array{"build_form_method": Node\Stmt\ClassMethod, "empty_to_replace": array} + */ + private function filterBuildFormMethod(Node\Stmt\ClassMethod $buildFormMethod, Node\Stmt\Class_ $node): array + { + $builderName = $buildFormMethod->params[0]->var->name; + + $newStmts = []; + $emptyDataToReplace = []; + + foreach ($buildFormMethod->stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Expression + // it must be a method call + && $stmt->expr instanceof Node\Expr\MethodCall + && false !== ($results = $this->handleMethodCallBuilderAdd($stmt->expr, $builderName, $node)) + ) { + ['stmt' => $newMethodCAll, 'emptyDataToReplace' => $newEmptyDataToReplace] = $results; + $newStmts[] = new Node\Stmt\Expression($newMethodCAll); + $emptyDataToReplace = [...$emptyDataToReplace, ...$newEmptyDataToReplace]; + } else { + $newStmts[] = $stmt; + } + } + + $buildFormMethod->stmts = $newStmts; + + return ['build_form_method' => $buildFormMethod, "empty_to_replace" => $emptyDataToReplace]; + } + + private function handleMethodCallBuilderAdd(Node\Expr\MethodCall $methodCall, string $builderName, Node\Stmt\Class_ $node): array|false + { + $emptyDataToReplace = []; + // check for chained method call + if ( + // this means that the MethodCall apply on another method call: a chained + $methodCall->var instanceof Node\Expr\MethodCall + ) { + // as this is chained, we make a recursion on this method + + $resultFormDeepMethodCall = $this->handleMethodCallBuilderAdd($methodCall->var, $builderName, $node); + + if (false === $resultFormDeepMethodCall) { + return false; + } + + ['stmt' => $chainedMethodCall, 'emptyDataToReplace' => $newEmptyDataToReplace] = $resultFormDeepMethodCall; + $emptyDataToReplace = $newEmptyDataToReplace; + $methodCall->var = $chainedMethodCall; + } + + if ( + $methodCall->var instanceof Node\Expr\Variable + ) { + if ($methodCall->var->name !== $builderName) { + // ho, this does not apply on a builder, so we cancel all the method calls + return false; + } + } + + if ($methodCall->name instanceof Node\Identifier && $methodCall->name->name !== 'add') { + return ['stmt' => $methodCall, 'emptyDataToReplace' => $emptyDataToReplace]; + } + + if ( + // the method call must be "add" + $methodCall->name instanceof Node\Identifier + && $methodCall->name->name === 'add' + // it must have a first argument, a string + // TODO what happens if a value, or a const ? + && ($methodCall->args[0] ?? null) instanceof Node\Arg + && $methodCall->args[0]->value instanceof Node\Scalar\String_ + // and a third argument, an array + && ($methodCall->args[2] ?? null) instanceof Node\Arg + && $methodCall->args[2]->value instanceof Node\Expr\Array_ + ) { + // we parse on the 3rd argument, to find if there is an 'empty_data' key + $emptyDataIndex = null; + foreach ($methodCall->args[2]->value->items as $arrayItemIndex => $item) { + /* @phpstan-ignore-next-line */ + if ($item->key->value === 'data' or $item->key->value === 'empty_data') { + $k = $methodCall->args[0]->value->value; + $emptyDataToReplace[$k] = $item->value; + $emptyDataIndex = $arrayItemIndex; + } + } + + if (null !== $emptyDataIndex) { + $methodCall->args[2]->value->items = array_values( + array_filter( + $methodCall->args[2]->value->items, + /* @phpstan-ignore-next-line */ + fn (Node\Expr\ArrayItem $item) => $item->key->value !== 'data' + ) + ); + } + + return ['stmt' => $methodCall, 'emptyDataToReplace' => $emptyDataToReplace]; + } + + return ['stmt' => $methodCall, 'emptyDataToReplace' => $emptyDataToReplace]; + } +} diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRectorTest.php b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRectorTest.php new file mode 100644 index 000000000..89606e970 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRectorTest.php @@ -0,0 +1,40 @@ +doTestFile($file); + } + + public function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__.'/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__.'/config/config.php'; + } +} diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/aggregator-with-no-method-get-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/aggregator-with-no-method-get-form-default-data.php.inc new file mode 100644 index 000000000..aa373e629 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/aggregator-with-no-method-get-form-default-data.php.inc @@ -0,0 +1,133 @@ + +----- + diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/direct-export-with-no-method-get-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/direct-export-with-no-method-get-form-default-data.php.inc new file mode 100644 index 000000000..d60f62dcb --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/direct-export-with-no-method-get-form-default-data.php.inc @@ -0,0 +1,77 @@ + +----- + diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/export-with-no-method-get-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/export-with-no-method-get-form-default-data.php.inc new file mode 100644 index 000000000..ba5a6d4ec --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/export-with-no-method-get-form-default-data.php.inc @@ -0,0 +1,95 @@ + +----- + diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data-with-chained-builder.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data-with-chained-builder.php.inc new file mode 100644 index 000000000..ed46f6381 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data-with-chained-builder.php.inc @@ -0,0 +1,111 @@ +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + 'data' => new RollingDate(RollingDate::T_TODAY) + ]) + ->anotherCall('test') + ->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + 'data' => 'Castor' + ]) + ->baz('foo'); + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> +----- +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing' + ]) + ->anotherCall('test') + ->add('baz', TextType::class, [ + 'label' => 'OrNiCar' + ]) + ->baz('foo'); + } + public function getFormDefaultData(): array + { + return ['foo' => new RollingDate(RollingDate::T_TODAY), 'baz' => 'Castor']; + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data.php.inc new file mode 100644 index 000000000..5429d3c82 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-multiple-reuse-data-on-form-default-data.php.inc @@ -0,0 +1,107 @@ +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + 'data' => new RollingDate(RollingDate::T_TODAY) + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + 'data' => 'Castor' + ]); + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> +----- +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing' + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar' + ]); + } + public function getFormDefaultData(): array + { + return ['foo' => new RollingDate(RollingDate::T_TODAY), 'baz' => 'Castor']; + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-no-data-on-builder.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-no-data-on-builder.php.inc new file mode 100644 index 000000000..285c16b50 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-no-data-on-builder.php.inc @@ -0,0 +1,105 @@ +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + ]); + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> +----- +add('foo', PickRollingDateType::class, [ + 'label' => 'Test thing', + ]); + + $builder->add('baz', TextType::class, [ + 'label' => 'OrNiCar', + ]); + } + public function getFormDefaultData(): array + { + return []; + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-reuse-data-on-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-reuse-data-on-form-default-data.php.inc new file mode 100644 index 000000000..b2e78e49c --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-reuse-data-on-form-default-data.php.inc @@ -0,0 +1,96 @@ +add('test', PickRollingDateType::class, [ + 'label' => 'Test thing', + 'data' => new RollingDate(RollingDate::T_TODAY) + ]); + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> +----- +add('test', PickRollingDateType::class, [ + 'label' => 'Test thing' + ]); + } + public function getFormDefaultData(): array + { + return ['test' => new RollingDate(RollingDate::T_TODAY)]; + } + + public function getTitle() + { + // TODO: Implement getTitle() method. + } + + public function addRole(): ?string + { + // TODO: Implement addRole() method. + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // TODO: Implement alterQuery() method. + } + + public function applyOn() + { + // TODO: Implement applyOn() method. + } +} +?> diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-with-no-method-get-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-with-no-method-get-form-default-data.php.inc new file mode 100644 index 000000000..687bd9d0c --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/filter-with-no-method-get-form-default-data.php.inc @@ -0,0 +1,87 @@ + +----- + diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/list-with-no-method-get-form-default-data.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/list-with-no-method-get-form-default-data.php.inc new file mode 100644 index 000000000..99cea7155 --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/list-with-no-method-get-form-default-data.php.inc @@ -0,0 +1,135 @@ + +----- + diff --git a/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/skip-filter-existing-get-form-default-data-method.php.inc b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/skip-filter-existing-get-form-default-data-method.php.inc new file mode 100644 index 000000000..2fefc908d --- /dev/null +++ b/utils/rector/tests/Rector/ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector/Fixture/skip-filter-existing-get-form-default-data-method.php.inc @@ -0,0 +1,46 @@ +rule(\Chill\Utils\Rector\Rector\ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector::class); +};