Compare commits

...

335 Commits

Author SHA1 Message Date
2927561c02 added changie 2023-10-26 15:22:22 +02:00
5188891108 php style fixer 2023-10-26 15:21:20 +02:00
c6deb21606 replace old method of getting translator with injection of translatorInterface 2023-10-26 15:20:19 +02:00
cdfb084fe4 update changelog 2023-10-26 14:17:15 +02:00
5ce21aadce Merge branch 'master' of gitlab.com:Chill-Projet/chill-bundles 2023-10-26 14:14:51 +02:00
b9000a38d3 add changie 2023-10-26 14:14:36 +02:00
89a185a34f replace get->('translator') with injection of translatorInterface 2023-10-26 14:13:12 +02:00
bc6c3a1089 Release: 2.10.1 2023-10-24 20:52:46 +02:00
2c50f484f0 Fix export controller when generating an export without any data in session 2023-10-24 20:46:23 +02:00
4bc1de01d6 Release: version 2.10.0: fix typos and French translation 2023-10-24 18:56:42 +02:00
e21fe70b75 Release: version 2.10.0 2023-10-24 15:50:47 +02:00
461995b56b Merge branch '172-missing-exports' into 'master'
Fix some issues with exports

Closes #172

See merge request Chill-Projet/chill-bundles!601
2023-10-24 13:47:30 +00:00
e635b73256 DX: mark a class as final 2023-10-24 15:39:57 +02:00
54ae17a8d2 Fix label on some filters 2023-10-24 15:39:57 +02:00
617d09ab8a Merge branch '179-remove-filter-by-center-in-exports' into 'master'
Resolve "Export: permettre de ne pas filtrer les résultats par centre"

Closes #179

See merge request Chill-Projet/chill-bundles!599
2023-10-24 13:18:03 +00:00
f8ee2903b2 Merge branch '172-missing-exports' into 'master'
[Export]: add missing grouping and filters and fix some issues

Closes #177 and #172

See merge request Chill-Projet/chill-bundles!598
2023-10-24 13:17:03 +00:00
36b0844e79 Fix issue with duration aggregator as month 2023-10-24 14:17:28 +02:00
7bff5ce39e DX: rename UserScopeFilter to CreatorScopeFilter 2023-10-24 14:17:08 +02:00
2a151d13ed Add querybuilder method to person resource repository 2023-10-23 14:22:51 +02:00
4375ecf49a [export controller] skip the page "select a center" when the configuration value of filter_stats_by_center is set to false 2023-10-19 17:43:32 +02:00
a6e930958b [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export 2023-10-19 17:19:28 +02:00
5f805626f7 [export] sort filters and aggregators by title 2023-10-19 14:39:22 +02:00
4c9ea740c8 [export] fix date range selection on filtre and grouping "by status of the course at date" on accompanying periods 2023-10-19 11:44:53 +02:00
981dc6a959 [export] add a filter and aggregator on accompanying periods: group by activity type (accompanying course having at least one activity from this type) 2023-10-19 10:33:56 +02:00
11fb9bcd0b [export] add a filter and aggregator on activities: filter/group by persons taking part to the activity 2023-10-19 10:33:55 +02:00
a4edb34668 [export] add a filter and aggregator on accompanying period work: group/filter by handling third party 2023-10-19 10:33:55 +02:00
f799fe0649 [export] add a grouping of accompanying period by opening and closing date 2023-10-19 10:33:54 +02:00
c7bd60a106 release for 2.9.2 2023-10-17 23:15:56 +02:00
9ec5a633ad Fix possible null values or not null values in some entity / string properties 2023-10-17 23:15:06 +02:00
d54d34be7c release of version 2.9.1 2023-10-17 17:39:30 +02:00
01292ba9ae more info about possible BC break in changelog [ci-skip] 2023-10-17 16:25:15 +02:00
794daa5c3e fix changelog [ci-skip] 2023-10-17 16:17:38 +02:00
37265c09f7 release of version 2.9.0 2023-10-17 16:05:27 +02:00
98cd0f3c00 Merge branch 'rector/rules-symfony' into 'master'
Rector: apply symfony rules "up to symfony 4.4"

See merge request Chill-Projet/chill-bundles!536
2023-10-17 11:34:12 +00:00
bc2041cbdd apply more cs rules for php-cs 2023-10-17 13:27:03 +02:00
0b0cbed9db DX: mark const as final 2023-10-17 10:43:13 +02:00
c9cfe4c7e9 DX: mark some functions as pure 2023-10-17 10:43:12 +02:00
75e15c1389 Fix ClosingMotiveRender: rendering of label 'canceled' at the end of child, and remove trailing spaces 2023-10-17 10:43:12 +02:00
48e0a0af7d DX: Increase the number of iteration to ensure that the test really pass on random executions 2023-10-17 10:27:33 +02:00
adf1110340 Merge remote-tracking branch 'origin/master' into rector/rules-symfony 2023-10-17 09:29:33 +02:00
a6fcdb5256 Merge remote-tracking branch 'origin/rector/rules-symfony' into rector/rules-symfony 2023-10-16 18:07:42 +02:00
6b8d6b76ba Upgrade code from 146 to new standards 2023-10-16 18:04:40 +02:00
bbf9c58fbf Merge branch '147-history-user-scope-job' into 'rector/rules-symfony'
Ajout de l'historique des services et métiers aux utilisateurs

See merge request Chill-Projet/chill-bundles!591
2023-10-16 16:01:57 +00:00
0c8ecfe493 Merge branch 'rector/rules-symfony' into '147-history-user-scope-job'
# Conflicts:
#   src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php
2023-10-16 16:00:40 +00:00
8523f14214 Fix closing motive render 2023-10-16 17:58:22 +02:00
b32fa42afa DX: fix test on AccompanyingCourseExportHelperTest.php 2023-10-16 17:52:25 +02:00
be8975ee04 Merge branch '146_parcours_annules' into rector/rules-symfony 2023-10-16 17:52:06 +02:00
05865521b5 Merge branch '147-history-on-acp-work' into '147-history-user-scope-job'
Finalisation de l'historique des métiers et services des utilisateurs: adaptation pour les actions d'accompagnement

See merge request Chill-Projet/chill-bundles!597
2023-10-16 15:39:25 +00:00
dd47ddc268 DX: Fix user repository test 2023-10-16 17:26:15 +02:00
0df93fb703 DX: Fix test for PersonMoveTest.php 2023-10-16 17:19:28 +02:00
c62495a280 Fix export of all users and mapping of columns in user csv export (admin zone) 2023-10-16 16:20:25 +02:00
93b189b091 DX: Fix HouseholdApiControllerTest.php 2023-10-16 16:20:25 +02:00
304bf4258b Remove usage of setParameters in various filters 2023-10-16 16:20:25 +02:00
efcb903d10 Fix direct kernel deprecation in AccompanyingCourseApiControllerTest 2023-10-16 16:20:24 +02:00
b65f76262a Refactor filters and aggregators of "acpwusers" for using the acpw referrer history instead 2023-10-16 16:20:24 +02:00
51a4ffca2e Fix cs with new cs rules (php-cs-fixer version 3.35) 2023-10-16 11:59:49 +02:00
68d28f3e28 Fix filtres and scopes to take into account job and scope when the refferrer is add to the accompanying period work 2023-10-16 11:52:03 +02:00
63e9d1a96f [export] add a filter and aggregator on activity: by creator job 2023-10-16 11:52:03 +02:00
21524f052e Create a custom dql function to build json object (JSON_BUILD_OBJECT) 2023-10-16 11:52:02 +02:00
978db5a5c5 update some queries in the interface to take into account history of user's scope and user's job 2023-10-16 11:52:02 +02:00
363785b779 Update schema to store accompanying period work referrer history 2023-10-11 15:37:44 +02:00
4e13b2ae3a fix type-hints 2023-10-05 11:17:42 +02:00
f0b3e3af14 merge changelog for 2.8.0 2023-10-05 09:48:11 +02:00
dbc19ca692 update to 2.8.0 2023-10-05 09:42:42 +02:00
239372270e Update schema to store accompanying period work referrer history 2023-10-05 09:33:23 +02:00
ada28265ee change join to leftjoin 2023-10-04 14:26:06 +02:00
0b6b25fd95 improve histories order since User entity 2023-10-04 12:49:30 +02:00
c526973475 [admin][templates] move job/scope history in an unique template and display history for a given user 2023-10-04 12:33:50 +02:00
9bbddd8405 add changie 2023-10-04 12:09:12 +02:00
935210aa1d use translation 2023-10-04 11:54:29 +02:00
58e189ee07 Improve type declaration 2023-10-04 11:21:39 +02:00
9f476dddaf php cs fixer 2023-10-04 11:20:20 +02:00
dac48ea4e0 last processing of review remarks 2023-10-04 11:19:39 +02:00
af4bee4d50 correct test 2023-10-04 10:43:37 +02:00
b4e5618e00 fix phpunit tests errors 2023-10-04 10:06:46 +02:00
15e23087ed cs-fixer, phpstan et rector 2023-10-04 09:45:15 +02:00
e3559774fd Improve the signature definition 2023-10-03 21:25:22 +02:00
d6a1044585 just mark other uses with mainScope and userJob !! 2023-10-03 19:43:18 +02:00
c6a06ebaf9 [export] fix 6 job/scope agg/filters in acp (queries with 2 history) 2023-10-03 19:43:18 +02:00
c00c26c3e5 [export] fix 2 job/scope 'WorkingOnCourse' filters in acp 2023-10-03 19:43:18 +02:00
fa3fc2c781 [export] fix activity filters/aggregators + tests: 'at' based on activity date 2023-10-03 19:43:16 +02:00
6e48d036d7 [export] fix aside activity filters/aggregators: 'at' based on aside date 2023-10-03 19:42:06 +02:00
31fc7fffe9 [export] fix calendar filters/aggregators + tests: 'at' based on calendar date 2023-10-03 19:42:06 +02:00
84ba626fb5 add missing form child in getFormDefaultData() + sort methods
try to resolve 2 last unit tests errors on ci (no errors in local)
2023-10-03 19:42:06 +02:00
eddcfc3921 cs-fixer 2023-10-03 19:42:06 +02:00
f025b0d184 [export] fix 4 job/scope filters in activity and acp 2023-10-03 19:42:03 +02:00
8c44e92079 [export] fix 2 job/scope filters aside activity 2023-10-03 19:40:23 +02:00
1973a4b849 [export] fix 2 job/scope aggregators in acp 2023-10-03 19:40:23 +02:00
bea21d45fc [export] fix 2 job/scope aggregators in activity and acp 2023-10-03 19:40:23 +02:00
3aa10927d7 [export] fix 4 job/scope aggregators in activity and aside activity 2023-10-03 19:40:23 +02:00
4460db1dc4 Fix syntax error 2023-10-03 19:40:23 +02:00
e4cf07c7b3 rector fix error 2023-10-03 19:40:23 +02:00
2100d45671 fix phpstan error 2023-10-03 19:40:23 +02:00
aeb0d5eab8 [export] fix acpw socialWork agent ScopeFilter query + unit test (partial) 2023-10-03 19:40:23 +02:00
bc69f83c37 [export] fix acpw socialWork agent JobFilter query + unit test (partial) 2023-10-03 19:40:23 +02:00
9b272e9b9e [export] fix acp user Scope Filter query + unit test (partial) 2023-10-03 19:40:23 +02:00
f225a83a3e [export] fix acp userJob Filter query + unit test (partial) 2023-10-03 19:40:23 +02:00
e738bf0f5e [export] fix translations in message yaml tree 2023-10-03 19:40:23 +02:00
0953faedc4 [export] fix acpw socialWork agent ScopeAggregator query + unit test 2023-10-03 19:40:23 +02:00
7c25ca8dd4 [export] fix acpw socialWork agent JobAggregator query + unit test 2023-10-03 19:40:23 +02:00
8b7600e09f [export] fix acp UserJobAggregator query + unit test 2023-10-03 19:40:23 +02:00
9db0011b2e [export] fix acp ReferrerScopeAggregator query + unit test
TO CHECK: logic in alterQuery. calc_date is same for 2 histories ?
2023-10-03 19:40:23 +02:00
3f4a42adb2 [export] fix calendar scope/job Filters query + unit test (partial) 2023-10-03 19:40:23 +02:00
f18ee2383c [export] fix calendar scopeAggregator query + unit test 2023-10-03 19:40:23 +02:00
28583f4193 [export] fix calendar jobAggregator query + unit test 2023-10-03 19:40:23 +02:00
c5b153e6ed fix missing queries in job/scope history migration: remove mainscope_id and userjob_id from user table 2023-10-03 19:40:23 +02:00
2d4d1eda50 cs-fixer 2023-10-03 19:40:23 +02:00
baeccf0970 fix Entity/UserTest and phpstan error 2023-10-03 19:40:23 +02:00
6665a443b9 phpstan, rector, cs-fixer 2023-10-03 19:40:23 +02:00
fc919e9547 add tests for MainScope and UserJob getters/setters 2023-10-03 19:40:23 +02:00
949c5424f0 improve check in setters and add types in repositories 2023-10-03 19:40:23 +02:00
e6e42777d7 add new changie 2023-10-03 19:40:23 +02:00
c590d60a7f make tables more readable in templates 2023-10-03 19:40:23 +02:00
6228cc5ede fix errors in user getter/setters for mainScope and userJob 2023-10-03 19:40:23 +02:00
024790128a adjust history order 2023-10-03 19:40:23 +02:00
d2feb0f0b4 Fix return type in user getters for mainScope and userJob 2023-10-03 19:40:23 +02:00
8a6f29ef79 add crud controller to user job/scope history 2023-10-03 19:40:23 +02:00
124abf563e Create twig templates for admin jobs/scopes histories 2023-10-03 19:40:20 +02:00
096fb6219f adapt User Entity to get/set MainScope and UserJob with Histories Collection 2023-10-03 19:35:44 +02:00
bebc746d57 migration for UserScopeHistory and UserJobHistory 2023-10-03 19:35:44 +02:00
d47e6c5ba1 add new entities UserScopeHistory and UserJobHistory 2023-10-03 19:35:44 +02:00
cffad6219f Update CONTRIBUTING.md 2023-10-03 07:52:45 +00:00
ef8ac6041a Fix deprecation of transchoice 2023-10-02 17:46:19 +02:00
41f4bbfdce remove container aware interface from timeline builder 2023-10-02 15:03:05 +02:00
6a37079ee5 update config for tasks workflow to symfony 4.4+ 2023-10-02 15:02:52 +02:00
2d7bc06539 Fix CS 2023-10-02 15:02:15 +02:00
bad302f512 Update template pathes to new syntax 2023-10-02 13:56:22 +02:00
294aaf5bed Replace the CenterControllerTest by a smoke test
Since that the center's admin has been replaced by a CRUD Controller, we have to adapt the test accordingly.
2023-10-02 12:52:40 +02:00
d2864605b9 Fix path to templates using the new syntax 2023-10-02 12:38:18 +02:00
2efd5ebc9a Merge branch 'master' into rector/rules-symfony 2023-10-02 12:30:15 +02:00
a625260c36 Merge branch '162-change-job-on-course-when-reassigning-user' into 'master'
Reassign list: when reassigning course, the job associated to the period...

Closes #162

See merge request Chill-Projet/chill-bundles!596
2023-10-02 10:24:55 +00:00
28006374fb Merge branch '143-doublon-list-acp' into 'master'
SocialActionFilter: use a subquery "exists" instead of a where clause (many-to-many association).

Closes #143

See merge request Chill-Projet/chill-bundles!590
2023-10-02 10:24:39 +00:00
b35838f840 Merge branch '163-re-associate-person-filters' into 'master'
[exports] fix the association between aggregators and filter and the export "count persons"

Closes #138 and #163

See merge request Chill-Projet/chill-bundles!595
2023-10-02 10:24:23 +00:00
e08ab0666f Add a constraint to avoid doublons in table chill_person_accompanying_period_location_history
#143
2023-10-02 12:20:15 +02:00
217232fe4f SocialActionFilter: use a subquery "exists" instead of a where clause (many-to-many association) 2023-10-02 12:14:36 +02:00
b0a7612329 make test easier to read 2023-09-29 08:51:14 +02:00
0c5b35926b php cs fixer and phpstan 2023-09-29 07:52:50 +02:00
b38f5800d9 Adapt calendar exports to not take into account calendars of canceled accompanying periods 2023-09-29 07:48:54 +02:00
8dce0473ff Fix signature for OneToOne CRUD Controller 2023-09-28 15:24:07 +02:00
e5a449118e Reassign list: when reassigning course, the job associated to the period becomes the job of the new referrer (user)
https://gitlab.com/Chill-Projet/chill-bundles/-/issues/162
2023-09-28 14:56:53 +02:00
9c436d5c69 Re-associate filters for export "count persons" 2023-09-28 14:32:58 +02:00
981be7b363 SocialWorkRepository: on search by accompanying period, enlarge the dateranges for take into account work with same endDate / startDate
Close https://gitlab.com/Chill-Projet/chill-bundles/-/issues/144
2023-09-28 12:36:33 +02:00
74e25e706e [ThirdParty] Fix display of civility in page "view"
https://gitlab.com/Chill-Projet/chill-bundles/-/issues/164
2023-09-28 12:12:17 +02:00
5562f418a5 Release of chill 2.7.0 (2) 2023-09-27 17:09:22 +02:00
05a8dba912 update cs using php-cs-fixer 3.30 2023-09-27 16:55:01 +02:00
27c1bb03ff update cs 2023-09-27 16:45:42 +02:00
2e5954f6fd fix phpstan issues with never-writter id properties 2023-09-27 16:21:37 +02:00
7eec366292 Release of chill 2.7.0 2023-09-27 16:16:14 +02:00
5f8b86b839 apply rector rules after merging master branch 2023-09-27 16:01:59 +02:00
65aa0a1588 Merge remote-tracking branch 'origin/master' into rector/rules-symfony 2023-09-27 15:25:29 +02:00
48b3ed0a1f Merge branch '155-fix-regulation-list-postal-code-search' into 'master'
Feature: in regulation list, search by postal code instead of postal code's string content

Closes #155

See merge request Chill-Projet/chill-bundles!594
2023-09-26 16:03:30 +00:00
df3781a993 Regulation list: serach by exact postal code, and not the postal code's string content 2023-09-26 18:00:59 +02:00
5dde58e175 Merge branch '140-re-associate-modifier-export-activities' into 'master'
Fix loading and association of some filters

Closes #142 and #140

See merge request Chill-Projet/chill-bundles!589
2023-09-26 15:59:42 +00:00
d10dc7344e Fix label of ActivityTypeFilter 2023-09-26 17:59:05 +02:00
4e27d71bea Re-associate activity exports and filters
Some filter can work on both exports and lists associated to persons and accompanyings periods. They are moved to a more common namespace.

The modifiers in list are also fixed to allow an association with these filters.
2023-09-26 17:59:04 +02:00
fcc00fdf8f Remove dump messages 2023-09-26 17:28:14 +02:00
044aac0a56 trust symfony/runtime to execute extensions 2023-09-26 17:24:22 +02:00
9e017b0d66 Export: fix filter household by composition 2023-09-26 17:24:22 +02:00
d8b0e0671a ScopeResolverDispatcher: better type hinting 2023-09-26 16:59:09 +02:00
29983cc2ad Work on test, but still fails 2023-09-21 16:18:51 +02:00
260a173a61 Add test for accompanyingPeriodExportHelper: closing motive exclusion 2023-09-21 15:21:14 +02:00
500b37601a implement new export service for accompanyingcourse exports 2023-09-21 14:15:44 +02:00
5d41b37620 create helper service to exclude accompanying periods from export result based on closing motive 2023-09-21 13:06:19 +02:00
c2c14be9d7 Remove setId methods 2023-09-21 09:57:14 +02:00
b7119a2733 add changelog 2023-09-19 09:47:33 +02:00
eca26a15e6 Bugfix document mappedsuperclass should not contain id property 2023-09-19 09:42:46 +02:00
05e86a3360 adjust rendering of closing motive: indicate if isCanceledAccompanyingPeriod 2023-09-18 15:17:26 +02:00
9b061eeaae handle children of closing motive for isCanceledAccompanyingPeriod 2023-09-18 15:16:59 +02:00
3816d68e18 add isCanceledAccompanyingPeriod field to form 2023-09-18 15:16:26 +02:00
7db7f34f62 Adjust closing motive form 2023-09-18 14:36:56 +02:00
6b958d193d add property to closing motive to identify motives related to erroneous accompanying periods 2023-09-18 14:36:28 +02:00
f609bb0645 update changelog 2023-09-18 11:54:12 +02:00
bdee637c9f phpstan 2023-09-18 11:49:33 +02:00
722026b768 changie added bugfix singletaskplaceevent 2023-09-18 10:48:53 +02:00
8ed899a9c4 fix bug in abstract/singletaskplaceevent due to doctrine update 2023-09-18 10:47:10 +02:00
da3c6f2dd1 php cs fix 2023-09-14 17:17:36 +02:00
c72af4d7db update changelog 2023-09-14 17:14:46 +02:00
370c9c6d74 only display active centers in center form for exports 2023-09-14 17:01:58 +02:00
1070d33670 Sync the database view when initializing unit test script 2023-09-13 12:36:33 +02:00
b93a822299 Force again the kernel to shutdown before creating the client 2023-09-13 11:45:01 +02:00
fc7cfb1760 Ensure kernel shutdown between each test on AsideActivityControllerTest.php 2023-09-13 10:29:12 +02:00
76f1814848 More identation on some method parameters 2023-09-13 10:12:04 +02:00
cd9611a669 Remove unused dependency on DefaultVoter (+ fix when throwing an exception) 2023-09-13 10:12:04 +02:00
d3b68f8f8f AuthorizationHelper: compare center and scope based on id, not on equality
For an unknown reason, in some circumstances, the use of the `===` comparator does not work when comparing Center instances and Scope instances. Then, we compare them based on the id.
2023-09-13 10:08:44 +02:00
2ce29f36ff avoid creating client on already booted kernel 2023-09-12 16:19:06 +02:00
d2323e91ca new cs rule: single_line_empty_body
Rule is added to the last version of php-cs-fixer
2023-09-12 15:58:59 +02:00
b9231a91a3 Fix CountryOfBirthAggregator: allow to receive null data in getLabels method 2023-09-12 15:54:12 +02:00
b36e37d9c5 Fix CompositionFilter 2023-09-12 15:54:12 +02:00
899ed5d0a4 Upgrade changes from master to last rector rules 2023-09-12 15:31:20 +02:00
9375d50112 Merge remote-tracking branch 'origin/master' into rector/rules-symfony
# Conflicts:
#	src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php
#	src/Bundle/ChillAsideActivityBundle/src/Export/Export/ListAsideActivity.php
2023-09-12 15:21:15 +02:00
e53540ec74 Fix test on ThirdPartyDocGenNormalizer 2023-09-12 15:18:44 +02:00
582b27fbd6 remove temporarily test from ChillReportBundle suite 2023-09-12 14:45:03 +02:00
19c6e3e6ba fix phpunit pathes 2023-09-03 15:45:27 +02:00
0711b7f84a Fix path to budget bundle tests 2023-09-03 14:55:42 +02:00
608663d25c Fix path to comply with psr-4 2023-09-03 14:55:15 +02:00
40b7c8ad8f fix rector and cs 2023-09-01 17:50:07 +02:00
412c55a1a5 add missing bundles to test suites 2023-09-01 17:49:09 +02:00
afa4b7ad2c temporarily remove test suite ont activity bundle 2023-09-01 17:31:21 +02:00
0db1e3e0d7 Exclude db intensive test to spare db connection 2023-09-01 17:17:17 +02:00
a2a660c954 Try to avoid open db connections 2023-09-01 17:07:10 +02:00
2c52a5bffa Fix tests 2023-09-01 16:10:04 +02:00
10a75f44e9 Ensure kernel shutdown after abstract export tests 2023-09-01 16:09:54 +02:00
1361e2bbf9 Fix test for TranslatableActivityTypeTest.php 2023-09-01 15:32:18 +02:00
37c1dfb0ba fix tests implementing AbstractAggregatorTest 2023-09-01 15:07:37 +02:00
a197a6b418 fix tests implementing AbstractFilterTest 2023-09-01 14:21:03 +02:00
f8f04c69d0 Remove test which seems to be not up to date with filter 2023-09-01 13:36:07 +02:00
355ed03500 Fix kernel booting problem on Aggregator and Filter tests 2023-09-01 11:08:15 +02:00
d8062be131 mark test as legacy 2023-09-01 11:08:13 +02:00
e72df84442 DX: rector corrections 2023-09-01 11:08:13 +02:00
d44f5d7af8 mark test as legacy 2023-09-01 10:53:53 +02:00
d595c17cd4 ensure kernel shutdown between client creations 2023-09-01 10:53:42 +02:00
cbb89ecf35 tests do not fails if indirect deprecations 2023-09-01 10:53:27 +02:00
6f11dffcbd Remove deprecation linked to kernel shutdown 2023-08-31 18:36:37 +02:00
7c58880139 Remove usage of deprecated Role class 2023-08-31 17:08:18 +02:00
76142c1264 Refactor twig template to avoid unclosed a element 2023-08-31 17:07:27 +02:00
650e3a84c8 Refactor rendering fragment: using controller path 2023-08-31 16:57:55 +02:00
6001e15907 Force "does not perform assertion" for test 2023-08-31 11:20:06 +02:00
2a9e461d6f Fix test: use fixed date instead of 'yesterday' 2023-08-31 11:18:38 +02:00
b85cd1b994 DX: apply rector rules for phpunit up to 90 2023-08-31 11:08:42 +02:00
e4e52234ad Rector: apply rules for doctrine code quality 2023-08-31 10:35:52 +02:00
bc9b7b1776 CI: remove "allow_failure" to unit_tests 2023-08-30 20:57:24 +02:00
1f2ecb923e Remove unnecessary return types 2023-08-30 20:49:26 +02:00
37419e06fc Skip test for reviewing duplication detection on person creation 2023-08-30 20:29:30 +02:00
bad3cdca09 Fix serializing collection with intersection types 2023-08-30 20:25:35 +02:00
711cdc3481 mark empty test as skipped 2023-08-30 16:35:13 +02:00
149ed2bd75 Refactor test to create people without accompanying period on each iteration 2023-08-30 16:26:15 +02:00
2f1f724860 Remove commented code 2023-08-30 16:25:30 +02:00
68e1384416 Remove echo with array to string conversion 2023-08-30 15:11:47 +02:00
0907d5b76a Configuration for messenger - use env=test in ci/step "unit_tests" 2023-08-30 14:58:13 +02:00
1c0fd57913 Apply rector rules + fix CS 2023-08-30 14:55:26 +02:00
d01172274d Remove unused properties 2023-08-30 14:37:20 +02:00
876ebca210 Birthdate validator: remove unused comparison 2023-08-30 14:37:08 +02:00
364a67b83a Skip test which apply on different kernel configuration 2023-08-30 14:31:37 +02:00
6bedd673cd Fix configuration for messenger in tests 2023-08-30 14:31:11 +02:00
df9f30265f Fix Birthdate validator DI and dedicated test 2023-08-30 14:14:36 +02:00
1b8acfab24 Fix person view test 2023-08-30 13:58:46 +02:00
690697cb35 Fix person update controller tests 2023-08-29 17:37:56 +02:00
5314e7b501 Fix tests on person's controller 2023-08-29 15:02:38 +02:00
939a6753bd Remove unexisting rule on rector 2023-08-29 14:49:33 +02:00
52d791f6d0 Refactor PersonControllerUpdateTest: separate validation test on dedicated test 2023-08-29 14:48:32 +02:00
80684f65fe Fix button selecton on PersonControllerCreateTest 2023-08-28 17:59:13 +02:00
b1a9749dc0 Remove class test with any test methods 2023-08-28 16:43:49 +02:00
2dfc228917 Fix initial query for calendar export query 2023-08-28 16:09:23 +02:00
3f2339bc60 Find person in center using centerCurrent in RelationshipApiControllerTest 2023-08-28 16:09:22 +02:00
e2a739eeff Fix strong typing on some entities's methods: allow null values 2023-08-28 16:09:22 +02:00
847fd71364 Fix tests on PersonContextWithThirdParty: fix construction of PersonContextWithThirdPartyTest 2023-08-28 16:09:22 +02:00
667104a595 Fix test on CalendarType: use the real IdToEntityDataTransformer, mocking the repository 2023-08-28 16:09:21 +02:00
2c83b4c912 Fix HouseholdACLAwareRepository: use the correct association to person's center 2023-08-28 16:09:21 +02:00
e2d62d5792 Fix loading of CalendarContext in CalendarContextTest. Needs to remove the final from PersonRepository 2023-08-28 16:09:21 +02:00
d1e09d7047 Fix constructor signature of BaseContext (in BaseContextDataTest.php) 2023-08-28 16:09:21 +02:00
5481d029e8 Fix ConverTest.php: fix argument to build Convert controller. 2023-08-28 16:09:20 +02:00
ebe1c11ca6 fix tests related to previous usage of deprecated STATUS_MOVED on Calendar 2023-08-28 16:09:20 +02:00
398bbd12d5 Fix tests on ChillDocumentLockManager: take expiration delay into account 2023-08-28 16:09:20 +02:00
c33330969c FIX CS 2023-08-28 12:49:31 +02:00
ea9c21e021 Fix calendarControllerTest: fix acl, and add calendar acl on fixtures 2023-08-25 23:09:46 +02:00
410aa7098a Fix docgen / PersonContextTest: there should not be any scope shown when only one scope is added. 2023-08-25 22:34:24 +02:00
ad1e5ecc95 Fix data provider for person, using the association with person center current 2023-08-25 22:23:18 +02:00
1e353ed74b Fix loading of random address reference in AddressToReferenceMatcherControllerTest.php 2023-08-25 18:26:32 +02:00
5136907d62 Fix deprecated lifecycleEvent to eventArgs in test 2023-08-02 23:25:20 +02:00
84dbfabd66 Fix double in test 2023-08-02 23:25:20 +02:00
43ac6726aa Fix selector button 2023-08-02 23:25:19 +02:00
0e0b0b8874 DX: fix cs 2023-08-02 23:25:19 +02:00
24cc6a816b Fix calls to templating service 2023-08-02 23:25:19 +02:00
f2d391ea2e cascading remove of Person\CenterHistory 2023-08-02 23:25:19 +02:00
e2b500ea5f Fix usage of twig environment in twig custom fields rendering extensions 2023-08-02 23:25:18 +02:00
dbccf7ff80 For integer for getting person_id in PersonController 2023-08-02 23:05:34 +02:00
65e6ad0fc4 Fix loading extension: use the new way 2023-08-02 23:05:33 +02:00
f68a163a30 Ensure loading of postal code does not fails 2023-08-02 23:05:33 +02:00
009a0326d9 Configure routes using annotation 2023-08-02 23:05:33 +02:00
4b20db7a9c build cache before running rector tests 2023-08-02 16:26:11 +02:00
458a59fe1b Fix loading extension: use the new way 2023-08-02 16:26:05 +02:00
378e417d5c Remove unnecessary comparison in ActivityController 2023-08-02 16:25:44 +02:00
cd7b91dd98 Avoid implicit creation of array 2023-08-01 18:35:36 +02:00
4b989fe25c fix tests for filter and aggregators: boot kernel instead of calling parent::setUp 2023-07-30 22:21:57 +02:00
984c35f8bc Fix loading countries 2023-07-30 22:15:39 +02:00
770d64a2f8 DX: fix loading of current professions for third parties 2023-07-28 13:21:33 +02:00
34c46f23e3 remove dead code 2023-07-28 13:10:58 +02:00
333579de06 DX: use more precise service parameter and use dataprovider for test 2023-07-28 13:06:45 +02:00
836cc7199e DX: add default autoconfigure and autowiring on Reports/Fixtures 2023-07-28 13:05:59 +02:00
7f96a895e1 DX: remove unused property on PersonController 2023-07-28 13:05:29 +02:00
a0d4a995d3 Rector config: provide kernel for rector configuration 2023-07-28 12:24:23 +02:00
e839b03cc9 Update path to twig template with new syntax 2023-07-28 12:16:50 +02:00
55b8502896 fix typing on Doctrine FunctionNode Age 2023-07-28 02:52:55 +02:00
a9c8f464bb Remove family member bundle 2023-07-28 02:41:37 +02:00
f570fe92a5 apply rector rules 2023-07-28 02:40:02 +02:00
157cdf6dfc update rector and adapt rules 2023-07-28 02:39:46 +02:00
c20f65eebb apply rector rules: symfony **UP TO** 44 2023-07-28 01:52:53 +02:00
b6a094aeee force readonly properties on dummy class used in test 2023-07-28 01:33:00 +02:00
0ed5544ad3 More useful error message when not enough people in database fixture 2023-07-28 01:22:58 +02:00
6f2b538e27 Use Person::centerHistory to load fixtures with given center 2023-07-28 01:22:55 +02:00
0e94e769cb Remove reference to deprecated Role class in tests 2023-07-28 01:16:53 +02:00
abc067adae More useful error message when not enough people in database fixture 2023-07-28 00:54:18 +02:00
ae04172929 Force type-hint and handle null value in ordering 2023-07-28 00:25:32 +02:00
dd21694544 Fix RefreshAddressToGeographicalUnitMaterializedViewCronJobTest: use ClockInterface to handle properly now and use more random tests 2023-07-27 23:52:38 +02:00
5f6e506300 Fix: AuthorizationHelperTest: remove deprecated and deprecation of PrepareScopeTrait 2023-07-27 23:51:57 +02:00
dba1d0548e Use the new syntax for prepending the load of twig templates in some Chill*Extension class 2023-07-27 23:23:18 +02:00
507bd5c6b5 Set the default env.test password on password, as hardcoded before 2023-07-27 23:22:19 +02:00
9f63d9ed0f Fix test on RefreshAddressToGeographicalUnitMaterializedViewCronJob
Alter the signature on run: add an empty array
2023-07-27 22:57:36 +02:00
97dad842ea Fix test on DateNormalizer 2023-07-27 22:55:52 +02:00
d08980c8d1 Fix deprecation on single task workflow declaration 2023-07-27 22:52:02 +02:00
da6f8511a8 Fix tests on ExportManager 2023-07-27 22:51:55 +02:00
9690359dfa Fix loading data for customfield, using proper DI 2023-07-23 00:31:27 +02:00
2ad82e8cc1 Fix loading data for customfield with new templating engine 2023-07-23 00:00:23 +02:00
169bf3c140 Fix bootstrapping of ci: step unit_test 2023-07-22 23:51:10 +02:00
9cdef5f951 Fix: remove data after executing CronJobDatabaseInteractionTest 2023-07-22 23:50:26 +02:00
df529be2ce Fix: Add missing prophecy methods in CronManagerTest 2023-07-22 23:50:22 +02:00
d87cd0c685 Fix DI for ReportDateFilter 2023-07-22 23:50:12 +02:00
7a5db59ac2 remove deprecated templating component 2023-07-22 23:09:00 +02:00
4028cc8a8b Set repositories for EventBundle on the new way + dependent issues 2023-07-22 23:05:30 +02:00
48cd8aaa9f Rewrite bootstrap of bundle when executing tests 2023-07-20 16:33:43 +02:00
d048ee3b44 fix configuration for EventSearch 2023-07-20 15:50:05 +02:00
aa553db659 apply rector rules after updating the code with master branch 2023-07-19 23:43:26 +02:00
e45430f0c9 Merge branch 'rector/rules-up-to-php82' into rector/rules-symfony 2023-07-19 23:22:57 +02:00
13abc36529 Merge branch 'rector/rules-up-to-php82-2023-08' into rector/rules-up-to-php82 2023-07-19 23:21:20 +02:00
023a29cb78 apply rector rules: php up to php82 2023-07-19 23:19:50 +02:00
7b637d1287 change rector config: up to php82 2023-07-19 23:15:42 +02:00
74ed34ba97 apply rules rector 2023-07-19 22:48:26 +02:00
6e6f19c499 fix small risky code 2023-07-19 16:28:51 +02:00
075aca493b DX: type-hing oneToMany and ManyToMany properties as collection 2023-07-19 16:21:17 +02:00
224c2c74e8 Merge remote-tracking branch 'origin/master' into rector/rules-up-to-php80
Conflicts:
	src/Bundle/ChillActivityBundle/Controller/ActivityController.php
	src/Bundle/ChillActivityBundle/Export/Aggregator/ACPAggregators/DateAggregator.php
	src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php
	src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php
	src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php
	src/Bundle/ChillCalendarBundle/Command/MapAndSubscribeUserCalendarCommand.php
	src/Bundle/ChillCalendarBundle/RemoteCalendar/Connector/MSGraph/MSGraphUserRepository.php
	src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php
	src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php
	src/Bundle/ChillDocStoreBundle/Repository/PersonDocumentACLAwareRepository.php
	src/Bundle/ChillEventBundle/Search/EventSearch.php
	src/Bundle/ChillMainBundle/Controller/ExportController.php
	src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php
	src/Bundle/ChillMainBundle/Cron/CronManager.php
	src/Bundle/ChillMainBundle/Entity/CronJobExecution.php
	src/Bundle/ChillMainBundle/Export/ExportManager.php
	src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php
	src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php
	src/Bundle/ChillMainBundle/Repository/NotificationRepository.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php
	src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php
	src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php
	src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php
	src/Bundle/ChillPersonBundle/Export/Aggregator/PersonAggregators/AgeAggregator.php
	src/Bundle/ChillPersonBundle/Export/Export/ListAccompanyingPeriod.php
	src/Bundle/ChillPersonBundle/Export/Export/ListHouseholdInPeriod.php
	src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php
	src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodContext.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/AccompanyingPeriodWorkEvaluationContext.php
	src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php
	src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php
	src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php
2023-07-17 12:49:13 +02:00
efaa01f4f6 DX: rector apply rules 'symfony up to 4.4 2023-05-05 18:21:33 +02:00
f04ef9c931 DX: add rector rules "symfony up to 4.4" 2023-05-05 18:20:16 +02:00
9252e92da0 gitlabci to new skeleton 2023-05-03 23:00:24 +02:00
4ab4554e63 DX: embed test app inside bundle 2023-05-03 23:00:08 +02:00
6d63177ff4 apply rules rector up to php82 2023-05-01 21:39:45 +02:00
81e8928344 DX: configure rector up to php82 2023-05-01 21:39:27 +02:00
737f5f9275 fixes 2023-05-01 21:22:56 +02:00
07c681fcec DX: update rector config 2023-04-28 23:19:05 +02:00
1c7d90a6ef fixes from a first test 2023-04-28 23:17:41 +02:00
24c33b306b Fix: urgent fix for EntityToJsonTransformer
The throw on error flag imposes us to propose a valid json string for decoding
2023-04-28 23:16:13 +02:00
7e19419861 fixes for last rebase and fixes for runtime 2023-04-28 23:03:36 +02:00
c35994203d fix phpstan issues 2023-04-28 22:55:01 +02:00
9027cbd196 DX: rector config: up to PHP8 [ci-skip][wip] 2023-04-28 22:30:35 +02:00
dde3002100 DX: apply rector rules up to php8.0 2023-04-28 22:30:33 +02:00
d8870e906f DX: rector in docs directory 2023-04-28 22:27:50 +02:00
1945 changed files with 21952 additions and 28656 deletions

View File

@@ -0,0 +1,5 @@
kind: Fixed
body: Replace old method of getting translator with injection of translatorInterface
time: 2023-10-26T15:22:05.134223653+02:00
custom:
Issue: "175"

20
.changes/v2.10.0.md Normal file
View File

@@ -0,0 +1,20 @@
## v2.10.0 - 2023-10-24
### Feature
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "grouping accompanying period by closing date"
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the activities
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period
* [export] sort filters and aggregators by title
* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export
### Fixed
* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods
### Résumé francophone des changements
- Ajout d'un regroupement sur les parcours: par date de cloture et d'ouverture;
- Ajouter d'un filtre et regroupement par tiers traitant sur les actions d'accompagnement;
- ajout d'un filtre et regroupement par usager participant sur les échanges
- ajout d'un regroupement: par type d'activité associé au parcours;
- trie les filtre et regroupements par ordre alphabétique dans els exports
- ajout d'un paramètre qui permet de désactiver le filtre par centre dans les exports
- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date"

3
.changes/v2.10.1.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.10.1 - 2023-10-24
### Fixed
* Fix export controller when generating an export without any data in session

3
.changes/v2.6.1.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.6.1 - 2023-09-14
### Fixed
* Filter out active centers in exports, which uses a different PickCenterType.

3
.changes/v2.6.2.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.6.2 - 2023-09-18
### Fixed
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.

4
.changes/v2.6.3.md Normal file
View File

@@ -0,0 +1,4 @@
## v2.6.3 - 2023-09-19
### Fixed
* Remove id property from document
mappedsuperclass

6
.changes/v2.7.0.md Normal file
View File

@@ -0,0 +1,6 @@
## v2.7.0 - 2023-09-27
### Feature
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
### Fixed
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"

19
.changes/v2.8.0.md Normal file
View File

@@ -0,0 +1,19 @@
## v2.8.0 - 2023-10-05
### Feature
* ([#162](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/162)) Reassigning list: when reassigning courses to a new user, the job associated with the course become the one of the new user (if any)
* Reassining list: the length of the list is increased to 100 courses
### Fixed
* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) Fix filter "accompanying course by social action" to avoid duplication in list
* ([#164](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/164)) View a third party: avoid errors when a contact has a civility
* ([#163](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/163)) Fix the filters and aggregators on exports "count peoples"
* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) From the database, avoid the creation of location history for same period and at same dates
### Traduction francophone des principaux changements
- Fonctionnalité: Réassigner les parcours en lot: lorsque des parcours sont réassignés "en lot", les parcours sont maintenant associés au métier du nouveau référent;
- Correction: certaines causes qui créaient des doublons dans les listes ont été corrigées;
- Correction des associations entre l'export "nombre de personnes" et les filtres et regroupements associés

23
.changes/v2.9.0.md Normal file
View File

@@ -0,0 +1,23 @@
## v2.9.0 - 2023-10-17
### Feature
* ([#147](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/147)) Add history to scopes and to jobs in administrator section. When user job or main scope of user is changed, automaticaly add a new row in history.
* ([#146](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/146)) Allow closing motives to be identified as 'canceling the accompanying period' + don't take canceled accompanying periods into account
* [export] add an aggregator for activities: group by job scope's creator aggregator
* DX: prepare the code for the upgrade to symfony 5.4
### Traductions francophones des principaux changements
- ajout de l'historique des services et métiers pour les utilisateurs. Les exports, filtres et regroupements sont adaptés pour tenir compte du métier et du service
de l'utilisateur au moment de l'échange, de sa désignation comme agent traitant de l'échange ou du moment du rendez-vous ([#147](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/147)))
- modification des motifs de cloture des parcours: ajout d'un chanmp "annule le parcours", qui permet d'indiquer que le motif "annule" le parcours. Les parcours annulés n'apparaissent
pas dans les statistiques
- ajouter d'un regroupement pour les échanges: grouper par métier et service du créateur de l'échange
### Possible BC break in configuration
This release remove the use of deprecated package [symfony/templating](https://symfony.com/components/Templating).
If you use this package in your own bundle (usually `src/` directory, or other dependencies), you should add this dependencies in your local composer.json (`composer require symfony/templating`).
But if you do not need this any more, you must ensure that the configuration key `framework.templating` is removed. This is usually located into `config/packages/framework.yaml`. [See here an example](https://gitea.champs-libres.be/Chill-project/chill-skeleton-basic/commit/cc716beaecc239e6a189f3db62ea95f169a37505#diff-df607fe73ff82c569824a7392edf5e760e998efe)

3
.changes/v2.9.1.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.9.1 - 2023-10-17
### Fixed
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers

3
.changes/v2.9.2.md Normal file
View File

@@ -0,0 +1,3 @@
## v2.9.2 - 2023-10-17
### Fixed
* Fix possible null values in string's entities

View File

@@ -3,3 +3,39 @@
# Run tests from root to adapt your own environment
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
ADMIN_PASSWORD=password
LOCALE=fr
REDIS_URL=redis
REDIS_PORT=6379
REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=2a30f6ba26521a2613821da35f28386e
TWILIO_SID=~
TWILIO_SECRET=~
DEFAULT_CARRIER_CODE=BE
ADD_ADDRESS_DEFAULT_COUNTRY=BE
ADD_ADDRESS_MAP_CENTER_X=50.8443
ADD_ADDRESS_MAP_CENTER_Y=4.3523
ADD_ADDRESS_MAP_CENTER_Z=15
SHORT_MESSAGE_DSN=null://null
MESSENGER_TRANSPORT_DSN=sync://
###< symfony/messenger ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
DATABASE_URL="postgresql://postgres:postgres@db:5432/test?serverVersion=14&charset=utf8"
###< doctrine/doctrine-bundle ###
ASYNC_UPLOAD_TEMP_URL_KEY=
ASYNC_UPLOAD_TEMP_URL_BASE_PATH=
ASYNC_UPLOAD_TEMP_URL_CONTAINER=

View File

@@ -3,7 +3,7 @@
# Select what we should cache between builds
cache:
paths:
- tests/app/vendor/
- /vendor/
- .cache
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
@@ -23,12 +23,10 @@ variables:
# configure database access
DATABASE_URL: postgresql://postgres:postgres@db:5432/postgres?serverVersion=14&charset=utf8
# fetch the chill-app using git submodules
GIT_SUBMODULE_STRATEGY: recursive
# GIT_SUBMODULE_STRATEGY: recursive
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_URL: redis://redis:6379
# change vendor dir to make the app install into tests/apps
COMPOSER_VENDOR_DIR: tests/app/vendor
DEFAULT_CARRIER_CODE: BE
stages:
@@ -50,7 +48,7 @@ build:
expire_in: 30 min
paths:
- bin
- tests/app/vendor/
- vendor/
code_style:
stage: Tests
@@ -64,7 +62,7 @@ code_style:
expire_in: 30 min
paths:
- bin
- tests/app/vendor/
- vendor/
phpstan_tests:
stage: Tests
@@ -78,13 +76,14 @@ phpstan_tests:
expire_in: 30 min
paths:
- bin
- tests/app/vendor/
- vendor/
rector_tests:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
script:
- bin/rector --dry-run
- tests/console cache:clear
- bin/rector process --dry-run
cache:
paths:
- .cache/
@@ -92,7 +91,7 @@ rector_tests:
expire_in: 30 min
paths:
- bin
- tests/app/vendor/
- vendor/
# psalm_tests:
# stage: Tests
@@ -109,19 +108,17 @@ rector_tests:
unit_tests:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
# until we fix testes
allow_failure: true
script:
- php tests/app/bin/console doctrine:migrations:migrate -n
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev
- php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n
- php -d memory_limit=2G tests/app/bin/console cache:clear --env=test
- php -d memory_limit=4G bin/phpunit --colors=never
- php tests/console doctrine:migrations:migrate -n --env=test
- php tests/console chill:db:sync-views --env=test
- php -d memory_limit=2G tests/console cache:clear --env=test
- php -d memory_limit=3G tests/console doctrine:fixtures:load -n
- php -d memory_limit=4G bin/phpunit --colors=never --exclude-group dbIntensive
artifacts:
expire_in: 30 min
paths:
- bin
- tests/app/vendor/
- vendor/
release:
stage: Deploy

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "_exts/sphinx-php"]
path = _exts/sphinx-php
url = https://github.com/fabpot/sphinx-php.git
[submodule "tests/app"]
path = tests/app
url = https://gitlab.com/Chill-projet/chill-app.git

View File

@@ -91,7 +91,7 @@ $rules = array_merge(
[
'@PhpCsFixer' => true,
'@PhpCsFixer:risky' => false,
'@Symfony' => false,
'@Symfony' => true,
'@Symfony:risky' => false,
'ordered_class_elements' => [
'order' => [
@@ -111,13 +111,13 @@ $rules = array_merge(
'method_private',
],
'sort_algorithm' => 'alpha',
]
],
],
$rules,
$riskyRules,
$untilFullSwitchToPhp8,
);
$rules['header_comment']['header'] = trim(file_get_contents(__DIR__ . '/resource/header.txt'));
$rules['header_comment']['header'] = trim(file_get_contents(__DIR__.'/resource/header.txt'));
return $config->setRules($rules);

View File

@@ -6,6 +6,107 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v2.10.2 - 2023-10-26
### Fixed
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
## v2.10.1 - 2023-10-24
### Fixed
* Fix export controller when generating an export without any data in session
## v2.10.0 - 2023-10-24
### Feature
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] Add a filter "grouping accompanying period by opening date" and "grouping accompanying period by closing date"
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on accompanying period work: group/filter by handling third party
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a filter and aggregator on activites: group/filter activities by people participating to the activities
* ([#172](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/172)) [export] add a grouping on accompanying period export: group by activity type associated to at least one activity within the accompanying period
* [export] sort filters and aggregators by title
* ([#179](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/179)) [export] create a parameter that will force to skip the filtering by center (ACL) when generating an export
### Fixed
* ([#177](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/177)) [export] fix date range selection on filter and grouping "by status of the course at date", on accompanying periods
### Résumé francophone des changements
- Ajout d'un regroupement sur les parcours: par date de cloture et d'ouverture;
- Ajouter d'un filtre et regroupement par tiers traitant sur les actions d'accompagnement;
- ajout d'un filtre et regroupement par usager participant sur les échanges
- ajout d'un regroupement: par type d'activité associé au parcours;
- trie les filtre et regroupements par ordre alphabétique dans els exports
- ajout d'un paramètre qui permet de désactiver le filtre par centre dans les exports
- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date"
## v2.9.2 - 2023-10-17
### Fixed
* Fix possible null values in string's entities
## v2.9.1 - 2023-10-17
### Fixed
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
## v2.9.0 - 2023-10-17
### Feature
* ([#147](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/147)) Add history to scopes and to jobs in administrator section. When user job or main scope of user is changed, automaticaly add a new row in history.
* ([#146](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/146)) Allow closing motives to be identified as 'canceling the accompanying period' + don't take canceled accompanying periods into account
* [export] add an aggregator for activities: group by job scope's creator aggregator
* DX: prepare the code for the upgrade to symfony 5.4
### Traductions francophones des principaux changements
- ajout de l'historique des services et métiers pour les utilisateurs. Les exports, filtres et regroupements sont adaptés pour tenir compte du métier et du service
de l'utilisateur au moment de l'échange, de sa désignation comme agent traitant de l'échange ou du moment du rendez-vous ([#147](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/147)))
- modification des motifs de cloture des parcours: ajout d'un chanmp "annule le parcours", qui permet d'indiquer que le motif "annule" le parcours. Les parcours annulés n'apparaissent
pas dans les statistiques
- ajouter d'un regroupement pour les échanges: grouper par métier et service du créateur de l'échange
### Possible BC break in configuration
This release remove the use of deprecated package [symfony/templating](https://symfony.com/components/Templating).
If you use this package in your own bundle (usually `src/` directory, or other dependencies), you should add this dependencies in your local composer.json (`composer require symfony/templating`).
But if you do not need this any more, you must ensure that the configuration key `framework.templating` is removed. This is usually located into `config/packages/framework.yaml`. [See here an example](https://gitea.champs-libres.be/Chill-project/chill-skeleton-basic/commit/cc716beaecc239e6a189f3db62ea95f169a37505#diff-df607fe73ff82c569824a7392edf5e760e998efe)
## v2.8.0 - 2023-10-05
### Feature
* ([#162](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/162)) Reassigning list: when reassigning courses to a new user, the job associated with the course become the one of the new user (if any)
* Reassining list: the length of the list is increased to 100 courses
### Fixed
* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) Fix filter "accompanying course by social action" to avoid duplication in list
* ([#164](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/164)) View a third party: avoid errors when a contact has a civility
* ([#163](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/163)) Fix the filters and aggregators on exports "count peoples"
* ([#143](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/143)) From the database, avoid the creation of location history for same period and at same dates
### Traduction francophone des principaux changements
- Fonctionnalité: Réassigner les parcours en lot: lorsque des parcours sont réassignés "en lot", les parcours sont maintenant associés au métier du nouveau référent;
- Correction: certaines causes qui créaient des doublons dans les listes ont été corrigées;
- Correction des associations entre l'export "nombre de personnes" et les filtres et regroupements associés
## v2.7.0 - 2023-09-27
### Feature
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
### Fixed
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
## v2.6.3 - 2023-09-19
### Fixed
* Remove id property from document
mappedsuperclass
## v2.6.2 - 2023-09-18
### Fixed
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
## v2.6.1 - 2023-09-14
### Fixed
* Filter out active centers in exports, which uses a different PickCenterType.
## v2.6.0 - 2023-09-14
### Feature
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.

View File

@@ -40,7 +40,7 @@ About once a year, the core team discusses the opportunity to invite new members
### Core Membership Revocation
A Symfony Core membership can be revoked for any of the following reasons:
A Chill Core membership can be revoked for any of the following reasons:
- Refusal to follow the rules and policies stated in this document;
- Lack of activity for the past six months;

View File

@@ -8,7 +8,7 @@
"social worker"
],
"require": {
"php": "^7.4|^8.2",
"php": "^8.2",
"ext-json": "*",
"ext-openssl": "*",
"ext-redis": "*",
@@ -48,7 +48,6 @@
"symfony/monolog-bundle": "^3.5",
"symfony/security-bundle": "^4.4",
"symfony/serializer": "^5.3",
"symfony/templating": "^4.4",
"symfony/translation": "^4.4",
"symfony/twig-bundle": "^4.4",
"symfony/validator": "^4.4",
@@ -76,7 +75,7 @@
"phpunit/phpunit": ">= 7.5",
"psalm/plugin-phpunit": "^0.18.4",
"psalm/plugin-symfony": "^4.0.2",
"rector/rector": "^0.15.23",
"rector/rector": "^0.17.7",
"symfony/debug-bundle": "^5.1",
"symfony/dotenv": "^4.4",
"symfony/maker-bundle": "^1.20",
@@ -98,7 +97,6 @@
"Chill\\DocGeneratorBundle\\": "src/Bundle/ChillDocGeneratorBundle",
"Chill\\DocStoreBundle\\": "src/Bundle/ChillDocStoreBundle",
"Chill\\EventBundle\\": "src/Bundle/ChillEventBundle",
"Chill\\FamilyMemberBundle\\": "src/Bundle/ChillFamilyMemberBundle",
"Chill\\MainBundle\\": "src/Bundle/ChillMainBundle",
"Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle",
"Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle",
@@ -110,7 +108,7 @@
},
"autoload-dev": {
"psr-4": {
"App\\": "tests/app/src/",
"App\\": "tests/",
"Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests",
"Chill\\WopiBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests",
"Chill\\Utils\\Rector\\Tests\\": "utils/rector/tests"
@@ -123,16 +121,15 @@
"ocramius/package-versions": true,
"phpro/grumphp": true,
"phpstan/extension-installer": true,
"roave/you-are-using-it-wrong": true
"roave/you-are-using-it-wrong": true,
"symfony/runtime": true
},
"bin-dir": "bin",
"optimize-autoloader": true,
"sort-packages": true,
"vendor-dir": "tests/app/vendor"
"sort-packages": true
},
"scripts": {
"auto-scripts": {
"assets:install %PUBLIC_DIR%": "symfony-cmd",
"cache:clear": "symfony-cmd"
}
}

View File

@@ -54,18 +54,9 @@ class CountPerson implements ExportInterface
public function getLabels($key, array $values, $data)
{
// the Closure which will be executed by the formatter.
return function ($value) {
switch ($value) {
case '_header':
// we have to process specifically the '_header' string,
// which will be used by the formatter to show a column title
return $this->getTitle();
default:
// for all value, we do not process them and return them
// immediatly
return $value;
}
return fn($value) => match ($value) {
'_header' => $this->getTitle(),
default => $value,
};
}

View File

@@ -13,7 +13,7 @@ namespace Chill\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class example extends Controller
class example extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
{
public function yourAction()
{

View File

@@ -16,7 +16,7 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Role\Role;
class ConsultationController extends Controller
class ConsultationController extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
{
/**
* @param int $id personId
@@ -43,7 +43,7 @@ class ConsultationController extends Controller
$circles = $authorizationHelper->getReachableCircles(
$this->getUser(),
new Role(ConsultationVoter::SEE),
ConsultationVoter::SEE,
$person->getCenter()
);

View File

@@ -23,25 +23,18 @@ class ChillMainConfiguration implements ConfigurationInterface
{
use AddWidgetConfigurationTrait;
/**
* @var ContainerBuilder
*/
private $containerBuilder;
public function __construct(
array $widgetFactories,
ContainerBuilder $containerBuilder
private readonly ContainerBuilder $containerBuilder
) {
// we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories);
// we will need the container builder later...
$this->containerBuilder = $containerBuilder;
}
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_main');
$treeBuilder = new TreeBuilder('chill_main');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()

View File

@@ -87,7 +87,7 @@ class ChillPersonAddAPersonWidget implements WidgetInterface
// show only the person from the authorized centers
$and = $qb->expr()->andX();
$centers = $this->authorizationHelper
->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE));
->getReachableCenters($this->getUser(), PersonVoter::SEE);
$and->add($qb->expr()->in('person.center', ':centers'));
$qb->setParameter('centers', $centers);

View File

@@ -1,63 +0,0 @@
Entity,Join,Attribute,Alias
AccompanyingPeriod::class,,,acp
,AccompanyingPeriodWork::class,acp.works,acpw
,AccompanyingPeriodParticipation::class,acp.participations,acppart
,Location::class,acp.administrativeLocation,acploc
,ClosingMotive::class,acp.closingMotive,acpmotive
,UserJob::class,acp.job,acpjob
,Origin::class,acp.origin,acporigin
,Scope::class,acp.scopes,acpscope
,SocialIssue::class,acp.socialIssues,acpsocialissue
,User::class,acp.user,acpuser
AccompanyingPeriodWork::class,,,acpw
,AccompanyingPeriodWorkEvaluation::class,acpw.accompanyingPeriodWorkEvaluations,workeval
,User::class,acpw.referrers,acpwuser
,SocialAction::class,acpw.socialAction,acpwsocialaction
,Goal::class,acpw.goals,goal
,Result::class,acpw.results,result
AccompanyingPeriodParticipation::class,,,acppart
,Person::class,acppart.person,partperson
AccompanyingPeriodWorkEvaluation::class,,,workeval
,Evaluation::class,workeval.evaluation,eval
Goal::class,,,goal
,Result::class,goal.results,goalresult
Person::class,,,person
,Center::class,person.center,center
,HouseholdMember::class,partperson.householdParticipations,householdmember
,MaritalStatus::class,person.maritalStatus,personmarital
,VendeePerson::class,,vp
,VendeePersonMineur::class,,vpm
ResidentialAddress::class,,,resaddr
,ThirdParty::class,resaddr.hostThirdParty,tparty
ThirdParty::class,,,tparty
,ThirdPartyCategory::class,tparty.categories,tpartycat
HouseholdMember::class,,,householdmember
,Household::class,householdmember.household,household
,Person::class,householdmember.person,memberperson
,,memberperson.center,membercenter
Household::class,,,household
,HouseholdComposition::class,household.compositions,composition
Activity::class,,,activity
,Person::class,activity.person,actperson
,AccompanyingPeriod::class,activity.accompanyingPeriod,acp
,Person::class,activity_person_having_activity.person,person_person_having_activity
,ActivityReason::class,activity_person_having_activity.reasons,reasons_person_having_activity
,ActivityType::class,activity.activityType,acttype
,Location::class,activity.location,actloc
,SocialAction::class,activity.socialActions,actsocialaction
,SocialIssue::class,activity.socialIssues,actsocialssue
,ThirdParty::class,activity.thirdParties,acttparty
,User::class,activity.user,actuser
,User::class,activity.users,actusers
,ActivityReason::class,activity.reasons,actreasons
,Center::class,actperson.center,actcenter
ActivityReason::class,,,actreasons
,ActivityReasonCategory::class,actreason.category,actreasoncat
Calendar::class,,,cal
,CancelReason::class,cal.cancelReason,calcancel
,Location::class,cal.location,calloc
,User::class,cal.user,caluser
VendeePerson::class,,,vp
,SituationProfessionelle::class,vp.situationProfessionelle,vpprof
,StatutLogement::class,vp.statutLogement,vplog
,TempsDeTravail::class,vp.tempsDeTravail,vptt
1 Entity Join Attribute Alias
2 AccompanyingPeriod::class acp
3 AccompanyingPeriodWork::class acp.works acpw
4 AccompanyingPeriodParticipation::class acp.participations acppart
5 Location::class acp.administrativeLocation acploc
6 ClosingMotive::class acp.closingMotive acpmotive
7 UserJob::class acp.job acpjob
8 Origin::class acp.origin acporigin
9 Scope::class acp.scopes acpscope
10 SocialIssue::class acp.socialIssues acpsocialissue
11 User::class acp.user acpuser
12 AccompanyingPeriodWork::class acpw
13 AccompanyingPeriodWorkEvaluation::class acpw.accompanyingPeriodWorkEvaluations workeval
14 User::class acpw.referrers acpwuser
15 SocialAction::class acpw.socialAction acpwsocialaction
16 Goal::class acpw.goals goal
17 Result::class acpw.results result
18 AccompanyingPeriodParticipation::class acppart
19 Person::class acppart.person partperson
20 AccompanyingPeriodWorkEvaluation::class workeval
21 Evaluation::class workeval.evaluation eval
22 Goal::class goal
23 Result::class goal.results goalresult
24 Person::class person
25 Center::class person.center center
26 HouseholdMember::class partperson.householdParticipations householdmember
27 MaritalStatus::class person.maritalStatus personmarital
28 VendeePerson::class vp
29 VendeePersonMineur::class vpm
30 ResidentialAddress::class resaddr
31 ThirdParty::class resaddr.hostThirdParty tparty
32 ThirdParty::class tparty
33 ThirdPartyCategory::class tparty.categories tpartycat
34 HouseholdMember::class householdmember
35 Household::class householdmember.household household
36 Person::class householdmember.person memberperson
37 memberperson.center membercenter
38 Household::class household
39 HouseholdComposition::class household.compositions composition
40 Activity::class activity
41 Person::class activity.person actperson
42 AccompanyingPeriod::class activity.accompanyingPeriod acp
43 Person::class activity_person_having_activity.person person_person_having_activity
44 ActivityReason::class activity_person_having_activity.reasons reasons_person_having_activity
45 ActivityType::class activity.activityType acttype
46 Location::class activity.location actloc
47 SocialAction::class activity.socialActions actsocialaction
48 SocialIssue::class activity.socialIssues actsocialssue
49 ThirdParty::class activity.thirdParties acttparty
50 User::class activity.user actuser
51 User::class activity.users actusers
52 ActivityReason::class activity.reasons actreasons
53 Center::class actperson.center actcenter
54 ActivityReason::class actreasons
55 ActivityReasonCategory::class actreason.category actreasoncat
56 Calendar::class cal
57 CancelReason::class cal.cancelReason calcancel
58 Location::class cal.location calloc
59 User::class cal.user caluser
60 VendeePerson::class vp
61 SituationProfessionelle::class vp.situationProfessionelle vpprof
62 StatutLogement::class vp.statutLogement vplog
63 TempsDeTravail::class vp.tempsDeTravail vptt

View File

@@ -21,7 +21,6 @@ These are alias conventions :
| | AccompanyingPeriodInfo::class | not existing (using custom WITH clause) | acpinfo |
| AccompanyingPeriodWork::class | | | acpw |
| | AccompanyingPeriodWorkEvaluation::class | acpw.accompanyingPeriodWorkEvaluations | workeval |
| | User::class | acpw.referrers | acpwuser |
| | SocialAction::class | acpw.socialAction | acpwsocialaction |
| | Goal::class | acpw.goals | goal |
| | Result::class | acpw.results | result |

View File

@@ -2,26 +2,51 @@
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="tests/app/vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/app/tests/bootstrap.php"
bootstrap="tests/bootstrap.php"
>
<php>
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0&amp;max[indirect]=999999" />
<server name="SHELL_VERBOSITY" value="-1" />
<env name="KERNEL_CLASS" value="\App\Kernel" />
</php>
<testsuites>
<!--
<testsuite name="ActivityBundle">
<directory suffix="Test.php">src/Bundle/ChillActivityBundle/Tests/</directory>
</testsuite>
-->
<testsuite name="AsideActivityBundle">
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory>
</testsuite>
<testsuite name="BudgetBundle">
<directory suffix="Test.php">src/Bundle/ChillBudgetBundle/Tests/</directory>
</testsuite>
<testsuite name="CalendarBundle">
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
</testsuite>
<!-- Missing CustomFieldBundle -->
<testsuite name="DocGeneratorBundle">
<directory suffix="Test.php">src/Bundle/ChillDocGeneratorBundle/tests/</directory>
</testsuite>
<testsuite name="DocStoreBundle">
<directory suffix="Test.php">src/Bundle/ChillDocStoreBundle/Tests/</directory>
</testsuite>
<!--
<testsuite name="EventBundle">
<directory suffix="Test.php">src/Bundle/ChillEventBundle/tests/</directory>
</testsuite>
-->
<testsuite name="MainBundle">
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
</testsuite>
<testsuite name="PersonBundle">
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
<!-- test for export will be runned later -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
<!-- we are rewriting accompanying periods... Work in progress -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php</exclude>
<!-- we are rewriting address, Work in progress -->
@@ -31,14 +56,18 @@
<!-- temporarily removed, the time to find a fix -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
</testsuite>
<testsuite name="AsideActivityBundle">
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory>
<!--
<testsuite name="ReportBundle">
<directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory>
</testsuite>
<testsuite name="CalendarBundle">
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
-->
<!--
<testsuite name="TaskBundle">
<directory suffix="Test.php">src/Bundle/ChillTaskBundle/Tests</directory>
</testsuite>
<testsuite name="DocGeneratorBundle">
<directory suffix="Test.php">src/Bundle/ChillDocGeneratorBundle/tests/</directory>
-->
<testsuite name="ThirdPartyBundle">
<directory suffix="Test.php">src/Bundle/ChillThirdPartyBundle/Tests</directory>
</testsuite>
<testsuite name="WopiBundle">
<directory suffix="Test.php">src/Bundle/ChillWopiBundle/tests/</directory>

View File

@@ -19,6 +19,9 @@ return static function (RectorConfig $rectorConfig): void {
__DIR__ . '/src',
]);
$rectorConfig->symfonyContainerXml(__DIR__ . '/var/cache/dev/testsApp_KernelDevDebugContainer.xml');
$rectorConfig->symfonyContainerPhp(__DIR__ . '/tests/symfony-container.php');
//$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
//$rectorConfig->cacheDirectory(__DIR__ . '/.cache/rector');
@@ -28,43 +31,25 @@ return static function (RectorConfig $rectorConfig): void {
//define sets of rules
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_74
LevelSetList::UP_TO_PHP_82,
\Rector\Symfony\Set\SymfonyLevelSetList::UP_TO_SYMFONY_44,
\Rector\Doctrine\Set\DoctrineSetList::DOCTRINE_CODE_QUALITY,
\Rector\PHPUnit\Set\PHPUnitLevelSetList::UP_TO_PHPUNIT_90,
]);
// some routes are added twice if it remains activated
// $rectorConfig->rule(\Rector\Symfony\Configs\Rector\ClassMethod\AddRouteAnnotationRector::class);
// chill rules
$rectorConfig->rule(\Chill\Utils\Rector\Rector\ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector::class);
//$rectorConfig->rule(\Chill\Utils\Rector\Rector\ChillBundleAddFormDefaultDataOnExportFilterAggregatorRector::class);
// skip some path...
$rectorConfig->skip([
// make rector stuck for some files
\Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector::class,
// we need to discuss this: are we going to have FALSE in tests instead of an error ?
\Rector\Php71\Rector\FuncCall\CountOnNullRector::class,
// must merge MR500 and review a typing of "ArrayCollection" in entities
\Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector::class,
// remove all PHP80 rules, in order to activate them one by one
\Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector::class,
\Rector\Php80\Rector\Class_\AnnotationToAttributeRector::class,
\Rector\Php80\Rector\Switch_\ChangeSwitchToMatchRector::class,
\Rector\Php80\Rector\FuncCall\ClassOnObjectRector::class,
\Rector\Php80\Rector\ClassConstFetch\ClassOnThisVariableObjectRector::class,
\Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector::class,
\Rector\Php80\Rector\Class_\DoctrineAnnotationClassToAttributeRector::class,
\Rector\Php80\Rector\ClassMethod\FinalPrivateToPrivateVisibilityRector::class,
\Rector\Php80\Rector\Ternary\GetDebugTypeRector::class,
\Rector\Php80\Rector\FunctionLike\MixedTypeRector::class,
\Rector\Php80\Rector\Property\NestedAnnotationToAttributeRector::class,
\Rector\Php80\Rector\FuncCall\Php8ResourceReturnToObjectRector::class,
\Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector::class,
\Rector\Php80\Rector\ClassMethod\SetStateToStaticRector::class,
\Rector\Php80\Rector\NotIdentical\StrContainsRector::class,
\Rector\Php80\Rector\Identical\StrEndsWithRector::class,
\Rector\Php80\Rector\Identical\StrStartsWithRector::class,
\Rector\Php80\Rector\Class_\StringableForToStringRector::class,
\Rector\Php80\Rector\FuncCall\TokenGetAllToObjectRector::class,
\Rector\Php80\Rector\FunctionLike\UnionTypesRector::class
// we must adapt service definition
\Rector\Symfony\Symfony28\Rector\MethodCall\GetToConstructorInjectionRector::class,
\Rector\Symfony\Symfony34\Rector\Closure\ContainerGetNameToTypeInTestsRector::class,
]);
};

View File

@@ -18,7 +18,6 @@ use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityUserJobRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\UserJob;
@@ -35,11 +34,8 @@ use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use InvalidArgumentException;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
@@ -49,7 +45,6 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
final class ActivityController extends AbstractController
{
@@ -77,9 +72,9 @@ final class ActivityController extends AbstractController
/**
* Deletes a Activity entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/{id}/delete", name="chill_activity_activity_delete", methods={"GET", "POST", "DELETE"})
*/
public function deleteAction(Request $request, $id)
public function deleteAction(Request $request, mixed $id)
{
$view = null;
@@ -92,10 +87,10 @@ final class ActivityController extends AbstractController
}
if ($activity->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/confirm_deleteAccompanyingCourse.html.twig';
$accompanyingPeriod = $activity->getAccompanyingPeriod();
} else {
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
$view = '@ChillActivity/Activity/confirm_deletePerson.html.twig';
}
// TODO
@@ -103,7 +98,7 @@ final class ActivityController extends AbstractController
$form = $this->createDeleteForm($activity->getId(), $person, $accompanyingPeriod);
if ($request->getMethod() === Request::METHOD_DELETE) {
if (Request::METHOD_DELETE === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -136,10 +131,6 @@ final class ActivityController extends AbstractController
}
}
if (null === $view) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
'activity' => $activity,
'delete_form' => $form->createView(),
@@ -150,6 +141,8 @@ final class ActivityController extends AbstractController
/**
* Displays a form to edit an existing Activity entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/{id}/edit", name="chill_activity_activity_edit", methods={"GET", "POST", "PUT"})
*/
public function editAction(int $id, Request $request): Response
{
@@ -165,10 +158,10 @@ final class ActivityController extends AbstractController
$person = $entity->getPerson();
if ($entity->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/editAccompanyingCourse.html.twig';
$accompanyingPeriod = $entity->getAccompanyingPeriod();
} else {
$view = 'ChillActivityBundle:Activity:editPerson.html.twig';
$view = '@ChillActivity/Activity/editPerson.html.twig';
}
// TODO
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
@@ -229,10 +222,6 @@ final class ActivityController extends AbstractController
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if (null === $view) {
throw $this->createNotFoundException('Template not found');
}
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, [
@@ -247,6 +236,8 @@ final class ActivityController extends AbstractController
/**
* Lists all Activity entities.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/", name="chill_activity_activity_list")
*/
public function listAction(Request $request): Response
{
@@ -282,9 +273,9 @@ final class ActivityController extends AbstractController
'element_class' => Activity::class,
'action' => 'list',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$this->eventDispatcher->dispatch($event, PrivacyEvent::PERSON_PRIVACY_EVENT);
$view = 'ChillActivityBundle:Activity:listPerson.html.twig';
$view = '@ChillActivity/Activity/listPerson.html.twig';
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod);
@@ -300,9 +291,9 @@ final class ActivityController extends AbstractController
$filterArgs
);
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/listAccompanyingCourse.html.twig';
} else {
throw new \LogicException("Unsupported");
throw new \LogicException('Unsupported');
}
return $this->render(
@@ -332,25 +323,28 @@ final class ActivityController extends AbstractController
->addEntityChoice('activity_types', 'activity_filter.Types', \Chill\ActivityBundle\Entity\ActivityType::class, $types, [
'choice_label' => function (\Chill\ActivityBundle\Entity\ActivityType $activityType) {
$text = match ($activityType->hasCategory()) {
true => $this->translatableStringHelper->localize($activityType->getCategory()->getName()) . ' > ',
true => $this->translatableStringHelper->localize($activityType->getCategory()->getName()).' > ',
false => '',
};
return $text . $this->translatableStringHelper->localize($activityType->getName());
}
return $text.$this->translatableStringHelper->localize($activityType->getName());
},
]);
}
if (1 < count($jobs)) {
$filterBuilder
->addEntityChoice('jobs', 'activity_filter.Jobs', UserJob::class, $jobs, [
'choice_label' => fn (UserJob $u) => $this->translatableStringHelper->localize($u->getLabel())
'choice_label' => fn (UserJob $u) => $this->translatableStringHelper->localize($u->getLabel()),
]);
}
return $filterBuilder->build();
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/new", name="chill_activity_activity_new", methods={"POST", "GET"})
*/
public function newAction(Request $request): Response
{
$view = null;
@@ -358,16 +352,16 @@ final class ActivityController extends AbstractController
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/newAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:newPerson.html.twig';
$view = '@ChillActivity/Activity/newPerson.html.twig';
}
$activityType_id = $request->get('activityType_id', 0);
$activityType = $this->activityTypeRepository->find($activityType_id);
if (isset($activityType) && !$activityType->isActive()) {
throw new InvalidArgumentException('Activity type must be active');
throw new \InvalidArgumentException('Activity type must be active');
}
$activityData = null;
@@ -402,45 +396,45 @@ final class ActivityController extends AbstractController
}
$entity->setActivityType($activityType);
$entity->setDate(new DateTime('now'));
$entity->setDate(new \DateTime('now'));
if ($request->query->has('activityData')) {
$activityData = $request->query->get('activityData');
if (array_key_exists('durationTime', $activityData) && $activityType->getDurationTimeVisible() > 0) {
if (\array_key_exists('durationTime', $activityData) && $activityType->getDurationTimeVisible() > 0) {
$durationTimeInMinutes = $activityData['durationTime'];
$hours = floor($durationTimeInMinutes / 60);
$minutes = $durationTimeInMinutes % 60;
$duration = DateTime::createFromFormat('H:i', $hours . ':' . $minutes);
$duration = \DateTime::createFromFormat('H:i', $hours.':'.$minutes);
if ($duration) {
$entity->setDurationTime($duration);
}
}
if (array_key_exists('date', $activityData)) {
$date = DateTime::createFromFormat('Y-m-d', $activityData['date']);
if (\array_key_exists('date', $activityData)) {
$date = \DateTime::createFromFormat('Y-m-d', $activityData['date']);
if ($date) {
$entity->setDate($date);
}
}
if (array_key_exists('personsId', $activityData) && $activityType->getPersonsVisible() > 0) {
if (\array_key_exists('personsId', $activityData) && $activityType->getPersonsVisible() > 0) {
foreach ($activityData['personsId'] as $personId) {
$concernedPerson = $this->personRepository->find($personId);
$entity->addPerson($concernedPerson);
}
}
if (array_key_exists('professionalsId', $activityData) && $activityType->getThirdPartiesVisible() > 0) {
if (\array_key_exists('professionalsId', $activityData) && $activityType->getThirdPartiesVisible() > 0) {
foreach ($activityData['professionalsId'] as $professionalsId) {
$professional = $this->thirdPartyRepository->find($professionalsId);
$entity->addThirdParty($professional);
}
}
if (array_key_exists('usersId', $activityData) && $activityType->getUsersVisible() > 0) {
if (\array_key_exists('usersId', $activityData) && $activityType->getUsersVisible() > 0) {
foreach ($activityData['usersId'] as $userId) {
$user = $this->userRepository->find($userId);
@@ -450,16 +444,16 @@ final class ActivityController extends AbstractController
}
}
if (array_key_exists('location', $activityData) && $activityType->getLocationVisible() > 0) {
if (\array_key_exists('location', $activityData) && $activityType->getLocationVisible() > 0) {
$location = $this->locationRepository->find($activityData['location']);
$entity->setLocation($location);
}
if (array_key_exists('comment', $activityData) && $activityType->getCommentVisible() > 0) {
if (\array_key_exists('comment', $activityData) && $activityType->getCommentVisible() > 0) {
$comment = new CommentEmbeddable();
$comment->setComment($activityData['comment']);
$comment->setUserId($this->getUser()->getid());
$comment->setDate(new DateTime('now'));
$comment->setDate(new \DateTime('now'));
$entity->setComment($comment);
}
}
@@ -531,6 +525,9 @@ final class ActivityController extends AbstractController
]);
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/select-type", name="chill_activity_activity_select_type")
*/
public function selectTypeAction(Request $request): Response
{
$view = null;
@@ -538,9 +535,9 @@ final class ActivityController extends AbstractController
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:selectTypeAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/selectTypeAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:selectTypePerson.html.twig';
$view = '@ChillActivity/Activity/selectTypePerson.html.twig';
}
$data = [];
@@ -575,6 +572,9 @@ final class ActivityController extends AbstractController
]);
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/activity/{id}/show", name="chill_activity_activity_show")
*/
public function showAction(Request $request, int $id): Response
{
$entity = $this->activityRepository->find($id);
@@ -587,11 +587,11 @@ final class ActivityController extends AbstractController
$person = $entity->getPerson();
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig';
$view = '@ChillActivity/Activity/showAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:showPerson.html.twig';
$view = '@ChillActivity/Activity/showPerson.html.twig';
} else {
throw new RuntimeException('the activity should be linked with a period or person');
throw new \RuntimeException('the activity should be linked with a period or person');
}
if (null !== $accompanyingPeriod) {
@@ -614,10 +614,6 @@ final class ActivityController extends AbstractController
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if (null === $view) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,

View File

@@ -24,6 +24,8 @@ class ActivityReasonCategoryController extends AbstractController
{
/**
* Creates a new ActivityReasonCategory entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/create", name="chill_activity_activityreasoncategory_create", methods={"POST"})
*/
public function createAction(Request $request)
{
@@ -31,15 +33,15 @@ class ActivityReasonCategoryController extends AbstractController
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', ['id' => $entity->getId()]));
return $this->redirectToRoute('chill_activity_activityreasoncategory_show', ['id' => $entity->getId()]);
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
@@ -48,9 +50,9 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Displays a form to edit an existing ActivityReasonCategory entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/{id}/edit", name="chill_activity_activityreasoncategory_edit")
*/
public function editAction($id)
public function editAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -62,7 +64,7 @@ class ActivityReasonCategoryController extends AbstractController
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
@@ -70,6 +72,8 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Lists all ActivityReasonCategory entities.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/", name="chill_activity_activityreasoncategory")
*/
public function indexAction()
{
@@ -77,20 +81,22 @@ class ActivityReasonCategoryController extends AbstractController
$entities = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityReasonCategory::class)->findAll();
return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new ActivityReasonCategory entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/new", name="chill_activity_activityreasoncategory_new")
*/
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
@@ -99,9 +105,9 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Finds and displays a ActivityReasonCategory entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/{id}/show", name="chill_activity_activityreasoncategory_show")
*/
public function showAction($id)
public function showAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -111,7 +117,7 @@ class ActivityReasonCategoryController extends AbstractController
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/show.html.twig', [
'entity' => $entity,
]);
}
@@ -119,9 +125,9 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Edits an existing ActivityReasonCategory entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreasoncategory/{id}/update", name="chill_activity_activityreasoncategory_update", methods={"POST", "PUT"})
*/
public function updateAction(Request $request, $id)
public function updateAction(Request $request, mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -134,13 +140,13 @@ class ActivityReasonCategoryController extends AbstractController
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', ['id' => $id]));
return $this->redirectToRoute('chill_activity_activityreasoncategory_edit', ['id' => $id]);
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
return $this->render('@ChillActivity/ActivityReasonCategory/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);

View File

@@ -24,15 +24,12 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/
class ActivityReasonController extends AbstractController
{
private ActivityReasonRepository $activityReasonRepository;
public function __construct(ActivityReasonRepository $activityReasonRepository)
{
$this->activityReasonRepository = $activityReasonRepository;
}
public function __construct(private readonly ActivityReasonRepository $activityReasonRepository) {}
/**
* Creates a new ActivityReason entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/create", name="chill_activity_activityreason_create", methods={"POST"})
*/
public function createAction(Request $request)
{
@@ -40,15 +37,15 @@ class ActivityReasonController extends AbstractController
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $entity->getId()]));
return $this->redirectToRoute('chill_activity_activityreason', ['id' => $entity->getId()]);
}
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
return $this->render('@ChillActivity/ActivityReason/new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
@@ -57,9 +54,9 @@ class ActivityReasonController extends AbstractController
/**
* Displays a form to edit an existing ActivityReason entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/{id}/edit", name="chill_activity_activityreason_edit")
*/
public function editAction($id)
public function editAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -71,7 +68,7 @@ class ActivityReasonController extends AbstractController
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
return $this->render('@ChillActivity/ActivityReason/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
@@ -79,6 +76,8 @@ class ActivityReasonController extends AbstractController
/**
* Lists all ActivityReason entities.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/", name="chill_activity_activityreason")
*/
public function indexAction()
{
@@ -86,20 +85,22 @@ class ActivityReasonController extends AbstractController
$entities = $this->activityReasonRepository->findAll();
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [
return $this->render('@ChillActivity/ActivityReason/index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new ActivityReason entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/new", name="chill_activity_activityreason_new")
*/
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
return $this->render('@ChillActivity/ActivityReason/new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
@@ -108,9 +109,9 @@ class ActivityReasonController extends AbstractController
/**
* Finds and displays a ActivityReason entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/{id}/show", name="chill_activity_activityreason_show")
*/
public function showAction($id)
public function showAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -120,7 +121,7 @@ class ActivityReasonController extends AbstractController
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', [
return $this->render('@ChillActivity/ActivityReason/show.html.twig', [
'entity' => $entity,
]);
}
@@ -128,9 +129,9 @@ class ActivityReasonController extends AbstractController
/**
* Edits an existing ActivityReason entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activityreason/{id}/update", name="chill_activity_activityreason_update", methods={"POST", "PUT"})
*/
public function updateAction(Request $request, $id)
public function updateAction(Request $request, mixed $id)
{
$em = $this->getDoctrine()->getManager();
@@ -143,13 +144,13 @@ class ActivityReasonController extends AbstractController
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $id]));
return $this->redirectToRoute('chill_activity_activityreason', ['id' => $id]);
}
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
return $this->render('@ChillActivity/ActivityReason/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);

View File

@@ -24,7 +24,7 @@ class AdminActivityPresenceController extends CRUDController
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
/* @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.id', 'ASC');
}
}

View File

@@ -24,7 +24,7 @@ class AdminActivityTypeCategoryController extends CRUDController
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
/* @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC');
}
}

View File

@@ -24,7 +24,7 @@ class AdminActivityTypeController extends CRUDController
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
/* @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC')
->addOrderBy('e.id', 'ASC');
}

View File

@@ -18,11 +18,18 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
*/
class AdminController extends AbstractController
{
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activity", name="chill_activity_admin_index")
*/
public function indexActivityAction()
{
return $this->render('ChillActivityBundle:Admin:layout_activity.html.twig');
return $this->render('@ChillActivity/Admin/layout_activity.html.twig');
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activity_redirect_to_main", name="chill_admin_aside_activity_redirect_to_admin_index", options={null})
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/activity_redirect_to_main", name="chill_admin_activity_redirect_to_admin_index")
*/
public function redirectToAdminIndexAction()
{
return $this->redirectToRoute('chill_main_admin_central');

View File

@@ -25,17 +25,11 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
{
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
private EntityManagerInterface $em;
private readonly \Faker\Generator $faker;
/**
* @var \Faker\Generator
*/
private $faker;
public function __construct(EntityManagerInterface $em)
public function __construct(private readonly EntityManagerInterface $em)
{
$this->faker = FakerFactory::create('fr_FR');
$this->em = $em;
}
public function getOrder()

View File

@@ -52,13 +52,13 @@ class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterf
];
foreach ($reasons as $r) {
echo 'Creating activity reason : ' . $r['name']['en'] . "\n";
echo 'Creating activity reason : '.$r['name']['en']."\n";
$activityReason = (new ActivityReason())
->setName(($r['name']))
->setName($r['name'])
->setActive(true)
->setCategory($this->getReference($r['category']));
$manager->persist($activityReason);
$reference = 'activity_reason_' . $r['name']['en'];
$reference = 'activity_reason_'.$r['name']['en'];
$this->addReference($reference, $activityReason);
static::$references[] = $reference;
}

View File

@@ -34,13 +34,13 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu
];
foreach ($categs as $c) {
echo 'Creating activity reason category : ' . $c['name']['en'] . "\n";
echo 'Creating activity reason category : '.$c['name']['en']."\n";
$activityReasonCategory = (new ActivityReasonCategory())
->setName(($c['name']))
->setName($c['name'])
->setActive(true);
$manager->persist($activityReasonCategory);
$this->addReference(
'cat_' . $c['name']['en'],
'cat_'.$c['name']['en'],
$activityReasonCategory
);
}

View File

@@ -54,14 +54,14 @@ class LoadActivityType extends Fixture implements OrderedFixtureInterface
];
foreach ($types as $t) {
echo 'Creating activity type : ' . $t['name']['fr'] . ' (cat:' . $t['category'] . " \n";
echo 'Creating activity type : '.$t['name']['fr'].' (cat:'.$t['category']." \n";
$activityType = (new ActivityType())
->setName(($t['name']))
->setCategory($this->getReference('activity_type_cat_' . $t['category']))
->setName($t['name'])
->setCategory($this->getReference('activity_type_cat_'.$t['category']))
->setSocialIssuesVisible(1)
->setSocialActionsVisible(1);
$manager->persist($activityType);
$reference = 'activity_type_' . $t['name']['fr'];
$reference = 'activity_type_'.$t['name']['fr'];
$this->addReference($reference, $activityType);
static::$references[] = $reference;
}

View File

@@ -42,13 +42,13 @@ class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterfac
];
foreach ($categories as $cat) {
echo 'Creating activity type category : ' . $cat['ref'] . "\n";
echo 'Creating activity type category : '.$cat['ref']."\n";
$newCat = (new ActivityTypeCategory())
->setName(($cat['name']));
->setName($cat['name']);
$manager->persist($newCat);
$reference = 'activity_type_cat_' . $cat['ref'];
$reference = 'activity_type_cat_'.$cat['ref'];
$this->addReference($reference, $newCat);
static::$references[] = $reference;

View File

@@ -20,8 +20,6 @@ use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use function in_array;
/**
* Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except administrative,
* and a role CHILL_ACTIVITY_SEE for administrative.
@@ -40,10 +38,10 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
foreach (LoadScopes::$references as $scopeRef) {
$scope = $this->getReference($scopeRef);
//create permission group
// create permission group
switch ($permissionsGroup->getName()) {
case 'social':
if ($scope->getName()['en'] === 'administrative') {
if ('administrative' === $scope->getName()['en']) {
break 2; // we do not want any power on administrative
}
@@ -51,7 +49,7 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
case 'administrative':
case 'direction':
if (in_array($scope->getName()['en'], ['administrative', 'social'], true)) {
if (\in_array($scope->getName()['en'], ['administrative', 'social'], true)) {
break 2; // we do not want any power on social or administrative
}
@@ -60,7 +58,7 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
printf(
'Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s '
. "permission group, scope '%s' \n",
."permission group, scope '%s' \n",
$permissionsGroup->getName(),
$scope->getName()['en']
);

View File

@@ -32,7 +32,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml');
$loader->load('services/export.yaml');
$loader->load('services/repositories.yaml');
@@ -73,7 +73,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
*/
public function prependRoutes(ContainerBuilder $container)
{
//add routes for custom bundle
// add routes for custom bundle
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [

View File

@@ -13,7 +13,6 @@ namespace Chill\ActivityBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use function is_int;
/**
@@ -59,7 +58,7 @@ class Configuration implements ConfigurationInterface
->info('The number of seconds of this duration. Must be an integer.')
->cannotBeEmpty()
->validate()
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
->ifTrue(static fn ($data) => !\is_int($data))->thenInvalid('The value %s is not a valid integer')
->end()
->end()
->scalarNode('label')

View File

@@ -36,7 +36,6 @@ use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
@@ -46,11 +45,15 @@ use Symfony\Component\Validator\Constraints as Assert;
* Class Activity.
*
* @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository")
*
* @ORM\Table(name="activity")
*
* @ORM\HasLifecycleCallbacks
*
* @DiscriminatorMap(typeProperty="type", mapping={
* "activity": Activity::class
* })
*
* @ActivityValidator\ActivityValidity
*
* TODO see if necessary
@@ -65,69 +68,84 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
use TrackUpdateTrait;
public const SENTRECEIVED_RECEIVED = 'received';
final public const SENTRECEIVED_RECEIVED = 'received';
public const SENTRECEIVED_SENT = 'sent';
final public const SENTRECEIVED_SENT = 'sent';
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
*
* @Groups({"read"})
*/
private ?AccompanyingPeriod $accompanyingPeriod = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*
* @Groups({"read", "docgen:read"})
*
* @SerializedName("activityType")
*
* @ORM\JoinColumn(name="type_id")
*/
private ActivityType $activityType;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityPresence")
*
* @Groups({"docgen:read"})
*/
private ?ActivityPresence $attendee = null;
/**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_")
*
* @Groups({"docgen:read"})
*/
private CommentEmbeddable $comment;
/**
* @ORM\Column(type="datetime")
*
* @Groups({"docgen:read"})
*/
private DateTime $date;
private \DateTime $date;
/**
* @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject", cascade={"persist"})
*
* @Assert\Valid(traverse=true)
*
* @var Collection<StoredObject>
*/
private Collection $documents;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?DateTime $durationTime = null;
private ?\DateTime $durationTime = null;
/**
* @ORM\Column(type="boolean", options={"default": false})
*
* @Groups({"docgen:read"})
*/
private bool $emergency = false;
/**
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*
* @Groups({"read", "docgen:read"})
*/
private ?int $id = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Location")
*
* @groups({"read", "docgen:read"})
*/
private ?Location $location = null;
@@ -139,9 +157,12 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person")
*
* @Groups({"read", "docgen:read"})
*
* @var Collection<Person>
*/
private ?Collection $persons = null;
private Collection $persons;
/**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable", columnPrefix="privateComment_")
@@ -150,58 +171,78 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
/**
* @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason")
*
* @Groups({"docgen:read"})
*
* @var Collection<ActivityReason>
*/
private Collection $reasons;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
*
* @Groups({"docgen:read"})
*/
private ?Scope $scope = null;
/**
* @ORM\Column(type="string", options={"default": ""})
*
* @Groups({"docgen:read"})
*/
private string $sentReceived = '';
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialAction")
*
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialaction")
*
* @Groups({"read", "docgen:read"})
*
* @var Collection<SocialAction>
*/
private Collection $socialActions;
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialIssue")
*
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialissue")
*
* @Groups({"read", "docgen:read"})
*
* @var Collection<SocialIssue>
*/
private Collection $socialIssues;
/**
* @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
*
* @Groups({"read", "docgen:read"})
*
* @var Collection<ThirdParty>
*/
private ?Collection $thirdParties = null;
private Collection $thirdParties;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?DateTime $travelTime = null;
private ?\DateTime $travelTime = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*
* @Groups({"docgen:read"})
*/
private ?User $user = null;
/**
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
*
* @Groups({"read", "docgen:read"})
*
* @var Collection<User>
*/
private ?Collection $users = null;
private Collection $users;
public function __construct()
{
@@ -268,7 +309,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
$this->socialIssues[] = $socialIssue;
}
if ($this->getAccompanyingPeriod() !== null) {
if (null !== $this->getAccompanyingPeriod()) {
$this->getAccompanyingPeriod()->addSocialIssue($socialIssue);
}
@@ -334,7 +375,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this->comment;
}
public function getDate(): DateTime
public function getDate(): \DateTime
{
return $this->date;
}
@@ -356,7 +397,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return (int) round(($this->durationTime->getTimestamp() + $this->durationTime->getOffset()) / 60.0, 0);
}
public function getDurationTime(): ?DateTime
public function getDurationTime(): ?\DateTime
{
return $this->durationTime;
}
@@ -410,7 +451,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
// TODO better semantic with: return $this->persons->filter(...);
foreach ($this->persons as $person) {
if ($this->accompanyingPeriod->getOpenParticipationContainsPerson($person) === null) {
if (null === $this->accompanyingPeriod->getOpenParticipationContainsPerson($person)) {
$personsNotAssociated[] = $person;
}
}
@@ -469,7 +510,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this->thirdParties;
}
public function getTravelTime(): ?DateTime
public function getTravelTime(): ?\DateTime
{
return $this->travelTime;
}
@@ -580,7 +621,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this;
}
public function setDate(DateTime $date): self
public function setDate(\DateTime $date): self
{
$this->date = $date;
@@ -594,7 +635,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this;
}
public function setDurationTime(?DateTime $durationTime): self
public function setDurationTime(?\DateTime $durationTime): self
{
$this->durationTime = $durationTime;
@@ -664,7 +705,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this;
}
public function setTravelTime(DateTime $travelTime): self
public function setTravelTime(\DateTime $travelTime): self
{
$this->travelTime = $travelTime;

View File

@@ -18,7 +18,9 @@ use Symfony\Component\Serializer\Annotation as Serializer;
* Class ActivityPresence.
*
* @ORM\Entity
*
* @ORM\Table(name="activitytpresence")
*
* @ORM\HasLifecycleCallbacks
*/
class ActivityPresence
@@ -30,15 +32,20 @@ class ActivityPresence
/**
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*
* @Serializer\Groups({"docgen:read"})
*/
private ?int $id = null;
/**
* @ORM\Column(type="json")
*
* @Serializer\Groups({"docgen:read"})
*
* @Serializer\Context({"is-translatable": true}, groups={"docgen:read"})
*/
private array $name = [];

View File

@@ -17,39 +17,38 @@ use Doctrine\ORM\Mapping as ORM;
* Class ActivityReason.
*
* @ORM\Entity
*
* @ORM\Table(name="activityreason")
*
* @ORM\HasLifecycleCallbacks
*/
class ActivityReason
{
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
private bool $active = true;
/**
* @var ActivityReasonCategory
* @ORM\ManyToOne(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory",
* inversedBy="reasons")
*/
private $category;
private ?ActivityReasonCategory $category = null;
/**
* @var int
*
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private ?int $id = null;
/**
* @var array
* @ORM\Column(type="json")
*/
private $name;
private array $name;
/**
* Get active.
@@ -81,27 +80,9 @@ class ActivityReason
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array | string
*/
public function getName($locale = null)
public function getName(): array
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this->name;
}

View File

@@ -12,34 +12,37 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* Class ActivityReasonCategory.
*
* @ORM\Entity
*
* @ORM\Table(name="activityreasoncategory")
*
* @ORM\HasLifecycleCallbacks
*/
class ActivityReasonCategory
class ActivityReasonCategory implements \Stringable
{
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
private bool $active = true;
/**
* @var int
*
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private ?int $id = null;
/**
* @var string
*
* @ORM\Column(type="json")
*/
private $name;
@@ -47,12 +50,13 @@ class ActivityReasonCategory
/**
* Array of ActivityReason.
*
* @var ArrayCollection
* @var Collection<ActivityReason>
*
* @ORM\OneToMany(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReason",
* mappedBy="category")
*/
private $reasons;
private Collection $reasons;
/**
* ActivityReasonCategory constructor.
@@ -62,12 +66,9 @@ class ActivityReasonCategory
$this->reasons = new ArrayCollection();
}
/**
* @return string
*/
public function __toString()
public function __toString(): string
{
return 'ActivityReasonCategory(' . $this->getName('x') . ')';
return 'ActivityReasonCategory('.$this->getName('x').')';
}
/**
@@ -121,11 +122,9 @@ class ActivityReasonCategory
* as unactive, all the reason have this entity as category is also
* set as unactive.
*
* @param bool $active
*
* @return ActivityReasonCategory
*/
public function setActive($active)
public function setActive(bool $active)
{
if ($this->active !== $active && !$active) {
foreach ($this->reasons as $reason) {

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@@ -22,31 +21,36 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
* Class ActivityType.
*
* @ORM\Entity
*
* @ORM\Table(name="activitytype")
*
* @ORM\HasLifecycleCallbacks
*/
class ActivityType
{
public const FIELD_INVISIBLE = 0;
final public const FIELD_INVISIBLE = 0;
public const FIELD_OPTIONAL = 1;
final public const FIELD_OPTIONAL = 1;
public const FIELD_REQUIRED = 2;
final public const FIELD_REQUIRED = 2;
/**
* @deprecated not in use
*
* @ORM\Column(type="string", nullable=false, options={"default": ""})
*/
private string $accompanyingPeriodLabel = '';
/**
* @deprecated not in use
*
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
*/
private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="boolean")
*
* @Groups({"read"})
*/
private bool $active = true;
@@ -118,8 +122,11 @@ class ActivityType
/**
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*
* @Groups({"docgen:read"})
*/
private ?int $id = null;
@@ -136,7 +143,9 @@ class ActivityType
/**
* @ORM\Column(type="json")
*
* @Groups({"read", "docgen:read"})
*
* @Serializer\Context({"is-translatable": true}, groups={"docgen:read"})
*/
private array $name = [];
@@ -158,6 +167,7 @@ class ActivityType
/**
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
*
* @Groups({"read"})
*/
private int $personsVisible = self::FIELD_OPTIONAL;
@@ -238,6 +248,7 @@ class ActivityType
/**
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
*
* @Groups({"read"})
*/
private int $thirdPartiesVisible = self::FIELD_INVISIBLE;
@@ -264,6 +275,7 @@ class ActivityType
/**
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
*
* @Groups({"read"})
*/
private int $usersVisible = self::FIELD_OPTIONAL;
@@ -275,10 +287,8 @@ class ActivityType
/**
* @Assert\Callback
*
* @param mixed $payload
*/
public function checkSocialActionsVisibility(ExecutionContextInterface $context, $payload)
public function checkSocialActionsVisibility(ExecutionContextInterface $context, mixed $payload)
{
if ($this->socialIssuesVisible !== $this->socialActionsVisible) {
if (!(2 === $this->socialIssuesVisible && 1 === $this->socialActionsVisible)) {
@@ -374,13 +384,13 @@ class ActivityType
public function getLabel(string $field): ?string
{
$property = $field . 'Label';
$property = $field.'Label';
if (!property_exists($this, $property)) {
throw new InvalidArgumentException('Field "' . $field . '" not found');
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
/** @phpstan-ignore-next-line */
/* @phpstan-ignore-next-line */
return $this->{$property};
}
@@ -533,25 +543,25 @@ class ActivityType
public function isRequired(string $field): bool
{
$property = $field . 'Visible';
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new InvalidArgumentException('Field "' . $field . '" not found');
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
/** @phpstan-ignore-next-line */
/* @phpstan-ignore-next-line */
return self::FIELD_REQUIRED === $this->{$property};
}
public function isVisible(string $field): bool
{
$property = $field . 'Visible';
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new InvalidArgumentException('Field "' . $field . '" not found');
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
/** @phpstan-ignore-next-line */
/* @phpstan-ignore-next-line */
return self::FIELD_INVISIBLE !== $this->{$property};
}

View File

@@ -15,7 +15,9 @@ use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*
* @ORM\Table(name="activitytypecategory")
*
* @ORM\HasLifecycleCallbacks
*/
class ActivityTypeCategory
@@ -27,7 +29,9 @@ class ActivityTypeCategory
/**
* @ORM\Id
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
private ?int $id = null;

View File

@@ -15,22 +15,11 @@ use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use function in_array;
class ActivityEntityListener
{
private EntityManagerInterface $em;
private AccompanyingPeriodWorkRepository $workRepository;
public function __construct(EntityManagerInterface $em, AccompanyingPeriodWorkRepository $workRepository)
{
$this->em = $em;
$this->workRepository = $workRepository;
}
public function __construct(private readonly EntityManagerInterface $em, private readonly AccompanyingPeriodWorkRepository $workRepository) {}
public function persistActionToCourse(Activity $activity)
{
@@ -39,11 +28,11 @@ class ActivityEntityListener
$accompanyingCourseWorks = $this->workRepository->findByAccompanyingPeriod($period);
$periodActions = [];
$now = new DateTimeImmutable();
$now = new \DateTimeImmutable();
foreach ($accompanyingCourseWorks as $key => $work) {
// take only the actions which are still opened
if ($work->getEndDate() === null || $work->getEndDate() > ($activity->getDate() ?? $now)) {
if (null === $work->getEndDate() || $work->getEndDate() > ($activity->getDate() ?? $now)) {
$periodActions[$key] = spl_object_hash($work->getSocialAction());
}
}
@@ -52,14 +41,14 @@ class ActivityEntityListener
$associatedThirdparties = $activity->getThirdParties();
foreach ($activity->getSocialActions() as $action) {
if (in_array(spl_object_hash($action), $periodActions, true)) {
if (\in_array(spl_object_hash($action), $periodActions, true)) {
continue;
}
$newAction = new AccompanyingPeriodWork();
$newAction->setSocialAction($action);
$period->addWork($newAction);
$date = DateTimeImmutable::createFromMutable($activity->getDate());
$date = \DateTimeImmutable::createFromMutable($activity->getDate());
$newAction->setStartDate($date);
foreach ($associatedPersons as $person) {

View File

@@ -27,7 +27,7 @@ class ByActivityNumberAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data): void
{
$qb
->addSelect('(SELECT COUNT(activity.id) FROM ' . Activity::class . ' activity WHERE activity.accompanyingPeriod = acp) AS activity_by_number_aggregator')
->addSelect('(SELECT COUNT(activity.id) FROM '.Activity::class.' activity WHERE activity.accompanyingPeriod = acp) AS activity_by_number_aggregator')
->addGroupBy('activity_by_number_aggregator');
}
@@ -40,6 +40,7 @@ class ByActivityNumberAggregator implements AggregatorInterface
{
// No form needed
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
final readonly class ByActivityTypeAggregator implements AggregatorInterface
{
private const PREFIX = 'acp_by_activity_type_agg';
public function __construct(
private RollingDateConverterInterface $rollingDateConverter,
private ActivityTypeRepositoryInterface $activityTypeRepository,
private TranslatableStringHelperInterface $translatableStringHelper,
) {}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('after_date', PickRollingDateType::class, [
'required' => false,
'label' => 'export.aggregator.acp.by_activity_type.after_date',
])
->add('before_date', PickRollingDateType::class, [
'required' => false,
'label' => 'export.aggregator.acp.by_activity_type.before_date',
]);
}
public function getFormDefaultData(): array
{
return [
'before_date' => null,
'after_date' => null,
];
}
public function getLabels($key, array $values, mixed $data)
{
return function (null|int|string $value): string {
if ('_header' === $value) {
return 'export.aggregator.acp.by_activity_type.activity_type';
}
if ('' === $value || null === $value || null === $activityType = $this->activityTypeRepository->find($value)) {
return '';
}
return $this->translatableStringHelper->localize($activityType->getName());
};
}
public function getQueryKeys($data)
{
return [self::PREFIX.'_actype_id'];
}
public function getTitle()
{
return 'export.aggregator.acp.by_activity_type.title';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
// we make a left join, with acp having at least one activity of the given type
$exists = 'EXISTS (SELECT 1 FROM '.Activity::class." {$p}_activity WHERE {$p}_activity.accompanyingPeriod = acp AND {$p}_activity.activityType = {$p}_activity_type";
if (null !== $data['after_date']) {
$exists .= " AND {$p}_activity.date > :{$p}_after_date";
$qb->setParameter("{$p}_after_date", $this->rollingDateConverter->convert($data['after_date']));
}
if (null !== $data['before_date']) {
$exists .= " AND {$p}_activity.date < :{$p}_before_date";
$qb->setParameter("{$p}_before_date", $this->rollingDateConverter->convert($data['before_date']));
}
$exists .= ')';
$qb->leftJoin(
ActivityType::class,
"{$p}_activity_type",
Join::WITH,
$exists
);
$qb
->addSelect("{$p}_activity_type.id AS {$p}_actype_id")
->addGroupBy("{$p}_actype_id");
}
public function applyOn()
{
return Declarations::ACP_TYPE;
}
}

View File

@@ -17,21 +17,10 @@ use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class BySocialActionAggregator implements AggregatorInterface
{
private SocialActionRender $actionRender;
private SocialActionRepository $actionRepository;
public function __construct(
SocialActionRender $actionRender,
SocialActionRepository $actionRepository
) {
$this->actionRender = $actionRender;
$this->actionRepository = $actionRepository;
}
public function __construct(private readonly SocialActionRender $actionRender, private readonly SocialActionRepository $actionRepository) {}
public function addRole(): ?string
{
@@ -40,7 +29,7 @@ class BySocialActionAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actsocialaction', $qb->getAllAliases(), true)) {
if (!\in_array('actsocialaction', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.socialActions', 'actsocialaction');
}
@@ -57,6 +46,7 @@ class BySocialActionAggregator implements AggregatorInterface
{
// no form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -17,21 +17,10 @@ use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class BySocialIssueAggregator implements AggregatorInterface
{
private SocialIssueRender $issueRender;
private SocialIssueRepository $issueRepository;
public function __construct(
SocialIssueRepository $issueRepository,
SocialIssueRender $issueRender
) {
$this->issueRepository = $issueRepository;
$this->issueRender = $issueRender;
}
public function __construct(private readonly SocialIssueRepository $issueRepository, private readonly SocialIssueRender $issueRender) {}
public function addRole(): ?string
{
@@ -40,7 +29,7 @@ class BySocialIssueAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actsocialissue', $qb->getAllAliases(), true)) {
if (!\in_array('actsocialissue', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.socialIssues', 'actsocialissue');
}
@@ -57,6 +46,7 @@ class BySocialIssueAggregator implements AggregatorInterface
{
// no form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -12,14 +12,9 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\LocationRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
final readonly class ActivityLocationAggregator implements AggregatorInterface
{
@@ -32,7 +27,7 @@ final readonly class ActivityLocationAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actloc', $qb->getAllAliases(), true)) {
if (!\in_array('actloc', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.location', 'actloc');
}
$qb->addSelect(sprintf('actloc.name AS %s', self::KEY));
@@ -48,12 +43,13 @@ final readonly class ActivityLocationAggregator implements AggregatorInterface
{
// no form required for this aggregator
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, $data): Closure
public function getLabels($key, array $values, $data): \Closure
{
return function ($value): string {
if ('_header' === $value) {

View File

@@ -15,26 +15,14 @@ use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ActivityTypeAggregator implements AggregatorInterface
{
public const KEY = 'activity_type_aggregator';
final public const KEY = 'activity_type_aggregator';
protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
ActivityTypeRepositoryInterface $activityTypeRepository,
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->activityTypeRepository = $activityTypeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(protected ActivityTypeRepositoryInterface $activityTypeRepository, protected TranslatableStringHelperInterface $translatableStringHelper) {}
public function addRole(): ?string
{
@@ -43,7 +31,7 @@ class ActivityTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('acttype', $qb->getAllAliases(), true)) {
if (!\in_array('acttype', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.activityType', 'acttype');
}
@@ -60,12 +48,13 @@ class ActivityTypeAggregator implements AggregatorInterface
{
// no form required for this aggregator
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, $data): Closure
public function getLabels($key, array $values, $data): \Closure
{
// for performance reason, we load data from db only once
$this->activityTypeRepository->findBy(['id' => $values]);

View File

@@ -15,25 +15,14 @@ use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Entity\UserRender;
use Closure;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class ActivityUserAggregator implements AggregatorInterface
{
public const KEY = 'activity_user_id';
final public const KEY = 'activity_user_id';
private UserRender $userRender;
private UserRepository $userRepository;
public function __construct(
UserRepository $userRepository,
UserRender $userRender
) {
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function __construct(private readonly UserRepository $userRepository, private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -58,12 +47,13 @@ class ActivityUserAggregator implements AggregatorInterface
{
// nothing to add
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, $values, $data): Closure
public function getLabels($key, $values, $data): \Closure
{
return function ($value) {
if ('_header' === $value) {

View File

@@ -17,19 +17,10 @@ use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Templating\Entity\UserRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ActivityUsersAggregator implements AggregatorInterface
{
private UserRender $userRender;
private UserRepositoryInterface $userRepository;
public function __construct(UserRepositoryInterface $userRepository, UserRender $userRender)
{
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function __construct(private readonly UserRepositoryInterface $userRepository, private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -38,7 +29,7 @@ class ActivityUsersAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actusers', $qb->getAllAliases(), true)) {
if (!\in_array('actusers', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.users', 'actusers');
}
@@ -56,6 +47,7 @@ class ActivityUsersAggregator implements AggregatorInterface
{
// nothing to add on the form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -12,23 +12,22 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\UserJobRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorInterface
class ActivityUsersJobAggregator implements AggregatorInterface
{
private TranslatableStringHelperInterface $translatableStringHelper;
private const PREFIX = 'act_agg_user_job';
private UserJobRepositoryInterface $userJobRepository;
public function __construct(UserJobRepositoryInterface $userJobRepository, TranslatableStringHelperInterface $translatableStringHelper)
{
$this->userJobRepository = $userJobRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -37,24 +36,37 @@ class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorI
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actusers', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.users', 'actusers');
}
$p = self::PREFIX;
$qb
->addSelect('IDENTITY(actusers.userJob) AS activity_users_job_aggregator')
->addGroupBy('activity_users_job_aggregator');
->leftJoin('activity.users', "{$p}_user")
->leftJoin(
UserJobHistory::class,
"{$p}_history",
Expr\Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// job_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->addSelect("IDENTITY({$p}_history.job) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn()
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// nothing to add in the form
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -81,11 +93,11 @@ class ActivityUsersJobAggregator implements \Chill\MainBundle\Export\AggregatorI
public function getQueryKeys($data): array
{
return ['activity_users_job_aggregator'];
return [self::PREFIX.'_select'];
}
public function getTitle()
public function getTitle(): string
{
return 'Aggregate by users job';
return 'export.aggregator.activity.by_user_job.Aggregate by users job';
}
}

View File

@@ -12,23 +12,22 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\AggregatorInterface
class ActivityUsersScopeAggregator implements AggregatorInterface
{
private ScopeRepositoryInterface $scopeRepository;
private const PREFIX = 'act_agg_user_scope';
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(ScopeRepositoryInterface $scopeRepository, TranslatableStringHelperInterface $translatableStringHelper)
{
$this->scopeRepository = $scopeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -37,24 +36,37 @@ class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\Aggregato
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actusers', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.users', 'actusers');
}
$p = self::PREFIX;
$qb
->addSelect('IDENTITY(actusers.mainScope) AS activity_users_main_scope_aggregator')
->addGroupBy('activity_users_main_scope_aggregator');
->leftJoin('activity.users', "{$p}_user")
->leftJoin(
UserScopeHistory::class,
"{$p}_history",
Expr\Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// scope_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn()
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// nothing to add in the form
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -81,11 +93,11 @@ class ActivityUsersScopeAggregator implements \Chill\MainBundle\Export\Aggregato
public function getQueryKeys($data): array
{
return ['activity_users_main_scope_aggregator'];
return [self::PREFIX.'_select'];
}
public function getTitle()
public function getTitle(): string
{
return 'Aggregate by users scope';
return 'export.aggregator.activity.by_user_scope.Aggregate by users scope';
}
}

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
@@ -20,17 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ByCreatorAggregator implements AggregatorInterface
{
private UserRender $userRender;
private UserRepositoryInterface $userRepository;
public function __construct(
UserRepositoryInterface $userRepository,
UserRender $userRender
) {
$this->userRepository = $userRepository;
$this->userRender = $userRender;
}
public function __construct(private readonly UserRepositoryInterface $userRepository, private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -45,13 +35,14 @@ class ByCreatorAggregator implements AggregatorInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
@@ -17,21 +17,10 @@ use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class ByThirdpartyAggregator implements AggregatorInterface
{
private ThirdPartyRender $thirdPartyRender;
private ThirdPartyRepository $thirdPartyRepository;
public function __construct(
ThirdPartyRepository $thirdPartyRepository,
ThirdPartyRender $thirdPartyRender
) {
$this->thirdPartyRepository = $thirdPartyRepository;
$this->thirdPartyRender = $thirdPartyRender;
}
public function __construct(private readonly ThirdPartyRepository $thirdPartyRepository, private readonly ThirdPartyRender $thirdPartyRender) {}
public function addRole(): ?string
{
@@ -40,7 +29,7 @@ class ByThirdpartyAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('acttparty', $qb->getAllAliases(), true)) {
if (!\in_array('acttparty', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.thirdParties', 'acttparty');
}
@@ -50,13 +39,14 @@ class ByThirdpartyAggregator implements AggregatorInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -9,29 +9,25 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class CreatorScopeAggregator implements AggregatorInterface
{
private ScopeRepository $scopeRepository;
private TranslatableStringHelper $translatableStringHelper;
private const PREFIX = 'acp_agg_creator_scope';
public function __construct(
ScopeRepository $scopeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->scopeRepository = $scopeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -40,23 +36,37 @@ class CreatorScopeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actcreator', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.createdBy', 'actcreator');
}
$p = self::PREFIX;
$qb->addSelect('IDENTITY(actcreator.mainScope) AS creatorscope_aggregator');
$qb->addGroupBy('creatorscope_aggregator');
$qb
->leftJoin('activity.createdBy', "{$p}_user")
->leftJoin(
UserScopeHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// scope_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->addSelect("IDENTITY({$p}_history.scope) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -83,11 +93,11 @@ class CreatorScopeAggregator implements AggregatorInterface
public function getQueryKeys($data): array
{
return ['creatorscope_aggregator'];
return [self::PREFIX.'_select'];
}
public function getTitle(): string
{
return 'Group activity by creator scope';
return 'export.aggregator.activity.by_creator_scope.Group activity by creator scope';
}
}

View File

@@ -9,15 +9,13 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class DateAggregator implements AggregatorInterface
{
@@ -56,7 +54,7 @@ class DateAggregator implements AggregatorInterface
break; // order DESC does not works !
default:
throw new RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
throw new \RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
}
$qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt));
@@ -66,7 +64,7 @@ class DateAggregator implements AggregatorInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -75,9 +73,9 @@ class DateAggregator implements AggregatorInterface
'choices' => self::CHOICES,
'multiple' => false,
'expanded' => true,
'empty_data' => self::DEFAULT_CHOICE,
]);
}
public function getFormDefaultData(): array
{
return ['frequency' => self::DEFAULT_CHOICE];
@@ -87,24 +85,16 @@ class DateAggregator implements AggregatorInterface
{
return static function ($value) use ($data): string {
if ('_header' === $value) {
return 'by ' . $data['frequency'];
return 'by '.$data['frequency'];
}
if (null === $value) {
return '';
}
switch ($data['frequency']) {
case 'month':
case 'week':
//return $this->translator->trans('for week') .' '. $value ;
case 'year':
//return $this->translator->trans('in year') .' '. $value ;
default:
return $value;
}
return match ($data['frequency']) {
default => $value,
};
};
}

View File

@@ -0,0 +1,103 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Repository\ScopeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
class JobScopeAggregator implements AggregatorInterface
{
private const PREFIX = 'acp_agg_creator_job';
public function __construct(
private readonly ScopeRepository $scopeRepository,
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin('activity.createdBy', "{$p}_user")
->leftJoin(
UserJobHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// job_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->addSelect("IDENTITY({$p}_history.job) AS {$p}_select")
->addGroupBy("{$p}_select");
}
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, $data)
{
return function ($value): string {
if ('_header' === $value) {
return 'Scope';
}
if (null === $value || '' === $value) {
return '';
}
$s = $this->scopeRepository->find($value);
return $this->translatableStringHelper->localize(
$s->getName()
);
};
}
public function getQueryKeys($data): array
{
return [self::PREFIX.'_select'];
}
public function getTitle(): string
{
return 'export.aggregator.activity.by_creator_job.Group activity by creator job';
}
}

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
@@ -17,21 +17,10 @@ use Chill\MainBundle\Repository\LocationTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class LocationTypeAggregator implements AggregatorInterface
{
private LocationTypeRepository $locationTypeRepository;
private TranslatableStringHelper $translatableStringHelper;
public function __construct(
LocationTypeRepository $locationTypeRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->locationTypeRepository = $locationTypeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(private readonly LocationTypeRepository $locationTypeRepository, private readonly TranslatableStringHelper $translatableStringHelper) {}
public function addRole(): ?string
{
@@ -40,7 +29,7 @@ class LocationTypeAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actloc', $qb->getAllAliases(), true)) {
if (!\in_array('actloc', $qb->getAllAliases(), true)) {
$qb->leftJoin('activity.location', 'actloc');
}
@@ -50,13 +39,14 @@ class LocationTypeAggregator implements AggregatorInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
// no form
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -17,34 +17,15 @@ use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function count;
use function in_array;
class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface
{
protected ActivityReasonCategoryRepository $activityReasonCategoryRepository;
protected ActivityReasonRepository $activityReasonRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
ActivityReasonCategoryRepository $activityReasonCategoryRepository,
ActivityReasonRepository $activityReasonRepository,
TranslatableStringHelper $translatableStringHelper
) {
$this->activityReasonCategoryRepository = $activityReasonCategoryRepository;
$this->activityReasonRepository = $activityReasonRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(protected ActivityReasonCategoryRepository $activityReasonCategoryRepository, protected ActivityReasonRepository $activityReasonRepository, protected TranslatableStringHelper $translatableStringHelper) {}
public function addRole(): ?string
{
@@ -61,20 +42,20 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
$elem = 'actreasoncat.id';
$alias = 'activity_categories_id';
} else {
throw new RuntimeException('The data provided are not recognized.');
throw new \RuntimeException('The data provided are not recognized.');
}
$qb->addSelect($elem . ' as ' . $alias);
$qb->addSelect($elem.' as '.$alias);
// make a jointure only if needed
if (!in_array('actreasons', $qb->getAllAliases(), true)) {
if (!\in_array('actreasons', $qb->getAllAliases(), true)) {
$qb->innerJoin('activity.reasons', 'actreasons');
}
// join category if necessary
if ('activity_categories_id' === $alias) {
// add join only if needed
if (!in_array('actreasoncat', $qb->getAllAliases(), true)) {
if (!\in_array('actreasoncat', $qb->getAllAliases(), true)) {
$qb->join('actreasons.category', 'actreasoncat');
}
}
@@ -82,7 +63,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
// add the "group by" part
$groupBy = $qb->getDQLPart('groupBy');
if (count($groupBy) > 0) {
if (\count($groupBy) > 0) {
$qb->addGroupBy($alias);
} else {
$qb->groupBy($alias);
@@ -110,6 +91,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
]
);
}
public function getFormDefaultData(): array
{
return [];
@@ -117,21 +99,11 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
switch ($data['level']) {
case 'reasons':
$this->activityReasonRepository->findBy(['id' => $values]);
break;
case 'categories':
$this->activityReasonCategoryRepository->findBy(['id' => $values]);
break;
default:
throw new RuntimeException(sprintf("The level data '%s' is invalid.", $data['level']));
}
match ($data['level']) {
'reasons' => $this->activityReasonRepository->findBy(['id' => $values]),
'categories' => $this->activityReasonCategoryRepository->findBy(['id' => $values]),
default => throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level'])),
};
return function ($value) use ($data) {
if ('_header' === $value) {
@@ -171,7 +143,7 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
return ['activity_categories_id'];
}
throw new RuntimeException('The data provided are not recognised.');
throw new \RuntimeException('The data provided are not recognised.');
}
public function getTitle()

View File

@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Tests\Export\Aggregator\PersonsAggregatorTest;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @see PersonsAggregatorTest
*/
final readonly class PersonsAggregator implements AggregatorInterface
{
private const PREFIX = 'act_persons_agg';
public function __construct(private LabelPersonHelper $labelPersonHelper) {}
public function buildForm(FormBuilderInterface $builder)
{
// nothing to add here
}
public function getFormDefaultData(): array
{
return [];
}
public function getLabels($key, array $values, mixed $data)
{
if ($key !== self::PREFIX.'_pid') {
throw new \UnexpectedValueException('this key should not be handled: '.$key);
}
return $this->labelPersonHelper->getLabel($key, $values, 'export.aggregator.activity.by_persons.Persons');
}
public function getQueryKeys($data)
{
return [self::PREFIX.'_pid'];
}
public function getTitle()
{
return 'export.aggregator.activity.by_persons.Group activity by persons';
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin('activity.persons', "{$p}_p")
->addSelect("{$p}_p.id AS {$p}_pid")
->addGroupBy("{$p}_pid");
}
public function applyOn()
{
return Declarations::ACTIVITY;
}
}

View File

@@ -14,18 +14,12 @@ namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\AggregatorInterface;
use Doctrine\ORM\QueryBuilder;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class SentReceivedAggregator implements AggregatorInterface
{
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function __construct(private readonly TranslatorInterface $translator) {}
public function addRole(): ?string
{
@@ -47,6 +41,7 @@ class SentReceivedAggregator implements AggregatorInterface
{
// No form needed
}
public function getFormDefaultData(): array
{
return [];
@@ -71,7 +66,7 @@ class SentReceivedAggregator implements AggregatorInterface
return $this->translator->trans('export.aggregator.activity.by_sent_received.is received');
default:
throw new LogicException(sprintf('The value %s is not valid', $value));
throw new \LogicException(sprintf('The value %s is not valid', $value));
}
};
}

View File

@@ -16,9 +16,9 @@ namespace Chill\ActivityBundle\Export;
*/
abstract class Declarations
{
public const ACTIVITY = 'activity';
final public const ACTIVITY = 'activity';
public const ACTIVITY_ACP = 'activity_linked_to_acp';
final public const ACTIVITY_ACP = 'activity_linked_to_acp';
public const ACTIVITY_PERSON = 'activity_linked_to_person';
final public const ACTIVITY_PERSON = 'activity_linked_to_person';
}

View File

@@ -11,32 +11,33 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class AvgActivityDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em
private readonly ActivityRepository $activityRepository,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -60,7 +61,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
if ('export_avg_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period duration' : $value;
@@ -90,23 +91,27 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
{
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository->createQueryBuilder('activity');
$qb = $this->activityRepository->createQueryBuilder('activity');
$qb
->join('activity.accompanyingPeriod', 'acp')
->select('AVG(activity.durationTime) as export_avg_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}

View File

@@ -14,6 +14,7 @@ namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
@@ -23,23 +24,28 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em
EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getFormDefaultData(): array
{
return [];
@@ -63,7 +69,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function getLabels($key, array $values, $data)
{
if ('export_avg_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period visit duration' : $value;
@@ -100,16 +106,20 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
->select('AVG(activity.travelTime) as export_avg_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}

View File

@@ -14,6 +14,7 @@ namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
@@ -23,20 +24,25 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountActivity implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em
EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -60,7 +66,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
if ('export_count_activity' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Number of activities linked to an accompanying period' : $value;
@@ -94,16 +100,20 @@ class CountActivity implements ExportInterface, GroupedExportInterface
->createQueryBuilder('activity')
->join('activity.accompanyingPeriod', 'acp');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
$qb->select('COUNT(DISTINCT activity.id) as export_count_activity');

View File

@@ -12,38 +12,37 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Export\Export\ListActivityHelper;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class ListActivity implements ListInterface, GroupedExportInterface
{
private EntityManagerInterface $entityManager;
private ListActivityHelper $helper;
private TranslatableStringExportLabelHelper $translatableStringExportLabelHelper;
private readonly bool $filterStatsByCenters;
public function __construct(
ListActivityHelper $helper,
EntityManagerInterface $entityManager,
TranslatableStringExportLabelHelper $translatableStringExportLabelHelper
private readonly ListActivityHelper $helper,
private readonly EntityManagerInterface $entityManager,
private readonly TranslatableStringExportLabelHelper $translatableStringExportLabelHelper,
ParameterBagInterface $parameterBag,
) {
$this->helper = $helper;
$this->entityManager = $entityManager;
$this->translatableStringExportLabelHelper = $translatableStringExportLabelHelper;
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
$this->helper->buildForm($builder);
}
public function getFormDefaultData(): array
{
return [];
@@ -56,7 +55,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
public function getDescription()
{
return ListActivityHelper::MSG_KEY . 'List activities linked to an accompanying course';
return ListActivityHelper::MSG_KEY.'List activities linked to an accompanying course';
}
public function getGroup(): string
@@ -66,22 +65,17 @@ class ListActivity implements ListInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
switch ($key) {
case 'acpId':
return static function ($value) {
return match ($key) {
'acpId' => static function ($value) {
if ('_header' === $value) {
return ListActivityHelper::MSG_KEY . 'accompanying course id';
return ListActivityHelper::MSG_KEY.'accompanying course id';
}
return $value ?? '';
},
'scopesNames' => $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY.'course circles'),
default => $this->helper->getLabels($key, $values, $data),
};
case 'scopesNames':
return $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY . 'course circles');
default:
return $this->helper->getLabels($key, $values, $data);
}
}
public function getQueryKeys($data)
@@ -103,7 +97,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
public function getTitle()
{
return ListActivityHelper::MSG_KEY . 'List activity linked to a course';
return ListActivityHelper::MSG_KEY.'List activity linked to a course';
}
public function getType()
@@ -123,30 +117,38 @@ class ListActivity implements ListInterface, GroupedExportInterface
->join('activity.accompanyingPeriod', 'acp')
->leftJoin('acp.participations', 'acppart')
->leftJoin('acppart.person', 'person')
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL')
->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL');
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1
FROM ' . PersonCenterHistory::class . ' acl_count_person_history
FROM '.PersonCenterHistory::class.' acl_count_person_history
WHERE acl_count_person_history.person = person
AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
$qb
// some grouping are necessary
->addGroupBy('acp.id')
->addOrderBy('activity.date')
->addOrderBy('activity.id')
->setParameter('authorized_centers', $centers);
->addOrderBy('activity.id');
$this->helper->addSelect($qb);
// add select for this step
$qb
->addSelect('acp.id AS acpId')
->addSelect('(SELECT AGGREGATE(acpScope.name) FROM ' . Scope::class . ' acpScope WHERE acpScope MEMBER OF acp.scopes) AS scopesNames')
->addSelect('(SELECT AGGREGATE(acpScope.name) FROM '.Scope::class.' acpScope WHERE acpScope MEMBER OF acp.scopes) AS scopesNames')
->addGroupBy('scopesNames');
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}
@@ -160,6 +162,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return array_merge(
$this->helper->supportsModifiers(),
[
Declarations::ACTIVITY,
\Chill\PersonBundle\Export\Declarations::ACP_TYPE,
]
);

View File

@@ -14,6 +14,7 @@ namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
@@ -23,23 +24,27 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class SumActivityDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em
EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getFormDefaultData(): array
{
return [];
@@ -63,7 +68,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
if ('export_sum_activity_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period duration' : $value;
@@ -100,16 +105,20 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration')
->andWhere($qb->expr()->isNotNull('activity.durationTime'));
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}

View File

@@ -14,6 +14,7 @@ namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AccompanyingCourseExportHelper;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
@@ -23,23 +24,27 @@ use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class SumActivityVisitDuration implements ExportInterface, GroupedExportInterface
{
protected EntityRepository $repository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em
EntityManagerInterface $em,
ParameterBagInterface $parameterBag,
) {
$this->repository = $em->getRepository(Activity::class);
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}
public function getFormDefaultData(): array
{
return [];
@@ -63,7 +68,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function getLabels($key, array $values, $data)
{
if ('export_sum_activity_visit_duration' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period visit duration' : $value;
@@ -100,16 +105,20 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration')
->andWhere($qb->expr()->isNotNull('activity.travelTime'));
if ($this->filterStatsByCenters) {
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . AccompanyingPeriodParticipation::class . ' acl_count_part
JOIN ' . PersonCenterHistory::class . ' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
'SELECT 1 FROM '.AccompanyingPeriodParticipation::class.' acl_count_part
JOIN '.PersonCenterHistory::class.' acl_count_person_history WITH IDENTITY(acl_count_person_history.person) = IDENTITY(acl_count_part.person)
WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers)
'
)
)
->setParameter('authorized_centers', $centers);
}
AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb);
return $qb;
}

View File

@@ -19,20 +19,22 @@ use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
class CountActivity implements ExportInterface, GroupedExportInterface
{
protected ActivityRepository $activityRepository;
private readonly bool $filterStatsByCenters;
public function __construct(
ActivityRepository $activityRepository
private readonly ActivityRepository $activityRepository,
ParameterBagInterface $parameterBag,
) {
$this->activityRepository = $activityRepository;
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -56,7 +58,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
if ('export_count_activity' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
throw new \LogicException("the key {$key} is not used by this export");
}
return static fn ($value) => '_header' === $value ? 'Number of activities linked to a person' : $value;
@@ -88,12 +90,13 @@ class CountActivity implements ExportInterface, GroupedExportInterface
$qb = $this->activityRepository
->createQueryBuilder('activity')
->join('activity.person', 'person')
->join('person.centerHistory', 'centerHistory');
->join('activity.person', 'person');
$qb->select('COUNT(activity.id) as export_count_activity');
if ($this->filterStatsByCenters) {
$qb
->join('person.centerHistory', 'centerHistory')
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
@@ -105,6 +108,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
return $qb;
}

View File

@@ -20,24 +20,18 @@ use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use DateTime;
use Doctrine\DBAL\Exception\InvalidArgumentException;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
use function count;
use function in_array;
class ListActivity implements ListInterface, GroupedExportInterface
{
protected EntityManagerInterface $entityManager;
protected array $fields = [
'id',
'date',
@@ -51,23 +45,16 @@ class ListActivity implements ListInterface, GroupedExportInterface
'person_lastname',
'person_id',
];
protected TranslatableStringHelperInterface $translatableStringHelper;
protected TranslatorInterface $translator;
private ActivityRepository $activityRepository;
private readonly bool $filterStatsByCenters;
public function __construct(
EntityManagerInterface $em,
TranslatorInterface $translator,
TranslatableStringHelperInterface $translatableStringHelper,
ActivityRepository $activityRepository
protected EntityManagerInterface $entityManager,
protected TranslatorInterface $translator,
protected TranslatableStringHelperInterface $translatableStringHelper,
private readonly ActivityRepository $activityRepository,
ParameterBagInterface $parameterBag,
) {
$this->entityManager = $em;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
$this->activityRepository = $activityRepository;
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder)
@@ -79,7 +66,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
'label' => 'Fields to include in export',
'constraints' => [new Callback([
'callback' => static function ($selected, ExecutionContextInterface $context) {
if (count($selected) === 0) {
if (0 === \count($selected)) {
$context->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
@@ -88,6 +75,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
])],
]);
}
public function getFormDefaultData(): array
{
return [];
@@ -117,7 +105,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return 'date';
}
$date = DateTime::createFromFormat('Y-m-d H:i:s', $value);
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value);
return $date->format('d-m-Y');
};
@@ -141,11 +129,11 @@ class ListActivity implements ListInterface, GroupedExportInterface
$activity = $activityRepository->find($value);
return implode(', ', array_map(fn (ActivityReason $r) => '"' .
return implode(', ', array_map(fn (ActivityReason $r) => '"'.
$this->translatableStringHelper->localize($r->getCategory()->getName())
. ' > ' .
.' > '.
$this->translatableStringHelper->localize($r->getName())
. '"', $activity->getReasons()->toArray()));
.'"', $activity->getReasons()->toArray()));
};
case 'circle_name':
@@ -154,7 +142,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return 'circle';
}
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
return $this->translatableStringHelper->localize(json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR));
};
case 'type_name':
@@ -163,7 +151,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return 'activity type';
}
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
return $this->translatableStringHelper->localize(json_decode((string) $value, true, 512, JSON_THROW_ON_ERROR));
};
default:
@@ -202,7 +190,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
$centers = array_map(static fn ($el) => $el['center'], $acl);
// throw an error if any fields are present
if (!array_key_exists('fields', $data)) {
if (!\array_key_exists('fields', $data)) {
throw new InvalidArgumentException('Any fields have been checked.');
}
@@ -210,9 +198,10 @@ class ListActivity implements ListInterface, GroupedExportInterface
$qb
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'actperson')
->join('actperson.centerHistory', 'centerHistory');
->join('activity.person', 'actperson');
if ($this->filterStatsByCenters) {
$qb->join('actperson.centerHistory', 'centerHistory');
$qb->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
@@ -224,9 +213,10 @@ class ListActivity implements ListInterface, GroupedExportInterface
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
foreach ($this->fields as $f) {
if (in_array($f, $data['fields'], true)) {
if (\in_array($f, $data['fields'], true)) {
switch ($f) {
case 'id':
$qb->addSelect('activity.id AS id');
@@ -299,7 +289,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE,
PersonDeclarations::PERSON_TYPE,
];
}
}

View File

@@ -20,7 +20,7 @@ use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\FormBuilderInterface;
/**
@@ -30,27 +30,25 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
class StatActivityDuration implements ExportInterface, GroupedExportInterface
{
public const SUM = 'sum';
/**
* The action for this report.
*/
protected string $action;
private ActivityRepository $activityRepository;
final public const SUM = 'sum';
private readonly bool $filterStatsByCenters;
/**
* @param string $action the stat to perform
*/
public function __construct(
ActivityRepository $activityRepository,
string $action = 'sum'
private readonly ActivityRepository $activityRepository,
ParameterBagInterface $parameterBag,
/**
* The action for this report.
*/
protected string $action = 'sum'
) {
$this->action = $action;
$this->activityRepository = $activityRepository;
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder) {}
public function getFormDefaultData(): array
{
return [];
@@ -67,7 +65,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
return 'Sum activities linked to a person duration by various parameters.';
}
throw new LogicException('this action is not supported: ' . $this->action);
throw new \LogicException('this action is not supported: '.$this->action);
}
public function getGroup(): string
@@ -78,7 +76,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
public function getLabels($key, array $values, $data)
{
if ('export_stat_activity' !== $key) {
throw new LogicException(sprintf('The key %s is not used by this export', $key));
throw new \LogicException(sprintf('The key %s is not used by this export', $key));
}
$header = self::SUM === $this->action ? 'Sum activities linked to a person duration' : false;
@@ -102,7 +100,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
return 'Sum activity linked to a person duration';
}
throw new LogicException('This action is not supported: ' . $this->action);
throw new \LogicException('This action is not supported: '.$this->action);
}
public function getType(): string
@@ -126,10 +124,11 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
}
$qb->select($select)
->join('activity.person', 'person')
->join('person.centerHistory', 'centerHistory');
->join('activity.person', 'person');
if ($this->filterStatsByCenters) {
$qb
->join('person.centerHistory', 'centerHistory')
->where(
$qb->expr()->andX(
$qb->expr()->lte('centerHistory.startDate', 'activity.date'),
@@ -141,6 +140,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
)
->andWhere($qb->expr()->in('centerHistory.center', ':centers'))
->setParameter('centers', $centers);
}
return $qb;
}
@@ -155,7 +155,7 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface
return [
Declarations::ACTIVITY,
Declarations::ACTIVITY_PERSON,
//PersonDeclarations::PERSON_TYPE,
PersonDeclarations::PERSON_TYPE,
];
}
}

View File

@@ -23,54 +23,24 @@ use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use LogicException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use const SORT_NUMERIC;
class ListActivityHelper
{
public const MSG_KEY = 'export.list.activity.';
private ActivityPresenceRepositoryInterface $activityPresenceRepository;
private ActivityTypeRepositoryInterface $activityTypeRepository;
private DateTimeHelper $dateTimeHelper;
private LabelPersonHelper $labelPersonHelper;
private LabelThirdPartyHelper $labelThirdPartyHelper;
private TranslatableStringHelperInterface $translatableStringHelper;
private TranslatableStringExportLabelHelper $translatableStringLabelHelper;
private TranslatorInterface $translator;
private UserHelper $userHelper;
final public const MSG_KEY = 'export.list.activity.';
public function __construct(
ActivityPresenceRepositoryInterface $activityPresenceRepository,
ActivityTypeRepositoryInterface $activityTypeRepository,
DateTimeHelper $dateTimeHelper,
LabelPersonHelper $labelPersonHelper,
LabelThirdPartyHelper $labelThirdPartyHelper,
TranslatorInterface $translator,
TranslatableStringHelperInterface $translatableStringHelper,
TranslatableStringExportLabelHelper $translatableStringLabelHelper,
UserHelper $userHelper
) {
$this->activityPresenceRepository = $activityPresenceRepository;
$this->activityTypeRepository = $activityTypeRepository;
$this->dateTimeHelper = $dateTimeHelper;
$this->labelPersonHelper = $labelPersonHelper;
$this->labelThirdPartyHelper = $labelThirdPartyHelper;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
$this->translatableStringLabelHelper = $translatableStringLabelHelper;
$this->userHelper = $userHelper;
}
private readonly ActivityPresenceRepositoryInterface $activityPresenceRepository,
private readonly ActivityTypeRepositoryInterface $activityTypeRepository,
private readonly DateTimeHelper $dateTimeHelper,
private readonly LabelPersonHelper $labelPersonHelper,
private readonly LabelThirdPartyHelper $labelThirdPartyHelper,
private readonly TranslatorInterface $translator,
private readonly TranslatableStringHelperInterface $translatableStringHelper,
private readonly TranslatableStringExportLabelHelper $translatableStringLabelHelper,
private readonly UserHelper $userHelper
) {}
public function addSelect(QueryBuilder $qb): void
{
@@ -85,7 +55,7 @@ class ListActivityHelper
->addSelect('AGGREGATE(actPerson.id) AS personsNames')
->leftJoin('activity.users', 'users_u')
->addSelect('AGGREGATE(users_u.id) AS usersIds')
->addSelect('AGGREGATE(users_u.id) AS usersNames')
->addSelect('AGGREGATE(JSON_BUILD_OBJECT(\'uid\', users_u.id, \'d\', activity.date)) AS usersNames')
->leftJoin('activity.thirdParties', 'thirdparty')
->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesIds')
->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesNames')
@@ -96,9 +66,9 @@ class ListActivityHelper
->leftJoin('activity.location', 'location')
->addSelect('location.name AS locationName')
->addSelect('activity.sentReceived')
->addSelect('IDENTITY(activity.createdBy) AS createdBy')
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.createdBy), \'d\', activity.createdAt) AS createdBy')
->addSelect('activity.createdAt')
->addSelect('IDENTITY(activity.updatedBy) AS updatedBy')
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.updatedBy), \'d\', activity.updatedAt) AS updatedBy')
->addSelect('activity.updatedAt')
->addGroupBy('activity.id')
->addGroupBy('location.id');
@@ -113,20 +83,11 @@ class ListActivityHelper
public function getLabels($key, array $values, $data)
{
switch ($key) {
case 'createdAt':
case 'updatedAt':
return $this->dateTimeHelper->getLabel($key);
case 'createdBy':
case 'updatedBy':
return $this->userHelper->getLabel($key, $values, $key);
case 'date':
return $this->dateTimeHelper->getLabel(self::MSG_KEY . $key);
case 'attendeeName':
return function ($value) {
return match ($key) {
'createdAt', 'updatedAt' => $this->dateTimeHelper->getLabel($key),
'createdBy', 'updatedBy' => $this->userHelper->getLabel($key, $values, $key),
'date' => $this->dateTimeHelper->getLabel(self::MSG_KEY.$key),
'attendeeName' => function ($value) {
if ('_header' === $value) {
return 'Attendee';
}
@@ -136,13 +97,9 @@ class ListActivityHelper
}
return $this->translatableStringHelper->localize($presence->getName());
};
case 'listReasons':
return $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons');
case 'typeName':
return function ($value) {
},
'listReasons' => $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons'),
'typeName' => function ($value) {
if ('_header' === $value) {
return 'Activity type';
}
@@ -152,52 +109,32 @@ class ListActivityHelper
}
return $this->translatableStringHelper->localize($type->getName());
};
case 'usersNames':
return $this->userHelper->getLabelMulti($key, $values, self::MSG_KEY . 'users name');
case 'usersIds':
case 'thirdPartiesIds':
case 'personsIds':
return static function ($value) use ($key) {
},
'usersNames' => $this->userHelper->getLabelMulti($key, $values, self::MSG_KEY.'users name'),
'usersIds', 'thirdPartiesIds', 'personsIds' => static function ($value) use ($key) {
if ('_header' === $value) {
switch ($key) {
case 'usersIds':
return self::MSG_KEY . 'users ids';
case 'thirdPartiesIds':
return self::MSG_KEY . 'third parties ids';
case 'personsIds':
return self::MSG_KEY . 'persons ids';
default:
throw new LogicException('key not supported');
}
return match ($key) {
'usersIds' => self::MSG_KEY.'users ids',
'thirdPartiesIds' => self::MSG_KEY.'third parties ids',
'personsIds' => self::MSG_KEY.'persons ids',
};
}
$decoded = json_decode($value, null, 512, JSON_THROW_ON_ERROR);
$decoded = json_decode((string) $value, null, 512, JSON_THROW_ON_ERROR);
return implode(
'|',
array_unique(
array_filter($decoded, static fn (?int $id) => null !== $id),
SORT_NUMERIC
\SORT_NUMERIC
)
);
};
case 'personsNames':
return $this->labelPersonHelper->getLabelMulti($key, $values, self::MSG_KEY . 'persons name');
case 'thirdPartiesNames':
return $this->labelThirdPartyHelper->getLabelMulti($key, $values, self::MSG_KEY . 'thirds parties');
case 'sentReceived':
return function ($value) {
},
'personsNames' => $this->labelPersonHelper->getLabelMulti($key, $values, self::MSG_KEY.'persons name'),
'thirdPartiesNames' => $this->labelThirdPartyHelper->getLabelMulti($key, $values, self::MSG_KEY.'thirds parties'),
'sentReceived' => function ($value) {
if ('_header' === $value) {
return self::MSG_KEY . 'sent received';
return self::MSG_KEY.'sent received';
}
if (null === $value) {
@@ -205,12 +142,10 @@ class ListActivityHelper
}
return $this->translator->trans($value);
};
default:
return function ($value) use ($key) {
},
default => function ($value) use ($key) {
if ('_header' === $value) {
return self::MSG_KEY . $key;
return self::MSG_KEY.$key;
}
if (null === $value) {
@@ -218,9 +153,9 @@ class ListActivityHelper
}
return $this->translator->trans($value);
},
};
}
}
public function getQueryKeys($data)
{

View File

@@ -23,17 +23,10 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityTypeFilter implements FilterInterface
{
private ActivityTypeRepositoryInterface $activityTypeRepository;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
ActivityTypeRepositoryInterface $activityTypeRepository,
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->activityTypeRepository = $activityTypeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
private readonly ActivityTypeRepositoryInterface $activityTypeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -44,7 +37,7 @@ class ActivityTypeFilter implements FilterInterface
{
$qb->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . Activity::class . ' act_type_filter_activity
'SELECT 1 FROM '.Activity::class.' act_type_filter_activity
WHERE act_type_filter_activity.activityType IN (:act_type_filter_activity_types) AND act_type_filter_activity.accompanyingPeriod = acp'
)
);
@@ -61,13 +54,14 @@ class ActivityTypeFilter implements FilterInterface
$builder->add('accepted_activitytypes', EntityType::class, [
'class' => ActivityType::class,
'choices' => $this->activityTypeRepository->findAllActive(),
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()).' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName()),
'multiple' => true,
'expanded' => true,
]);
}
public function getFormDefaultData(): array
{
return [];
@@ -81,7 +75,7 @@ class ActivityTypeFilter implements FilterInterface
$types[] = $this->translatableStringHelper->localize($aty->getName());
}
return ['Filtered by activity types: only %activitytypes%', [
return ['export.filter.activity.acp_by_activity_type.acp_containing_at_least_one_%activitytypes%', [
'%activitytypes%' => implode(', ', $types),
]];
}

View File

@@ -18,16 +18,10 @@ use Chill\PersonBundle\Form\Type\PickSocialActionType;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class BySocialActionFilter implements FilterInterface
{
private SocialActionRender $actionRender;
public function __construct(SocialActionRender $actionRender)
{
$this->actionRender = $actionRender;
}
public function __construct(private readonly SocialActionRender $actionRender) {}
public function addRole(): ?string
{
@@ -36,7 +30,7 @@ class BySocialActionFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actsocialaction', $qb->getAllAliases(), true)) {
if (!\in_array('actsocialaction', $qb->getAllAliases(), true)) {
$qb->join('activity.socialActions', 'actsocialaction');
}
@@ -60,6 +54,7 @@ class BySocialActionFilter implements FilterInterface
'multiple' => true,
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -18,16 +18,10 @@ use Chill\PersonBundle\Form\Type\PickSocialIssueType;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class BySocialIssueFilter implements FilterInterface
{
private SocialIssueRender $issueRender;
public function __construct(SocialIssueRender $issueRender)
{
$this->issueRender = $issueRender;
}
public function __construct(private readonly SocialIssueRender $issueRender) {}
public function addRole(): ?string
{
@@ -36,7 +30,7 @@ class BySocialIssueFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actsocialissue', $qb->getAllAliases(), true)) {
if (!\in_array('actsocialissue', $qb->getAllAliases(), true)) {
$qb->join('activity.socialIssues', 'actsocialissue');
}
@@ -60,6 +54,7 @@ class BySocialIssueFilter implements FilterInterface
'multiple' => true,
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -17,6 +17,9 @@ use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
/**
* Filter accompanying periods to keep only the one without any activity.
*/
class HasNoActivityFilter implements FilterInterface
{
public function addRole(): ?string
@@ -29,7 +32,7 @@ class HasNoActivityFilter implements FilterInterface
$qb
->andWhere('
NOT EXISTS (
SELECT 1 FROM ' . Activity::class . ' activity
SELECT 1 FROM '.Activity::class.' activity
WHERE activity.accompanyingPeriod = acp
)
');
@@ -42,8 +45,9 @@ class HasNoActivityFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder)
{
//no form needed
// no form needed
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -34,10 +34,10 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
{
$builder
->add('start_date', PickRollingDateType::class, [
'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity after'
'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity after',
])
->add('end_date', PickRollingDateType::class, [
'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity before'
'label' => 'export.filter.activity.course_having_activity_between_date.Receiving an activity before',
]);
}
@@ -45,7 +45,7 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
{
return [
'start_date' => new RollingDate(RollingDate::T_YEAR_CURRENT_START),
'end_date' => new RollingDate(RollingDate::T_TODAY)
'end_date' => new RollingDate(RollingDate::T_TODAY),
];
}
@@ -56,7 +56,7 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
[
'from' => $this->rollingDateConverter->convert($data['start_date']),
'to' => $this->rollingDateConverter->convert($data['end_date']),
]
],
];
}
@@ -73,7 +73,7 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
$qb->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . Activity::class . " {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = acp"
'SELECT 1 FROM '.Activity::class." {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = acp"
)
);

View File

@@ -1,98 +0,0 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class UserScopeFilter implements FilterInterface
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actuser', $qb->getAllAliases(), true)) {
$qb->join('activity.user', 'actuser');
}
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('actuser.mainScope', ':userscope');
if ($where instanceof Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('userscope', $data['accepted_userscope']);
}
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_userscope', EntityType::class, [
'class' => Scope::class,
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
$s->getName()
),
'multiple' => true,
'expanded' => true,
]);
}
public function getFormDefaultData(): array
{
return [];
}
public function describeAction($data, $format = 'string'): array
{
$scopes = [];
foreach ($data['accepted_userscope'] as $s) {
$scopes[] = $this->translatableStringHelper->localize(
$s->getName()
);
}
return ['Filtered activity by userscope: only %scopes%', [
'%scopes%' => implode(', ', $scopes),
]];
}
public function getTitle(): string
{
return 'Filter activity by userscope';
}
}

View File

@@ -27,17 +27,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class ActivityDateFilter implements FilterInterface
{
protected TranslatorInterface $translator;
private RollingDateConverterInterface $rollingDateConverter;
public function __construct(
TranslatorInterface $translator,
RollingDateConverterInterface $rollingDateConverter
) {
$this->translator = $translator;
$this->rollingDateConverter = $rollingDateConverter;
}
public function __construct(protected TranslatorInterface $translator, private readonly RollingDateConverterInterface $rollingDateConverter) {}
public function addRole(): ?string
{
@@ -100,14 +90,14 @@ class ActivityDateFilter implements FilterInterface
if (null === $date_from) {
$form->get('date_from')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
.'should not be empty')
));
}
if (null === $date_to) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
.'should not be empty')
));
}
@@ -118,13 +108,14 @@ class ActivityDateFilter implements FilterInterface
) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This date should be after '
. 'the date given in "Implied in an activity after '
. 'this date" field')
.'the date given in "Implied in an activity after '
.'this date" field')
));
}
}
});
}
public function getFormDefaultData(): array
{
return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)];

View File

@@ -22,21 +22,12 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function count;
class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInterface
{
protected ActivityTypeRepositoryInterface $activityTypeRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
TranslatableStringHelperInterface $translatableStringHelper,
ActivityTypeRepositoryInterface $activityTypeRepository
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->activityTypeRepository = $activityTypeRepository;
}
protected TranslatableStringHelperInterface $translatableStringHelper,
protected ActivityTypeRepositoryInterface $activityTypeRepository
) {}
public function addRole(): ?string
{
@@ -61,7 +52,7 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
$builder->add('types', EntityType::class, [
'choices' => $this->activityTypeRepository->findAllActive(),
'class' => ActivityType::class,
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()).' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName()),
'group_by' => function (ActivityType $type) {
@@ -78,6 +69,7 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
],
]);
}
public function getFormDefaultData(): array
{
return [];
@@ -103,7 +95,7 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['types'] || count($data['types']) === 0) {
if (null === $data['types'] || 0 === \count($data['types'])) {
$context
->buildViolation('At least one type must be chosen')
->addViolation();

View File

@@ -20,12 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityUsersFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function __construct(private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -37,8 +32,8 @@ class ActivityUsersFilter implements FilterInterface
$orX = $qb->expr()->orX();
foreach ($data['accepted_users'] as $key => $user) {
$orX->add($qb->expr()->isMemberOf(':activity_users_filter_u' . $key, 'activity.users'));
$qb->setParameter('activity_users_filter_u' . $key, $user);
$orX->add($qb->expr()->isMemberOf(':activity_users_filter_u'.$key, 'activity.users'));
$qb->setParameter('activity_users_filter_u'.$key, $user);
}
$qb->andWhere($orX);
@@ -56,6 +51,7 @@ class ActivityUsersFilter implements FilterInterface
'label' => 'Users',
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
@@ -20,12 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ByCreatorFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function __construct(private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -43,7 +38,7 @@ class ByCreatorFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -52,6 +47,7 @@ class ByCreatorFilter implements FilterInterface
'multiple' => true,
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
class CreatorScopeFilter implements FilterInterface
{
private const PREFIX = 'acp_act_filter_creator_scope';
public function __construct(
private readonly TranslatableStringHelper $translatableStringHelper
) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->leftJoin('activity.createdBy', "{$p}_user")
->leftJoin(
UserScopeHistory::class,
"{$p}_history",
Join::WITH,
$qb->expr()->eq("{$p}_history.user", "{$p}_user")
)
// scope_at based on activity.date
->andWhere(
$qb->expr()->andX(
$qb->expr()->lte("{$p}_history.startDate", 'activity.date'),
$qb->expr()->orX(
$qb->expr()->isNull("{$p}_history.endDate"),
$qb->expr()->gt("{$p}_history.endDate", 'activity.date')
)
)
)
->andWhere(
$qb->expr()->in("{$p}_history.scope", ":{$p}_scopes")
)
->setParameter(
"{$p}_scopes",
$data['scopes'],
);
}
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('scopes', EntityType::class, [
'class' => Scope::class,
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
$s->getName()
),
'multiple' => true,
'expanded' => true,
]);
}
public function describeAction($data, $format = 'string'): array
{
$scopes = [];
foreach ($data['scopes'] as $s) {
$scopes[] = $this->translatableStringHelper->localize(
$s->getName()
);
}
return ['export.filter.activity.by_creator_scope.Filtered activity by user scope: only %scopes%', [
'%scopes%' => implode(', ', $scopes),
]];
}
public function getFormDefaultData(): array
{
return [
'scopes' => [],
];
}
public function getTitle(): string
{
return 'export.filter.activity.by_creator_scope.Filter activity by user scope';
}
}

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
@@ -28,12 +28,7 @@ class EmergencyFilter implements FilterInterface
private const DEFAULT_CHOICE = 'false';
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function __construct(private readonly TranslatorInterface $translator) {}
public function addRole(): ?string
{
@@ -58,7 +53,7 @@ class EmergencyFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -70,6 +65,7 @@ class EmergencyFilter implements FilterInterface
'empty_data' => self::DEFAULT_CHOICE,
]);
}
public function getFormDefaultData(): array
{
return ['accepted_emergency' => self::DEFAULT_CHOICE];

View File

@@ -9,12 +9,11 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\PickUserLocationType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
@@ -36,7 +35,7 @@ class LocationFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -46,6 +45,7 @@ class LocationFilter implements FilterInterface
'label' => 'pick location',
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
@@ -18,16 +18,10 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use function in_array;
class LocationTypeFilter implements FilterInterface
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(private readonly TranslatableStringHelper $translatableStringHelper) {}
public function addRole(): ?string
{
@@ -36,7 +30,7 @@ class LocationTypeFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
if (!in_array('actloc', $qb->getAllAliases(), true)) {
if (!\in_array('actloc', $qb->getAllAliases(), true)) {
$qb->join('activity.location', 'actloc');
}
@@ -55,16 +49,17 @@ class LocationTypeFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_locationtype', PickLocationTypeType::class, [
'multiple' => true,
//'label' => false,
// 'label' => false,
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -17,29 +17,15 @@ use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function count;
use function in_array;
class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInterface
{
protected ActivityReasonRepository $activityReasonRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
TranslatableStringHelper $helper,
ActivityReasonRepository $activityReasonRepository
) {
$this->translatableStringHelper = $helper;
$this->activityReasonRepository = $activityReasonRepository;
}
public function __construct(protected TranslatableStringHelper $translatableStringHelper, protected ActivityReasonRepository $activityReasonRepository) {}
public function addRole(): ?string
{
@@ -52,7 +38,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
$join = $qb->getDQLPart('join');
$clause = $qb->expr()->in('actreasons', ':selected_activity_reasons');
if (!in_array('actreasons', $qb->getAllAliases(), true)) {
if (!\in_array('actreasons', $qb->getAllAliases(), true)) {
$qb->join('activity.reasons', 'actreasons');
}
@@ -82,6 +68,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
'expanded' => false,
]);
}
public function getFormDefaultData(): array
{
return [];
@@ -91,7 +78,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
fn (ActivityReason $r): string => '"'.$this->translatableStringHelper->localize($r->getName()).'"',
$this->activityReasonRepository->findBy(['id' => $data['reasons']->toArray()])
);
@@ -110,7 +97,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
if (null === $data['reasons'] || 0 === \count($data['reasons'])) {
$context
->buildViolation('At least one reason must be chosen')
->addViolation();

View File

@@ -16,42 +16,23 @@ use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Chill\MainBundle\Form\Type\PickRollingDateType;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInterface, FilterInterface
final readonly class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInterface, FilterInterface
{
protected ActivityReasonRepository $activityReasonRepository;
protected TranslatableStringHelperInterface $translatableStringHelper;
protected TranslatorInterface $translator;
public function __construct(
TranslatableStringHelper $translatableStringHelper,
ActivityReasonRepository $activityReasonRepository,
TranslatorInterface $translator
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->activityReasonRepository = $activityReasonRepository;
$this->translator = $translator;
}
private TranslatableStringHelper $translatableStringHelper,
private ActivityReasonRepository $activityReasonRepository,
private RollingDateConverterInterface $rollingDateConverter,
) {}
public function addRole(): ?string
{
@@ -62,16 +43,19 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
{
// create a subquery for activity
$sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select('person_person_having_activity.id')
$sqb->select('1')
->from(Activity::class, 'activity_person_having_activity')
->join('activity_person_having_activity.person', 'person_person_having_activity');
->leftJoin('activity_person_having_activity.person', 'person_person_having_activity');
// add clause between date
$sqb->where('activity_person_having_activity.date BETWEEN '
. ':person_having_activity_between_date_from'
. ' AND '
. ':person_having_activity_between_date_to');
.':person_having_activity_between_date_from'
.' AND '
.':person_having_activity_between_date_to'
.' AND '
.'(person_person_having_activity.id = person.id OR person MEMBER OF activity_person_having_activity.persons)');
if (isset($data['reasons']) && [] !== $data['reasons']) {
// add clause activity reason
$sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
@@ -82,114 +66,74 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
)
);
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('person.id', $sqb->getDQL());
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
$qb->setParameter('person_having_activity_reasons', $data['reasons']);
}
$qb->add('where', $where);
$qb->andWhere(
$qb->expr()->exists($sqb->getDQL())
);
$qb->setParameter(
'person_having_activity_between_date_from',
$data['date_from']
$this->rollingDateConverter->convert($data['date_from_rolling'])
);
$qb->setParameter(
'person_having_activity_between_date_to',
$data['date_to']
$this->rollingDateConverter->convert($data['date_to_rolling'])
);
$qb->setParameter('person_having_activity_reasons', $data['reasons']);
}
public function applyOn(): string
{
return Declarations::PERSON_IMPLIED_IN;
return Declarations::PERSON_TYPE;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, [
'label' => 'Implied in an activity after this date',
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
$builder->add('date_from_rolling', PickRollingDateType::class, [
'label' => 'export.filter.activity.person_between_dates.Implied in an activity after this date',
]);
$builder->add('date_to', DateType::class, [
'label' => 'Implied in an activity before this date',
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
$builder->add('date_to_rolling', PickRollingDateType::class, [
'label' => 'export.filter.activity.person_between_dates.Implied in an activity before this date',
]);
if ([] !== $reasons = $this->activityReasonRepository->findAll()) {
$builder->add('reasons', EntityType::class, [
'class' => ActivityReason::class,
'choices' => $reasons,
'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()),
'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
'multiple' => true,
'expanded' => false,
'label' => 'Activity reasons for those activities',
'label' => 'export.filter.activity.person_between_dates.Activity reasons for those activities',
'help' => 'export.filter.activity.person_between_dates.if no reasons',
]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/** @var FormInterface $filterForm */
$filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if (true === $enabled) {
// if the filter is enabled, add some validation
$form = $event->getForm();
$date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData();
// check that fields are not empty
if (null === $date_from) {
$form->get('date_from')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
}
if (null === $date_to) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
}
// check that date_from is before date_to
if (
(null !== $date_from && null !== $date_to)
&& $date_from >= $date_to
) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This date '
. 'should be after the date given in "Implied in an '
. 'activity after this date" field')
));
}
}
});
}
public function getFormDefaultData(): array
{
return ['date_from' => new DateTime(), 'date_to' => new DateTime(), 'reasons' => $this->activityReasonRepository->findAll()];
return [
'date_from_rolling' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START),
'date_to_rolling' => new RollingDate(RollingDate::T_TODAY),
'reasons' => [],
];
}
public function describeAction($data, $format = 'string')
{
return [
'Filtered by person having an activity between %date_from% and '
. '%date_to% with reasons %reasons_name%',
[] === $data['reasons'] ?
'export.filter.person_between_dates.describe_action_with_no_subject'
: 'export.filter.person_between_dates.describe_action_with_subject',
[
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
'%reasons_name%' => implode(
'date_from' => $this->rollingDateConverter->convert($data['date_from_rolling']),
'date_to' => $this->rollingDateConverter->convert($data['date_to_rolling']),
'reasons' => implode(
', ',
array_map(
fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
fn (ActivityReason $r): string => '"'.$this->translatableStringHelper->localize($r->getName()).'"',
$data['reasons']
)
),
@@ -199,13 +143,15 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
public function getTitle()
{
return 'Filter by person having an activity in a period';
return 'export.filter.activity.person_between_dates.title';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
$context->buildViolation('At least one reason must be chosen')
if ($this->rollingDateConverter->convert($data['date_from_rolling'])
>= $this->rollingDateConverter->convert($data['date_to_rolling'])) {
$context->buildViolation('export.filter.activity.person_between_dates.date mismatch')
->setTranslationDomain('messages')
->addViolation();
}
}

View File

@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Tests\Export\Filter\PersonsFilterTest;
use Chill\MainBundle\Export\FilterInterface;
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @see PersonsFilterTest
*/
final readonly class PersonsFilter implements FilterInterface
{
private const PREFIX = 'act_persons_filter';
public function __construct(private PersonRenderInterface $personRender) {}
public function addRole(): ?string
{
return null;
}
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$orX = $qb->expr()->orX();
foreach (array_values($data['accepted_persons']) as $key => $person) {
$orX->add($qb->expr()->isMemberOf(":{$p}_p_{$key}", 'activity.persons'));
$qb->setParameter(":{$p}_p_{$key}", $person);
}
$qb->andWhere($orX);
}
public function applyOn()
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('accepted_persons', PickPersonDynamicType::class, [
'multiple' => true,
'label' => 'export.filter.activity.by_persons.persons taking part on the activity',
]);
}
public function getFormDefaultData(): array
{
return [
'accepted_persons' => [],
];
}
public function describeAction($data, $format = 'string')
{
$users = [];
foreach ($data['accepted_persons'] as $u) {
$users[] = $this->personRender->renderString($u, []);
}
return ['export.filter.activity.by_persons.Filtered activity by persons: only %persons%', [
'%persons%' => implode(', ', $users),
]];
}
public function getTitle(): string
{
return 'export.filter.activity.by_persons.Filter activity by persons';
}
}

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
@@ -23,18 +23,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class SentReceivedFilter implements FilterInterface
{
private const CHOICES = [
'is sent' => Activity::SENTRECEIVED_SENT,
'is received' => Activity::SENTRECEIVED_RECEIVED,
'export.filter.activity.by_sent_received.is sent' => Activity::SENTRECEIVED_SENT,
'export.filter.activity.by_sent_received.is received' => Activity::SENTRECEIVED_RECEIVED,
];
private const DEFAULT_CHOICE = Activity::SENTRECEIVED_SENT;
private TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function __construct(private readonly TranslatorInterface $translator) {}
public function addRole(): ?string
{
@@ -59,7 +54,7 @@ class SentReceivedFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -69,8 +64,10 @@ class SentReceivedFilter implements FilterInterface
'multiple' => false,
'expanded' => true,
'empty_data' => self::DEFAULT_CHOICE,
'label' => 'export.filter.activity.by_sent_received.Sent or received',
]);
}
public function getFormDefaultData(): array
{
return ['accepted_sentreceived' => self::DEFAULT_CHOICE];

View File

@@ -9,7 +9,7 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface;
@@ -21,12 +21,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class UserFilter implements FilterInterface
{
private UserRender $userRender;
public function __construct(UserRender $userRender)
{
$this->userRender = $userRender;
}
public function __construct(private readonly UserRender $userRender) {}
public function addRole(): ?string
{
@@ -51,7 +46,7 @@ class UserFilter implements FilterInterface
public function applyOn(): string
{
return Declarations::ACTIVITY_ACP;
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
@@ -61,6 +56,7 @@ class UserFilter implements FilterInterface
'label' => 'Creators',
]);
}
public function getFormDefaultData(): array
{
return [];

View File

@@ -13,6 +13,7 @@ namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\User\UserJobHistory;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
@@ -22,12 +23,11 @@ use Symfony\Component\Form\FormBuilderInterface;
class UsersJobFilter implements FilterInterface
{
private TranslatableStringHelperInterface $translatableStringHelper;
private const PREFIX = 'act_filter_user_job';
public function __construct(TranslatableStringHelperInterface $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function __construct(
private readonly TranslatableStringHelperInterface $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -36,14 +36,25 @@ class UsersJobFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . Activity::class . ' activity_users_job_filter_act
JOIN activity_users_job_filter_act.users users WHERE users.userJob IN (:activity_users_job_filter_jobs) AND activity_users_job_filter_act = activity '
'SELECT 1 FROM '.Activity::class." {$p}_act "
."JOIN {$p}_act.users {$p}_user "
.'JOIN '.UserJobHistory::class." {$p}_history WITH {$p}_history.user = {$p}_user "
."WHERE {$p}_act = activity "
// job_at based on activity.date
."AND {$p}_history.startDate <= activity.date "
."AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > activity.date) "
."AND {$p}_history.job IN ( :{$p}_jobs )"
)
)
->setParameter('activity_users_job_filter_jobs', $data['jobs']);
->setParameter(
"{$p}_jobs",
$data['jobs']
);
}
public function applyOn()
@@ -53,21 +64,18 @@ class UsersJobFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('jobs', EntityType::class, [
$builder
->add('jobs', EntityType::class, [
'class' => UserJob::class,
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()),
'multiple' => true,
'expanded' => true,
]);
}
public function getFormDefaultData(): array
{
return [];
}
public function describeAction($data, $format = 'string')
{
return ['export.filter.activity.by_usersjob.Filtered activity by users job: only %jobs%', [
return ['export.filter.activity.by_users_job.Filtered activity by users job: only %jobs%', [
'%jobs%' => implode(
', ',
array_map(
@@ -78,8 +86,15 @@ class UsersJobFilter implements FilterInterface
]];
}
public function getFormDefaultData(): array
{
return [
'jobs' => [],
];
}
public function getTitle()
{
return 'export.filter.activity.by_usersjob.Filter by users job';
return 'export.filter.activity.by_users_job.Filter by users job';
}
}

View File

@@ -14,6 +14,7 @@ namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User\UserScopeHistory;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
@@ -23,17 +24,12 @@ use Symfony\Component\Form\FormBuilderInterface;
class UsersScopeFilter implements FilterInterface
{
private ScopeRepositoryInterface $scopeRepository;
private TranslatableStringHelperInterface $translatableStringHelper;
private const PREFIX = 'act_filter_user_scope';
public function __construct(
ScopeRepositoryInterface $scopeRepository,
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->scopeRepository = $scopeRepository;
$this->translatableStringHelper = $translatableStringHelper;
}
private readonly ScopeRepositoryInterface $scopeRepository,
private readonly TranslatableStringHelperInterface $translatableStringHelper
) {}
public function addRole(): ?string
{
@@ -42,24 +38,36 @@ class UsersScopeFilter implements FilterInterface
public function alterQuery(QueryBuilder $qb, $data)
{
$p = self::PREFIX;
$qb
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . Activity::class . ' activity_users_scope_filter_act
JOIN activity_users_scope_filter_act.users users WHERE users.mainScope IN (:activity_users_scope_filter_scopes) AND activity_users_scope_filter_act = activity '
'SELECT 1 FROM '.Activity::class." {$p}_act "
."JOIN {$p}_act.users {$p}_user "
.'JOIN '.UserScopeHistory::class." {$p}_history WITH {$p}_history.user = {$p}_user "
."WHERE {$p}_act = activity "
// scope_at based on activity.date
."AND {$p}_history.startDate <= activity.date "
."AND ({$p}_history.endDate IS NULL OR {$p}_history.endDate > activity.date) "
."AND {$p}_history.scope IN ( :{$p}_scopes )"
)
)
->setParameter('activity_users_scope_filter_scopes', $data['scopes']);
->setParameter(
"{$p}_scopes",
$data['scopes']
);
}
public function applyOn()
public function applyOn(): string
{
return Declarations::ACTIVITY;
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('scopes', EntityType::class, [
$builder
->add('scopes', EntityType::class, [
'class' => Scope::class,
'choices' => $this->scopeRepository->findAllActive(),
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()),
@@ -67,14 +75,10 @@ class UsersScopeFilter implements FilterInterface
'expanded' => true,
]);
}
public function getFormDefaultData(): array
{
return [];
}
public function describeAction($data, $format = 'string')
public function describeAction($data, $format = 'string'): array
{
return ['export.filter.activity.by_usersscope.Filtered activity by users scope: only %scopes%', [
return ['export.filter.activity.by_users_scope.Filtered activity by users scope: only %scopes%', [
'%scopes%' => implode(
', ',
array_map(
@@ -85,8 +89,15 @@ class UsersScopeFilter implements FilterInterface
]];
}
public function getTitle()
public function getFormDefaultData(): array
{
return 'export.filter.activity.by_usersscope.Filter by users scope';
return [
'scopes' => [],
];
}
public function getTitle(): string
{
return 'export.filter.activity.by_users_scope.Filter by users scope';
}
}

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