mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-24 22:23:13 +00:00 
			
		
		
		
	Compare commits
	
		
			300 Commits
		
	
	
		
			2.8.0
			...
			replace_tr
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2927561c02 | |||
| 5188891108 | |||
| c6deb21606 | |||
| cdfb084fe4 | |||
| 5ce21aadce | |||
| b9000a38d3 | |||
| 89a185a34f | |||
| bc6c3a1089 | |||
| 2c50f484f0 | |||
| 4bc1de01d6 | |||
| e21fe70b75 | |||
| 461995b56b | |||
| e635b73256 | |||
| 54ae17a8d2 | |||
| 617d09ab8a | |||
| f8ee2903b2 | |||
| 36b0844e79 | |||
| 7bff5ce39e | |||
| 2a151d13ed | |||
| 4375ecf49a | |||
| a6e930958b | |||
| 5f805626f7 | |||
| 4c9ea740c8 | |||
| 981dc6a959 | |||
| 11fb9bcd0b | |||
| a4edb34668 | |||
| f799fe0649 | |||
| c7bd60a106 | |||
| 9ec5a633ad | |||
| d54d34be7c | |||
| 01292ba9ae | |||
| 794daa5c3e | |||
| 37265c09f7 | |||
| 98cd0f3c00 | |||
| bc2041cbdd | |||
| 0b0cbed9db | |||
| c9cfe4c7e9 | |||
| 75e15c1389 | |||
| 48e0a0af7d | |||
| adf1110340 | |||
| a6fcdb5256 | |||
| 6b8d6b76ba | |||
| bbf9c58fbf | |||
| 0c8ecfe493 | |||
| 8523f14214 | |||
| b32fa42afa | |||
| be8975ee04 | |||
| 05865521b5 | |||
| dd47ddc268 | |||
| 0df93fb703 | |||
| c62495a280 | |||
| 93b189b091 | |||
| 304bf4258b | |||
| efcb903d10 | |||
| b65f76262a | |||
| 51a4ffca2e | |||
| 68d28f3e28 | |||
| 63e9d1a96f | |||
| 21524f052e | |||
| 978db5a5c5 | |||
| 363785b779 | |||
| 4e13b2ae3a | |||
| 239372270e | |||
| ada28265ee | |||
| 0b6b25fd95 | |||
| c526973475 | |||
| 9bbddd8405 | |||
| 935210aa1d | |||
| 58e189ee07 | |||
| 9f476dddaf | |||
| dac48ea4e0 | |||
| af4bee4d50 | |||
| b4e5618e00 | |||
| 15e23087ed | |||
| e3559774fd | |||
| d6a1044585 | |||
| c6a06ebaf9 | |||
| c00c26c3e5 | |||
| fa3fc2c781 | |||
| 6e48d036d7 | |||
| 31fc7fffe9 | |||
| 84ba626fb5 | |||
| eddcfc3921 | |||
| f025b0d184 | |||
| 8c44e92079 | |||
| 1973a4b849 | |||
| bea21d45fc | |||
| 3aa10927d7 | |||
| 4460db1dc4 | |||
| e4cf07c7b3 | |||
| 2100d45671 | |||
| aeb0d5eab8 | |||
| bc69f83c37 | |||
| 9b272e9b9e | |||
| f225a83a3e | |||
| e738bf0f5e | |||
| 0953faedc4 | |||
| 7c25ca8dd4 | |||
| 8b7600e09f | |||
| 9db0011b2e | |||
| 3f4a42adb2 | |||
| f18ee2383c | |||
| 28583f4193 | |||
| c5b153e6ed | |||
| 2d4d1eda50 | |||
| baeccf0970 | |||
| 6665a443b9 | |||
| fc919e9547 | |||
| 949c5424f0 | |||
| e6e42777d7 | |||
| c590d60a7f | |||
| 6228cc5ede | |||
| 024790128a | |||
| d2feb0f0b4 | |||
| 8a6f29ef79 | |||
| 124abf563e | |||
| 096fb6219f | |||
| bebc746d57 | |||
| d47e6c5ba1 | |||
| ef8ac6041a | |||
| 41f4bbfdce | |||
| 6a37079ee5 | |||
| 2d7bc06539 | |||
| bad302f512 | |||
| 294aaf5bed | |||
| d2864605b9 | |||
| 2efd5ebc9a | |||
| b0a7612329 | |||
| 0c5b35926b | |||
| b38f5800d9 | |||
| 8dce0473ff | |||
| 5f8b86b839 | |||
| 65aa0a1588 | |||
| d8b0e0671a | |||
| 29983cc2ad | |||
| 260a173a61 | |||
| 500b37601a | |||
| 5d41b37620 | |||
| 05e86a3360 | |||
| 9b061eeaae | |||
| 3816d68e18 | |||
| 7db7f34f62 | |||
| 6b958d193d | |||
| 1070d33670 | |||
| b93a822299 | |||
| fc7cfb1760 | |||
| 76f1814848 | |||
| cd9611a669 | |||
| d3b68f8f8f | |||
| 2ce29f36ff | |||
| d2323e91ca | |||
| b9231a91a3 | |||
| b36e37d9c5 | |||
| 899ed5d0a4 | |||
| 9375d50112 | |||
| e53540ec74 | |||
| 582b27fbd6 | |||
| 19c6e3e6ba | |||
| 0711b7f84a | |||
| 608663d25c | |||
| 40b7c8ad8f | |||
| 412c55a1a5 | |||
| afa4b7ad2c | |||
| 0db1e3e0d7 | |||
| a2a660c954 | |||
| 2c52a5bffa | |||
| 10a75f44e9 | |||
| 1361e2bbf9 | |||
| 37c1dfb0ba | |||
| a197a6b418 | |||
| f8f04c69d0 | |||
| 355ed03500 | |||
| d8062be131 | |||
| e72df84442 | |||
| d44f5d7af8 | |||
| d595c17cd4 | |||
| cbb89ecf35 | |||
| 6f11dffcbd | |||
| 7c58880139 | |||
| 76142c1264 | |||
| 650e3a84c8 | |||
| 6001e15907 | |||
| 2a9e461d6f | |||
| b85cd1b994 | |||
| e4e52234ad | |||
| bc9b7b1776 | |||
| 1f2ecb923e | |||
| 37419e06fc | |||
| bad3cdca09 | |||
| 711cdc3481 | |||
| 149ed2bd75 | |||
| 2f1f724860 | |||
| 68e1384416 | |||
| 0907d5b76a | |||
| 1c0fd57913 | |||
| d01172274d | |||
| 876ebca210 | |||
| 364a67b83a | |||
| 6bedd673cd | |||
| df9f30265f | |||
| 1b8acfab24 | |||
| 690697cb35 | |||
| 5314e7b501 | |||
| 939a6753bd | |||
| 52d791f6d0 | |||
| 80684f65fe | |||
| b1a9749dc0 | |||
| 2dfc228917 | |||
| 3f2339bc60 | |||
| e2a739eeff | |||
| 847fd71364 | |||
| 667104a595 | |||
| 2c83b4c912 | |||
| e2d62d5792 | |||
| d1e09d7047 | |||
| 5481d029e8 | |||
| ebe1c11ca6 | |||
| 398bbd12d5 | |||
| c33330969c | |||
| ea9c21e021 | |||
| 410aa7098a | |||
| ad1e5ecc95 | |||
| 1e353ed74b | |||
| 5136907d62 | |||
| 84dbfabd66 | |||
| 43ac6726aa | |||
| 0e0b0b8874 | |||
| 24cc6a816b | |||
| f2d391ea2e | |||
| e2b500ea5f | |||
| dbccf7ff80 | |||
| 65e6ad0fc4 | |||
| f68a163a30 | |||
| 009a0326d9 | |||
| 4b20db7a9c | |||
| 458a59fe1b | |||
| 378e417d5c | |||
| cd7b91dd98 | |||
| 4b989fe25c | |||
| 984c35f8bc | |||
| 770d64a2f8 | |||
| 34c46f23e3 | |||
| 333579de06 | |||
| 836cc7199e | |||
| 7f96a895e1 | |||
| a0d4a995d3 | |||
| e839b03cc9 | |||
| 55b8502896 | |||
| a9c8f464bb | |||
| f570fe92a5 | |||
| 157cdf6dfc | |||
| c20f65eebb | |||
| b6a094aeee | |||
| 0ed5544ad3 | |||
| 6f2b538e27 | |||
| 0e94e769cb | |||
| abc067adae | |||
| ae04172929 | |||
| dd21694544 | |||
| 5f6e506300 | |||
| dba1d0548e | |||
| 507bd5c6b5 | |||
| 9f63d9ed0f | |||
| 97dad842ea | |||
| d08980c8d1 | |||
| da6f8511a8 | |||
| 9690359dfa | |||
| 2ad82e8cc1 | |||
| 169bf3c140 | |||
| 9cdef5f951 | |||
| df529be2ce | |||
| d87cd0c685 | |||
| 7a5db59ac2 | |||
| 4028cc8a8b | |||
| 48cd8aaa9f | |||
| d048ee3b44 | |||
| aa553db659 | |||
| e45430f0c9 | |||
| 13abc36529 | |||
| 023a29cb78 | |||
| 7b637d1287 | |||
| 74ed34ba97 | |||
| 6e6f19c499 | |||
| 075aca493b | |||
| 224c2c74e8 | |||
| efaa01f4f6 | |||
| f04ef9c931 | |||
| 9252e92da0 | |||
| 4ab4554e63 | |||
| 6d63177ff4 | |||
| 81e8928344 | |||
| 737f5f9275 | |||
| 07c681fcec | |||
| 1c7d90a6ef | |||
| 24c33b306b | |||
| 7e19419861 | |||
| c35994203d | |||
| 9027cbd196 | |||
| dde3002100 | |||
| d8870e906f | 
							
								
								
									
										5
									
								
								.changes/unreleased/Fixed-20231026-152205.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.changes/unreleased/Fixed-20231026-152205.yaml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										20
									
								
								.changes/v2.10.0.md
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										3
									
								
								.changes/v2.10.1.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| ## v2.10.1 - 2023-10-24 | ||||
| ### Fixed | ||||
| * Fix export controller when generating an export without any data in session  | ||||
							
								
								
									
										23
									
								
								.changes/v2.9.0.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.changes/v2.9.0.md
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										3
									
								
								.changes/v2.9.1.md
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										3
									
								
								.changes/v2.9.2.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| ## v2.9.2 - 2023-10-17 | ||||
| ### Fixed | ||||
| * Fix possible null values in string's entities  | ||||
							
								
								
									
										36
									
								
								.env.test
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								.env.test
									
									
									
									
									
								
							| @@ -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= | ||||
|   | ||||
| @@ -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
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										61
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -6,6 +6,67 @@ 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 | ||||
|   | ||||
| @@ -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" | ||||
| @@ -128,12 +126,10 @@ | ||||
|         }, | ||||
|         "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" | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|     { | ||||
|   | ||||
| @@ -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() | ||||
|         ); | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| 
 | 
| @@ -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                                 | | ||||
|   | ||||
| @@ -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&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> | ||||
|   | ||||
							
								
								
									
										43
									
								
								rector.php
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								rector.php
									
									
									
									
									
								
							| @@ -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, | ||||
|     ]); | ||||
| }; | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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(), | ||||
|         ]); | ||||
|   | ||||
| @@ -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(), | ||||
|         ]); | ||||
|   | ||||
| @@ -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'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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'); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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'); | ||||
|     } | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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; | ||||
|         } | ||||
|   | ||||
| @@ -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 | ||||
|             ); | ||||
|         } | ||||
|   | ||||
| @@ -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; | ||||
|         } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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'] | ||||
|                 ); | ||||
|   | ||||
| @@ -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' => [ | ||||
|   | ||||
| @@ -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') | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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 = []; | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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}; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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]); | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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'; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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'; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|     { | ||||
| @@ -52,6 +42,7 @@ class ByCreatorAggregator implements AggregatorInterface | ||||
|     { | ||||
|         // no form | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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'); | ||||
|         } | ||||
|  | ||||
| @@ -57,6 +46,7 @@ class ByThirdpartyAggregator implements AggregatorInterface | ||||
|     { | ||||
|         // no form | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -12,26 +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\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,12 +36,28 @@ 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 | ||||
| @@ -53,10 +65,8 @@ class CreatorScopeAggregator implements AggregatorInterface | ||||
|         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'; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,10 +14,8 @@ 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)); | ||||
| @@ -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, | ||||
|             }; | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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'; | ||||
|     } | ||||
| } | ||||
| @@ -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'); | ||||
|         } | ||||
|  | ||||
| @@ -57,6 +46,7 @@ class LocationTypeAggregator implements AggregatorInterface | ||||
|     { | ||||
|         // no form | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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)); | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|   | ||||
| @@ -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'; | ||||
| } | ||||
|   | ||||
| @@ -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')); | ||||
|  | ||||
|         $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) | ||||
|         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) | ||||
|                     WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|                 ->setParameter('authorized_centers', $centers); | ||||
|         } | ||||
|  | ||||
|         AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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')); | ||||
|  | ||||
|         $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) | ||||
|         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) | ||||
|                     WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|                 ->setParameter('authorized_centers', $centers); | ||||
|         } | ||||
|  | ||||
|         AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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'); | ||||
|  | ||||
|         $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) | ||||
|         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) | ||||
|                     WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|                 ->setParameter('authorized_centers', $centers); | ||||
|         } | ||||
|  | ||||
|         AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); | ||||
|  | ||||
|         $qb->select('COUNT(DISTINCT activity.id) as export_count_activity'); | ||||
|  | ||||
|   | ||||
| @@ -16,35 +16,33 @@ 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 []; | ||||
| @@ -57,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 | ||||
| @@ -67,22 +65,17 @@ class ListActivity implements ListInterface, GroupedExportInterface | ||||
|  | ||||
|     public function getLabels($key, array $values, $data) | ||||
|     { | ||||
|         switch ($key) { | ||||
|             case 'acpId': | ||||
|                 return static function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return ListActivityHelper::MSG_KEY . 'accompanying course id'; | ||||
|                     } | ||||
|         return match ($key) { | ||||
|             'acpId' => static function ($value) { | ||||
|                 if ('_header' === $value) { | ||||
|                     return ListActivityHelper::MSG_KEY.'accompanying course id'; | ||||
|                 } | ||||
|  | ||||
|                     return $value ?? ''; | ||||
|                 }; | ||||
|  | ||||
|             case 'scopesNames': | ||||
|                 return $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY . 'course circles'); | ||||
|  | ||||
|             default: | ||||
|                 return $this->helper->getLabels($key, $values, $data); | ||||
|         } | ||||
|                 return $value ?? ''; | ||||
|             }, | ||||
|             'scopesNames' => $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY.'course circles'), | ||||
|             default => $this->helper->getLabels($key, $values, $data), | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public function getQueryKeys($data) | ||||
| @@ -104,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() | ||||
| @@ -124,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( | ||||
|                 $qb->expr()->exists( | ||||
|                     'SELECT 1 | ||||
|                     FROM ' . PersonCenterHistory::class . ' acl_count_person_history | ||||
|             ->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 | ||||
|                     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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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')); | ||||
|  | ||||
|         $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) | ||||
|         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) | ||||
|                     WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|                 ->setParameter('authorized_centers', $centers); | ||||
|         } | ||||
|  | ||||
|         AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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')); | ||||
|  | ||||
|         $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) | ||||
|         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) | ||||
|                     WHERE acl_count_part.accompanyingPeriod = acp.id AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|                 ->setParameter('authorized_centers', $centers); | ||||
|         } | ||||
|  | ||||
|         AccompanyingCourseExportHelper::addClosingMotiveExclusionClause($qb); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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,23 +90,25 @@ 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'); | ||||
|  | ||||
|         $qb | ||||
|             ->where( | ||||
|                 $qb->expr()->andX( | ||||
|                     $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                     $qb->expr()->orX( | ||||
|                         $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                         $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|         if ($this->filterStatsByCenters) { | ||||
|             $qb | ||||
|                 ->join('person.centerHistory', 'centerHistory') | ||||
|                 ->where( | ||||
|                     $qb->expr()->andX( | ||||
|                         $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                         $qb->expr()->orX( | ||||
|                             $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                             $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|                         ) | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) | ||||
|             ->setParameter('centers', $centers); | ||||
|                 ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) | ||||
|                 ->setParameter('centers', $centers); | ||||
|         } | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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,23 +198,25 @@ class ListActivity implements ListInterface, GroupedExportInterface | ||||
|  | ||||
|         $qb | ||||
|             ->from('ChillActivityBundle:Activity', 'activity') | ||||
|             ->join('activity.person', 'actperson') | ||||
|             ->join('actperson.centerHistory', 'centerHistory'); | ||||
|             ->join('activity.person', 'actperson'); | ||||
|  | ||||
|         $qb->where( | ||||
|             $qb->expr()->andX( | ||||
|                 $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                 $qb->expr()->orX( | ||||
|                     $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                     $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|         if ($this->filterStatsByCenters) { | ||||
|             $qb->join('actperson.centerHistory', 'centerHistory'); | ||||
|             $qb->where( | ||||
|                 $qb->expr()->andX( | ||||
|                     $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                     $qb->expr()->orX( | ||||
|                         $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                         $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|         ) | ||||
|             ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) | ||||
|             ->setParameter('centers', $centers); | ||||
|                 ->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'); | ||||
|   | ||||
| @@ -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,21 +124,23 @@ class StatActivityDuration implements ExportInterface, GroupedExportInterface | ||||
|         } | ||||
|  | ||||
|         $qb->select($select) | ||||
|             ->join('activity.person', 'person') | ||||
|             ->join('person.centerHistory', 'centerHistory'); | ||||
|             ->join('activity.person', 'person'); | ||||
|  | ||||
|         $qb | ||||
|             ->where( | ||||
|                 $qb->expr()->andX( | ||||
|                     $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                     $qb->expr()->orX( | ||||
|                         $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                         $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|         if ($this->filterStatsByCenters) { | ||||
|             $qb | ||||
|                 ->join('person.centerHistory', 'centerHistory') | ||||
|                 ->where( | ||||
|                     $qb->expr()->andX( | ||||
|                         $qb->expr()->lte('centerHistory.startDate', 'activity.date'), | ||||
|                         $qb->expr()->orX( | ||||
|                             $qb->expr()->isNull('centerHistory.endDate'), | ||||
|                             $qb->expr()->gt('centerHistory.endDate', 'activity.date') | ||||
|                         ) | ||||
|                     ) | ||||
|                 ) | ||||
|             ) | ||||
|             ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) | ||||
|             ->setParameter('centers', $centers); | ||||
|                 ->andWhere($qb->expr()->in('centerHistory.center', ':centers')) | ||||
|                 ->setParameter('centers', $centers); | ||||
|         } | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|   | ||||
| @@ -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,113 +83,78 @@ class ListActivityHelper | ||||
|  | ||||
|     public function getLabels($key, array $values, $data) | ||||
|     { | ||||
|         switch ($key) { | ||||
|             case 'createdAt': | ||||
|             case 'updatedAt': | ||||
|                 return $this->dateTimeHelper->getLabel($key); | ||||
|         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'; | ||||
|                 } | ||||
|  | ||||
|             case 'createdBy': | ||||
|             case 'updatedBy': | ||||
|                 return $this->userHelper->getLabel($key, $values, $key); | ||||
|                 if (null === $value || null === $presence = $this->activityPresenceRepository->find($value)) { | ||||
|                     return ''; | ||||
|                 } | ||||
|  | ||||
|             case 'date': | ||||
|                 return $this->dateTimeHelper->getLabel(self::MSG_KEY . $key); | ||||
|                 return $this->translatableStringHelper->localize($presence->getName()); | ||||
|             }, | ||||
|             'listReasons' => $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons'), | ||||
|             'typeName' => function ($value) { | ||||
|                 if ('_header' === $value) { | ||||
|                     return 'Activity type'; | ||||
|                 } | ||||
|  | ||||
|             case 'attendeeName': | ||||
|                 return function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return 'Attendee'; | ||||
|                     } | ||||
|                 if (null === $value || null === $type = $this->activityTypeRepository->find($value)) { | ||||
|                     return ''; | ||||
|                 } | ||||
|  | ||||
|                     if (null === $value || null === $presence = $this->activityPresenceRepository->find($value)) { | ||||
|                         return ''; | ||||
|                     } | ||||
|                 return $this->translatableStringHelper->localize($type->getName()); | ||||
|             }, | ||||
|             'usersNames' => $this->userHelper->getLabelMulti($key, $values, self::MSG_KEY.'users name'), | ||||
|             'usersIds', 'thirdPartiesIds', 'personsIds' => static function ($value) use ($key) { | ||||
|                 if ('_header' === $value) { | ||||
|                     return match ($key) { | ||||
|                         'usersIds' => self::MSG_KEY.'users ids', | ||||
|                         'thirdPartiesIds' => self::MSG_KEY.'third parties ids', | ||||
|                         'personsIds' => self::MSG_KEY.'persons ids', | ||||
|                     }; | ||||
|                 } | ||||
|  | ||||
|                     return $this->translatableStringHelper->localize($presence->getName()); | ||||
|                 }; | ||||
|                 $decoded = json_decode((string) $value, null, 512, JSON_THROW_ON_ERROR); | ||||
|  | ||||
|             case 'listReasons': | ||||
|                 return $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons'); | ||||
|                 return implode( | ||||
|                     '|', | ||||
|                     array_unique( | ||||
|                         array_filter($decoded, static fn (?int $id) => null !== $id), | ||||
|                         \SORT_NUMERIC | ||||
|                     ) | ||||
|                 ); | ||||
|             }, | ||||
|             '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'; | ||||
|                 } | ||||
|  | ||||
|             case 'typeName': | ||||
|                 return function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return 'Activity type'; | ||||
|                     } | ||||
|                 if (null === $value) { | ||||
|                     return ''; | ||||
|                 } | ||||
|  | ||||
|                     if (null === $value || null === $type = $this->activityTypeRepository->find($value)) { | ||||
|                         return ''; | ||||
|                     } | ||||
|                 return $this->translator->trans($value); | ||||
|             }, | ||||
|             default => function ($value) use ($key) { | ||||
|                 if ('_header' === $value) { | ||||
|                     return self::MSG_KEY.$key; | ||||
|                 } | ||||
|  | ||||
|                     return $this->translatableStringHelper->localize($type->getName()); | ||||
|                 }; | ||||
|                 if (null === $value) { | ||||
|                     return ''; | ||||
|                 } | ||||
|  | ||||
|             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) { | ||||
|                     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'); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     $decoded = json_decode($value, null, 512, JSON_THROW_ON_ERROR); | ||||
|  | ||||
|                     return implode( | ||||
|                         '|', | ||||
|                         array_unique( | ||||
|                             array_filter($decoded, static fn (?int $id) => null !== $id), | ||||
|                             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) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return self::MSG_KEY . 'sent received'; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translator->trans($value); | ||||
|                 }; | ||||
|  | ||||
|             default: | ||||
|                 return function ($value) use ($key) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return self::MSG_KEY . $key; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translator->trans($value); | ||||
|                 }; | ||||
|         } | ||||
|                 return $this->translator->trans($value); | ||||
|             }, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public function getQueryKeys($data) | ||||
|   | ||||
| @@ -21,9 +21,6 @@ use Doctrine\ORM\QueryBuilder; | ||||
| use Symfony\Bridge\Doctrine\Form\Type\EntityType; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
|  | ||||
| /** | ||||
|  * Filter accompanying period to keep only the one having at list one activity from the given ActivityType. | ||||
|  */ | ||||
| class ActivityTypeFilter implements FilterInterface | ||||
| { | ||||
|     public function __construct( | ||||
| @@ -40,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' | ||||
|             ) | ||||
|         ); | ||||
| @@ -57,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 []; | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ use Doctrine\ORM\QueryBuilder; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
|  | ||||
| /** | ||||
|  * Filter accompanying periods to keep only the one without any activity | ||||
|  * Filter accompanying periods to keep only the one without any activity. | ||||
|  */ | ||||
| class HasNoActivityFilter implements FilterInterface | ||||
| { | ||||
| @@ -32,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 | ||||
|                 ) | ||||
|             '); | ||||
| @@ -45,8 +45,9 @@ class HasNoActivityFilter implements FilterInterface | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder) | ||||
|     { | ||||
|         //no form needed | ||||
|         // no form needed | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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" | ||||
|             ) | ||||
|         ); | ||||
|  | ||||
|   | ||||
| @@ -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)]; | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 []; | ||||
|   | ||||
| @@ -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 | ||||
|     { | ||||
| @@ -52,6 +47,7 @@ class ByCreatorFilter implements FilterInterface | ||||
|             'multiple' => true, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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'; | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|     { | ||||
| @@ -70,6 +65,7 @@ class EmergencyFilter implements FilterInterface | ||||
|             'empty_data' => self::DEFAULT_CHOICE, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return ['accepted_emergency' => self::DEFAULT_CHOICE]; | ||||
|   | ||||
| @@ -14,7 +14,6 @@ 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; | ||||
|  | ||||
| @@ -46,6 +45,7 @@ class LocationFilter implements FilterInterface | ||||
|             'label' => 'pick location', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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'); | ||||
|         } | ||||
|  | ||||
| @@ -62,9 +56,10 @@ class LocationTypeFilter implements FilterInterface | ||||
|     { | ||||
|         $builder->add('accepted_locationtype', PickLocationTypeType::class, [ | ||||
|             'multiple' => true, | ||||
|             //'label' => false, | ||||
|             // 'label' => false, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -16,46 +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, | ||||
|         private readonly RollingDateConverterInterface $rollingDateConverter, | ||||
|     ) { | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|         $this->activityReasonRepository = $activityReasonRepository; | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|         private TranslatableStringHelper $translatableStringHelper, | ||||
|         private ActivityReasonRepository $activityReasonRepository, | ||||
|         private RollingDateConverterInterface $rollingDateConverter, | ||||
|     ) {} | ||||
|  | ||||
|     public function addRole(): ?string | ||||
|     { | ||||
| @@ -72,11 +49,11 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt | ||||
|  | ||||
|         // 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' | ||||
|             . ' AND ' | ||||
|             . '(person_person_having_activity.id = person.id OR person MEMBER OF activity_person_having_activity.persons)'); | ||||
|             .':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 | ||||
| @@ -134,6 +111,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt | ||||
|             ]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return [ | ||||
| @@ -155,7 +133,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt | ||||
|                 'reasons' => implode( | ||||
|                     ', ', | ||||
|                     array_map( | ||||
|                         fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', | ||||
|                         fn (ActivityReason $r): string => '"'.$this->translatableStringHelper->localize($r->getName()).'"', | ||||
|                         $data['reasons'] | ||||
|                     ) | ||||
|                 ), | ||||
|   | ||||
| @@ -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'; | ||||
|     } | ||||
| } | ||||
| @@ -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 | ||||
|     { | ||||
| @@ -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]; | ||||
|   | ||||
| @@ -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 | ||||
|     { | ||||
| @@ -61,6 +56,7 @@ class UserFilter implements FilterInterface | ||||
|             'label' => 'Creators', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
| 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; | ||||
|     } | ||||
|  | ||||
|     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'; | ||||
|     } | ||||
| } | ||||
| @@ -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, [ | ||||
|             'class' => UserJob::class, | ||||
|             'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()), | ||||
|             'multiple' => true, | ||||
|             'expanded' => true, | ||||
|         ]); | ||||
|     } | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|         $builder | ||||
|             ->add('jobs', EntityType::class, [ | ||||
|                 'class' => UserJob::class, | ||||
|                 'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize($j->getLabel()), | ||||
|                 'multiple' => true, | ||||
|                 'expanded' => true, | ||||
|             ]); | ||||
|     } | ||||
|  | ||||
|     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'; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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,39 +38,47 @@ 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, [ | ||||
|             'class' => Scope::class, | ||||
|             'choices' => $this->scopeRepository->findAllActive(), | ||||
|             'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()), | ||||
|             'multiple' => true, | ||||
|             'expanded' => true, | ||||
|         ]); | ||||
|     } | ||||
|     public function getFormDefaultData(): array | ||||
|     { | ||||
|         return []; | ||||
|         $builder | ||||
|             ->add('scopes', EntityType::class, [ | ||||
|                 'class' => Scope::class, | ||||
|                 'choices' => $this->scopeRepository->findAllActive(), | ||||
|                 'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize($s->getName()), | ||||
|                 'multiple' => true, | ||||
|                 'expanded' => true, | ||||
|             ]); | ||||
|     } | ||||
|  | ||||
|     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'; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -34,12 +34,8 @@ use Chill\PersonBundle\Entity\SocialWork\SocialIssue; | ||||
| use Chill\PersonBundle\Templating\Entity\SocialActionRender; | ||||
| use Chill\PersonBundle\Templating\Entity\SocialIssueRender; | ||||
| use Chill\ThirdPartyBundle\Entity\ThirdParty; | ||||
| use DateInterval; | ||||
| use DateTime; | ||||
| use DateTimeZone; | ||||
| use Doctrine\ORM\EntityRepository; | ||||
| use Doctrine\Persistence\ObjectManager; | ||||
| use RuntimeException; | ||||
| use Symfony\Bridge\Doctrine\Form\Type\EntityType; | ||||
| use Symfony\Component\Form\AbstractType; | ||||
| use Symfony\Component\Form\CallbackTransformer; | ||||
| @@ -53,45 +49,24 @@ use Symfony\Component\Form\FormEvents; | ||||
| use Symfony\Component\OptionsResolver\OptionsResolver; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
|  | ||||
| use Symfony\Component\Security\Core\Role\Role; | ||||
| use function in_array; | ||||
|  | ||||
| class ActivityType extends AbstractType | ||||
| { | ||||
|     protected AuthorizationHelper $authorizationHelper; | ||||
|  | ||||
|     protected ObjectManager $om; | ||||
|  | ||||
|     protected SocialActionRender $socialActionRender; | ||||
|  | ||||
|     protected SocialIssueRender $socialIssueRender; | ||||
|  | ||||
|     protected array $timeChoices; | ||||
|  | ||||
|     protected TranslatableStringHelper $translatableStringHelper; | ||||
|  | ||||
|     protected User $user; | ||||
|  | ||||
|     public function __construct( | ||||
|         TokenStorageInterface $tokenStorage, | ||||
|         AuthorizationHelper $authorizationHelper, | ||||
|         ObjectManager $om, | ||||
|         TranslatableStringHelper $translatableStringHelper, | ||||
|         array $timeChoices, | ||||
|         SocialIssueRender $socialIssueRender, | ||||
|         SocialActionRender $socialActionRender | ||||
|         protected AuthorizationHelper $authorizationHelper, | ||||
|         protected ObjectManager $om, | ||||
|         protected TranslatableStringHelper $translatableStringHelper, | ||||
|         protected array $timeChoices, | ||||
|         protected SocialIssueRender $socialIssueRender, | ||||
|         protected SocialActionRender $socialActionRender | ||||
|     ) { | ||||
|         if (!$tokenStorage->getToken()->getUser() instanceof User) { | ||||
|             throw new RuntimeException('you should have a valid user'); | ||||
|             throw new \RuntimeException('you should have a valid user'); | ||||
|         } | ||||
|  | ||||
|         $this->user = $tokenStorage->getToken()->getUser(); | ||||
|         $this->authorizationHelper = $authorizationHelper; | ||||
|         $this->om = $om; | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|         $this->timeChoices = $timeChoices; | ||||
|         $this->socialIssueRender = $socialIssueRender; | ||||
|         $this->socialActionRender = $socialActionRender; | ||||
|     } | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options): void | ||||
| @@ -112,8 +87,7 @@ class ActivityType extends AbstractType | ||||
|         /** @var \Chill\ActivityBundle\Entity\ActivityType $activityType */ | ||||
|         $activityType = $options['activityType']; | ||||
|  | ||||
|         // TODO revoir la gestion des center au niveau du form des activité. | ||||
|         if ($options['center'] instanceof Center && null !== $options['data']->getPerson()) { | ||||
|         if (null !== $options['data']->getPerson()) { | ||||
|             $builder->add('scope', ScopePickerType::class, [ | ||||
|                 'center' => $options['center'], | ||||
|                 'role' => ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'], | ||||
| @@ -121,16 +95,16 @@ class ActivityType extends AbstractType | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         /** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod  $accompanyingPeriod */ | ||||
|         /** @var \Chill\PersonBundle\Entity\AccompanyingPeriod|null $accompanyingPeriod */ | ||||
|         $accompanyingPeriod = null; | ||||
|  | ||||
|         if ($options['accompanyingPeriod'] instanceof AccompanyingPeriod) { | ||||
|             $accompanyingPeriod = $options['accompanyingPeriod']; | ||||
|         } | ||||
|  | ||||
|         if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) { | ||||
|         if ($activityType->isVisible('socialIssues') && null !== $accompanyingPeriod) { | ||||
|             $builder->add('socialIssues', HiddenType::class, [ | ||||
|                 'required' => $activityType->getSocialIssuesVisible() === 2, | ||||
|                 'required' => 2 === $activityType->getSocialIssuesVisible(), | ||||
|             ]); | ||||
|             $builder->get('socialIssues') | ||||
|                 ->addModelTransformer(new CallbackTransformer( | ||||
| @@ -156,9 +130,9 @@ class ActivityType extends AbstractType | ||||
|                 )); | ||||
|         } | ||||
|  | ||||
|         if ($activityType->isVisible('socialActions') && $accompanyingPeriod) { | ||||
|         if ($activityType->isVisible('socialActions') && null !== $accompanyingPeriod) { | ||||
|             $builder->add('socialActions', HiddenType::class, [ | ||||
|                 'required' => $activityType->getSocialActionsVisible() === 2, | ||||
|                 'required' => 2 === $activityType->getSocialActionsVisible(), | ||||
|             ]); | ||||
|             $builder->get('socialActions') | ||||
|                 ->addModelTransformer(new CallbackTransformer( | ||||
| @@ -217,7 +191,7 @@ class ActivityType extends AbstractType | ||||
|             ]); | ||||
|         } | ||||
|  | ||||
|         if ($activityType->isVisible('user') && $options['center'] instanceof Center) { | ||||
|         if ($activityType->isVisible('user')) { | ||||
|             $builder->add('user', PickUserDynamicType::class, [ | ||||
|                 'label' => $activityType->getLabel('user'), | ||||
|                 'required' => $activityType->isRequired('user'), | ||||
| @@ -342,7 +316,7 @@ class ActivityType extends AbstractType | ||||
|  | ||||
|         if ($activityType->isVisible('location')) { | ||||
|             $builder->add('location', HiddenType::class, [ | ||||
|                 'required' => $activityType->getLocationVisible() === 2, | ||||
|                 'required' => 2 === $activityType->getLocationVisible(), | ||||
|             ]) | ||||
|                 ->get('location') | ||||
|                 ->addModelTransformer(new CallbackTransformer( | ||||
| @@ -393,16 +367,16 @@ class ActivityType extends AbstractType | ||||
|                 ) { | ||||
|                     // set the timezone to GMT, and fix the difference between current and GMT | ||||
|                     // the datetimetransformer will then handle timezone as GMT | ||||
|                     $timezoneUTC = new DateTimeZone('GMT'); | ||||
|                     /** @var DateTime $data */ | ||||
|                     $data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300'); | ||||
|                     $timezoneUTC = new \DateTimeZone('GMT'); | ||||
|                     /** @var \DateTime $data */ | ||||
|                     $data = $formEvent->getData() ?? \DateTime::createFromFormat('U', '300'); | ||||
|                     $seconds = $data->getTimezone()->getOffset($data); | ||||
|                     $data->setTimeZone($timezoneUTC); | ||||
|                     $data->add(new DateInterval('PT' . $seconds . 'S')); | ||||
|                     $data->add(new \DateInterval('PT'.$seconds.'S')); | ||||
|  | ||||
|                     // test if the timestamp is in the choices. | ||||
|                     // If not, recreate the field with the new timestamp | ||||
|                     if (!in_array($data->getTimestamp(), $timeChoices, true)) { | ||||
|                     if (!\in_array($data->getTimestamp(), $timeChoices, true)) { | ||||
|                         // the data are not in the possible values. add them | ||||
|                         $timeChoices[$data->format('H:i')] = $data->getTimestamp(); | ||||
|                         $form = $builder->create($fieldName, ChoiceType::class, array_merge( | ||||
| @@ -427,8 +401,8 @@ class ActivityType extends AbstractType | ||||
|  | ||||
|         $resolver | ||||
|             ->setRequired(['center', 'role', 'activityType', 'accompanyingPeriod']) | ||||
|             ->setAllowedTypes('center', ['null', Center::class]) | ||||
|             ->setAllowedTypes('role', [Role::class, 'string']) | ||||
|             ->setAllowedTypes('center', ['null', Center::class, 'array']) | ||||
|             ->setAllowedTypes('role', ['string']) | ||||
|             ->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class) | ||||
|             ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']); | ||||
|     } | ||||
|   | ||||
| @@ -25,12 +25,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; | ||||
|  | ||||
| class ActivityTypeType extends AbstractType | ||||
| { | ||||
|     private TranslatableStringHelper $translatableStringHelper; | ||||
|  | ||||
|     public function __construct(TranslatableStringHelper $translatableStringHelper) | ||||
|     { | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|     } | ||||
|     public function __construct(private readonly TranslatableStringHelper $translatableStringHelper) {} | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder, array $options) | ||||
|     { | ||||
| @@ -61,8 +56,8 @@ class ActivityTypeType extends AbstractType | ||||
|  | ||||
|         foreach ($fields as $field) { | ||||
|             $builder | ||||
|                 ->add($field . 'Visible', ActivityFieldPresence::class) | ||||
|                 ->add($field . 'Label', TextType::class, [ | ||||
|                 ->add($field.'Visible', ActivityFieldPresence::class) | ||||
|                 ->add($field.'Label', TextType::class, [ | ||||
|                     'required' => false, | ||||
|                     'empty_data' => '', | ||||
|                 ]); | ||||
|   | ||||
| @@ -24,21 +24,11 @@ use Symfony\Component\OptionsResolver\OptionsResolver; | ||||
|  */ | ||||
| class PickActivityReasonType extends AbstractType | ||||
| { | ||||
|     private ActivityReasonRepository $activityReasonRepository; | ||||
|  | ||||
|     private ActivityReasonRender $reasonRender; | ||||
|  | ||||
|     private TranslatableStringHelperInterface $translatableStringHelper; | ||||
|  | ||||
|     public function __construct( | ||||
|         ActivityReasonRepository $activityReasonRepository, | ||||
|         ActivityReasonRender $reasonRender, | ||||
|         TranslatableStringHelperInterface $translatableStringHelper | ||||
|     ) { | ||||
|         $this->activityReasonRepository = $activityReasonRepository; | ||||
|         $this->reasonRender = $reasonRender; | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|     } | ||||
|         private readonly ActivityReasonRepository $activityReasonRepository, | ||||
|         private readonly ActivityReasonRender $reasonRender, | ||||
|         private readonly TranslatableStringHelperInterface $translatableStringHelper | ||||
|     ) {} | ||||
|  | ||||
|     public function configureOptions(OptionsResolver $resolver) | ||||
|     { | ||||
|   | ||||
| @@ -23,15 +23,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; | ||||
|  */ | ||||
| class TranslatableActivityReasonCategoryType extends AbstractType | ||||
| { | ||||
|     private TranslatableStringHelperInterface $translatableStringHelper; | ||||
|  | ||||
|     private TranslatorInterface $translator; | ||||
|  | ||||
|     public function __construct(TranslatableStringHelperInterface $translatableStringHelper, TranslatorInterface $translator) | ||||
|     { | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|     public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper, private readonly TranslatorInterface $translator) {} | ||||
|  | ||||
|     public function configureOptions(OptionsResolver $resolver) | ||||
|     { | ||||
| @@ -39,16 +31,11 @@ class TranslatableActivityReasonCategoryType extends AbstractType | ||||
|             [ | ||||
|                 'class' => ActivityReasonCategory::class, | ||||
|                 'choice_label' => fn (ActivityReasonCategory $category) => $this->translatableStringHelper->localize($category->getName()) | ||||
|                     . (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : ''), | ||||
|                     .(!$category->getActive() ? ' ('.$this->translator->trans('inactive').')' : ''), | ||||
|             ] | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     public function getBlockPrefix() | ||||
|     { | ||||
|         return 'translatable_activity_reason_category'; | ||||
|     } | ||||
|  | ||||
|     public function getParent() | ||||
|     { | ||||
|         return EntityType::class; | ||||
|   | ||||
| @@ -20,17 +20,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; | ||||
|  | ||||
| class TranslatableActivityType extends AbstractType | ||||
| { | ||||
|     protected ActivityTypeRepositoryInterface $activityTypeRepository; | ||||
|  | ||||
|     protected TranslatableStringHelperInterface $translatableStringHelper; | ||||
|  | ||||
|     public function __construct( | ||||
|         TranslatableStringHelperInterface $helper, | ||||
|         ActivityTypeRepositoryInterface $activityTypeRepository | ||||
|     ) { | ||||
|         $this->translatableStringHelper = $helper; | ||||
|         $this->activityTypeRepository = $activityTypeRepository; | ||||
|     } | ||||
|     public function __construct(protected TranslatableStringHelperInterface $translatableStringHelper, protected ActivityTypeRepositoryInterface $activityTypeRepository) {} | ||||
|  | ||||
|     public function configureOptions(OptionsResolver $resolver) | ||||
|     { | ||||
|   | ||||
| @@ -23,17 +23,7 @@ use Symfony\Contracts\Translation\TranslatorInterface; | ||||
|  */ | ||||
| class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface | ||||
| { | ||||
|     protected Security $security; | ||||
|  | ||||
|     protected TranslatorInterface $translator; | ||||
|  | ||||
|     public function __construct( | ||||
|         Security $security, | ||||
|         TranslatorInterface $translator | ||||
|     ) { | ||||
|         $this->security = $security; | ||||
|         $this->translator = $translator; | ||||
|     } | ||||
|     public function __construct(protected Security $security, protected TranslatorInterface $translator) {} | ||||
|  | ||||
|     public function buildMenu($menuId, MenuItem $menu, array $parameters) | ||||
|     { | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user