Merge remote-tracking branch 'origin/master' into doc/authorizaton-documentation-update

This commit is contained in:
Julien Fastré 2021-11-22 10:30:05 +01:00
commit 98760bc5e8
300 changed files with 9998 additions and 5391 deletions

View File

@ -12,12 +12,45 @@ and this project adheres to
<!-- write down unreleased development here --> <!-- write down unreleased development here -->
* [task] Select2 field in task form to allow search for a user (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/167)
* remove "search by phone configuration option": search by phone is now executed by default
* remplacer le classement par ordre alphabétique par un classement par ordre de pertinence, qui tient compte:
* de la présence d'une string avec le nom de la ville;
* de la similarité;
* du fait que la recherche commence par une partie du mot recherché
* ajouter la recherche par numéro de téléphone directement dans la barre de recherche et dans le formulaire recherche avancée;
* ajouter la recherche par date de naissance directement dans la barre de recherche;
* ajouter la recherche par ville dans la recherche avancée
* ajouter un lien vers le ménage dans les résultats de recherche
* ajouter l'id du parcours dans les résultats de recherche
* ajouter le demandeur dans les résultats de recherche
* ajout d'un bouton "recherche avancée" sur la page d'accueil
* [person] create an accompanying course: add client-side validation if no origin (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/210)
* [person] fix bounds for computing current person address: the new address appears immediatly
* [docgen] create a normalizer and serializer for normalization on doc format
## Test releases ## Test releases
### Test release 2021-11-15
* [main] fix adding multiple AddresseDeRelais (combine PickAddressType with ChillCollection)
* [person]: do not suggest the current household of the person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/51)
* [person]: display other phone numbers in view + add message in case no others phone numbers (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/184)
* unnecessary whitespace removed from person banner after person-id + double parentheses removed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/290)
* [person]: delete accompanying period work, including related objects (cascade) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/36)
* [address]: Display of incomplete address adjusted.
* [household]: improve relationship graph
* add form to create/edit/delete relationship link,
* improve graph refresh mechanism
* add feature to export canvas as image (png)
* [person suggest] In widget "add person", improve the pertinence of persons when one of the names starts with the pattern;
* [person] do not ask for center any more on person creation
* [3party] do not ask for center any more on 3party creation
### Test release 2021-11-08 ### Test release 2021-11-08
* [person]: Display the name of a user when searching after a User (TMS)
* [person]: Add civility to the person * [person]: Add civility to the person
* [person]: Various improvements on the edit person form * [person]: Various improvements on the edit person form
* [person]: Set available_languages and available_countries as parameters for use in the edit person form * [person]: Set available_languages and available_countries as parameters for use in the edit person form
@ -45,7 +78,6 @@ and this project adheres to
* [socialWorkAction]: display of social issue and parent issues + banner context added. * [socialWorkAction]: display of social issue and parent issues + banner context added.
* [DBAL dependencies] Upgrade to DBAL 3.1 * [DBAL dependencies] Upgrade to DBAL 3.1
### Test release 2021-10-27 ### Test release 2021-10-27
* [person]: delete double actions buttons on search person page * [person]: delete double actions buttons on search person page
@ -64,6 +96,9 @@ and this project adheres to
* [household members editor] finalisation of editor * [household members editor] finalisation of editor
* [AccompanyingCourse banner]: replace translation referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/70) * [AccompanyingCourse banner]: replace translation referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/70)
* [Location]: add location system in activity and RV (calendar). User can choose in location list or create a new location. * [Location]: add location system in activity and RV (calendar). User can choose in location list or create a new location.
* [household]: add relationship page with dynamic data visualisation graph
## Test releases
### Test release 2021-10-11 ### Test release 2021-10-11

View File

@ -54,6 +54,9 @@
"doctrine/doctrine-fixtures-bundle": "^3.3", "doctrine/doctrine-fixtures-bundle": "^3.3",
"fakerphp/faker": "^1.13", "fakerphp/faker": "^1.13",
"nelmio/alice": "^3.8", "nelmio/alice": "^3.8",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^7.0", "phpunit/phpunit": "^7.0",
"symfony/debug-bundle": "^5.1", "symfony/debug-bundle": "^5.1",
"symfony/dotenv": "^5.1", "symfony/dotenv": "^5.1",
@ -88,7 +91,8 @@
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"App\\": "tests/app/src/" "App\\": "tests/app/src/",
"Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests"
} }
}, },
"minimum-stability": "dev", "minimum-stability": "dev",

111
phpstan-baseline.neon Normal file
View File

@ -0,0 +1,111 @@
parameters:
ignoreErrors:
-
message: "#^Variable property access on \\$this\\(Chill\\\\ActivityBundle\\\\Entity\\\\ActivityType\\)\\.$#"
count: 3
path: src/Bundle/ChillActivityBundle/Entity/ActivityType.php
-
message: "#^Foreach overwrites \\$key with its key variable\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php
-
message: "#^Instantiated class PhpOffice\\\\PhpWord\\\\TemplateProcessor not found\\.$#"
count: 1
path: src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorController.php
-
message: "#^Instantiated class PhpOffice\\\\PhpWord\\\\TemplateProcessor not found\\.$#"
count: 1
path: src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php
-
message: "#^Variable \\$participation might not be defined\\.$#"
count: 3
path: src/Bundle/ChillEventBundle/Controller/ParticipationController.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php
-
message: "#^Variable method call on object\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php
-
message: "#^Cannot unset offset '_token' on array\\{formatter\\: mixed, export\\: mixed, centers\\: mixed, alias\\: string\\}\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Controller/ExportController.php
-
message: "#^Foreach overwrites \\$line with its value variable\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php
-
message: "#^Foreach overwrites \\$key with its key variable\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php
-
message: "#^Foreach overwrites \\$key with its value variable\\.$#"
count: 3
path: src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php
-
message: "#^Variable \\$message on left side of \\?\\? always exists and is not nullable\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php
-
message: "#^Variable \\$sqls on left side of \\?\\? always exists and is not nullable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php
-
message: "#^Class Chill\\\\PersonBundle\\\\Entity\\\\Person constructor invoked with 1 parameter, 0 required\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
-
message: "#^Variable \\$street1Value might not be defined\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
-
message: "#^Variable method call on mixed\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
-
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php
-
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php
-
message: "#^Foreach overwrites \\$value with its value variable\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php

131
phpstan-critical.neon Normal file
View File

@ -0,0 +1,131 @@
parameters:
ignoreErrors:
-
message: "#^Implicit array creation is not allowed \\- variable \\$centers might not exist\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Person\\:\\:\\$currentHouseholdParticipationAt\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Entity/Person.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\Household\\\\PersonHouseholdAddress\\:\\:\\$relation\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Entity\\\\AccompanyingPeriod\\:\\:\\$work\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
-
message: "#^Undefined variable\\: \\$person$#"
count: 1
path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Household\\\\MembersEditorFactory\\:\\:\\$validator\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php
-
message: "#^Parameter \\$action of method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:buildQueryBySocialActionWithDescendants\\(\\) has invalid type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\SocialAction\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Parameter \\$action of method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:countBySocialActionWithDescendants\\(\\) has invalid type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\SocialAction\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Undefined variable\\: \\$action$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Undefined variable\\: \\$limit$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Undefined variable\\: \\$offset$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Undefined variable\\: \\$orderBy$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Variable variables are not allowed\\.$#"
count: 4
path: src/Bundle/ChillPersonBundle/Search/PersonSearch.php
-
message: "#^Function Chill\\\\PersonBundle\\\\Serializer\\\\Normalizer\\\\·\\\\is_array not found\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php
-
message: "#^Undefined variable\\: \\$value$#"
count: 1
path: src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php
-
message: "#^Undefined variable\\: \\$choiceSlug$#"
count: 1
path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php
-
message: "#^Undefined variable\\: \\$choiceSlug$#"
count: 1
path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php
-
message: "#^Undefined variable\\: \\$type$#"
count: 1
path: src/Bundle/ChillTaskBundle/Controller/TaskController.php
-
message: "#^Call to an undefined method Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\AbstractCRUDController\\:\\:getRoleFor\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php
-
message: "#^Call to an undefined method Chill\\\\MainBundle\\\\Controller\\\\UserController\\:\\:createEditForm\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Controller/UserController.php
-
message: "#^Undefined variable\\: \\$current$#"
count: 1
path: src/Bundle/ChillMainBundle/Pagination/PageGenerator.php
-
message: "#^Call to an undefined method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AbstractChillVoter\\:\\:getSupportedAttributes\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php
-
message: "#^Call to an undefined method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AbstractChillVoter\\:\\:getSupportedClasses\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php
-
message: "#^Call to an undefined method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AbstractChillVoter\\:\\:isGranted\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php
-
message: "#^Access to an undefined property Chill\\\\PersonBundle\\\\Controller\\\\PersonController\\:\\:\\$security\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Controller/PersonController.php
-
message: "#^Call to an undefined method Chill\\\\ThirdPartyBundle\\\\Form\\\\Type\\\\PickThirdPartyTypeCategoryType\\:\\:transform\\(\\)\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php

852
phpstan-types.neon Normal file
View File

@ -0,0 +1,852 @@
parameters:
ignoreErrors:
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Entity/Activity.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Entity/ActivityReason.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php
-
message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getDescription\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php
-
message: "#^Method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:getTitle\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
-
message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#"
count: 3
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityFormType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 3
path: src/Bundle/ChillBudgetBundle/Form/ChargeType.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillBudgetBundle/Form/ResourceType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillCalendarBundle/Entity/Calendar.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Command/CreateFieldsOnGroupCommand.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/AbstractCustomField.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 3
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 4
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldChoice\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldDate\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldLongChoice\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldNumber\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldText\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php
-
message: "#^Method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldTitle\\:\\:buildForm\\(\\) should return Symfony\\\\Component\\\\Form\\\\FormTypeInterface but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 1
path: src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldType.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Entity/Participation.php
-
message: "#^Method Chill\\\\EventBundle\\\\Entity\\\\Participation\\:\\:offsetGet\\(\\) should return mixed but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Entity/Participation.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php
-
message: "#^Parameter \\$resolver of method Chill\\\\EventBundle\\\\Form\\\\EventTypeType\\:\\:setDefaultOptions\\(\\) has invalid type Symfony\\\\Component\\\\OptionsResolver\\\\OptionsResolverInterface\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/EventTypeType.php
-
message: "#^Parameter \\$resolver of method Chill\\\\EventBundle\\\\Form\\\\RoleType\\:\\:setDefaultOptions\\(\\) has invalid type Symfony\\\\Component\\\\OptionsResolver\\\\OptionsResolverInterface\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/RoleType.php
-
message: "#^Parameter \\$resolver of method Chill\\\\EventBundle\\\\Form\\\\StatusType\\:\\:setDefaultOptions\\(\\) has invalid type Symfony\\\\Component\\\\OptionsResolver\\\\OptionsResolverInterface\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/StatusType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Form/Type/PickEventType.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillEventBundle/Search/EventSearch.php
-
message: "#^Method Chill\\\\EventBundle\\\\Search\\\\EventSearch\\:\\:renderResult\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillEventBundle/Search/EventSearch.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php
-
message: "#^Casting to string something that's already string\\.$#"
count: 5
path: src/Bundle/ChillFamilyMembersBundle/Entity/AbstractFamilyMember.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillFamilyMembersBundle/Form/FamilyMemberType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php
-
message: "#^Parameter \\$scope of method Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\CRUDController\\:\\:getReachableCenters\\(\\) has invalid type Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\Scope\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php
-
message: "#^Method Chill\\\\MainBundle\\\\CRUD\\\\Resolver\\\\Resolver\\:\\:getConfigValue\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php
-
message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\ChillImportUsersCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/ChillImportUsersCommand.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/ChillImportUsersCommand.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\ChillUserSendRenewPasswordCodeCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\LoadAndUpdateLanguagesCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\LoadCountriesCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\LoadPostalCodesCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php
-
message: "#^Method Chill\\\\MainBundle\\\\Command\\\\SetPasswordCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Command/SetPasswordCommand.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Controller/PasswordController.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Controller/PostalCodeController.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php
-
message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#"
count: 5
path: src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ExportsCompilerPass.php
-
message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/SearchableServicesCompilerPass.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php
-
message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Entity/Address.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Entity/User.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Entity/User.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 6
path: src/Bundle/ChillMainBundle/Export/ExportManager.php
-
message: "#^Only booleans are allowed in a ternary operator condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Form/Type/AddressType.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Form/Type/AddressType.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 3
path: src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php
-
message: "#^Only booleans are allowed in a negated boolean, mixed given\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Form/Type/TranslatableStringFormType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Security/ParentRoleHelper.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverVoter.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 3
path: src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php
-
message: "#^Method Chill\\\\MainBundle\\\\Timeline\\\\TimelineBuilder\\:\\:getTemplateData\\(\\) should return array but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php
-
message: "#^Method Chill\\\\PersonBundle\\\\Command\\\\ChillPersonMoveCommand\\:\\:execute\\(\\) should return int but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php
-
message: "#^Call to function array_search\\(\\) requires parameter \\#3 to be set\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 6
path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Controller/PersonController.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Entity/Person.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Entity/PersonPhone.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php
-
message: "#^Only booleans are allowed in a ternary operator condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/Type/PersonAltNameType.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Household/MembersEditor.php
-
message: "#^Method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:buildQueryBySocialActionWithDescendants\\(\\) has invalid return type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\QueryBuilder\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Repository/PersonRepository.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 3
path: src/Bundle/ChillPersonBundle/Search/PersonSearch.php
-
message: "#^Method Chill\\\\PersonBundle\\\\Search\\\\PersonSearch\\:\\:renderResult\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Search/PersonSearch.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillPersonBundle/Templating/Entity/ClosingMotiveRender.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillPersonBundle/Timeline/AbstractTimelineAccompanyingPeriod.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReportACL.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php
-
message: "#^Method Chill\\\\ReportBundle\\\\DataFixtures\\\\ORM\\\\LoadReports\\:\\:getRandomChoice\\(\\) should return array\\<string\\>\\|string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 4
path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 2
path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php
-
message: "#^Method Chill\\\\ReportBundle\\\\Security\\\\Authorization\\\\ReportVoter\\:\\:supports\\(\\) should return bool but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 4
path: src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillTaskBundle/DataFixtures/ORM/LoadTaskACL.php
-
message: "#^Casting to string something that's already string\\.$#"
count: 3
path: src/Bundle/ChillTaskBundle/Entity/AbstractTask.php
-
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
count: 2
path: src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 5
path: src/Bundle/ChillTaskBundle/Repository/SingleTaskRepository.php
-
message: "#^Method Chill\\\\TaskBundle\\\\Timeline\\\\SingleTaskTaskLifeCycleEventTimelineProvider\\:\\:getTransitionByName\\(\\) should return Symfony\\\\Component\\\\Workflow\\\\Transition but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillTaskBundle/Timeline/SingleTaskTaskLifeCycleEventTimelineProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php
-
message: "#^Method Chill\\\\TaskBundle\\\\Timeline\\\\TaskLifeCycleEventTimelineProvider\\:\\:getTransitionByName\\(\\) should return Symfony\\\\Component\\\\Workflow\\\\Transition but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 4
path: src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
-
message: "#^Method Chill\\\\ThirdPartyBundle\\\\Search\\\\ThirdPartySearch\\:\\:renderResult\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php
-
message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php
-
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
count: 1
path: src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php

24
phpstan.neon.dist Normal file
View File

@ -0,0 +1,24 @@
parameters:
level: 1
paths:
- src/
excludePaths:
- src/Bundle/*/Tests/*
- src/Bundle/*/tests/*
- src/Bundle/*/Test/*
- src/Bundle/*/config/*
- src/Bundle/*/migrations/*
- src/Bundle/*/translations/*
- src/Bundle/*/Resources/*
- src/Bundle/*/src/Tests/*
- src/Bundle/*/src/Test/*
- src/Bundle/*/src/config/*
- src/Bundle/*/src/migrations/*
- src/Bundle/*/src/translations/*
- src/Bundle/*/src/Resources/*
includes:
- phpstan-types.neon
- phpstan-critical.neon
- phpstan-baseline.neon

View File

@ -37,6 +37,9 @@
<testsuite name="CalendarBundle"> <testsuite name="CalendarBundle">
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory> <directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
</testsuite> </testsuite>
<testsuite name="DocGeneratorBundle">
<directory suffix="Test.php">src/Bundle/ChillDocGeneratorBundle/tests/</directory>
</testsuite>
</testsuites> </testsuites>
<listeners> <listeners>

View File

@ -1,37 +1,26 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Repository\LocationRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form; use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -42,33 +31,56 @@ use Chill\ActivityBundle\Form\ActivityType;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\SerializerInterface;
/** final class ActivityController extends AbstractController
* Class ActivityController
*
* @package Chill\ActivityBundle\Controller
*/
class ActivityController extends AbstractController
{ {
protected EventDispatcherInterface $eventDispatcher; private EventDispatcherInterface $eventDispatcher;
protected AuthorizationHelper $authorizationHelper; private LoggerInterface $logger;
protected LoggerInterface $logger; private SerializerInterface $serializer;
protected SerializerInterface $serializer; private ActivityACLAwareRepositoryInterface $activityACLAwareRepository;
protected ActivityACLAwareRepositoryInterface $activityACLAwareRepository; private ActivityTypeRepository $activityTypeRepository;
private ThirdPartyRepository $thirdPartyRepository;
private PersonRepository $personRepository;
private LocationRepository $locationRepository;
private EntityManagerInterface $entityManager;
private ActivityRepository $activityRepository;
private AccompanyingPeriodRepository $accompanyingPeriodRepository;
private ActivityTypeCategoryRepository $activityTypeCategoryRepository;
public function __construct( public function __construct(
ActivityACLAwareRepositoryInterface $activityACLAwareRepository, ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
ActivityTypeRepository $activityTypeRepository,
ActivityTypeCategoryRepository $activityTypeCategoryRepository,
PersonRepository $personRepository,
ThirdPartyRepository $thirdPartyRepository,
LocationRepository $locationRepository,
ActivityRepository $activityRepository,
AccompanyingPeriodRepository $accompanyingPeriodRepository,
EntityManagerInterface $entityManager,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger, LoggerInterface $logger,
SerializerInterface $serializer SerializerInterface $serializer
) { ) {
$this->activityACLAwareRepository = $activityACLAwareRepository; $this->activityACLAwareRepository = $activityACLAwareRepository;
$this->activityTypeRepository = $activityTypeRepository;
$this->activityTypeCategoryRepository = $activityTypeCategoryRepository;
$this->personRepository = $personRepository;
$this->thirdPartyRepository = $thirdPartyRepository;
$this->locationRepository = $locationRepository;
$this->activityRepository = $activityRepository;
$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
$this->entityManager = $entityManager;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
$this->logger = $logger; $this->logger = $logger;
$this->serializer = $serializer; $this->serializer = $serializer;
} }
@ -78,8 +90,8 @@ class ActivityController extends AbstractController
*/ */
public function listAction(Request $request): Response public function listAction(Request $request): Response
{ {
$em = $this->getDoctrine()->getManager();
$view = null; $view = null;
$activities = [];
// TODO: add pagination // TODO: add pagination
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -89,10 +101,10 @@ class ActivityController extends AbstractController
$activities = $this->activityACLAwareRepository $activities = $this->activityACLAwareRepository
->findByPerson($person, ActivityVoter::SEE, 0, null); ->findByPerson($person, ActivityVoter::SEE, 0, null);
$event = new PrivacyEvent($person, array( $event = new PrivacyEvent($person, [
'element_class' => Activity::class, 'element_class' => Activity::class,
'action' => 'list' 'action' => 'list'
)); ]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$view = 'ChillActivityBundle:Activity:listPerson.html.twig'; $view = 'ChillActivityBundle:Activity:listPerson.html.twig';
@ -105,16 +117,18 @@ class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
} }
return $this->render($view, array( return $this->render(
$view,
[
'activities' => $activities, 'activities' => $activities,
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, 'accompanyingCourse' => $accompanyingPeriod,
)); ]
);
} }
public function selectTypeAction(Request $request): Response public function selectTypeAction(Request $request): Response
{ {
$em = $this->getDoctrine()->getManager();
$view = null; $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -127,12 +141,17 @@ class ActivityController extends AbstractController
$data = []; $data = [];
$activityTypeCategories = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityTypeCategory::class) $activityTypeCategories = $this
->activityTypeCategoryRepository
->findBy(['active' => true], ['ordering' => 'ASC']); ->findBy(['active' => true], ['ordering' => 'ASC']);
foreach ($activityTypeCategories as $activityTypeCategory) { foreach ($activityTypeCategories as $activityTypeCategory) {
$activityTypes = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) $activityTypes = $this
->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']); ->activityTypeRepository
->findBy(
['active' => true, 'category' => $activityTypeCategory],
['ordering' => 'ASC']
);
$data[] = [ $data[] = [
'activityTypeCategory' => $activityTypeCategory, 'activityTypeCategory' => $activityTypeCategory,
@ -140,12 +159,6 @@ class ActivityController extends AbstractController
]; ];
} }
if ($request->query->has('activityData')) {
$activityData = $request->query->get('activityData');
} else {
$activityData = [];
}
if ($view === null) { if ($view === null) {
throw $this->createNotFoundException('Template not found'); throw $this->createNotFoundException('Template not found');
} }
@ -154,13 +167,13 @@ class ActivityController extends AbstractController
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, 'accompanyingCourse' => $accompanyingPeriod,
'data' => $data, 'data' => $data,
'activityData' => $activityData 'activityData' => $request->query->get('activityData', []),
]); ]);
} }
public function newAction(Request $request): Response public function newAction(Request $request): Response
{ {
$em = $this->getDoctrine()->getManager(); $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -171,8 +184,7 @@ class ActivityController extends AbstractController
} }
$activityType_id = $request->get('activityType_id', 0); $activityType_id = $request->get('activityType_id', 0);
$activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) $activityType = $this->activityTypeRepository->find($activityType_id);
->find($activityType_id);
if (isset($activityType) && !$activityType->isActive()) { if (isset($activityType) && !$activityType->isActive()) {
throw new \InvalidArgumentException('Activity type must be active'); throw new \InvalidArgumentException('Activity type must be active');
@ -230,20 +242,20 @@ class ActivityController extends AbstractController
if (array_key_exists('personsId', $activityData)) { if (array_key_exists('personsId', $activityData)) {
foreach($activityData['personsId'] as $personId){ foreach($activityData['personsId'] as $personId){
$concernedPerson = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)->find($personId); $concernedPerson = $this->personRepository->find($personId);
$entity->addPerson($concernedPerson); $entity->addPerson($concernedPerson);
} }
} }
if (array_key_exists('professionalsId', $activityData)) { if (array_key_exists('professionalsId', $activityData)) {
foreach($activityData['professionalsId'] as $professionalsId){ foreach($activityData['professionalsId'] as $professionalsId){
$professional = $em->getRepository(\Chill\ThirdPartyBundle\Entity\ThirdParty::class)->find($professionalsId); $professional = $this->thirdPartyRepository->find($professionalsId);
$entity->addThirdParty($professional); $entity->addThirdParty($professional);
} }
} }
if (array_key_exists('location', $activityData)) { if (array_key_exists('location', $activityData)) {
$location = $em->getRepository(\Chill\MainBundle\Entity\Location::class)->find($activityData['location']); $location = $this->locationRepository->find($activityData['location']);
$entity->setLocation($location); $entity->setLocation($location);
} }
@ -268,8 +280,8 @@ class ActivityController extends AbstractController
])->handleRequest($request); ])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity); $this->entityManager->persist($entity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); $this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
@ -297,7 +309,7 @@ class ActivityController extends AbstractController
public function showAction(Request $request, $id): Response public function showAction(Request $request, $id): Response
{ {
$em = $this->getDoctrine()->getManager(); $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -307,13 +319,14 @@ class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:showPerson.html.twig'; $view = 'ChillActivityBundle:Activity:showPerson.html.twig';
} }
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); $entity = $this->activityRepository->find($id);
if (!$entity) { if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
} }
if (null !== $accompanyingPeriod) { if (null !== $accompanyingPeriod) {
// @TODO: Properties created dynamically.
$entity->personsAssociated = $entity->getPersonsAssociated(); $entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated(); $entity->personsNotAssociated = $entity->getPersonsNotAssociated();
} }
@ -321,7 +334,7 @@ class ActivityController extends AbstractController
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); $deleteForm = $this->createDeleteForm($entity->getId(), $person, $accompanyingPeriod);
// TODO // TODO
/* /*
@ -337,21 +350,20 @@ class ActivityController extends AbstractController
throw $this->createNotFoundException('Template not found'); throw $this->createNotFoundException('Template not found');
} }
return $this->render($view, array( return $this->render($view, [
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, 'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity, 'entity' => $entity,
'delete_form' => $deleteForm->createView(), 'delete_form' => $deleteForm->createView(),
)); ]);
} }
/** /**
* Displays a form to edit an existing Activity entity. * Displays a form to edit an existing Activity entity.
*
*/ */
public function editAction($id, Request $request): Response public function editAction($id, Request $request): Response
{ {
$em = $this->getDoctrine()->getManager(); $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -361,9 +373,9 @@ class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:editPerson.html.twig'; $view = 'ChillActivityBundle:Activity:editPerson.html.twig';
} }
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); $entity = $this->activityRepository->find($id);
if (!$entity) { if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
} }
@ -378,17 +390,18 @@ class ActivityController extends AbstractController
])->handleRequest($request); ])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity); $this->entityManager->persist($entity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!'));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id; $params['id'] = $entity->getId();
return $this->redirectToRoute('chill_activity_activity_show', $params); return $this->redirectToRoute('chill_activity_activity_show', $params);
} }
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); $deleteForm = $this->createDeleteForm($entity->getId(), $person, $accompanyingPeriod);
/* /*
* TODO * TODO
@ -406,23 +419,22 @@ class ActivityController extends AbstractController
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, array( return $this->render($view, [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $form->createView(), 'edit_form' => $form->createView(),
'delete_form' => $deleteForm->createView(), 'delete_form' => $deleteForm->createView(),
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, 'accompanyingCourse' => $accompanyingPeriod,
'activity_json' => $activity_array 'activity_json' => $activity_array
)); ]);
} }
/** /**
* Deletes a Activity entity. * Deletes a Activity entity.
*
*/ */
public function deleteAction(Request $request, $id) public function deleteAction(Request $request, $id)
{ {
$em = $this->getDoctrine()->getManager(); $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -432,8 +444,7 @@ class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
} }
/* @var $activity Activity */ $activity = $this->activityRepository->find($id);
$activity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$activity) { if (!$activity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
@ -442,35 +453,37 @@ class ActivityController extends AbstractController
// TODO // TODO
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
$form = $this->createDeleteForm($id, $person, $accompanyingPeriod); $form = $this->createDeleteForm($activity->getId(), $person, $accompanyingPeriod);
if ($request->getMethod() === Request::METHOD_DELETE) { if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isValid()) { if ($form->isValid()) {
$this->logger->notice("An activity has been removed", [
$this->logger->notice("An activity has been removed", array(
'by_user' => $this->getUser()->getUsername(), 'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(), 'activity_id' => $activity->getId(),
'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, 'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null,
'comment' => $activity->getComment()->getComment(), 'comment' => $activity->getComment()->getComment(),
'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, 'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null,
'reasons_ids' => $activity->getReasons() 'reasons_ids' => $activity->getReasons()
->map(function ($ar) { return $ar->getId(); }) ->map(
static fn (ActivityReason $ar): int => $ar->getId()
)
->toArray(), ->toArray(),
'type_id' => $activity->getType()->getId(), 'type_id' => $activity->getType()->getId(),
'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, 'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null,
'date' => $activity->getDate()->format('Y-m-d'), 'date' => $activity->getDate()->format('Y-m-d'),
'attendee' => $activity->getAttendee() 'attendee' => $activity->getAttendee()
)); ]);
$em->remove($activity); $this->entityManager->remove($activity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator') $this->addFlash('success', $this->get('translator')
->trans("The activity has been successfully removed.")); ->trans("The activity has been successfully removed."));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params = $this->buildParamsToUrl($person, $accompanyingPeriod);
return $this->redirectToRoute('chill_activity_activity_list', $params); return $this->redirectToRoute('chill_activity_activity_list', $params);
} }
} }
@ -479,18 +492,18 @@ class ActivityController extends AbstractController
throw $this->createNotFoundException('Template not found'); throw $this->createNotFoundException('Template not found');
} }
return $this->render($view, array( return $this->render($view, [
'activity' => $activity, 'activity' => $activity,
'delete_form' => $form->createView(), 'delete_form' => $form->createView(),
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, 'accompanyingCourse' => $accompanyingPeriod,
)); ]);
} }
/** /**
* Creates a form to delete a Activity entity by id. * Creates a form to delete a Activity entity by id.
*/ */
private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): FormInterface
{ {
$params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id; $params['id'] = $id;
@ -498,19 +511,17 @@ class ActivityController extends AbstractController
return $this->createFormBuilder() return $this->createFormBuilder()
->setAction($this->generateUrl('chill_activity_activity_delete', $params)) ->setAction($this->generateUrl('chill_activity_activity_delete', $params))
->setMethod('DELETE') ->setMethod('DELETE')
->add('submit', SubmitType::class, array('label' => 'Delete')) ->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm() ->getForm();
;
} }
private function getEntity(Request $request): array private function getEntity(Request $request): array
{ {
$em = $this->getDoctrine()->getManager();
$person = $accompanyingPeriod = null; $person = $accompanyingPeriod = null;
if ($request->query->has('person_id')) { if ($request->query->has('person_id')) {
$person_id = $request->get('person_id'); $person_id = $request->get('person_id');
$person = $em->getRepository(Person::class)->find($person_id); $person = $this->personRepository->find($person_id);
if ($person === null) { if ($person === null) {
throw $this->createNotFoundException('Person not found'); throw $this->createNotFoundException('Person not found');
@ -519,7 +530,7 @@ class ActivityController extends AbstractController
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} elseif ($request->query->has('accompanying_period_id')) { } elseif ($request->query->has('accompanying_period_id')) {
$accompanying_period_id = $request->get('accompanying_period_id'); $accompanying_period_id = $request->get('accompanying_period_id');
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id); $accompanyingPeriod = $this->accompanyingPeriodRepository->find($accompanying_period_id);
if ($accompanyingPeriod === null) { if ($accompanyingPeriod === null) {
throw $this->createNotFoundException('Accompanying Period not found'); throw $this->createNotFoundException('Accompanying Period not found');
@ -532,21 +543,20 @@ class ActivityController extends AbstractController
} }
return [ return [
$person, $accompanyingPeriod $person,
$accompanyingPeriod
]; ];
} }
private function buildParamsToUrl( private function buildParamsToUrl(?Person $person, ?AccompanyingPeriod $accompanyingPeriod): array
?Person $person, {
?AccompanyingPeriod $accompanyingPeriod
): array {
$params = []; $params = [];
if ($person) { if (null !== $person) {
$params['person_id'] = $person->getId(); $params['person_id'] = $person->getId();
} }
if ($accompanyingPeriod) { if (null !== $accompanyingPeriod) {
$params['accompanying_period_id'] = $accompanyingPeriod->getId(); $params['accompanying_period_id'] = $accompanyingPeriod->getId();
} }

View File

@ -22,9 +22,10 @@
namespace Chill\ActivityBundle\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\PersonBundle\DataFixtures\Helper\RandomPersonHelperTrait; use Chill\PersonBundle\Entity\Person;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Faker\Factory as FakerFactory; use Faker\Factory as FakerFactory;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
@ -32,26 +33,21 @@ use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason; use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType; use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes; use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/** class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
* Load reports into DB
*
* @author Champs-Libres Coop
*/
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{ {
use \Symfony\Component\DependencyInjection\ContainerAwareTrait; use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
use RandomPersonHelperTrait;
/** /**
* @var \Faker\Generator * @var \Faker\Generator
*/ */
private $faker; private $faker;
private EntityManagerInterface $em;
public function __construct() public function __construct(EntityManagerInterface $em)
{ {
$this->faker = FakerFactory::create('fr_FR'); $this->faker = FakerFactory::create('fr_FR');
$this->em = $em;
} }
public function getOrder() public function getOrder()
@ -86,15 +82,10 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
* *
* @return \Chill\ActivityBundle\Entity\ActivityReason * @return \Chill\ActivityBundle\Entity\ActivityReason
*/ */
private function getRandomActivityReason(array $excludingIds) private function getRandomActivityReason()
{ {
$reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)]; $reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)];
if (in_array($this->getReference($reasonRef)->getId(), $excludingIds)) {
// we have a reason which should be excluded. Find another...
return $this->getRandomActivityReason($excludingIds);
}
return $this->getReference($reasonRef); return $this->getReference($reasonRef);
} }
@ -109,7 +100,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
return $this->getReference($userRef); return $this->getReference($userRef);
} }
public function newRandomActivity($person) public function newRandomActivity($person): ?Activity
{ {
$activity = (new Activity()) $activity = (new Activity())
->setUser($this->getRandomUser()) ->setUser($this->getRandomUser())
@ -122,11 +113,13 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
// ->setAttendee($this->faker->boolean()) // ->setAttendee($this->faker->boolean())
$usedId = array();
for ($i = 0; $i < rand(0, 4); $i++) { for ($i = 0; $i < rand(0, 4); $i++) {
$reason = $this->getRandomActivityReason($usedId); $reason = $this->getRandomActivityReason();
$usedId[] = $reason->getId(); if (null !== $reason) {
$activity->addReason($reason); $activity->addReason($reason);
} else {
return null;
}
} }
return $activity; return $activity;
@ -134,20 +127,19 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
public function load(ObjectManager $manager) public function load(ObjectManager $manager)
{ {
$persons = $this->container->get('doctrine.orm.entity_manager') $persons = $this->em
->getRepository('ChillPersonBundle:Person') ->getRepository(Person::class)
->findAll(); ->findAll();
foreach ($persons as $person) { foreach ($persons as $person) {
$activityNbr = rand(0,3); $activityNbr = rand(0,3);
$ref = 'activity_'.$person->getFullnameCanonical();
for ($i = 0; $i < $activityNbr; $i ++) { for ($i = 0; $i < $activityNbr; $i ++) {
$activity = $this->newRandomActivity($person); $activity = $this->newRandomActivity($person);
if (null !== $activity) {
$manager->persist($activity); $manager->persist($activity);
} }
}
$this->setReference($ref, $activity);
} }
$manager->flush(); $manager->flush();
} }

View File

@ -1,27 +1,8 @@
<?php <?php
/*
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Entity; namespace Chill\ActivityBundle\Entity;
use Chill\DocStoreBundle\Entity\Document; use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\Location;
use Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodLinkedWithSocialIssuesEntityInterface; use Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodLinkedWithSocialIssuesEntityInterface;
@ -38,7 +19,7 @@ use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\HasScopeInterface;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
@ -202,7 +183,7 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
return $this->id; return $this->id;
} }
public function setUser(User $user): self public function setUser(UserInterface $user): self
{ {
$this->user = $user; $this->user = $user;

View File

@ -1,31 +1,12 @@
<?php <?php
/* declare(strict_types=1);
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Entity; namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Class ActivityTypeCateogry
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity() * @ORM\Entity()
* @ORM\Table(name="activitytypecategory") * @ORM\Table(name="activitytypecategory")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks()
@ -37,7 +18,7 @@ class ActivityTypeCategory
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private ?int $id; private ?int $id = null;
/** /**
* @ORM\Column(type="json") * @ORM\Column(type="json")
@ -54,10 +35,7 @@ class ActivityTypeCategory
*/ */
private float $ordering = 0.0; private float $ordering = 0.0;
/** public function getId(): ?int
* Get id
*/
public function getId(): int
{ {
return $this->id; return $this->id;
} }

View File

@ -1,70 +1,39 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
/** class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonAggregator implements AggregatorInterface,
ExportElementValidatedInterface
{ {
/** protected ActivityReasonCategoryRepository $activityReasonCategoryRepository;
*
* @var EntityRepository
*/
protected $categoryRepository;
/** protected ActivityReasonRepository $activityReasonRepository;
*
* @var EntityRepository
*/
protected $reasonRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
public function __construct( public function __construct(
EntityRepository $categoryRepository, ActivityReasonCategoryRepository $activityReasonCategoryRepository,
EntityRepository $reasonRepository, ActivityReasonRepository $activityReasonRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelper $translatableStringHelper
) { ) {
$this->categoryRepository = $categoryRepository; $this->activityReasonCategoryRepository = $activityReasonCategoryRepository;
$this->reasonRepository = $reasonRepository; $this->activityReasonRepository = $activityReasonRepository;
$this->stringHelper = $stringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
@ -77,7 +46,7 @@ class ActivityReasonAggregator implements AggregatorInterface,
$elem = 'category.id'; $elem = 'category.id';
$alias = 'activity_categories_id'; $alias = 'activity_categories_id';
} else { } 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);
@ -94,10 +63,11 @@ class ActivityReasonAggregator implements AggregatorInterface,
) { ) {
$qb->add( $qb->add(
'join', 'join',
array('activity' => [
new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') 'activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')
), ],
true); true
);
} }
// join category if necessary // join category if necessary
@ -143,28 +113,33 @@ class ActivityReasonAggregator implements AggregatorInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('level', ChoiceType::class, array( $builder->add(
'choices' => array( 'level',
ChoiceType::class,
[
'choices' => [
'By reason' => 'reasons', 'By reason' => 'reasons',
'By category of reason' => 'categories' 'By category of reason' => 'categories'
), ],
'multiple' => false, 'multiple' => false,
'expanded' => true, 'expanded' => true,
'label' => 'Reason\'s level' 'label' => "Reason's level"
)); ]
);
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['level'] === null) { if ($data['level'] === null) {
$context->buildViolation("The reasons's level should not be empty") $context
->buildViolation("The reasons's level should not be empty.")
->addViolation(); ->addViolation();
} }
} }
public function getTitle() public function getTitle()
{ {
return "Aggregate by activity reason"; return 'Aggregate by activity reason';
} }
public function addRole() public function addRole()
@ -177,41 +152,33 @@ class ActivityReasonAggregator implements AggregatorInterface,
// for performance reason, we load data from db only once // for performance reason, we load data from db only once
switch ($data['level']) { switch ($data['level']) {
case 'reasons': case 'reasons':
$this->reasonRepository->findBy(array('id' => $values)); $this->activityReasonRepository->findBy(['id' => $values]);
break; break;
case 'categories': case 'categories':
$this->categoryRepository->findBy(array('id' => $values)); $this->activityReasonCategoryRepository->findBy(['id' => $values]);
break; break;
default: default:
throw new \RuntimeException(sprintf("the level data '%s' is invalid", throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level']));
$data['level']));
} }
return function($value) use ($data) { return function($value) use ($data) {
if ($value === '_header') { if ($value === '_header') {
return $data['level'] === 'reasons' ? return $data['level'] === 'reasons' ? 'Group by reasons' : 'Group by categories of reason';
'Group by reasons'
:
'Group by categories of reason'
;
} }
switch ($data['level']) { switch ($data['level']) {
case 'reasons': case 'reasons':
/* @var $r \Chill\ActivityBundle\Entity\ActivityReason */ $r = $this->activityReasonRepository->find($value);
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName()) return sprintf(
." > " "%s > %s",
. $this->stringHelper->localize($r->getName()); $this->translatableStringHelper->localize($r->getCategory()->getName()),
; $this->translatableStringHelper->localize($r->getName())
break; );
case 'categories': case 'categories':
$c = $this->categoryRepository->find($value); $c = $this->activityReasonCategoryRepository->find($value);
return $this->stringHelper->localize($c->getName()); return $this->translatableStringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
} }
}; };
@ -222,12 +189,14 @@ class ActivityReasonAggregator implements AggregatorInterface,
// add select element // add select element
if ($data['level'] === 'reasons') { if ($data['level'] === 'reasons') {
return array('activity_reasons_id'); return array('activity_reasons_id');
} elseif ($data['level'] === 'categories') { }
if ($data['level'] === 'categories') {
return array ('activity_categories_id'); return array ('activity_categories_id');
} else {
throw new \RuntimeException('the data provided are not recognised');
} }
throw new \RuntimeException('The data provided are not recognised.');
} }
} }

View File

@ -1,61 +1,32 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityTypeAggregator implements AggregatorInterface class ActivityTypeAggregator implements AggregatorInterface
{ {
protected ActivityTypeRepository $activityTypeRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var EntityRepository
*/
protected $typeRepository;
/** public const KEY = 'activity_type_aggregator';
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
const KEY = 'activity_type_aggregator';
public function __construct( public function __construct(
EntityRepository $typeRepository, ActivityTypeRepository $activityTypeRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->typeRepository = $typeRepository; $this->activityTypeRepository = $activityTypeRepository;
$this->stringHelper = $stringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
@ -64,7 +35,7 @@ class ActivityTypeAggregator implements AggregatorInterface
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
// add the "group by" part // add the "group by" part
$groupBy = $qb->addGroupBy(self::KEY); $qb->addGroupBy(self::KEY);
} }
/** /**
@ -97,7 +68,7 @@ class ActivityTypeAggregator implements AggregatorInterface
public function getTitle() public function getTitle()
{ {
return "Aggregate by activity type"; return 'Aggregate by activity type';
} }
public function addRole() public function addRole()
@ -105,27 +76,25 @@ class ActivityTypeAggregator implements AggregatorInterface
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data): \Closure
{ {
// for performance reason, we load data from db only once // for performance reason, we load data from db only once
$this->typeRepository->findBy(array('id' => $values)); $this->activityTypeRepository->findBy(['id' => $values]);
return function($value) use ($data) { return function($value): string {
if ($value === '_header') { if ($value === '_header') {
return 'Activity type'; return 'Activity type';
} }
/* @var $r \Chill\ActivityBundle\Entity\ActivityType */ $t = $this->activityTypeRepository->find($value);
$t = $this->typeRepository->find($value);
return $this->stringHelper->localize($t->getName()); return $this->translatableStringHelper->localize($t->getName());
}; };
} }
public function getQueryKeys($data) public function getQueryKeys($data): array
{ {
return array(self::KEY); return [self::KEY];
} }
} }

View File

@ -1,49 +1,24 @@
<?php <?php
/*
* Copyright (C) 2019 Champs Libres Cooperative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\MainBundle\Repository\UserRepository;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query\Expr\Join;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityUserAggregator implements AggregatorInterface class ActivityUserAggregator implements AggregatorInterface
{ {
/** public const KEY = 'activity_user_id';
*
* @var EntityManagerInterface
*/
protected $em;
const KEY = 'activity_user_id'; private UserRepository $userRepository;
function __construct(EntityManagerInterface $em) public function __construct(
{ UserRepository $userRepository
$this->em = $em; ) {
$this->userRepository = $userRepository;
} }
public function addRole() public function addRole()
@ -73,17 +48,14 @@ class ActivityUserAggregator implements AggregatorInterface
public function getLabels($key, $values, $data): \Closure public function getLabels($key, $values, $data): \Closure
{ {
// preload users at once // preload users at once
$this->em->getRepository(User::class) $this->userRepository->findBy(['id' => $values]);
->findBy(['id' => $values]);
return function($value) { return function($value) {
switch ($value) { if ($value === '_header') {
case '_header':
return 'activity user'; return 'activity user';
default:
return $this->em->getRepository(User::class)->find($value)
->getUsername();
} }
return $this->userRepository->find($value)->getUsername();
}; };
} }
@ -94,6 +66,6 @@ class ActivityUserAggregator implements AggregatorInterface
public function getTitle(): string public function getTitle(): string
{ {
return "Aggregate by activity user"; return 'Aggregate by activity user';
} }
} }

View File

@ -1,64 +1,40 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountActivity implements ExportInterface class CountActivity implements ExportInterface
{ {
/** protected ActivityRepository $activityRepository;
*
* @var EntityManagerInterface
*/
protected $entityManager;
public function __construct( public function __construct(
EntityManagerInterface $em ActivityRepository $activityRepository
) ) {
{ $this->activityRepository = $activityRepository;
$this->entityManager = $em;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
} }
public function getDescription() public function getDescription()
{ {
return "Count activities by various parameters."; return 'Count activities by various parameters.';
} }
public function getTitle() public function getTitle()
{ {
return "Count activities"; return 'Count activities';
} }
public function getType() public function getType()
@ -68,24 +44,24 @@ class CountActivity implements ExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{ {
$qb = $this->entityManager->createQueryBuilder(); $centers = array_map(static fn($el) => $el['center'], $acl);
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb->select('COUNT(activity.id) as export_count_activity') $qb = $this
->from('ChillActivityBundle:Activity', 'activity') ->activityRepository
->join('activity.person', 'person') ->createQueryBuilder('activity')
; ->select('COUNT(activity.id) as export_count_activity')
->join('activity.person', 'person');
$qb->where($qb->expr()->in('person.center', ':centers')) $qb
->setParameter('centers', $centers) ->where($qb->expr()->in('person.center', ':centers'))
; ->setParameter('centers', $centers);
return $qb; return $qb;
} }
public function supportsModifiers() public function supportsModifiers()
{ {
return array('person', 'activity'); return ['person', 'activity'];
} }
public function requiredRole() public function requiredRole()
@ -95,7 +71,7 @@ class CountActivity implements ExportInterface
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [FormatterInterface::TYPE_TABULAR];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
@ -104,18 +80,12 @@ class CountActivity implements ExportInterface
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 function($value) { return static fn($value) => $value === '_header' ? 'Number of activities' : $value;
return $value === '_header' ?
'Number of activities'
:
$value
;
};
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array('export_count_activity'); return ['export_count_activity'];
} }
public function getResult($qb, $data) public function getResult($qb, $data)

View File

@ -1,31 +1,14 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Export\ListInterface;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Entity\Scope; use Doctrine\DBAL\Exception\InvalidArgumentException;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -37,33 +20,17 @@ use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Create a list for all activities
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ListActivity implements ListInterface class ListActivity implements ListInterface
{ {
private ActivityRepository $activityRepository;
/** protected EntityManagerInterface $entityManager;
*
* @var EntityManagerInterface
*/
protected $entityManager;
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $fields = array( protected array $fields = [
'id', 'id',
'date', 'date',
'durationTime', 'durationTime',
@ -75,32 +42,28 @@ class ListActivity implements ListInterface
'person_firstname', 'person_firstname',
'person_lastname', 'person_lastname',
'person_id' 'person_id'
); ];
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
TranslatorInterface $translator, TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper,
) ActivityRepository $activityRepository
{ ) {
$this->entityManager = $em; $this->entityManager = $em;
$this->translator = $translator; $this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityRepository = $activityRepository;
} }
/**
* {@inheritDoc}
*
* @param FormBuilderInterface $builder
*/
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('fields', ChoiceType::class, array( $builder->add('fields', ChoiceType::class, [
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choices' => array_combine($this->fields, $this->fields), 'choices' => array_combine($this->fields, $this->fields),
'label' => 'Fields to include in export', 'label' => 'Fields to include in export',
'constraints' => [new Callback(array( 'constraints' => [new Callback([
'callback' => function($selected, ExecutionContextInterface $context) { 'callback' => function($selected, ExecutionContextInterface $context) {
if (count($selected) === 0) { if (count($selected) === 0) {
$context->buildViolation('You must select at least one element') $context->buildViolation('You must select at least one element')
@ -108,19 +71,14 @@ class ListActivity implements ListInterface
->addViolation(); ->addViolation();
} }
} }
))] ])]
)); ]);
} }
/**
* {@inheritDoc}
*
* @return type
*/
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(FormatterInterface::TYPE_LIST); return [FormatterInterface::TYPE_LIST];
} }
public function getDescription() public function getDescription()
@ -133,29 +91,32 @@ class ListActivity implements ListInterface
switch ($key) switch ($key)
{ {
case 'date' : case 'date' :
return function($value) { return static function($value) {
if ($value === '_header') return 'date'; if ($value === '_header') {
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'); return $date->format('d-m-Y');
}; };
case 'attendee': case 'attendee':
return function($value) { return static function($value) {
if ($value === '_header') return 'attendee'; if ($value === '_header') {
return 'attendee';
}
return $value ? 1 : 0; return $value ? 1 : 0;
}; };
case 'list_reasons' : case 'list_reasons' :
/* @var $activityReasonsRepository EntityRepository */ $activityRepository = $this->activityRepository;
$activityRepository = $this->entityManager
->getRepository('ChillActivityBundle:Activity');
return function($value) use ($activityRepository) { return function($value) use ($activityRepository): string {
if ($value === '_header') return 'activity reasons'; if ($value === '_header') {
return 'activity reasons';
}
$activity = $activityRepository $activity = $activityRepository->find($value);
->find($value);
return implode(", ", array_map(function(ActivityReason $r) { return implode(", ", array_map(function(ActivityReason $r) {
@ -168,21 +129,25 @@ class ListActivity implements ListInterface
}; };
case 'circle_name' : case 'circle_name' :
return function($value) { return function($value) {
if ($value === '_header') return 'circle'; if ($value === '_header') {
return 'circle';
}
return $this->translatableStringHelper return $this->translatableStringHelper->localize(json_decode($value, true));
->localize(json_decode($value, true));
}; };
case 'type_name' : case 'type_name' :
return function($value) { return function($value) {
if ($value === '_header') return 'activity type'; if ($value === '_header') {
return 'activity type';
}
return $this->translatableStringHelper return $this->translatableStringHelper->localize(json_decode($value, true));
->localize(json_decode($value, true));
}; };
default: default:
return function($value) use ($key) { return static function($value) use ($key) {
if ($value === '_header') return $key; if ($value === '_header') {
return $key;
}
return $value; return $value;
}; };
@ -209,14 +174,13 @@ class ListActivity implements ListInterface
return 'activity'; return 'activity';
} }
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{ {
$centers = array_map(function($el) { return $el['center']; }, $acl); $centers = array_map(function($el) { return $el['center']; }, $acl);
// throw an error if any fields are present // throw an error if any fields are present
if (!\array_key_exists('fields', $data)) { if (!\array_key_exists('fields', $data)) {
throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " throw new InvalidArgumentException('Any fields have been checked.');
. "have been checked");
} }
$qb = $this->entityManager->createQueryBuilder(); $qb = $this->entityManager->createQueryBuilder();
@ -227,7 +191,6 @@ class ListActivity implements ListInterface
->join('person.center', 'center') ->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)') ->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers); ->setParameter('authorized_centers', $centers);
;
foreach ($this->fields as $f) { foreach ($this->fields as $f) {
if (in_array($f, $data['fields'])) { if (in_array($f, $data['fields'])) {
@ -269,8 +232,6 @@ class ListActivity implements ListInterface
} }
} }
return $qb; return $qb;
} }
@ -281,7 +242,7 @@ class ListActivity implements ListInterface
public function supportsModifiers() public function supportsModifiers()
{ {
return array('activity', 'person'); return ['activity', 'person'];
} }
} }

View File

@ -1,72 +1,45 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/** /**
* This export allow to compute stats on activity duration. * This export allow to compute stats on activity duration.
* *
* The desired stat must be given in constructor. * The desired stat must be given in constructor.
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class StatActivityDuration implements ExportInterface class StatActivityDuration implements ExportInterface
{ {
/** private ActivityRepository $activityRepository;
*
* @var EntityManagerInterface
*/
protected $entityManager;
const SUM = 'sum'; public const SUM = 'sum';
/** /**
* The action for this report. * The action for this report.
*
* @var string
*/ */
protected $action; protected string $action;
/** /**
* constructor
*
* @param EntityManagerInterface $em
* @param string $action the stat to perform * @param string $action the stat to perform
*/ */
public function __construct( public function __construct(
EntityManagerInterface $em, ActivityRepository $activityRepository,
$action = 'sum' string $action = 'sum'
) ) {
{
$this->entityManager = $em;
$this->action = $action; $this->action = $action;
$this->activityRepository = $activityRepository;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
} }
@ -74,14 +47,14 @@ class StatActivityDuration implements ExportInterface
public function getDescription() public function getDescription()
{ {
if ($this->action === self::SUM) { if ($this->action === self::SUM) {
return "Sum activities duration by various parameters."; return 'Sum activities duration by various parameters.';
} }
} }
public function getTitle() public function getTitle()
{ {
if ($this->action === self::SUM) { if ($this->action === self::SUM) {
return "Sum activity duration"; return 'Sum activity duration';
} }
} }
@ -91,29 +64,31 @@ class StatActivityDuration implements ExportInterface
return 'activity'; return 'activity';
} }
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{ {
$centers = array_map(function($el) { return $el['center']; }, $acl); $centers = array_map(
$qb = $this->entityManager->createQueryBuilder(); static fn(array $el): string => $el['center'],
$acl
);
$qb = $this->activityRepository->createQueryBuilder('activity');
$select = null;
if ($this->action === self::SUM) { if ($this->action === self::SUM) {
$select = "SUM(activity.durationTime) AS export_stat_activity"; $select = 'SUM(activity.durationTime) AS export_stat_activity';
} }
$qb->select($select) return $qb->select($select)
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person') ->join('activity.person', 'person')
->join('person.center', 'center') ->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers')) ->where($qb->expr()->in('center', ':centers'))
->setParameter(':centers', $centers) ->setParameter(':centers', $centers);
;
return $qb;
} }
public function supportsModifiers() public function supportsModifiers()
{ {
return array('person', 'activity'); return ['person', 'activity'];
} }
public function requiredRole() public function requiredRole()
@ -123,32 +98,23 @@ class StatActivityDuration implements ExportInterface
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [FormatterInterface::TYPE_TABULAR];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ($key !== 'export_stat_activity') { if ($key !== 'export_stat_activity') {
throw new \LogicException("the key $key is not used by this export"); throw new \LogicException(sprintf('The key %s is not used by this export', $key));
} }
switch ($this->action) { $header = $this->action === self::SUM ? 'Sum of activities duration' : false;
case self::SUM:
$header = "Sum of activities duration";
}
return function($value) use ($header) { return static fn(string $value) => $value === '_header' ? $header : $value;
return $value === '_header' ?
$header
:
$value
;
};
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array('export_stat_activity'); return ['export_stat_activity'];
} }
public function getResult($qb, $data) public function getResult($qb, $data)

View File

@ -1,25 +1,12 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
@ -28,31 +15,21 @@ use Chill\MainBundle\Form\Type\Export\FilterType;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityDateFilter implements FilterInterface class ActivityDateFilter implements FilterInterface
{ {
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
function __construct(TranslatorInterface $translator) function __construct(TranslatorInterface $translator)
{ {
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
} }
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$clause = $qb->expr()->between('activity.date', ':date_from', $clause = $qb->expr()->between('activity.date', ':date_from',
@ -74,23 +51,31 @@ class ActivityDateFilter implements FilterInterface
return 'activity'; return 'activity';
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add(
'label' => "Activities after this date", 'date_from',
DateType::class,
[
'label' => 'Activities after this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]
);
$builder->add('date_to', DateType::class, array( $builder->add(
'label' => "Activities before this date", 'date_to',
DateType::class,
[
'label' => 'Activities before this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]
);
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var $filterForm \Symfony\Component\Form\FormInterface */
@ -132,17 +117,18 @@ class ActivityDateFilter implements FilterInterface
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by date of activity: only between %date_from% and %date_to%", 'Filtered by date of activity: only between %date_from% and %date_to%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y') '%date_to%' => $data['date_to']->format('d-m-Y')
)); ]
];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by date activity"; return 'Filtered by date activity';
} }
} }

View File

@ -1,25 +1,12 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@ -28,41 +15,24 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
/** class ActivityReasonFilter implements FilterInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/** protected ActivityReasonRepository $activityReasonRepository;
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $reasonRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelper $helper,
EntityRepository $reasonRepository ActivityReasonRepository $activityReasonRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->reasonRepository = $reasonRepository; $this->activityReasonRepository = $activityReasonRepository;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@ -75,7 +45,7 @@ class ActivityReasonFilter implements FilterInterface,
&& &&
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons') !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
) )
OR ||
(! array_key_exists('activity', $join)) (! array_key_exists('activity', $join))
) { ) {
$qb->add( $qb->add(
@ -101,7 +71,7 @@ class ActivityReasonFilter implements FilterInterface,
* @param Join[] $joins * @param Join[] $joins
* @return boolean * @return boolean
*/ */
private function checkJoinAlreadyDefined(array $joins, $alias) private function checkJoinAlreadyDefined(array $joins, $alias): bool
{ {
foreach ($joins as $join) { foreach ($joins as $join) {
if ($join->getAlias() === $alias) { if ($join->getAlias() === $alias) {
@ -119,26 +89,20 @@ class ActivityReasonFilter implements FilterInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
//create a local copy of translatableStringHelper $builder->add('reasons', EntityType::class, [
$helper = $this->translatableStringHelper; 'class' => ActivityReason::class,
'choice_label' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()),
$builder->add('reasons', EntityType::class, array( 'group_by' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getName());
},
'group_by' => function(ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getCategory()->getName());
},
'multiple' => true, 'multiple' => true,
'expanded' => false 'expanded' => false
)); ]);
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['reasons'] === null || count($data['reasons']) === 0) { if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen") $context
->buildViolation('At least one reason must be chosen')
->addViolation(); ->addViolation();
} }
} }
@ -157,13 +121,15 @@ class ActivityReasonFilter implements FilterInterface,
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityReason $r) { fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
return "\"".$this->translatableStringHelper->localize($r->getName())."\""; $this->activityReasonRepository->findBy(array('id' => $data['reasons']->toArray()))
},
$this->reasonRepository->findBy(array('id' => $data['reasons']->toArray()))
); );
return array("Filtered by reasons: only %list%", return [
["%list%" => implode(", ", $reasonsNames)]); 'Filtered by reasons: only %list%',
[
'%list%' => implode(", ", $reasonsNames),
]
];
} }
} }

View File

@ -1,67 +1,37 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
/** class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInterface
*
*
*/
class ActivityTypeFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/** protected ActivityTypeRepository $activityTypeRepository;
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $typeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelperInterface $translatableStringHelper,
EntityRepository $typeRepository ActivityTypeRepository $activityTypeRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $translatableStringHelper;
$this->typeRepository = $typeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@ -101,23 +71,23 @@ class ActivityTypeFilter implements FilterInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
//create a local copy of translatableStringHelper $builder->add(
$helper = $this->translatableStringHelper; 'types',
EntityType::class,
$builder->add('types', EntityType::class, array( [
'class' => ActivityType::class, 'class' => ActivityType::class,
'choice_label' => function (ActivityType $type) use ($helper) { 'choice_label' => fn(ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
return $helper->localize($type->getName());
},
'multiple' => true, 'multiple' => true,
'expanded' => false 'expanded' => false
)); ]
);
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['types'] === null || count($data['types']) === 0) { if ($data['types'] === null || count($data['types']) === 0) {
$context->buildViolation("At least one type must be choosen") $context
->buildViolation('At least one type must be chosen')
->addViolation(); ->addViolation();
} }
} }
@ -136,13 +106,15 @@ class ActivityTypeFilter implements FilterInterface,
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityType $t) { fn(ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"',
return "\"".$this->translatableStringHelper->localize($t->getName())."\""; $this->activityTypeRepository->findBy(['id' => $data['types']->toArray()])
},
$this->typeRepository->findBy(array('id' => $data['types']->toArray()))
); );
return array("Filtered by activity type: only %list%", return [
["%list%" => implode(", ", $reasonsNames)]); 'Filtered by activity type: only %list%',
[
'%list%' => implode(", ", $reasonsNames),
]
];
} }
} }

View File

@ -1,25 +1,14 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
@ -29,43 +18,23 @@ use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
/** class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonHavingActivityBetweenDateFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
protected TranslatableStringHelperInterface $translatableStringHelper;
/** protected ActivityReasonRepository $activityReasonRepository;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/** protected TranslatorInterface $translator;
*
* @var EntityRepository
*/
protected $activityReasonRepository;
/**
*
* @var TranslatorInterface
*/
protected $translator;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
EntityRepository $activityReasonRepository, ActivityReasonRepository $activityReasonRepository,
TranslatorInterface $translator TranslatorInterface $translator
) { ) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
@ -73,32 +42,32 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
} }
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// create a query for activity // create a query for activity
$sqb = $qb->getEntityManager()->createQueryBuilder(); $sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select("person_person_having_activity.id") $sqb->select('person_person_having_activity.id')
->from("ChillActivityBundle:Activity", "activity_person_having_activity") ->from('ChillActivityBundle:Activity', 'activity_person_having_activity')
->join("activity_person_having_activity.person", "person_person_having_activity") ->join('activity_person_having_activity.person', 'person_person_having_activity');
;
// add clause between date // add clause between date
$sqb->where("activity_person_having_activity.date BETWEEN " $sqb->where('activity_person_having_activity.date BETWEEN '
. ":person_having_activity_between_date_from" . ':person_having_activity_between_date_from'
. " AND " . ' AND '
. ":person_having_activity_between_date_to"); . ':person_having_activity_between_date_to');
// add clause activity reason // add clause activity reason
$sqb->join('activity_person_having_activity.reasons', $sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
'reasons_person_having_activity');
$sqb->andWhere( $sqb->andWhere(
$sqb->expr()->in( $sqb->expr()->in(
'reasons_person_having_activity', 'reasons_person_having_activity', ':person_having_activity_reasons'
":person_having_activity_reasons") )
); );
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@ -123,42 +92,36 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
return Declarations::PERSON_IMPLIED_IN; return Declarations::PERSON_IMPLIED_IN;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add('date_from', DateType::class, [
'label' => "Implied in an activity after this date", 'label' => 'Implied in an activity after this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('date_to', DateType::class, array( $builder->add('date_to', DateType::class, [
'label' => "Implied in an activity before this date", 'label' => 'Implied in an activity before this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('reasons', EntityType::class, array( $builder->add('reasons', EntityType::class, [
'class' => 'ChillActivityBundle:ActivityReason', 'class' => ActivityReason::class,
'choice_label' => function (ActivityReason $reason) { 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()),
return $this->translatableStringHelper 'group_by' => fn(ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
->localize($reason->getName());
},
'group_by' => function(ActivityReason $reason) {
return $this->translatableStringHelper
->localize($reason->getCategory()->getName());
},
'data' => $this->activityReasonRepository->findAll(), 'data' => $this->activityReasonRepository->findAll(),
'multiple' => true, 'multiple' => true,
'expanded' => false, 'expanded' => false,
'label' => "Activity reasons for those activities" 'label' => 'Activity reasons for those activities'
)); ]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var FormInterface $filterForm */
$filterForm = $event->getForm()->getParent(); $filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
@ -198,31 +161,33 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['reasons'] === null || count($data['reasons']) === 0) { if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen") $context->buildViolation('At least one reason must be chosen')
->addViolation(); ->addViolation();
} }
} }
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by person having an activity between %date_from% and " 'Filtered by person having an activity between %date_from% and '
. "%date_to% with reasons %reasons_name%", . '%date_to% with reasons %reasons_name%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'), '%date_to%' => $data['date_to']->format('d-m-Y'),
"%reasons_name%" => implode(", ", array_map( '%reasons_name%' => implode(
function (ActivityReason $r) { ", ",
return '"'.$this->translatableStringHelper-> array_map(
localize($r->getName()).'"'; fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
}, $data['reasons']
$data['reasons'])) )
)); )
]
];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by person having an activity in a period"; return 'Filtered by person having an activity in a period';
} }
} }

View File

@ -1,56 +1,29 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Form\Type; namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
/**
* Description of TranslatableActivityType
*
* @author Champs-Libres Coop
*/
class TranslatableActivityType extends AbstractType class TranslatableActivityType extends AbstractType
{ {
protected TranslatableStringHelperInterface $translatableStringHelper;
/** protected ActivityTypeRepository $activityTypeRepository;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $activityTypeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelperInterface $helper,
EntityRepository $activityTypeRepository ActivityTypeRepository $activityTypeRepository
) ) {
{
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
@ -65,22 +38,21 @@ class TranslatableActivityType extends AbstractType
return EntityType::class; return EntityType::class;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) { public function buildForm(FormBuilderInterface $builder, array $options) {
/* @var $qb \Doctrine\ORM\QueryBuilder */ /* @var QueryBuilder $qb */
$qb = $options['query_builder']; $qb = $options['query_builder'];
if ($options['active_only'] === true) { if ($options['active_only'] === true) {
$qb->where($qb->expr()->eq('at.active', ':active')); $qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Types::BOOLEAN); $qb->setParameter('active', true, Types::BOOLEAN);
} }
} }
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults( $resolver->setDefaults(
array( array(
'class' => 'ChillActivityBundle:ActivityType', 'class' => ActivityType::class,
'active_only' => true, 'active_only' => true,
'query_builder' => $this->activityTypeRepository 'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'), ->createQueryBuilder('at'),

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityReasonCategory|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityReasonCategory|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityReasonCategory[] findAll()
* @method ActivityReasonCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityReasonCategoryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityReasonCategory::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityReason|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityReason|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityReason[] findAll()
* @method ActivityReason[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityReasonRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityReason::class);
}
}

View File

@ -1,24 +1,6 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Repository; namespace Chill\ActivityBundle\Repository;
@ -29,10 +11,10 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
/** /**
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null) * @method Activity|null find($id, $lockMode = null, $lockVersion = null)
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null) * @method Activity|null findOneBy(array $criteria, array $orderBy = null)
* @method AccompanyingPeriodParticipation[] findAll() * @method Activity[] findAll()
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) * @method Activity[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/ */
class ActivityRepository extends ServiceEntityRepository class ActivityRepository extends ServiceEntityRepository
{ {
@ -42,12 +24,7 @@ class ActivityRepository extends ServiceEntityRepository
} }
/** /**
* @param $person * @return Activity[]
* @param array $scopes
* @param string[] $orderBy
* @param int $limit
* @param int $offset
* @return array|Activity[]
*/ */
public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array
{ {
@ -63,8 +40,7 @@ class ActivityRepository extends ServiceEntityRepository
':person MEMBER OF a.persons' ':person MEMBER OF a.persons'
) )
) )
->setParameter('person', $person) ->setParameter('person', $person);
;
foreach ($orderBy as $k => $dir) { foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir); $qb->addOrderBy('a.'.$k, $dir);
@ -72,17 +48,11 @@ class ActivityRepository extends ServiceEntityRepository
$qb->setMaxResults($limit)->setFirstResult($offset); $qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery() return $qb->getQuery()->getResult();
->getResult();
} }
/** /**
* @param AccompanyingPeriod $period * @return Activity[]
* @param array $scopes
* @param int|null $limit
* @param int|null $offset
* @param array|string[] $orderBy
* @return array|Activity[]
*/ */
public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array
{ {
@ -92,8 +62,7 @@ class ActivityRepository extends ServiceEntityRepository
if (!$allowNullScope) { if (!$allowNullScope) {
$qb $qb
->where($qb->expr()->in('a.scope', ':scopes')) ->where($qb->expr()->in('a.scope', ':scopes'))
->setParameter('scopes', $scopes) ->setParameter('scopes', $scopes);
;
} else { } else {
$qb $qb
->where( ->where(
@ -102,16 +71,14 @@ class ActivityRepository extends ServiceEntityRepository
$qb->expr()->isNull('a.scope') $qb->expr()->isNull('a.scope')
) )
) )
->setParameter('scopes', $scopes) ->setParameter('scopes', $scopes);
;
} }
$qb $qb
->andWhere( ->andWhere(
$qb->expr()->eq('a.accompanyingPeriod', ':period') $qb->expr()->eq('a.accompanyingPeriod', ':period')
) )
->setParameter('period', $period) ->setParameter('period', $period);
;
foreach ($orderBy as $k => $dir) { foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir); $qb->addOrderBy('a.'.$k, $dir);
@ -119,7 +86,6 @@ class ActivityRepository extends ServiceEntityRepository
$qb->setMaxResults($limit)->setFirstResult($offset); $qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery() return $qb->getQuery()->getResult();
->getResult();
} }
} }

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityTypeCategory|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityTypeCategory|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityTypeCategory[] findAll()
* @method ActivityTypeCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityTypeCategoryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityTypeCategory::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityType|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityType|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityType[] findAll()
* @method ActivityType[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityTypeRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityType::class);
}
}

View File

@ -11,9 +11,12 @@
</div> </div>
<div v-if="getContext === 'accompanyingCourse' && filterSuggestedPersons.length > 0"> <div v-if="getContext === 'accompanyingCourse' && filterSuggestedPersons.length > 0">
<ul> <ul class="list-unstyled">
<li v-for="p in filterSuggestedPersons" @click="addNewPerson(p)"> <li v-for="p in filterSuggestedPersons" @click="addNewPerson(p)">
<span class="badge bg-primary" style="cursor: pointer;">
<i class="fa fa-plus fa-fw text-success"></i>
{{ p.text }} {{ p.text }}
</span>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -4,7 +4,7 @@
<span class="chill_denomination"> <span class="chill_denomination">
{{ textCutted }} {{ textCutted }}
</span> </span>
<a class="fa fa-fw fa-times" <a class="fa fa-fw fa-times text-danger text-decoration-none"
@click.prevent="$emit('remove', person)"> @click.prevent="$emit('remove', person)">
</a> </a>
</span> </span>

View File

@ -27,14 +27,16 @@
{{ activity.type.name | localize_translatable_string }} {{ activity.type.name | localize_translatable_string }}
<ul class="small_in_title"> <ul class="small_in_title">
{% if activity.location and t.locationVisible %}
<li> <li>
<abbr title="{{ 'location'|trans }}">{{ 'location'|trans ~ ': ' }}</abbr> <span class="item-key">{{ 'location'|trans ~ ': ' }}</span>
{# TODO {% if activity.location %}{{ activity.location }}{% endif %} #} <span>{{ activity.location.locationType.title|localize_translatable_string }}</span>
Domicile de l'usager {{ activity.location.name }}
</li> </li>
{% endif %}
{% if activity.user and t.userVisible %} {% if activity.user and t.userVisible %}
<li> <li>
<abbr title="{{ 'Referrer'|trans }}">{{ 'Referrer'|trans ~ ': ' }}</abbr> <span class="item-key">{{ 'Referrer'|trans ~ ': ' }}</span>
{{ activity.user.usernameCanonical }} {{ activity.user.usernameCanonical }}
</li> </li>
{% endif %} {% endif %}

View File

@ -40,7 +40,6 @@
}, },
{ 'title': 'Users concerned'|trans, { 'title': 'Users concerned'|trans,
'items': entity.users, 'items': entity.users,
'path' : 'admin_user_show',
'key' : 'id' 'key' : 'id'
}, },
] %} ] %}
@ -58,6 +57,7 @@
<ul class="list-content"> <ul class="list-content">
{% for item in bloc.items %} {% for item in bloc.items %}
<li> <li>
{% if bloc.path is defined %}
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}"> <a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}"> <span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{{ item|chill_entity_render_box({ {{ item|chill_entity_render_box({
@ -66,6 +66,14 @@
}) }} }) }}
</span> </span>
</a> </a>
{% else %}
<span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{{ item|chill_entity_render_box({
'render': 'raw',
'addAltNames': false
}) }}
</span>
{% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
@ -85,6 +93,7 @@
<ul class="list-content"> <ul class="list-content">
{% for item in bloc.items %} {% for item in bloc.items %}
<li> <li>
{% if bloc.path is defined %}
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}"> <a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}"> <span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{{ item|chill_entity_render_box({ {{ item|chill_entity_render_box({
@ -93,6 +102,12 @@
}) }} }) }}
</span> </span>
</a> </a>
{% else %}
{{ item|chill_entity_render_box({
'render': 'raw',
'addAltNames': false
}) }}
{% endif %}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
@ -114,12 +129,19 @@
{% for item in bloc.items %} {% for item in bloc.items %}
<span class="wl-item {% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}"> <span class="wl-item {% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{% if bloc.path is defined %}
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}"> <a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
{{ item|chill_entity_render_box({ {{ item|chill_entity_render_box({
'render': 'raw', 'render': 'raw',
'addAltNames': false 'addAltNames': false
}) }} }) }}
</a> </a>
{% else %}
{{ item|chill_entity_render_box({
'render': 'raw',
'addAltNames': false
}) }}
{% endif %}
</span> </span>
{% endfor %} {% endfor %}

View File

@ -10,7 +10,7 @@
'title' : 'Remove activity'|trans, 'title' : 'Remove activity'|trans,
'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : accompanyingCourse.id } ), 'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : accompanyingCourse.id } ),
'cancel_route' : 'chill_activity_activity_list', 'cancel_route' : 'chill_activity_activity_list',
'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : activity.id }, 'cancel_parameters' : { 'accompanying_period_id' : accompanyingCourse.id, 'id' : activity.id },
'form' : delete_form 'form' : delete_form
} ) }} } ) }}
{% endblock %} {% endblock %}

View File

@ -55,7 +55,7 @@
{% endif %} {% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2> <h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc' } %} {% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc', 'badge_person': 'true' } %}
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2> <h2 class="chill-red">{{ 'Activity data'|trans }}</h2>

View File

@ -1,4 +1,2 @@
{{ dump(notification) }}
<a href="{{ path('chill_activity_activity_show', {'id': notification.relatedEntityId }) }}">Go to Activity</a> <a href="{{ path('chill_activity_activity_show', {'id': notification.relatedEntityId }) }}">Go to Activity</a>

View File

@ -1,85 +1,44 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Timeline; namespace Chill\ActivityBundle\Timeline;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository; use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Mapping\ClassMetadata;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Timeline\TimelineSingleQuery; use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Provide activity for inclusion in timeline
*
*/
class TimelineActivityProvider implements TimelineProviderInterface class TimelineActivityProvider implements TimelineProviderInterface
{ {
protected EntityManagerInterface $em;
/** protected AuthorizationHelperInterface $helper;
*
* @var EntityManager
*/
protected $em;
/** protected UserInterface $user;
*
* @var AuthorizationHelper
*/
protected $helper;
/**
*
* @var \Chill\MainBundle\Entity\User
*/
protected $user;
protected ActivityACLAwareRepository $aclAwareRepository; protected ActivityACLAwareRepository $aclAwareRepository;
private const SUPPORTED_CONTEXTS = [ 'center', 'person']; private const SUPPORTED_CONTEXTS = [ 'center', 'person'];
/**
* TimelineActivityProvider constructor.
*
* @param EntityManager $em
* @param AuthorizationHelper $helper
* @param TokenStorageInterface $storage
*/
public function __construct( public function __construct(
EntityManager $em, EntityManagerInterface $em,
AuthorizationHelper $helper, AuthorizationHelperInterface $helper,
TokenStorageInterface $storage, TokenStorageInterface $storage,
ActivityACLAwareRepository $aclAwareRepository ActivityACLAwareRepository $aclAwareRepository
) ) {
{
$this->em = $em; $this->em = $em;
$this->helper = $helper; $this->helper = $helper;
$this->aclAwareRepository = $aclAwareRepository; $this->aclAwareRepository = $aclAwareRepository;
if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) if (!$storage->getToken()->getUser() instanceof User)
{ {
throw new \RuntimeException('A user should be authenticated !'); throw new \RuntimeException('A user should be authenticated !');
} }
@ -108,7 +67,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
'type' => 'activity', 'type' => 'activity',
'date' => $metadataActivity->getTableName() 'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'), .'.'.$metadataActivity->getColumnName('date'),
'FROM' => $this->getFromClausePerson($args['person']), 'FROM' => $this->getFromClausePerson(),
'WHERE' => $where, 'WHERE' => $where,
'parameters' => $parameters 'parameters' => $parameters
]); ]);
@ -120,8 +79,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
$metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataActivity = $this->em->getClassMetadata(Activity::class);
$associationMapping = $metadataActivity->getAssociationMapping('person'); $associationMapping = $metadataActivity->getAssociationMapping('person');
$role = new Role('CHILL_ACTIVITY_SEE'); $role = new Role('CHILL_ACTIVITY_SEE');
$reachableScopes = $this->helper->getReachableScopes($this->user, $reachableScopes = $this->helper->getReachableScopes($this->user, $role->getRole(), $person->getCenter());
$role, $person->getCenter());
$whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) ');
$scopes_ids = []; $scopes_ids = [];
@ -152,26 +110,23 @@ class TimelineActivityProvider implements TimelineProviderInterface
]; ];
} }
private function getFromClausePerson() private function getFromClausePerson(): string
{ {
$metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class); $metadataPerson = $this->em->getClassMetadata(Person::class);
$associationMapping = $metadataActivity->getAssociationMapping('person'); $associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName().' JOIN ' return sprintf(
.$metadataPerson->getTableName().' ON ' "%s JOIN %s ON %s.%s = %s",
.$metadataPerson->getTableName().'.'. $metadataActivity->getTableName(),
$associationMapping['joinColumns'][0]['referencedColumnName'] $metadataPerson->getTableName(),
.' = ' $metadataPerson->getTableName(),
.$associationMapping['joinColumns'][0]['name'] $associationMapping['joinColumns'][0]['referencedColumnName'],
; $associationMapping['joinColumns'][0]['name']
);
} }
/** public function getEntities(array $ids): array
*
* {@inheritDoc}
*/
public function getEntities(array $ids)
{ {
$activities = $this->em->getRepository(Activity::class) $activities = $this->em->getRepository(Activity::class)
->findBy(array('id' => $ids)); ->findBy(array('id' => $ids));
@ -184,11 +139,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
return $result; return $result;
} }
/** public function getEntityTemplate($entity, $context, array $args): array
*
* {@inheritDoc}
*/
public function getEntityTemplate($entity, $context, array $args)
{ {
$this->checkContext($context); $this->checkContext($context);
@ -201,26 +152,25 @@ class TimelineActivityProvider implements TimelineProviderInterface
]; ];
} }
/** public function supportsType($type): bool
*
* {@inheritDoc}
*/
public function supportsType($type)
{ {
return $type === 'activity'; return $type === 'activity';
} }
/** /**
* check if the context is supported * Check if the context is supported.
* *
* @param string $context
* @throws \LogicException if the context is not supported * @throws \LogicException if the context is not supported
*/ */
private function checkContext($context) private function checkContext(string $context)
{ {
if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) {
throw new \LogicException("The context '$context' is not " throw new \LogicException(
. "supported. Currently only 'person' is supported"); sprintf(
"The context '%s' is not supported. Currently only 'person' is supported",
$context
)
);
} }
} }

View File

@ -1,4 +1,7 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.activity.timeline: chill.activity.timeline:
class: Chill\ActivityBundle\Timeline\TimelineActivityProvider class: Chill\ActivityBundle\Timeline\TimelineActivityProvider
@ -13,17 +16,14 @@ services:
- { name: chill.timeline, context: 'center' } - { name: chill.timeline, context: 'center' }
Chill\ActivityBundle\Menu\: Chill\ActivityBundle\Menu\:
autowire: true
autoconfigure: true
resource: '../Menu/' resource: '../Menu/'
tags: ['chill.menu_builder'] tags: ['chill.menu_builder']
Chill\ActivityBundle\Notification\: Chill\ActivityBundle\Notification\:
autowire: true
autoconfigure: true
resource: '../Notification' resource: '../Notification'
Chill\ActivityBundle\Security\Authorization\: Chill\ActivityBundle\Security\Authorization\:
resource: '../Security/Authorization/' resource: '../Security/Authorization/'
autowire: true
autoconfigure: true Chill\ActivityBundle\Repository\:
resource: '../Repository/'

View File

@ -1,57 +1,40 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.activity.export.count_activity: chill.activity.export.count_activity:
class: Chill\ActivityBundle\Export\Export\CountActivity class: Chill\ActivityBundle\Export\Export\CountActivity
arguments:
- "@doctrine.orm.entity_manager"
tags: tags:
- { name: chill.export, alias: 'count_activity' } - { name: chill.export, alias: 'count_activity' }
chill.activity.export.sum_activity_duration: chill.activity.export.sum_activity_duration:
class: Chill\ActivityBundle\Export\Export\StatActivityDuration class: Chill\ActivityBundle\Export\Export\StatActivityDuration
arguments:
- "@doctrine.orm.entity_manager"
- "sum"
tags: tags:
- { name: chill.export, alias: 'sum_activity_duration' } - { name: chill.export, alias: 'sum_activity_duration' }
chill.activity.export.list_activity: chill.activity.export.list_activity:
class: Chill\ActivityBundle\Export\Export\ListActivity class: Chill\ActivityBundle\Export\Export\ListActivity
arguments:
- "@doctrine.orm.entity_manager"
- "@translator"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export, alias: 'list_activity' } - { name: chill.export, alias: 'list_activity' }
chill.activity.export.reason_filter: chill.activity.export.reason_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.reason"
tags: tags:
- { name: chill.export_filter, alias: 'activity_reason_filter' } - { name: chill.export_filter, alias: 'activity_reason_filter' }
chill.activity.export.type_filter: chill.activity.export.type_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.activity_type"
tags: tags:
- { name: chill.export_filter, alias: 'activity_type_filter' } - { name: chill.export_filter, alias: 'activity_type_filter' }
chill.activity.export.date_filter: chill.activity.export.date_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter
arguments:
- "@translator"
tags: tags:
- { name: chill.export_filter, alias: 'activity_date_filter' } - { name: chill.export_filter, alias: 'activity_date_filter' }
chill.activity.export.person_having_an_activity_between_date_filter: chill.activity.export.person_having_an_activity_between_date_filter:
class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.reason"
- "@translator"
tags: tags:
- #0 register as a filter - #0 register as a filter
name: chill.export_filter name: chill.export_filter
@ -59,24 +42,15 @@ services:
chill.activity.export.reason_aggregator: chill.activity.export.reason_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
arguments:
- "@chill_activity.repository.reason_category"
- "@chill_activity.repository.reason"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export_aggregator, alias: activity_reason_aggregator } - { name: chill.export_aggregator, alias: activity_reason_aggregator }
chill.activity.export.type_aggregator: chill.activity.export.type_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator
arguments:
- "@chill_activity.repository.activity_type"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export_aggregator, alias: activity_type_aggregator } - { name: chill.export_aggregator, alias: activity_type_aggregator }
chill.activity.export.user_aggregator: chill.activity.export.user_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
arguments:
$em: "@doctrine.orm.entity_manager"
tags: tags:
- { name: chill.export_aggregator, alias: activity_user_aggregator } - { name: chill.export_aggregator, alias: activity_user_aggregator }

View File

@ -1,4 +1,6 @@
services: services:
Chill\ActivityBundle\DataFixtures\ORM\: Chill\ActivityBundle\DataFixtures\ORM\:
autowire: true
autoconfigure: true
resource: ../../DataFixtures/ORM resource: ../../DataFixtures/ORM
tags: [ 'doctrine.fixture.orm' ] tags: [ 'doctrine.fixture.orm' ]

View File

@ -1,28 +1,12 @@
--- ---
services: services:
chill_activity.repository.activity_type: chill_activity.repository.activity_type: '@Chill\ActivityBundle\Repository\ActivityTypeRepository'
class: Doctrine\ORM\EntityRepository chill_activity.repository.reason: '@Chill\ActivityBundle\Repository\ActivityReasonRepository'
factory: ['@doctrine.orm.entity_manager', getRepository] chill_activity.repository.reason_category: '@Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository'
arguments:
- 'Chill\ActivityBundle\Entity\ActivityType'
chill_activity.repository.reason:
class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Chill\ActivityBundle\Entity\ActivityReason'
chill_activity.repository.reason_category:
class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments:
- 'Chill\ActivityBundle\Entity\ActivityReasonCategory'
Chill\ActivityBundle\Repository\ActivityRepository:
tags: [doctrine.repository_service]
arguments:
- '@Doctrine\Persistence\ManagerRegistry'
# This is not a repository but merely a service. It needs to be moved out for simplicity.
# The autowire and autoconfigure should be enabled globally and removed from the definition of the service.
# Once autoloaded, there is no need to alias it to the interface here, it will be done automatically by Symfony.
Chill\ActivityBundle\Repository\ActivityACLAwareRepository: Chill\ActivityBundle\Repository\ActivityACLAwareRepository:
autowire: true autowire: true
autoconfigure: true autoconfigure: true

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Activity;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20211119173555 extends AbstractMigration
{
public function getDescription(): string
{
return 'remove comment on deprecated json_array type';
}
public function up(Schema $schema): void
{
$columns = [
'activitytype.name',
'activitytypecategory.name'
];
foreach ($columns as $col) {
$this->addSql("COMMENT ON COLUMN $col IS NULL");
}
}
public function down(Schema $schema): void
{
$this->throwIrreversibleMigrationException();
}
}

View File

@ -15,8 +15,7 @@ use Doctrine\Common\Collections\Criteria;
final class AsideActivityController extends CRUDController final class AsideActivityController extends CRUDController
{ {
private AsideActivityCategoryRepository $categoryRepository;
private $categoryRepository;
public function __construct(AsideActivityCategoryRepository $categoryRepository) public function __construct(AsideActivityCategoryRepository $categoryRepository)
{ {
@ -25,7 +24,7 @@ final class AsideActivityController extends CRUDController
protected function buildQueryEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null) protected function buildQueryEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null)
{ {
$qb = parent::buildQueryEntities($action, $request, $filterOrder); $qb = parent::buildQueryEntities($action, $request);
if ('index' === $action) { if ('index' === $action) {
$qb->where($qb->expr()->eq('e.agent', ':user')); $qb->where($qb->expr()->eq('e.agent', ':user'));

View File

@ -19,8 +19,6 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @phpstan-ignore-next-line
*/ */
public function load(array $configs, ContainerBuilder $container): void public function load(array $configs, ContainerBuilder $container): void
{ {

View File

@ -44,13 +44,15 @@ class AsideActivityCategory
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children") * @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children")
* @ORM\JoinColumn(nullable=true) * @ORM\JoinColumn(nullable=true)
*/ */
private $parent; private ?AsideActivityCategory $parent = null;
/** /**
* @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent") * @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent")
*/ */
private $children; private $children;
private AsideActivityCategory $oldParent;
public function __construct() public function __construct()
{ {
$this->children = new ArrayCollection(); $this->children = new ArrayCollection();

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Form; namespace Chill\AsideActivityBundle\Form;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory; use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
@ -14,12 +16,11 @@ use Symfony\Component\Form\FormBuilderInterface;
final class AsideActivityCategoryType extends AbstractType final class AsideActivityCategoryType extends AbstractType
{ {
private CategoryRender $categoryRender;
protected $translatableStringHelper; public function __construct(
CategoryRender $categoryRender
public function __construct(TranslatableStringHelper $translatableStringHelper, CategoryRender $categoryRender) ) {
{
$this->translatableStringHelper = $translatableStringHelper;
$this->categoryRender = $categoryRender; $this->categoryRender = $categoryRender;
} }

View File

@ -25,18 +25,16 @@ use Symfony\Component\Templating\EngineInterface;
final class AsideActivityFormType extends AbstractType final class AsideActivityFormType extends AbstractType
{ {
protected array $timeChoices; private array $timeChoices;
private TokenStorageInterface $storage; private TokenStorageInterface $storage;
private CategoryRender $categoryRender; private CategoryRender $categoryRender;
public function __construct ( public function __construct (
TranslatableStringHelper $translatableStringHelper,
ParameterBagInterface $parameterBag, ParameterBagInterface $parameterBag,
TokenStorageInterface $storage, TokenStorageInterface $storage,
CategoryRender $categoryRender CategoryRender $categoryRender
){ ){
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration'); $this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
$this->translatableStringHelper = $translatableStringHelper;
$this->storage = $storage; $this->storage = $storage;
$this->categoryRender = $categoryRender; $this->categoryRender = $categoryRender;
} }

View File

@ -30,7 +30,9 @@ final class CategoryRender implements ChillEntityRenderInterface
{ {
$options = array_merge(self::DEFAULT_ARGS, $options); $options = array_merge(self::DEFAULT_ARGS, $options);
$titles[] = $this->translatableStringHelper->localize($asideActivityCategory->getTitle()); $titles = [
$this->translatableStringHelper->localize($asideActivityCategory->getTitle()),
];
while ($asideActivityCategory->hasParent()) { while ($asideActivityCategory->hasParent()) {
$asideActivityCategory = $asideActivityCategory->getParent(); $asideActivityCategory = $asideActivityCategory->getParent();

View File

@ -1,42 +1,34 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form; namespace Chill\AMLI\BudgetBundle\Form;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository; use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\AMLI\BudgetBundle\Entity\Charge; use Chill\AMLI\BudgetBundle\Entity\Charge;
class ChargeType extends AbstractType class ChargeType extends AbstractType
{ {
/** protected ConfigRepository $configRepository;
*
* @var ConfigRepository
*/
protected $configRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
ConfigRepository $configRepository, ConfigRepository $configRepository,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->configRepository = $configRepository; $this->configRepository = $configRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
@ -45,10 +37,9 @@ class ChargeType extends AbstractType
'placeholder' => 'Choose a charge type' 'placeholder' => 'Choose a charge type'
]) ])
->add('amount', MoneyType::class) ->add('amount', MoneyType::class)
->add('comment', TextAreaType::class, [ ->add('comment', TextareaType::class, [
'required' => false 'required' => false
]) ]);
;
if ($options['show_start_date']) { if ($options['show_start_date']) {
$builder->add('startDate', ChillDateType::class, [ $builder->add('startDate', ChillDateType::class, [
@ -93,13 +84,10 @@ class ChargeType extends AbstractType
return \array_flip($charges); return \array_flip($charges);
} }
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults(array(
'data_class' => 'Chill\AMLI\BudgetBundle\Entity\Charge', 'data_class' => Charge::class,
'show_start_date' => true, 'show_start_date' => true,
'show_end_date' => true, 'show_end_date' => true,
'show_help' => true 'show_help' => true
@ -108,17 +96,11 @@ class ChargeType extends AbstractType
$resolver $resolver
->setAllowedTypes('show_start_date', 'boolean') ->setAllowedTypes('show_start_date', 'boolean')
->setAllowedTypes('show_end_date', 'boolean') ->setAllowedTypes('show_end_date', 'boolean')
->setAllowedTypes('show_help', 'boolean') ->setAllowedTypes('show_help', 'boolean');
;
} }
/**
* {@inheritdoc}
*/
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'chill_amli_budgetbundle_charge'; return 'chill_amli_budgetbundle_charge';
} }
} }

View File

@ -1,7 +1,10 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form; namespace Chill\AMLI\BudgetBundle\Form;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
@ -10,32 +13,22 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository; use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class ResourceType extends AbstractType class ResourceType extends AbstractType
{ {
/** protected ConfigRepository $configRepository;
*
* @var ConfigRepository
*/
protected $configRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
ConfigRepository $configRepository, ConfigRepository $configRepository,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->configRepository = $configRepository; $this->configRepository = $configRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
@ -45,10 +38,9 @@ class ResourceType extends AbstractType
'label' => 'Resource element type' 'label' => 'Resource element type'
]) ])
->add('amount', MoneyType::class) ->add('amount', MoneyType::class)
->add('comment', TextAreaType::class, [ ->add('comment', TextareaType::class, [
'required' => false 'required' => false
]) ]);
;
if ($options['show_start_date']) { if ($options['show_start_date']) {
$builder->add('startDate', ChillDateType::class, [ $builder->add('startDate', ChillDateType::class, [
@ -64,6 +56,24 @@ class ResourceType extends AbstractType
} }
} }
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Resource::class,
'show_start_date' => true,
'show_end_date' => true
));
$resolver
->setAllowedTypes('show_start_date', 'boolean')
->setAllowedTypes('show_end_date', 'boolean');
}
public function getBlockPrefix()
{
return 'chill_amli_budgetbundle_resource';
}
private function getTypes() private function getTypes()
{ {
$resources = $this->configRepository $resources = $this->configRepository
@ -78,31 +88,4 @@ class ResourceType extends AbstractType
return \array_flip($resources); return \array_flip($resources);
} }
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Resource::class,
'show_start_date' => true,
'show_end_date' => true
));
$resolver
->setAllowedTypes('show_start_date', 'boolean')
->setAllowedTypes('show_end_date', 'boolean')
;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'chill_amli_budgetbundle_resource';
}
} }

View File

@ -1,24 +1,6 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\CalendarBundle\Controller; namespace Chill\CalendarBundle\Controller;
@ -26,9 +8,11 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form; use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
@ -42,11 +26,6 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
/**
* Class CalendarController
*
* @package Chill\CalendarBundle\Controller
*/
class CalendarController extends AbstractController class CalendarController extends AbstractController
{ {
protected EventDispatcherInterface $eventDispatcher; protected EventDispatcherInterface $eventDispatcher;
@ -97,9 +76,9 @@ class CalendarController extends AbstractController
'calendarItems' => $calendarItems, 'calendarItems' => $calendarItems,
'user' => $user 'user' => $user
]); ]);
}
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) { if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$total = $this->calendarRepository->countByAccompanyingPeriod($accompanyingPeriod); $total = $this->calendarRepository->countByAccompanyingPeriod($accompanyingPeriod);
$paginator = $this->paginator->create($total); $paginator = $this->paginator->create($total);
$calendarItems = $this->calendarRepository->findBy( $calendarItems = $this->calendarRepository->findBy(
@ -117,6 +96,8 @@ class CalendarController extends AbstractController
'paginator' => $paginator 'paginator' => $paginator
]); ]);
} }
throw new \Exception('Unable to list actions.');
} }
/** /**
@ -125,6 +106,7 @@ class CalendarController extends AbstractController
*/ */
public function newAction(Request $request): Response public function newAction(Request $request): Response
{ {
$view = null;
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request); [$user, $accompanyingPeriod] = $this->getEntity($request);
@ -161,10 +143,11 @@ class CalendarController extends AbstractController
$params = $this->buildParamsToUrl($user, $accompanyingPeriod); $params = $this->buildParamsToUrl($user, $accompanyingPeriod);
return $this->redirectToRoute('chill_calendar_calendar_list', $params); return $this->redirectToRoute('chill_calendar_calendar_list', $params);
} elseif ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
} }
if ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
}
if ($view === null) { if ($view === null) {
throw $this->createNotFoundException('Template not found'); throw $this->createNotFoundException('Template not found');
@ -187,6 +170,7 @@ class CalendarController extends AbstractController
*/ */
public function showAction(Request $request, $id): Response public function showAction(Request $request, $id): Response
{ {
$view = null;
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request); [$user, $accompanyingPeriod] = $this->getEntity($request);
@ -198,32 +182,36 @@ class CalendarController extends AbstractController
$view = '@ChillCalendar/Calendar/showByUser.html.twig'; $view = '@ChillCalendar/Calendar/showByUser.html.twig';
} }
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
/** @var Calendar $entity */
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id); $entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
if (!$entity) { if (null === $entity) {
throw $this->createNotFoundException('Unable to find Calendar entity.'); throw $this->createNotFoundException('Unable to find Calendar entity.');
} }
if (null !== $accompanyingPeriod) { if (null !== $accompanyingPeriod) {
// @TODO: These properties are declared dynamically.
// It must be removed.
// @See https://wiki.php.net/rfc/deprecate_dynamic_properties
$entity->personsAssociated = $entity->getPersonsAssociated(); $entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated(); $entity->personsNotAssociated = $entity->getPersonsNotAssociated();
} }
// $deleteForm = $this->createDeleteForm($id, $accompanyingPeriod); // $deleteForm = $this->createDeleteForm($id, $accompanyingPeriod);
if ($view === null) { $personsId = array_map(
throw $this->createNotFoundException('Template not found'); static fn (Person $p): int => $p->getId(),
} $entity->getPersons()
);
$personsId = []; $professionalsId = array_map(
foreach ($entity->getPersons() as $p) { static fn (ThirdParty $thirdParty): ?int => $thirdParty->getId(),
array_push($personsId, $p->getId()); $entity->getProfessionals()
} );
$professionalsId = [];
foreach ($entity->getProfessionals() as $p) {
array_push($professionalsId, $p->getId());
}
$durationTime = $entity->getEndDate()->diff($entity->getStartDate()); $durationTime = $entity->getEndDate()->diff($entity->getStartDate());
$durationTimeInMinutes = $durationTime->days*1440 + $durationTime->h*60 + $durationTime->i; $durationTimeInMinutes = $durationTime->days*1440 + $durationTime->h*60 + $durationTime->i;
@ -255,6 +243,7 @@ class CalendarController extends AbstractController
*/ */
public function editAction($id, Request $request): Response public function editAction($id, Request $request): Response
{ {
$view = null;
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request); [$user, $accompanyingPeriod] = $this->getEntity($request);
@ -283,8 +272,11 @@ class CalendarController extends AbstractController
$this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!')); $this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!'));
$params = $this->buildParamsToUrl($user, $accompanyingPeriod); $params = $this->buildParamsToUrl($user, $accompanyingPeriod);
return $this->redirectToRoute('chill_calendar_calendar_list', $params); return $this->redirectToRoute('chill_calendar_calendar_list', $params);
} elseif ($form->isSubmitted() and !$form->isValid()) { }
if ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->get('translator')->trans('This form contains errors')); $this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
} }
@ -312,6 +304,7 @@ class CalendarController extends AbstractController
*/ */
public function deleteAction(Request $request, $id) public function deleteAction(Request $request, $id)
{ {
$view = null;
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request); [$user, $accompanyingPeriod] = $this->getEntity($request);
@ -367,7 +360,7 @@ class CalendarController extends AbstractController
/** /**
* Creates a form to delete a Calendar entity by id. * Creates a form to delete a Calendar entity by id.
*/ */
private function createDeleteForm(int $id, ?User $user, ?AccompanyingPeriod $accompanyingPeriod): Form private function createDeleteForm(int $id, ?User $user, ?AccompanyingPeriod $accompanyingPeriod): FormInterface
{ {
$params = $this->buildParamsToUrl($user, $accompanyingPeriod); $params = $this->buildParamsToUrl($user, $accompanyingPeriod);
$params['id'] = $id; $params['id'] = $id;
@ -414,17 +407,14 @@ class CalendarController extends AbstractController
]; ];
} }
private function buildParamsToUrl( private function buildParamsToUrl(?User $user, ?AccompanyingPeriod $accompanyingPeriod): array {
?User $user,
?AccompanyingPeriod $accompanyingPeriod
): array {
$params = []; $params = [];
if ($user) { if (null !== $user) {
$params['user_id'] = $user->getId(); $params['user_id'] = $user->getId();
} }
if ($accompanyingPeriod) { if (null !== $accompanyingPeriod) {
$params['accompanying_period_id'] = $accompanyingPeriod->getId(); $params['accompanying_period_id'] = $accompanyingPeriod->getId();
} }

View File

@ -1,25 +1,30 @@
<?php <?php
declare(strict_types=1);
namespace Chill\CalendarBundle\DataFixtures\ORM; namespace Chill\CalendarBundle\DataFixtures\ORM;
use Chill\CalendarBundle\Entity\CalendarRange; use Chill\CalendarBundle\Entity\CalendarRange;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers; use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepository;
use DateTimeImmutable; use DateTimeImmutable;
use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface; use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
class LoadCalendarRange extends Fixture implements FixtureGroupInterface, OrderedFixtureInterface class LoadCalendarRange extends Fixture implements FixtureGroupInterface, OrderedFixtureInterface
{ {
private UserRepository $userRepository;
public static array $references = [];
public function __construct( public function __construct(
EntityManagerInterface $em UserRepository $userRepository
) { ) {
$this->userRepository = $em->getRepository(User::class); $this->userRepository = $userRepository;
} }
public function getOrder(): int public function getOrder(): int
@ -32,8 +37,6 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere
return ['calendar']; return ['calendar'];
} }
public static $references = [];
public function load(ObjectManager $manager): void public function load(ObjectManager $manager): void
{ {
$arr = range(-50, 50); $arr = range(-50, 50);

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Calendar;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20211119173557 extends AbstractMigration
{
public function getDescription(): string
{
return 'remove comment on deprecated json_array type';
}
public function up(Schema $schema): void
{
$columns = [
'chill_calendar.cancel_reason.name',
'chill_calendar.invite.status',
];
foreach ($columns as $col) {
$this->addSql("COMMENT ON COLUMN $col IS NULL");
}
}
public function down(Schema $schema): void
{
$this->throwIrreversibleMigrationException();
}
}

View File

@ -151,8 +151,7 @@ class CreateFieldsOnGroupCommand extends Command
return $customFieldsGroup; return $customFieldsGroup;
} }
} }
throw new \RunTimeException('The id does not match an existing ' throw new \RuntimeException('The id does not match an existing CustomFieldsGroup');
. 'CustomFieldsGroup');
} }
); );
$customFieldsGroup = $helper->ask($input, $output, $question); $customFieldsGroup = $helper->ask($input, $output, $question);
@ -205,13 +204,13 @@ class CreateFieldsOnGroupCommand extends Command
$parser = new Parser(); $parser = new Parser();
if (!file_exists($path)) { if (!file_exists($path)) {
throw new \RunTimeException("file does not exist"); throw new \RuntimeException("file does not exist");
} }
try { try {
$values = $parser->parse(file_get_contents($path)); $values = $parser->parse(file_get_contents($path));
} catch (ParseException $ex) { } catch (ParseException $ex) {
throw new \RunTimeException("The yaml file is not valid", 0, $ex); throw new \RuntimeException("The yaml file is not valid", 0, $ex);
} }
return $values; return $values;
@ -228,7 +227,7 @@ class CreateFieldsOnGroupCommand extends Command
//check the cf type exists //check the cf type exists
$cfType = $this->customFieldProvider->getCustomFieldByType($field['type']); $cfType = $this->customFieldProvider->getCustomFieldByType($field['type']);
if ($cfType === NULL) { if ($cfType === NULL) {
throw new \RunTimeException('the type '.$field['type'].' ' throw new \RuntimeException('the type '.$field['type'].' '
. 'does not exists'); . 'does not exists');
} }
@ -255,7 +254,7 @@ class CreateFieldsOnGroupCommand extends Command
.$cf->getType()."\t with slug ".$cf->getSlug(). .$cf->getType()."\t with slug ".$cf->getSlug().
"\t and names : ".implode($names, ', ')."</info>"); "\t and names : ".implode($names, ', ')."</info>");
} else { } else {
throw new \RunTimeException("Error in field ".$slug); throw new \RuntimeException("Error in field ".$slug);
} }
} }

View File

@ -1,21 +1,6 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\CustomFieldsBundle\CustomFields; namespace Chill\CustomFieldsBundle\CustomFields;
@ -29,36 +14,21 @@ use Symfony\Bridge\Twig\TwigEngine;
use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Form\Type\Select2ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CustomFieldLongChoice extends AbstractCustomField class CustomFieldLongChoice extends AbstractCustomField
{ {
/** private OptionRepository $optionRepository;
*
* @var OptionRepository
*/
private $optionRepository;
/** private TranslatableStringHelper $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
private $translatableStringHelper;
/** private TwigEngine $templating;
* @var TwigEngine
*/
private $templating;
const KEY = 'key'; public const KEY = 'key';
public function __construct(OptionRepository $optionRepository, public function __construct(
OptionRepository $optionRepository,
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
TwigEngine $twigEngine) TwigEngine $twigEngine
{ ) {
$this->optionRepository = $optionRepository; $this->optionRepository = $optionRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->templating = $twigEngine; $this->templating = $twigEngine;
@ -76,12 +46,7 @@ class CustomFieldLongChoice extends AbstractCustomField
'choice_label' => function(Option $option) use ($translatableStringHelper) { 'choice_label' => function(Option $option) use ($translatableStringHelper) {
return $translatableStringHelper->localize($option->getText()); return $translatableStringHelper->localize($option->getText());
}, },
'choice_value' => function ($key) use ($entries) { 'choice_value' => static fn (Option $key): ?int => $key === null ? null : $key->getId(),
if ($key === NULL) {
return null;
}
return $key->getId();
},
'multiple' => false, 'multiple' => false,
'expanded' => false, 'expanded' => false,
'required' => $customField->isRequired(), 'required' => $customField->isRequired(),
@ -89,15 +54,16 @@ class CustomFieldLongChoice extends AbstractCustomField
'group_by' => function(Option $option) use ($translatableStringHelper) { 'group_by' => function(Option $option) use ($translatableStringHelper) {
if ($option->hasParent()) { if ($option->hasParent()) {
return $translatableStringHelper->localize($option->getParent()->getText()); return $translatableStringHelper->localize($option->getParent()->getText());
} else {
return $translatableStringHelper->localize($option->getText());
} }
return $translatableStringHelper->localize($option->getText());
}, },
'label' => $translatableStringHelper->localize($customField->getName()) 'label' => $translatableStringHelper->localize($customField->getName())
)); ));
$builder->get($customField->getSlug())
->addModelTransformer(new CustomFieldDataTransformer($this, $customField));
$builder
->get($customField->getSlug())
->addModelTransformer(new CustomFieldDataTransformer($this, $customField));
} }
public function buildOptionsForm(FormBuilderInterface $builder) public function buildOptionsForm(FormBuilderInterface $builder)

View File

@ -46,7 +46,11 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn
public function prepend(ContainerBuilder $container) public function prepend(ContainerBuilder $container)
{ {
// add form layout to twig resources // add form layout to twig resources
$twigConfig['form_themes'][] = 'ChillCustomFieldsBundle:Form:fields.html.twig'; $twigConfig = [
'form_themes' => [
'ChillCustomFieldsBundle:Form:fields.html.twig',
],
];
$container->prependExtensionConfig('twig', $twigConfig); $container->prependExtensionConfig('twig', $twigConfig);
//add routes for custom bundle //add routes for custom bundle

View File

@ -2,6 +2,7 @@
namespace Chill\CustomFieldsBundle\Form; namespace Chill\CustomFieldsBundle\Form;
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
@ -52,7 +53,8 @@ class CustomFieldsGroupType extends AbstractType
)) ))
; ;
$builder->addEventListener(FormEvents::POST_SET_DATA, $builder->addEventListener(
FormEvents::POST_SET_DATA,
function(FormEvent $event) use ($customizableEntities, $builder) { function(FormEvent $event) use ($customizableEntities, $builder) {
$form = $event->getForm(); $form = $event->getForm();
$group = $event->getData(); $group = $event->getData();
@ -62,40 +64,37 @@ class CustomFieldsGroupType extends AbstractType
return; return;
} }
$optionBuilder = null;
if (count($customizableEntities[$group->getEntity()]['options']) > 0) { if (count($customizableEntities[$group->getEntity()]['options']) > 0) {
$optionBuilder = $builder $optionBuilder = $builder
->getFormFactory() ->getFormFactory()
->createBuilderForProperty( ->createBuilderForProperty(CustomFieldsGroup::class, 'options')
'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup', ->create(
'options' 'options',
) null,
->create('options', null, array( [
'compound' => true, 'compound' => true,
'auto_initialize' => false, 'auto_initialize' => false,
'required' => false) 'required' => false
]
); );
}
foreach($customizableEntities[$group->getEntity()]['options'] as $key => $option) { foreach($customizableEntities[$group->getEntity()]['options'] as $key => $option) {
$optionBuilder $optionBuilder->add($key, $option['form_type'], $option['form_options']);
->add($key, $option['form_type'], $option['form_options'])
;
} }
if (isset($optionBuilder) && $optionBuilder->count() > 0) {
$form->add($optionBuilder->getForm());
} }
if ((null !== $optionBuilder) && $optionBuilder->count() > 0) {
$form->add($optionBuilder->getForm());
}
}); });
} }
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup' 'data_class' => CustomFieldsGroup::class,
)); ]);
} }
/** /**

View File

@ -59,22 +59,27 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface
} }
if ($id instanceof CustomFieldsGroup) { if ($id instanceof CustomFieldsGroup) {
throw new TransformationFailedException(sprintf( throw new TransformationFailedException(
sprintf(
'The transformation failed: the expected argument on ' 'The transformation failed: the expected argument on '
. 'reverseTransform is an object of type int,' . 'reverseTransform is an object of type int,'
. 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' . 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, '
. 'given', gettype($id))); . 'given'
)
);
} }
$customFieldsGroup = $this->om $customFieldsGroup = $this->om
->getRepository('ChillCustomFieldsBundle:customFieldsGroup')->find($id) ->getRepository(CustomFieldsGroup::class)->find($id)
; ;
if (null === $customFieldsGroup) { if (null === $customFieldsGroup) {
throw new TransformationFailedException(sprintf( throw new TransformationFailedException(
sprintf(
'Le group avec le numéro "%s" ne peut pas être trouvé!', 'Le group avec le numéro "%s" ne peut pas être trouvé!',
$id $id
)); )
);
} }
return $customFieldsGroup; return $customFieldsGroup;

View File

@ -1,28 +1,27 @@
<?php <?php
declare(strict_types=1);
namespace Chill\CustomFieldsBundle\Form\DataTransformer; namespace Chill\CustomFieldsBundle\Form\DataTransformer;
use Chill\CustomFieldsBundle\Entity\CustomField;
use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\DataTransformerInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Doctrine\Common\Collections\ArrayCollection;
class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { class JsonCustomFieldToArrayTransformer implements DataTransformerInterface {
/** private ObjectManager $om;
* @var ObjectManager
*/ private array $customField;
private $om;
/**
* @param ObjectManager $om
*/
public function __construct(ObjectManager $om) public function __construct(ObjectManager $om)
{ {
$this->om = $om; $this->om = $om;
$customFields = $this->om $customFields = $this->om
->getRepository('ChillCustomFieldsBundle:CustomField') ->getRepository(CustomField::class)
->findAll(); ->findAll();
// @TODO: in the array_map callback, CustomField::getLabel() does not exist. What do we do here?
$customFieldsLablels = array_map( $customFieldsLablels = array_map(
function($e) { return $e->getLabel(); }, function($e) { return $e->getLabel(); },
$customFields); $customFields);
@ -36,20 +35,12 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface {
{ {
echo $customFieldsJSON; echo $customFieldsJSON;
if($customFieldsJSON === null) { // lors de la creation if($customFieldsJSON === null) {
$customFieldsArray = array(); $customFieldsArray = [];
} else { } else {
$customFieldsArray = json_decode($customFieldsJSON,true); $customFieldsArray = json_decode($customFieldsJSON, true, 512, JSON_THROW_ON_ERROR);
} }
/*
echo "<br> - 4 - <br>";
var_dump($customFieldsArray);
echo "<br> - 5 - <br>";
*/
$customFieldsArrayRet = array(); $customFieldsArrayRet = array();
foreach ($customFieldsArray as $key => $value) { foreach ($customFieldsArray as $key => $value) {

View File

@ -145,5 +145,7 @@ class DocGeneratorTemplateController extends AbstractController
} catch (TransferException $e) { } catch (TransferException $e) {
throw $e; throw $e;
} }
throw new \Exception('Unable to generate document.');
} }
} }

View File

@ -0,0 +1,69 @@
<?php
namespace Chill\DocGeneratorBundle\Serializer\Encoder;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
class DocGenEncoder implements \Symfony\Component\Serializer\Encoder\EncoderInterface
{
/**
* @inheritDoc
*/
public function encode($data, string $format, array $context = [])
{
if (!$this->isAssociative($data)) {
throw new UnexpectedValueException("Only associative arrays are allowed; lists are not allowed");
}
$result = [];
$this->recusiveEncoding($data, $result, '');
return $result;
}
private function recusiveEncoding(array $data, array &$result, $path)
{
if ($this->isAssociative($data)) {
foreach ($data as $key => $value) {
if (\is_array($value)) {
$this->recusiveEncoding($value, $result, $this->canonicalizeKey($path, $key));
} else {
$result[$this->canonicalizeKey($path, $key)] = $value;
}
}
} else {
foreach ($data as $elem) {
if (!$this->isAssociative($elem)) {
throw new UnexpectedValueException(sprintf("Embedded loops are not allowed. See data under %s path", $path));
}
$sub = [];
$this->recusiveEncoding($elem, $sub, '');
$result[$path][] = $sub;
}
}
}
private function canonicalizeKey(string $path, string $key): string
{
return $path === '' ? $key : $path.'_'.$key;
}
private function isAssociative(array $data)
{
$keys = \array_keys($data);
return $keys !== \array_keys($keys);
}
/**
* @inheritDoc
*/
public function supportsEncoding(string $format)
{
return $format === 'docgen';
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Chill\DocGeneratorBundle\Serializer\Helper;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class NormalizeNullValueHelper
{
private NormalizerInterface $normalizer;
public function __construct(NormalizerInterface $normalizer)
{
$this->normalizer = $normalizer;
}
public function normalize(array $attributes, string $format = 'docgen', ?array $context = [])
{
$data = [];
foreach ($attributes as $key => $class) {
if (is_numeric($key)) {
$data[$class] = '';
} else {
switch ($class) {
case 'array':
case 'bool':
case 'double':
case 'float':
case 'int':
case 'resource':
case 'string':
case 'null':
$data[$key] = '';
break;
default:
$data[$key] = $this->normalizer->normalize(null, $format, \array_merge(
$context,
['docgen:expects' => $class]
));
break;
}
}
}
return $data;
}
}

View File

@ -0,0 +1,177 @@
<?php
namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
private ClassMetadataFactoryInterface $classMetadataFactory;
private PropertyAccessor $propertyAccess;
public function __construct(ClassMetadataFactoryInterface $classMetadataFactory)
{
$this->classMetadataFactory = $classMetadataFactory;
$this->propertyAccess = PropertyAccess::createPropertyAccessor();
}
/**
* @inheritDoc
*/
public function normalize($object, string $format = null, array $context = [])
{
$classMetadataKey = $object ?? $context['docgen:expects'];
if (!$this->classMetadataFactory->hasMetadataFor($classMetadataKey)) {
throw new LogicException(sprintf("This object does not have metadata: %s. Add groups on this entity to allow to serialize with the format %s and groups %s", is_object($object) ? get_class($object) : $context['docgen:expects'], $format, \implode(', ', $context['groups'])));
}
$metadata = $this->classMetadataFactory->getMetadataFor($classMetadataKey);
$expectedGroups = \array_key_exists(AbstractNormalizer::GROUPS, $context) ?
\is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]]
: [];
$attributes = \array_filter(
$metadata->getAttributesMetadata(),
function (AttributeMetadata $a) use ($expectedGroups) {
foreach ($a->getGroups() as $g) {
if (\in_array($g, $expectedGroups, true)) {
return true;
}
}
return false;
});
if (null === $object) {
return $this->normalizeNullData($format, $context, $metadata, $attributes);
}
return $this->normalizeObject($object, $format, $context, $expectedGroups, $metadata, $attributes);
}
/**
* @param string $format
* @param array $context
* @param array $expectedGroups
* @param ClassMetadata $metadata
* @param array|AttributeMetadata[] $attributes
*/
private function normalizeNullData(string $format, array $context, ClassMetadata $metadata, array $attributes): array
{
$keys = [];
foreach ($attributes as $attribute) {
$key = $attribute->getSerializedName() ?? $attribute->getName();
$keys[$key] = $this->getExpectedType($attribute, $metadata->getReflectionClass());
}
$normalizer = new NormalizeNullValueHelper($this->normalizer);
return $normalizer->normalize($keys, $format, $context);
}
/**
* @param $object
* @param $format
* @param array $context
* @param array $expectedGroups
* @param ClassMetadata $metadata
* @param array|AttributeMetadata[] $attributes
* @return array
* @throws ExceptionInterface
*/
private function normalizeObject($object, $format, array $context, array $expectedGroups, ClassMetadata $metadata, array $attributes)
{
$data = [];
$reflection = $metadata->getReflectionClass();
foreach ($attributes as $attribute) {
/** @var AttributeMetadata $attribute */
$value = $this->propertyAccess->getValue($object, $attribute->getName());
$key = $attribute->getSerializedName() ?? $attribute->getName();
if (is_object($value)) {
$data[$key] =
$this->normalizer->normalize($value, $format, \array_merge(
$context, $attribute->getNormalizationContextForGroups($expectedGroups)
));
} elseif (null === $value) {
$data[$key] = $this->normalizeNullOutputValue($format, $context, $attribute, $reflection);
} else {
$data[$key] = (string) $value;
}
}
return $data;
}
private function getExpectedType(AttributeMetadata $attribute, \ReflectionClass $reflection): string
{
// we have to get the expected content
if ($reflection->hasProperty($attribute->getName())) {
$type = $reflection->getProperty($attribute->getName())->getType();
} elseif ($reflection->hasMethod($attribute->getName())) {
$type = $reflection->getMethod($attribute->getName())->getReturnType();
} else {
throw new \LogicException(sprintf(
"Could not determine how the content is determined for the attribute %s. Add attribute property only on property or method", $attribute->getName()
));
}
if (null === $type) {
throw new \LogicException(sprintf(
"Could not determine the type for this attribute: %s. Add a return type to the method or property declaration", $attribute->getName()
));
}
return $type->getName();
}
/**
*/
private function normalizeNullOutputValue($format, array $context, AttributeMetadata $attribute, \ReflectionClass $reflection)
{
$type = $this->getExpectedType($attribute, $reflection);
switch ($type) {
case 'array':
case 'bool':
case 'double':
case 'float':
case 'int':
case 'resource':
case 'string':
return '';
default:
return $this->normalizer->normalize(
null,
$format,
\array_merge(
$context,
['docgen:expects' => $type]
)
);
}
}
/**
* @inheritDoc
*/
public function supportsNormalization($data, string $format = null): bool
{
return $format === 'docgen' && (is_object($data) || null === $data);
}
}

View File

@ -8,3 +8,10 @@ services:
autowire: true autowire: true
autoconfigure: true autoconfigure: true
resource: '../Repository/' resource: '../Repository/'
Chill\DocGeneratorBundle\Serializer\Normalizer\:
autowire: true
autoconfigure: true
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: -152 }

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\DocGenerator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20211119173556 extends AbstractMigration
{
public function getDescription(): string
{
return 'remove comment on deprecated json_array type';
}
public function up(Schema $schema): void
{
$columns = [
'chill_docgen_template.name'
];
foreach ($columns as $col) {
$this->addSql("COMMENT ON COLUMN $col IS NULL");
}
}
public function down(Schema $schema): void
{
$this->throwIrreversibleMigrationException();
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace Chill\DocGeneratorBundle\Tests\Serializer\Encoder;
use Chill\DocGeneratorBundle\Serializer\Encoder\DocGenEncoder;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
class DocGenEncoderTest extends TestCase
{
private DocGenEncoder $encoder;
protected function setUp()
{
parent::setUp();
$this->encoder = new DocGenEncoder();
}
/**
* @dataProvider generateEncodeData
*/
public function testEncode($expected, $data, string $msg)
{
$generated = $this->encoder->encode($data, 'docgen');
$this->assertEquals($expected, $generated, $msg);
}
public function testEmbeddedLoopsThrowsException()
{
$this->expectException(UnexpectedValueException::class);
$data = [
'data' => [
['item' => 'one'],
[
'embedded' => [
[
['subitem' => 'two'],
['subitem' => 'three']
]
]
],
]
];
$this->encoder->encode($data, 'docgen');
}
public function generateEncodeData()
{
yield [ ['tests' => 'ok'], ['tests' => 'ok'], "A simple test with a simple array"];
yield [
// expected:
['item_subitem' => 'value'],
// data:
['item' => ['subitem' => 'value']],
"A test with multidimensional array"
];
yield [
// expected:
[ 'data' => [['item' => 'one'], ['item' => 'two']] ],
// data:
[ 'data' => [['item' => 'one'], ['item' => 'two']] ],
"a list of items"
];
yield [
// expected:
[ 'data' => [['item_subitem' => 'alpha'], ['item' => 'two']] ],
// data:
[ 'data' => [['item' => ['subitem' => 'alpha']], ['item' => 'two'] ] ],
"a list of items with multidimensional array inside item"
];
yield [
// expected:
[
'persons' => [
[
'firstname' => 'Jonathan',
'lastname' => 'Dupont',
'dateOfBirth_long' => '16 juin 1981',
'dateOfBirth_short' => '16/06/1981',
'father_firstname' => 'Marcel',
'father_lastname' => 'Dupont',
'father_dateOfBirth_long' => '10 novembre 1953',
'father_dateOfBirth_short' => '10/11/1953'
],
]
],
// data:
[
'persons' => [
[
'firstname' => 'Jonathan',
'lastname' => 'Dupont',
'dateOfBirth' => [ 'long' => '16 juin 1981', 'short' => '16/06/1981'],
'father' => [
'firstname' => 'Marcel',
'lastname' => 'Dupont',
'dateOfBirth' => ['long' => '10 novembre 1953', 'short' => '10/11/1953']
]
],
]
],
"a longer list, with near real data inside and embedded associative arrays"
];
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace Chill\DocGeneratorBundle\tests\Serializer\Normalizer;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\User;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class DocGenObjectNormalizerTest extends KernelTestCase
{
private NormalizerInterface $normalizer;
protected function setUp()
{
parent::setUp();
self::bootKernel();
$this->normalizer = self::$container->get(NormalizerInterface::class);
}
public function testNormalizationBasic()
{
$user = new User();
$user->setUsername('User Test');
$user->setMainCenter($center = new Center());
$center->setName('test');
$normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]);
$expected = [
'label' => 'User Test',
'email' => '',
'mainCenter' => [
'name' => 'test'
]
];
$this->assertEquals($expected, $normalized, "test normalization fo an user");
}
public function testNormalizeWithNullValueEmbedded()
{
$user = new User();
$user->setUsername('User Test');
$normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]);
$expected = [
'label' => 'User Test',
'email' => '',
'mainCenter' => [
'name' => ''
]
];
$this->assertEquals($expected, $normalized, "test normalization fo an user with null center");
}
public function testNormalizeNullObjectWithObjectEmbedded()
{
$normalized = $this->normalizer->normalize(null, 'docgen', [
AbstractNormalizer::GROUPS => ['docgen:read'],
'docgen:expects' => User::class,
]);
$expected = [
'label' => '',
'email' => '',
'mainCenter' => [
'name' => ''
]
];
$this->assertEquals($expected, $normalized, "test normalization for a null user");
}
}

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\DocStoreBundle\Controller; namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\Entity\DocumentCategory; use Chill\DocStoreBundle\Entity\DocumentCategory;
@ -9,11 +11,9 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Chill\DocStoreBundle\ChillDocStoreBundle;
/** /**
* Class DocumentCategoryController
*
* @package Chill\DocStoreBundle\Controller
* @Route("/{_locale}/admin/document/category") * @Route("/{_locale}/admin/document/category")
*/ */
class DocumentCategoryController extends AbstractController class DocumentCategoryController extends AbstractController
@ -24,11 +24,14 @@ class DocumentCategoryController extends AbstractController
public function index(): Response public function index(): Response
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$categories = $em->getRepository("ChillDocStoreBundle:DocumentCategory")->findAll(); $categories = $em->getRepository(DocumentCategory::class)->findAll();
return $this->render( return $this->render(
'ChillDocStoreBundle:DocumentCategory:index.html.twig', 'ChillDocStoreBundle:DocumentCategory:index.html.twig',
['document_categories' => $categories]); [
'document_categories' => $categories,
]
);
} }
/** /**
@ -37,13 +40,10 @@ class DocumentCategoryController extends AbstractController
public function new(Request $request): Response public function new(Request $request): Response
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$documentCategory = new DocumentCategory(); $documentCategory = new DocumentCategory(
$documentCategory ChillDocStoreBundle::class,
->setBundleId('Chill\DocStoreBundle\ChillDocStoreBundle'); $em->getRepository(DocumentCategory::class)->nextIdInsideBundle()
$documentCategory );
->setIdInsideBundle(
$em->getRepository("ChillDocStoreBundle:DocumentCategory")
->nextIdInsideBundle());
$documentCategory $documentCategory
->setDocumentClass(PersonDocument::class); ->setDocumentClass(PersonDocument::class);
@ -56,11 +56,10 @@ class DocumentCategoryController extends AbstractController
$em->flush(); $em->flush();
return $this->redirectToRoute('document_category_index'); return $this->redirectToRoute('document_category_index');
} else {
$documentCategory->setBundleId(
'Chill\DocStoreBundle\ChillDocStoreBundle');
} }
$documentCategory->setBundleId(ChillDocStoreBundle::class);
return $this->render('ChillDocStoreBundle:DocumentCategory:new.html.twig', [ return $this->render('ChillDocStoreBundle:DocumentCategory:new.html.twig', [
'document_category' => $documentCategory, 'document_category' => $documentCategory,
'form' => $form->createView(), 'form' => $form->createView(),

View File

@ -57,7 +57,7 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface
break; break;
case 'administrative': case 'administrative':
case 'direction': case 'direction':
if (in_array($scope->getName()['en'], array('administrative', 'social'))) { if (in_array($scope->getName()['en'], array('administrative', 'social'), true)) {
printf("denying power on %s\n", $scope->getName()['en']); printf("denying power on %s\n", $scope->getName()['en']);
break 2; // we do not want any power on social or administrative break 2; // we do not want any power on social or administrative
} }

View File

@ -1,8 +1,10 @@
<?php <?php
namespace Chill\DocStoreBundle\Repository; declare(strict_types=1);
use App\Entity\AccompanyingCourseDocument; namespace Chill\DocStoreBundle\EntityRepository;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;

View File

@ -34,6 +34,6 @@ class DocumentCategoryRepository extends EntityRepository
'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c') 'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c')
->getSingleResult(); ->getSingleResult();
return $array_res[1] ?: 0; return reset($array_res);
} }
} }

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\DocStore;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20211119173558 extends AbstractMigration
{
public function getDescription(): string
{
return 'remove comment on deprecated json_array type';
}
public function up(Schema $schema): void
{
$columns = [
'chill_doc.document_category.name',
'chill_doc.stored_object.key',
'chill_doc.stored_object.iv',
'chill_doc.stored_object.datas',
];
foreach ($columns as $col) {
$this->addSql("COMMENT ON COLUMN $col IS NULL");
}
}
public function down(Schema $schema): void
{
$this->throwIrreversibleMigrationException();
}
}

View File

@ -23,6 +23,7 @@ use ArrayIterator;
use Chill\EventBundle\Entity\Event; use Chill\EventBundle\Entity\Event;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Chill\EventBundle\Entity\Participation; use Chill\EventBundle\Entity\Participation;
@ -181,9 +182,9 @@ class ParticipationController extends AbstractController
protected function newMultiple(Request $request) protected function newMultiple(Request $request)
{ {
$participations = $this->handleRequest($request, new Participation(), true); $participations = $this->handleRequest($request, new Participation(), true);
$ignoredParticipations = $newParticipations = [];
foreach ($participations as $participation) {
foreach ($participations as $i => $participation) {
// check for authorization // check for authorization
$this->denyAccessUnlessGranted(ParticipationVoter::CREATE, $this->denyAccessUnlessGranted(ParticipationVoter::CREATE,
$participation, 'The user is not allowed to create this participation'); $participation, 'The user is not allowed to create this participation');
@ -209,7 +210,7 @@ class ParticipationController extends AbstractController
// this is where the function redirect depending on valid participation // this is where the function redirect depending on valid participation
if (!isset($newParticipations)) { if ([] === $newParticipations) {
// if we do not have nay participants, redirect to event view // if we do not have nay participants, redirect to event view
$this->addFlash('error', $this->get('translator')->trans( $this->addFlash('error', $this->get('translator')->trans(
'None of the requested people may participate ' 'None of the requested people may participate '
@ -218,26 +219,33 @@ class ParticipationController extends AbstractController
return $this->redirectToRoute('chill_event__event_show', array( return $this->redirectToRoute('chill_event__event_show', array(
'event_id' => $request->query->getInt('event_id', 0) 'event_id' => $request->query->getInt('event_id', 0)
)); ));
} elseif (count($newParticipations) > 1) { }
if (count($newParticipations) > 1) {
// if we have multiple participations, show a form with multiple participations // if we have multiple participations, show a form with multiple participations
$form = $this->createCreateFormMultiple($newParticipations); $form = $this->createCreateFormMultiple($newParticipations);
return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', array( return $this->render(
'ChillEventBundle:Participation:new-multiple.html.twig',
[
'form' => $form->createView(), 'form' => $form->createView(),
'participations' => $newParticipations, 'participations' => $newParticipations,
'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() 'ignored_participations' => $ignoredParticipations
)); ]
} else { );
}
// if we have only one participation, show the same form than for single participation // if we have only one participation, show the same form than for single participation
$form = $this->createCreateForm($participation); $form = $this->createCreateForm($participation);
return $this->render('ChillEventBundle:Participation:new.html.twig', array( return $this->render(
'ChillEventBundle:Participation:new.html.twig',
[
'form' => $form->createView(), 'form' => $form->createView(),
'participation' => $participation, 'participation' => $participation,
'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() 'ignored_participations' => $ignoredParticipations,
)); ]
);
}
} }
/** /**
@ -367,9 +375,6 @@ class ParticipationController extends AbstractController
* If the request is multiple, the $participation object is cloned. * If the request is multiple, the $participation object is cloned.
* Limitations: the $participation should not be persisted. * Limitations: the $participation should not be persisted.
* *
* @param Request $request
* @param Participation $participation
* @param boolean $multiple (default false)
* @return Participation|Participations[] return one single participation if $multiple == false * @return Participation|Participations[] return one single participation if $multiple == false
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the event/person is not found * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the event/person is not found
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException if the user does not have access to event/person * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException if the user does not have access to event/person
@ -377,7 +382,7 @@ class ParticipationController extends AbstractController
protected function handleRequest( protected function handleRequest(
Request $request, Request $request,
Participation $participation, Participation $participation,
$multiple = false) bool $multiple = false)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
if ($em->contains($participation)) { if ($em->contains($participation)) {
@ -436,11 +441,9 @@ class ParticipationController extends AbstractController
} }
/** /**
* @param Participation $participation
* @param null $return_path * @param null $return_path
* @return \Symfony\Component\Form\FormInterface
*/ */
public function createCreateForm(Participation $participation, $return_path = null) public function createCreateForm(Participation $participation, $return_path = null): FormInterface
{ {
$form = $this->createForm(ParticipationType::class, $participation, array( $form = $this->createForm(ParticipationType::class, $participation, array(
@ -459,11 +462,7 @@ class ParticipationController extends AbstractController
return $form; return $form;
} }
/** public function createCreateFormMultiple(array $participations): FormInterface
* @param array $participations
* @return \Symfony\Component\Form\FormInterface
*/
public function createCreateFormMultiple(array $participations)
{ {
$form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class, $form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class,
array('participations' => $participations), array( array('participations' => $participations), array(
@ -490,18 +489,16 @@ class ParticipationController extends AbstractController
} }
/** /**
* show an edit form for the participation with the given id. * Show an edit form for the participation with the given id.
* *
* @param int $participation_id
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the participation is not found * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the participation is not found
* @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException if the user is not allowed to edit the participation * @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException if the user is not allowed to edit the participation
*/ */
public function editAction($participation_id) public function editAction(int $participation_id): Response
{ {
/* @var $participation Participation */ /* @var $participation Participation */
$participation = $this->getDoctrine()->getManager() $participation = $this->getDoctrine()->getManager()
->getRepository('ChillEventBundle:Participation') ->getRepository(Participation::class)
->find($participation_id); ->find($participation_id);
if ($participation === NULL) { if ($participation === NULL) {
@ -513,22 +510,17 @@ class ParticipationController extends AbstractController
$form = $this->createEditForm($participation); $form = $this->createEditForm($participation);
return $this->render('ChillEventBundle:Participation:edit.html.twig', array( return $this->render('ChillEventBundle:Participation:edit.html.twig', [
'form' => $form->createView(), 'form' => $form->createView(),
'participation' => $participation 'participation' => $participation,
)); ]);
} }
/** public function updateAction(int $participation_id, Request $request): Response
* @param $participation_id
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
*/
public function updateAction($participation_id, Request $request)
{ {
/* @var $participation Participation */ /* @var $participation Participation */
$participation = $this->getDoctrine()->getManager() $participation = $this->getDoctrine()->getManager()
->getRepository('ChillEventBundle:Participation') ->getRepository(Participation::class)
->find($participation_id); ->find($participation_id);
if ($participation === NULL) { if ($participation === NULL) {
@ -551,35 +543,40 @@ class ParticipationController extends AbstractController
'The participation was updated' 'The participation was updated'
)); ));
return $this->redirectToRoute('chill_event__event_show', array( return $this->redirectToRoute('chill_event__event_show', [
'event_id' => $participation->getEvent()->getId() 'event_id' => $participation->getEvent()->getId(),
)); ]);
} }
return $this->render('ChillEventBundle:Participation:edit.html.twig', array( return $this->render('ChillEventBundle:Participation:edit.html.twig', [
'form' => $form->createView(), 'form' => $form->createView(),
'participation' => $participation 'participation' => $participation,
)); ]);
} }
/** public function createEditForm(Participation $participation): FormInterface
*
* @param Participation $participation
* @return \Symfony\Component\Form\FormInterface
*/
public function createEditForm(Participation $participation)
{ {
$form = $this->createForm(ParticipationType::class, $participation, array( $form = $this->createForm(
ParticipationType::class,
$participation,
[
'event_type' => $participation->getEvent()->getType(), 'event_type' => $participation->getEvent()->getType(),
'action' => $this->generateUrl('chill_event_participation_update', array( 'action' => $this->generateUrl(
'participation_id' => $participation->getId() 'chill_event_participation_update',
)) [
)); 'participation_id' => $participation->getId(),
]
),
]
);
$form->add('submit', SubmitType::class, array( $form->add(
'label' => 'Edit' 'submit',
)); SubmitType::class, [
'label' => 'Edit',
]
);
return $form; return $form;
} }

View File

@ -50,7 +50,7 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface
break; break;
case 'administrative': case 'administrative':
case 'direction': case 'direction':
if (in_array($scope->getName()['en'], array('administrative', 'social'))) { if (in_array($scope->getName()['en'], array('administrative', 'social'), true)) {
break 2; // we do not want any power on social or administrative break 2; // we do not want any power on social or administrative
} }
break; break;

View File

@ -1,50 +1,46 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\FamilyMembersBundle\Controller; namespace Chill\AMLI\FamilyMembersBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Chill\AMLI\FamilyMembersBundle\Repository\FamilyMemberRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember; use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember;
use Chill\AMLI\FamilyMembersBundle\Security\Voter\FamilyMemberVoter; use Chill\AMLI\FamilyMembersBundle\Security\Voter\FamilyMemberVoter;
use Chill\AMLI\FamilyMembersBundle\Form\FamilyMemberType; use Chill\AMLI\FamilyMembersBundle\Form\FamilyMemberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Annotation\Route;
class FamilyMemberController extends Controller class FamilyMemberController extends AbstractController
{ {
/** private EntityManagerInterface $em;
*
* @var EntityManagerInterface
*/
protected $em;
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
/** protected LoggerInterface $chillMainLogger;
*
* @var LoggerInterface private FamilyMemberRepository $familyMemberRepository;
*/
protected $chillMainLogger;
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $entityManager,
TranslatorInterface $translator, TranslatorInterface $translator,
LoggerInterface $chillMainLogger LoggerInterface $chillMainLogger,
FamilyMemberRepository $familyMemberRepository
) { ) {
$this->em = $em; $this->em = $entityManager;
$this->translator = $translator; $this->translator = $translator;
$this->chillMainLogger = $chillMainLogger; $this->chillMainLogger = $chillMainLogger;
$this->familyMemberRepository = $familyMemberRepository;
} }
/** /**
* @Route( * @Route(
* "{_locale}/family-members/family-members/by-person/{id}", * "{_locale}/family-members/family-members/by-person/{id}",
@ -55,14 +51,12 @@ class FamilyMemberController extends Controller
{ {
$this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person); $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person);
$familyMembers = $this->em $familyMembers = $this->familyMemberRepository->findByPerson($person);
->getRepository(FamilyMember::class)
->findByPerson($person);
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', [
'person' => $person, 'person' => $person,
'familyMembers' => $familyMembers 'familyMembers' => $familyMembers
)); ]);
} }
/** /**
@ -73,9 +67,7 @@ class FamilyMemberController extends Controller
*/ */
public function newAction(Person $person, Request $request) public function newAction(Person $person, Request $request)
{ {
$familyMember = (new FamilyMember()) $familyMember = (new FamilyMember())->setPerson($person);
->setPerson($person)
;
$this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember); $this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember);
@ -84,10 +76,9 @@ class FamilyMemberController extends Controller
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager(); $this->em->persist($familyMember);
$em->persist($familyMember); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator->trans('Family member created')); $this->addFlash('success', $this->translator->trans('Family member created'));
@ -96,10 +87,10 @@ class FamilyMemberController extends Controller
]); ]);
} }
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', [
'form' => $form->createView(), 'form' => $form->createView(),
'person' => $person 'person' => $person
)); ]);
} }
/** /**
@ -117,9 +108,8 @@ class FamilyMemberController extends Controller
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager(); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator->trans('Family member updated')); $this->addFlash('success', $this->translator->trans('Family member updated'));
@ -128,11 +118,11 @@ class FamilyMemberController extends Controller
]); ]);
} }
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', [
'familyMember' => $familyMember, 'familyMember' => $familyMember,
'form' => $form->createView(), 'form' => $form->createView(),
'person' => $familyMember->getPerson() 'person' => $familyMember->getPerson()
)); ]);
} }
/** /**
@ -141,47 +131,42 @@ class FamilyMemberController extends Controller
* "{_locale}/family-members/family-members/{id}/delete", * "{_locale}/family-members/family-members/{id}/delete",
* name="chill_family_members_family_members_delete" * name="chill_family_members_family_members_delete"
* ) * )
*
* @param FamilyMember $familyMember
* @param Request $request
* @return \Symfony\Component\BrowserKit\Response
*/ */
public function deleteAction(FamilyMember $familyMember, Request $request) public function deleteAction(FamilyMember $familyMember, Request $request): Response
{ {
$this->denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not ' $this->denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not '
. 'allowed to delete this family membership'); . 'allowed to delete this family membership');
$form = $this->createDeleteForm($id); $form = $this->createDeleteForm();
if ($request->getMethod() === Request::METHOD_DELETE) { if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isValid()) { if ($form->isValid()) {
$this->chillMainLogger->notice("A family member has been removed", array( $this->chillMainLogger->notice("A family member has been removed", [
'by_user' => $this->getUser()->getUsername(), 'by_user' => $this->getUser()->getUsername(),
'family_member_id' => $familyMember->getId(), 'family_member_id' => $familyMember->getId(),
'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(), 'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(),
'link' => $familyMember->getLink() 'link' => $familyMember->getLink()
)); ]);
$em = $this->getDoctrine()->getManager(); $this->em->remove($familyMember);
$em->remove($familyMember); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator $this->addFlash('success', $this->translator
->trans("The family member has been successfully removed.")); ->trans("The family member has been successfully removed."));
return $this->redirectToRoute('chill_family_members_family_members_index', array( return $this->redirectToRoute('chill_family_members_family_members_index', [
'id' => $familyMember->getPerson()->getId() 'id' => $familyMember->getPerson()->getId()
)); ]);
} }
} }
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', [
'familyMember' => $familyMember, 'familyMember' => $familyMember,
'delete_form' => $form->createView() 'delete_form' => $form->createView()
)); ]);
} }
/** /**
@ -194,23 +179,20 @@ class FamilyMemberController extends Controller
{ {
$this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember); $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember);
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', [
'familyMember' => $familyMember 'familyMember' => $familyMember
)); ]);
} }
/** /**
* Creates a form to delete a help request entity by id. * Creates a form to delete a help request entity by id.
*
* @param mixed $id The entity id
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createDeleteForm($id) private function createDeleteForm(): FormInterface
{ {
return $this->createFormBuilder() return $this
->createFormBuilder()
->setMethod(Request::METHOD_DELETE) ->setMethod(Request::METHOD_DELETE)
->add('submit', SubmitType::class, array('label' => 'Delete')) ->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm() ->getForm()
; ;
} }

View File

@ -1,16 +1,31 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\FamilyMembersBundle\Repository; namespace Chill\AMLI\FamilyMembersBundle\Repository;
use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/** /**
* FamilyMemberRepository * @method FamilyMember|null find($id, $lockMode = null, $lockVersion = null)
* * @method FamilyMember|null findOneBy(array $criteria, array $orderBy = null)
* @method FamilyMember[] findAll()
* @method FamilyMember[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/ */
class FamilyMemberRepository extends \Doctrine\ORM\EntityRepository class FamilyMemberRepository extends ServiceEntityRepository
{ {
public function findActiveByPerson(Person $person) public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, FamilyMember::class);
}
/**
* @return FamilyMember[]
*/
public function findByPerson(Person $person): array
{ {
return $this->findBy(['person' => $person]); return $this->findBy(['person' => $person]);
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\CRUD\Controller; namespace Chill\MainBundle\CRUD\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -14,49 +16,39 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
class AbstractCRUDController extends AbstractController abstract class AbstractCRUDController extends AbstractController
{ {
/** /**
* The crud configuration * The crud configuration
* *
* This configuration si defined by `chill_main['crud']` or `chill_main['apis']` * This configuration si defined by `chill_main['crud']` or `chill_main['apis']`
*
* @var array
*/ */
protected array $crudConfig = []; protected array $crudConfig = [];
/** /**
* get the instance of the entity with the given id * get the instance of the entity with the given id
* *
* @param string $id
* @return object
* @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found * @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
*/ */
protected function getEntity($action, $id, Request $request): object protected function getEntity($action, string $id, Request $request): object
{ {
$e = $this->getDoctrine() $e = $this
->getDoctrine()
->getRepository($this->getEntityClass()) ->getRepository($this->getEntityClass())
->find($id); ->find($id);
if (NULL === $e) { if (null === $e) {
throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id)); throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id));
} }
return $e; return $e;
} }
/**
* Create an entity.
*
* @param string $action
* @param Request $request
* @return object
*/
protected function createEntity(string $action, Request $request): object protected function createEntity(string $action, Request $request): object
{ {
$type = $this->getEntityClass(); $class = $this->getEntityClass();
return new $type; return new $class;
} }
/** /**
@ -64,18 +56,13 @@ class AbstractCRUDController extends AbstractController
* *
* By default, count all entities. You can customize the query by * By default, count all entities. You can customize the query by
* using the method `customizeQuery`. * using the method `customizeQuery`.
*
* @param string $action
* @param Request $request
* @return int
*/ */
protected function countEntities(string $action, Request $request, $_format): int protected function countEntities(string $action, Request $request, $_format): int
{ {
return $this->buildQueryEntities($action, $request) return $this->buildQueryEntities($action, $request)
->select('COUNT(e)') ->select('COUNT(e)')
->getQuery() ->getQuery()
->getSingleScalarResult() ->getSingleScalarResult();
;
} }
/** /**
@ -87,7 +74,6 @@ class AbstractCRUDController extends AbstractController
* The method `orderEntity` is called internally to order entities. * The method `orderEntity` is called internally to order entities.
* *
* It returns, by default, a query builder. * It returns, by default, a query builder.
*
*/ */
protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator) protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator)
{ {
@ -101,7 +87,6 @@ class AbstractCRUDController extends AbstractController
/** /**
* Add ordering fields in the query build by self::queryEntities * Add ordering fields in the query build by self::queryEntities
*
*/ */
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{ {
@ -118,8 +103,6 @@ class AbstractCRUDController extends AbstractController
* *
* The alias for the entity is "e". * The alias for the entity is "e".
* *
* @param string $action
* @param Request $request
* @return QueryBuilder * @return QueryBuilder
*/ */
protected function buildQueryEntities(string $action, Request $request) protected function buildQueryEntities(string $action, Request $request)
@ -127,8 +110,7 @@ class AbstractCRUDController extends AbstractController
$qb = $this->getDoctrine()->getManager() $qb = $this->getDoctrine()->getManager()
->createQueryBuilder() ->createQueryBuilder()
->select('e') ->select('e')
->from($this->getEntityClass(), 'e') ->from($this->getEntityClass(), 'e');
;
$this->customizeQuery($action, $request, $qb); $this->customizeQuery($action, $request, $qb);
@ -138,7 +120,7 @@ class AbstractCRUDController extends AbstractController
protected function customizeQuery(string $action, Request $request, $query): void {} protected function customizeQuery(string $action, Request $request, $query): void {}
/** /**
* Get the result of the query * Get the result of the query.
*/ */
protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query) protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query)
{ {
@ -151,7 +133,7 @@ class AbstractCRUDController extends AbstractController
} }
/** /**
* method used by indexAction * Method used by indexAction.
*/ */
protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response
{ {
@ -159,7 +141,7 @@ class AbstractCRUDController extends AbstractController
} }
/** /**
* method used by indexAction * Method used by indexAction.
*/ */
protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response
{ {
@ -167,18 +149,17 @@ class AbstractCRUDController extends AbstractController
} }
/** /**
* method used by indexAction * Method used by indexAction.
*/ */
protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response
{ {
return null; return null;
} }
/** /**
* Get the complete FQDN of the class * Get the FQDN of the class.
* *
* @return string the complete fqdn of the class * @return class-string The FQDN of the class
*/ */
protected function getEntityClass(): string protected function getEntityClass(): string
{ {
@ -186,7 +167,7 @@ class AbstractCRUDController extends AbstractController
} }
/** /**
* called on post fetch entity * Called on post fetch entity.
*/ */
protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response
{ {
@ -194,7 +175,7 @@ class AbstractCRUDController extends AbstractController
} }
/** /**
* Called on post check ACL * Called on post check ACL.
*/ */
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
{ {
@ -214,12 +195,12 @@ class AbstractCRUDController extends AbstractController
*/ */
protected function checkACL(string $action, Request $request, string $_format, $entity = null) protected function checkACL(string $action, Request $request, string $_format, $entity = null)
{ {
// @TODO: Implements abstract getRoleFor method or do it in the interface.
$this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity); $this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity);
} }
/** /**
* * @return string The crud name.
* @return string the crud name
*/ */
protected function getCrudName(): string protected function getCrudName(): string
{ {
@ -241,9 +222,6 @@ class AbstractCRUDController extends AbstractController
$this->crudConfig = $config; $this->crudConfig = $config;
} }
/**
* @return PaginatorFactory
*/
protected function getPaginatorFactory(): PaginatorFactory protected function getPaginatorFactory(): PaginatorFactory
{ {
return $this->container->get('chill_main.paginator_factory'); return $this->container->get('chill_main.paginator_factory');
@ -254,9 +232,6 @@ class AbstractCRUDController extends AbstractController
return $this->get('validator'); return $this->get('validator');
} }
/**
* @return array
*/
public static function getSubscribedServices(): array public static function getSubscribedServices(): array
{ {
return \array_merge( return \array_merge(

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\CRUD\Controller; namespace Chill\MainBundle\CRUD\Controller;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -34,7 +36,7 @@ class ApiController extends AbstractCRUDController
*/ */
protected function entityGet(string $action, Request $request, $id, $_format = 'html'): Response protected function entityGet(string $action, Request $request, $id, $_format = 'html'): Response
{ {
$entity = $this->getEntity($action, $id, $request, $_format); $entity = $this->getEntity($action, $id, $request);
$postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
@ -86,7 +88,7 @@ class ApiController extends AbstractCRUDController
case Request::METHOD_PATCH: case Request::METHOD_PATCH:
return $this->entityPut('_entity', $request, $id, $_format); return $this->entityPut('_entity', $request, $id, $_format);
case Request::METHOD_POST: case Request::METHOD_POST:
return $this->entityPostAction('_entity', $request, $id, $_format); return $this->entityPostAction('_entity', $request, $id);
case Request::METHOD_DELETE: case Request::METHOD_DELETE:
return $this->entityDelete('_entity', $request, $id, $_format); return $this->entityDelete('_entity', $request, $id, $_format);
default: default:
@ -158,7 +160,7 @@ class ApiController extends AbstractCRUDController
} }
public function entityPut($action, Request $request, $id, string $_format): Response public function entityPut($action, Request $request, $id, string $_format): Response
{ {
$entity = $this->getEntity($action, $id, $request, $_format); $entity = $this->getEntity($action, $id, $request);
$postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
if ($postFetch instanceof Response) { if ($postFetch instanceof Response) {
@ -221,7 +223,7 @@ class ApiController extends AbstractCRUDController
} }
public function entityDelete($action, Request $request, $id, string $_format): Response public function entityDelete($action, Request $request, $id, string $_format): Response
{ {
$entity = $this->getEntity($action, $id, $request, $_format); $entity = $this->getEntity($action, $id, $request);
if (NULL === $entity) { if (NULL === $entity) {
throw $this->createNotFoundException(sprintf("The %s with id %s " throw $this->createNotFoundException(sprintf("The %s with id %s "
@ -345,7 +347,6 @@ class ApiController extends AbstractCRUDController
* *
* @param string $action * @param string $action
* @param Request $request * @param Request $request
* @return type
*/ */
protected function indexApiAction($action, Request $request, $_format) protected function indexApiAction($action, Request $request, $_format)
{ {
@ -356,9 +357,7 @@ class ApiController extends AbstractCRUDController
return $response; return $response;
} }
if (!isset($entity)) {
$entity = ''; $entity = '';
}
$response = $this->onPostCheckACL($action, $request, $_format, $entity); $response = $this->onPostCheckACL($action, $request, $_format, $entity);
if ($response instanceof Response) { if ($response instanceof Response) {
@ -368,8 +367,13 @@ class ApiController extends AbstractCRUDController
$totalItems = $this->countEntities($action, $request, $_format); $totalItems = $this->countEntities($action, $request, $_format);
$paginator = $this->getPaginatorFactory()->create($totalItems); $paginator = $this->getPaginatorFactory()->create($totalItems);
$response = $this->onPreIndexBuildQuery($action, $request, $_format, $totalItems, $response = $this->onPreIndexBuildQuery(
$paginator); $action,
$request,
$_format,
$totalItems,
$paginator
);
if ($response instanceof Response) { if ($response instanceof Response) {
return $response; return $response;
@ -504,6 +508,8 @@ class ApiController extends AbstractCRUDController
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData]) $this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData])
); );
} }
throw new \Exception('Unable to handle such request method.');
} }
/** /**

View File

@ -1,22 +1,4 @@
<?php <?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2019, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\CRUD\Controller; namespace Chill\MainBundle\CRUD\Controller;
@ -37,60 +19,40 @@ use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\SerializerInterface;
/**
* Class CRUDController
*
* @package Chill\MainBundle\CRUD\Controller
*/
class CRUDController extends AbstractController class CRUDController extends AbstractController
{ {
/** /**
* The crud configuration * The crud configuration
* *
* This configuration si defined by `chill_main['crud']`. * This configuration si defined by `chill_main['crud']`.
*
* @var array
*/ */
protected $crudConfig; protected array $crudConfig;
/** public function setCrudConfig(array $config): void
* @param array $config
*/
public function setCrudConfig(array $config)
{ {
$this->crudConfig = $config; $this->crudConfig = $config;
} }
/** public function CRUD(?string $parameter): Response
* @param $parameter
* @return Response
*/
public function CRUD($parameter)
{ {
return new Response($parameter); return new Response($parameter);
} }
/** /**
* @param Request $request
* @param $id * @param $id
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
*/ */
public function delete(Request $request, $id) public function delete(Request $request, $id): Response
{ {
return $this->deleteAction('delete', $request, $id); return $this->deleteAction('delete', $request, $id);
} }
/** /**
* @param string $action
* @param Request $request
* @param $id * @param $id
* @param null $formClass * @param null $formClass
* @return null|\Symfony\Component\HttpFoundation\RedirectResponse|Response|void
*/ */
protected function deleteAction(string $action, Request $request, $id, $formClass = null) protected function deleteAction(string $action, Request $request, $id, $formClass = null): Response
{ {
$this->onPreDelete($action, $request, $id); $this->onPreDelete($action, $request);
$entity = $this->getEntity($action, $id, $request); $entity = $this->getEntity($action, $id, $request);
@ -101,8 +63,13 @@ class CRUDController extends AbstractController
} }
if (NULL === $entity) { if (NULL === $entity) {
throw $this->createNotFoundException(sprintf("The %s with id %s " throw $this->createNotFoundException(
. "is not found"), $this->getCrudName(), $id); sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
} }
$response = $this->checkACL($action, $entity); $response = $this->checkACL($action, $entity);
@ -141,7 +108,9 @@ class CRUDController extends AbstractController
return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]); return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]);
} elseif ($form->isSubmitted()) { }
if ($form->isSubmitted()) {
$this->addFlash('error', $this->generateFormErrorMessage($action, $form)); $this->addFlash('error', $this->generateFormErrorMessage($action, $form));
} }
@ -233,7 +202,6 @@ class CRUDController extends AbstractController
* *
* @param string $action * @param string $action
* @param Request $request * @param Request $request
* @return type
*/ */
protected function indexEntityAction($action, Request $request) protected function indexEntityAction($action, Request $request)
{ {
@ -244,9 +212,7 @@ class CRUDController extends AbstractController
return $response; return $response;
} }
if (!isset($entity)) {
$entity = ''; $entity = '';
}
$response = $this->onPostCheckACL($action, $request, $entity); $response = $this->onPostCheckACL($action, $request, $entity);
if ($response instanceof Response) { if ($response instanceof Response) {
@ -342,11 +308,12 @@ class CRUDController extends AbstractController
*/ */
protected function buildQueryEntities(string $action, Request $request) protected function buildQueryEntities(string $action, Request $request)
{ {
$query = $this->getDoctrine()->getManager() $query = $this
->getDoctrine()
->getManager()
->createQueryBuilder() ->createQueryBuilder()
->select('e') ->select('e')
->from($this->getEntityClass(), 'e') ->from($this->getEntityClass(), 'e');
;
$this->customizeQuery($action, $request, $query); $this->customizeQuery($action, $request, $query);
@ -371,7 +338,7 @@ class CRUDController extends AbstractController
*/ */
protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator, ?FilterOrderHelper $filterOrder = null) protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator, ?FilterOrderHelper $filterOrder = null)
{ {
$query = $this->buildQueryEntities($action, $request, $filterOrder) $query = $this->buildQueryEntities($action, $request)
->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
->setMaxResults($paginator->getItemsPerPage()); ->setMaxResults($paginator->getItemsPerPage());
@ -420,7 +387,7 @@ class CRUDController extends AbstractController
*/ */
protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int
{ {
return $this->buildQueryEntities($action, $request, $filterOrder) return $this->buildQueryEntities($action, $request)
->select('COUNT(e)') ->select('COUNT(e)')
->getQuery() ->getQuery()
->getSingleScalarResult() ->getSingleScalarResult()
@ -505,8 +472,13 @@ class CRUDController extends AbstractController
} }
if (NULL === $entity) { if (NULL === $entity) {
throw $this->createNotFoundException(sprintf("The %s with id %s " throw $this->createNotFoundException(
. "is not found", $this->getCrudName(), $id)); sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
} }
$response = $this->checkACL($action, $entity); $response = $this->checkACL($action, $entity);
@ -598,8 +570,13 @@ class CRUDController extends AbstractController
$entity = $this->getEntity($action, $id, $request); $entity = $this->getEntity($action, $id, $request);
if (NULL === $entity) { if (NULL === $entity) {
throw $this->createNotFoundException(sprintf("The %s with id %s " throw $this->createNotFoundException(
. "is not found", $this->getCrudName(), $id)); sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
} }
$response = $this->checkACL($action, $entity); $response = $this->checkACL($action, $entity);

View File

@ -1,22 +1,6 @@
<?php <?php
/*
* Chill is a software for social workers declare(strict_types=1);
*
* Copyright (C) 2019, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\CRUD\Routing; namespace Chill\MainBundle\CRUD\Routing;
@ -27,22 +11,13 @@ use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\CRUD\Controller\ApiController; use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\CRUD\Controller\CRUDController; use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class CRUDRoutesLoader
* Load the route for CRUD
*
* @package Chill\MainBundle\CRUD\Routing
*/
class CRUDRoutesLoader extends Loader class CRUDRoutesLoader extends Loader
{ {
protected array $crudConfig = []; protected array $crudConfig = [];
protected array $apiCrudConfig = []; protected array $apiCrudConfig = [];
/** private bool $isLoaded = false;
* @var bool
*/
private $isLoaded = false;
private const ALL_SINGLE_METHODS = [ private const ALL_SINGLE_METHODS = [
Request::METHOD_GET, Request::METHOD_GET,
@ -53,16 +28,12 @@ class CRUDRoutesLoader extends Loader
private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ]; private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ];
/** public function __construct(array $crudConfig, array $apiCrudConfig)
* CRUDRoutesLoader constructor.
*
* @param $crudConfig the config from cruds
* @param $apicrudConfig the config from api_crud
*/
public function __construct(array $crudConfig, array $apiConfig)
{ {
$this->crudConfig = $crudConfig; $this->crudConfig = $crudConfig;
$this->apiConfig = $apiConfig; $this->apiCrudConfig = $apiCrudConfig;
parent::__construct();
} }
/** /**
@ -89,7 +60,7 @@ class CRUDRoutesLoader extends Loader
foreach ($this->crudConfig as $crudConfig) { foreach ($this->crudConfig as $crudConfig) {
$collection->addCollection($this->loadCrudConfig($crudConfig)); $collection->addCollection($this->loadCrudConfig($crudConfig));
} }
foreach ($this->apiConfig as $crudConfig) { foreach ($this->apiCrudConfig as $crudConfig) {
$collection->addCollection($this->loadApi($crudConfig)); $collection->addCollection($this->loadApi($crudConfig));
} }

View File

@ -3,6 +3,7 @@
namespace Chill\MainBundle; namespace Chill\MainBundle;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchInterface; use Chill\MainBundle\Search\SearchInterface;
use Chill\MainBundle\Security\Authorization\ChillVoterInterface; use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
use Chill\MainBundle\Security\ProvideRoleInterface; use Chill\MainBundle\Security\ProvideRoleInterface;
@ -41,6 +42,8 @@ class ChillMainBundle extends Bundle
->addTag('chill_main.scope_resolver'); ->addTag('chill_main.scope_resolver');
$container->registerForAutoconfiguration(ChillEntityRenderInterface::class) $container->registerForAutoconfiguration(ChillEntityRenderInterface::class)
->addTag('chill.render_entity'); ->addTag('chill.render_entity');
$container->registerForAutoconfiguration(SearchApiInterface::class)
->addTag('chill.search_api_provider');
$container->addCompilerPass(new SearchableServicesCompilerPass()); $container->addCompilerPass(new SearchableServicesCompilerPass());
$container->addCompilerPass(new ConfigConsistencyCompilerPass()); $container->addCompilerPass(new ConfigConsistencyCompilerPass());

View File

@ -1,7 +1,10 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Command; namespace Chill\MainBundle\Command;
use Chill\MainBundle\Repository\UserRepository;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -23,101 +26,51 @@ use League\Csv\Writer;
class ChillImportUsersCommand extends Command class ChillImportUsersCommand extends Command
{ {
protected EntityManagerInterface $em;
/** protected ValidatorInterface $validator;
*
* @var EntityManagerInterface
*/
protected $em;
/** protected LoggerInterface $logger;
*
* @var ValidatorInterface
*/
protected $validator;
/** protected UserPasswordEncoderInterface $passwordEncoder;
*
* @var LoggerInterface
*/
protected $logger;
/** protected UserRepository $userRepository;
*
* @var UserPasswordEncoderInterface
*/
protected $passwordEncoder;
/** protected bool $doChanges = true;
*
* @var \Chill\MainBundle\Repository\UserRepository
*/
protected $userRepository;
/** protected OutputInterface $tempOutput;
*
* @var bool
*/
protected $doChanges = true;
/** protected InputInterface $tempInput;
*
* @var OutputInterface
*/
protected $tempOutput;
/**
*
* @var InputInterface
*/
protected $tempInput;
/** /**
* Centers and aliases. * Centers and aliases.
* *
* key are aliases, values are an array of centers * key are aliases, values are an array of centers
*
* @var array
*/ */
protected $centers = []; protected array $centers;
/** protected array $permissionGroups;
*
* @var array
*/
protected $permissionGroups = [];
/** protected array $groupCenters;
*
* @var array
*/
protected $groupCenters = [];
/** protected Writer $output;
*
* @var Writer
*/
protected $output = null;
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
LoggerInterface $logger, LoggerInterface $logger,
UserPasswordEncoderInterface $passwordEncoder, UserPasswordEncoderInterface $passwordEncoder,
ValidatorInterface $validator ValidatorInterface $validator,
UserRepository $userRepository
) { ) {
$this->em = $em; $this->em = $em;
$this->passwordEncoder = $passwordEncoder; $this->passwordEncoder = $passwordEncoder;
$this->validator = $validator; $this->validator = $validator;
$this->logger = $logger; $this->logger = $logger;
$this->userRepository = $userRepository;
$this->userRepository = $em->getRepository(User::class);
parent::__construct('chill:main:import-users'); parent::__construct('chill:main:import-users');
} }
protected function configure() protected function configure()
{ {
$this $this
@ -126,8 +79,7 @@ class ChillImportUsersCommand extends Command
->addArgument('csvfile', InputArgument::REQUIRED, 'Path to the csv file. Columns are: `username`, `email`, `center` (can contain alias), `permission group`') ->addArgument('csvfile', InputArgument::REQUIRED, 'Path to the csv file. Columns are: `username`, `email`, `center` (can contain alias), `permission group`')
->addOption('grouping-centers', null, InputOption::VALUE_OPTIONAL, 'Path to a csv file to aggregate multiple centers into a single alias') ->addOption('grouping-centers', null, InputOption::VALUE_OPTIONAL, 'Path to a csv file to aggregate multiple centers into a single alias')
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit the changes') ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit the changes')
->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file') ->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file');
;
} }
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
@ -309,21 +261,14 @@ class ChillImportUsersCommand extends Command
} }
return $this->permissionGroups[$alias]; return $this->permissionGroups[$alias];
} else {
$this->logger->error("Error while responding to a a question");
$this->tempOutput("Ok, I accept, but I do not know what to do. Please try again.");
throw new \RuntimeException("Error while responding to a question");
}
} }
/** $this->logger->error('Error while responding to a a question');
* $this->tempOutput->writeln('Ok, I accept, but I do not know what to do. Please try again.');
* @param Center $center
* @param \Chill\MainBundle\Command\PermissionGroup $pg throw new \RuntimeException('Error while responding to a question');
* @return GroupCenter }
*/
protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter
{ {
if (\array_key_exists($center->getId(), $this->groupCenters)) { if (\array_key_exists($center->getId(), $this->groupCenters)) {

View File

@ -72,6 +72,7 @@ class LoadCountriesCommand extends Command
public static function prepareCountryList($languages) public static function prepareCountryList($languages)
{ {
$regionBundle = Intl::getRegionBundle(); $regionBundle = Intl::getRegionBundle();
$countries = [];
foreach ($languages as $language) { foreach ($languages as $language) {
$countries[$language] = $regionBundle->getCountryNames($language); $countries[$language] = $regionBundle->getCountryNames($language);

View File

@ -1,27 +1,13 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Command; namespace Chill\MainBundle\Command;
use Chill\MainBundle\Doctrine\Model\Point; use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Country; use Chill\MainBundle\Entity\Country;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
@ -31,32 +17,13 @@ use Symfony\Component\Filesystem\Filesystem;
use Chill\MainBundle\Entity\PostalCode; use Chill\MainBundle\Entity\PostalCode;
use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class LoadPostalCodesCommand
*
* @package Chill\MainBundle\Command
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadPostalCodesCommand extends Command class LoadPostalCodesCommand extends Command
{ {
private EntityManagerInterface $entityManager;
/** private ValidatorInterface $validator;
* @var EntityManager
*/
private $entityManager;
/** public function __construct(EntityManagerInterface $entityManager, ValidatorInterface $validator)
* @var ValidatorInterface
*/
private $validator;
/**
* LoadPostalCodesCommand constructor.
*
* @param EntityManager $entityManager
* @param ValidatorInterface $validator
*/
public function __construct(EntityManager $entityManager, ValidatorInterface $validator)
{ {
$this->entityManager = $entityManager; $this->entityManager = $entityManager;
$this->validator = $validator; $this->validator = $validator;
@ -102,12 +69,7 @@ class LoadPostalCodesCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
try {
$csv = $this->getCSVResource($input); $csv = $this->getCSVResource($input);
} catch (\RuntimeException $e) {
$output->writeln('<error>Error during opening the csv file : '.
$e->getMessage().'</error>');
}
if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERY_VERBOSE) { if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERY_VERBOSE) {
$output->writeln('The content of the file is ...'); $output->writeln('The content of the file is ...');

View File

@ -1,20 +1,12 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Controller; namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController; use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Pagination\PaginatorFactory;
/**
*
*
*/
class AdminCountryCRUDController extends CRUDController class AdminCountryCRUDController extends CRUDController
{ {
function __construct(PaginatorFactory $paginator)
{
$this->paginatorFactory = $paginator;
}
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Controller; namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\AbstractCRUDController; use Chill\MainBundle\CRUD\Controller\AbstractCRUDController;
@ -7,6 +9,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface; use Chill\MainBundle\Pagination\PaginatorInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -16,40 +19,23 @@ use Chill\MainBundle\Form\UserType;
use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Form\Type\ComposedGroupCenterType; use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
use Chill\MainBundle\Form\UserPasswordType; use Chill\MainBundle\Form\UserPasswordType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter; use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
/**
* Class UserController
*
* @package Chill\MainBundle\Controller
*/
class UserController extends CRUDController class UserController extends CRUDController
{ {
const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter'; const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
/** private LoggerInterface $logger;
* @var \Psr\Log\LoggerInterface
*/
private $logger;
/** private ValidatorInterface $validator;
* @var ValidatorInterface
*/
private $validator;
private UserPasswordEncoderInterface $passwordEncoder; private UserPasswordEncoderInterface $passwordEncoder;
/**
* UserController constructor.
*
* @param LoggerInterface $logger
* @param ValidatorInterface $validator
*/
public function __construct( public function __construct(
LoggerInterface $chillLogger, LoggerInterface $chillLogger,
ValidatorInterface $validator, ValidatorInterface $validator,
@ -121,7 +107,7 @@ class UserController extends CRUDController
*/ */
public function editPasswordAction(User $user, Request $request) public function editPasswordAction(User $user, Request $request)
{ {
$editForm = $this->createEditPasswordForm($user, $request); $editForm = $this->createEditPasswordForm($user);
$editForm->handleRequest($request); $editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) { if ($editForm->isSubmitted() && $editForm->isValid()) {
@ -150,20 +136,17 @@ class UserController extends CRUDController
]); ]);
} }
/** private function createEditPasswordForm(User $user): FormInterface
*
*
* @param User $user
* @return \Symfony\Component\Form\Form
*/
private function createEditPasswordForm(User $user)
{ {
return $this->createForm(UserPasswordType::class, null, array( return $this->createForm(
UserPasswordType::class,
null,
[
'user' => $user 'user' => $user
)) ]
)
->add('submit', SubmitType::class, array('label' => 'Change password')) ->add('submit', SubmitType::class, array('label' => 'Change password'))
->remove('actual_password') ->remove('actual_password');
;
} }
/** /**
@ -208,7 +191,7 @@ class UserController extends CRUDController
* @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter", * @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter",
* name="admin_user_add_groupcenter") * name="admin_user_add_groupcenter")
*/ */
public function addLinkGroupCenterAction(Request $request, $uid): RedirectResponse public function addLinkGroupCenterAction(Request $request, $uid): Response
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
@ -238,23 +221,22 @@ class UserController extends CRUDController
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', return $this->redirect($this->generateUrl('chill_crud_admin_user_edit',
\array_merge(['id' => $uid], $returnPathParams))); \array_merge(['id' => $uid], $returnPathParams)));
} else { }
foreach($this->validator->validate($user) as $error)
foreach($this->validator->validate($user) as $error) {
$this->addFlash('error', $error->getMessage()); $this->addFlash('error', $error->getMessage());
} }
} }
return $this->render('@ChillMain/User/edit.html.twig', array( return $this->render('@ChillMain/User/edit.html.twig', [
'entity' => $user, 'entity' => $user,
'edit_form' => $this->createEditForm($user)->createView(), 'edit_form' => $this->createEditForm($user)->createView(),
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(), 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(),
'delete_groupcenter_form' => array_map( 'delete_groupcenter_form' => array_map(
function(\Symfony\Component\Form\Form $form) { static fn(Form $form) => $form->createView(),
return $form->createView(); iterator_to_array($this->getDeleteLinkGroupCenterByUser($user, $request), true)
)
}, ]);
iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true))
));
} }
private function getPersistedGroupCenter(GroupCenter $groupCenter) private function getPersistedGroupCenter(GroupCenter $groupCenter)
@ -279,10 +261,8 @@ class UserController extends CRUDController
* Creates a form to delete a link to a GroupCenter * Creates a form to delete a link to a GroupCenter
* *
* @param mixed $permissionsGroup The entity id * @param mixed $permissionsGroup The entity id
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request) private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface
{ {
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
@ -291,17 +271,13 @@ class UserController extends CRUDController
array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()]))) array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()])))
->setMethod('DELETE') ->setMethod('DELETE')
->add('submit', SubmitType::class, array('label' => 'Delete')) ->add('submit', SubmitType::class, array('label' => 'Delete'))
->getForm() ->getForm();
;
} }
/** /**
* create a form to add a link to a groupcenter * Create a form to add a link to a groupcenter.
*
* @param User $user
* @return \Symfony\Component\Form\Form
*/ */
private function createAddLinkGroupCenterForm(User $user, Request $request) private function createAddLinkGroupCenterForm(User $user, Request $request): FormInterface
{ {
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
@ -311,19 +287,13 @@ class UserController extends CRUDController
->setMethod('POST') ->setMethod('POST')
->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class) ->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class)
->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter')) ->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter'))
->getForm() ->getForm();
;
} }
/**
*
* @param User $user
*/
private function getDeleteLinkGroupCenterByUser(User $user, Request $request) private function getDeleteLinkGroupCenterByUser(User $user, Request $request)
{ {
foreach ($user->getGroupCenters() as $groupCenter) { foreach ($user->getGroupCenters() as $groupCenter) {
yield $groupCenter->getId() => $this yield $groupCenter->getId() => $this->createDeleteLinkGroupCenterForm($user, $groupCenter, $request);
->createDeleteLinkGroupCenterForm($user, $groupCenter, $request);
} }
} }
} }

View File

@ -63,12 +63,13 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
} }
/** /**
* prepare names for languages * Prepare names for languages.
* *
* @param string $languageCode
* @return string[] languages name indexed by available language code * @return string[] languages name indexed by available language code
*/ */
private function prepareName($languageCode) { private function prepareName(string $languageCode): array {
$names = [];
foreach ($this->container->getParameter('chill_main.available_languages') as $lang) { foreach ($this->container->getParameter('chill_main.available_languages') as $lang) {
$names[$lang] = Intl::getLanguageBundle()->getLanguageName($languageCode); $names[$lang] = Intl::getLanguageBundle()->getLanguageName($languageCode);
} }

View File

@ -1,18 +1,15 @@
<?php <?php
/*
*/ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection\CompilerPass; namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\Form\PermissionsGroupType; use Chill\MainBundle\Form\PermissionsGroupType;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use LogicException;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ACLFlagsCompilerPass implements CompilerPassInterface class ACLFlagsCompilerPass implements CompilerPassInterface
{ {
public function process(ContainerBuilder $container) public function process(ContainerBuilder $container)
@ -29,7 +26,7 @@ class ACLFlagsCompilerPass implements CompilerPassInterface
$permissionGroupType->addMethodCall('addFlagProvider', [ $reference ]); $permissionGroupType->addMethodCall('addFlagProvider', [ $reference ]);
break; break;
default: default:
throw new \LogicalException(sprintf( throw new LogicException(sprintf(
"This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id) "This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id)
); );
} }

View File

@ -19,14 +19,11 @@ class Configuration implements ConfigurationInterface
use AddWidgetConfigurationTrait; use AddWidgetConfigurationTrait;
/** private ContainerBuilder $containerBuilder;
*
* @var ContainerBuilder
*/
private $containerBuilder;
public function __construct(array $widgetFactories = array(), public function __construct(
array $widgetFactories,
ContainerBuilder $containerBuilder) ContainerBuilder $containerBuilder)
{ {
$this->setWidgetFactories($widgetFactories); $this->setWidgetFactories($widgetFactories);
@ -107,6 +104,9 @@ class Configuration implements ConfigurationInterface
->booleanNode('form_show_scopes') ->booleanNode('form_show_scopes')
->defaultTrue() ->defaultTrue()
->end() ->end()
->booleanNode('form_show_centers')
->defaultTrue()
->end()
->end() ->end()
->end() ->end()
->arrayNode('redis') ->arrayNode('redis')

View File

@ -124,11 +124,12 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
* @param string $containerWidgetConfigParameterName the key under which we can use the widget configuration * @param string $containerWidgetConfigParameterName the key under which we can use the widget configuration
* @throws \LogicException * @throws \LogicException
* @throws \UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface * @throws \UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface
* @throws \InvalidConfigurationException if there are errors in the config
*/ */
public function doProcess(ContainerBuilder $container, $extension, public function doProcess(
$containerWidgetConfigParameterName) ContainerBuilder $container,
{ $extension,
$containerWidgetConfigParameterName
) {
if (!$container->hasDefinition(self::WIDGET_MANAGER)) { if (!$container->hasDefinition(self::WIDGET_MANAGER)) {
throw new \LogicException("the service ".self::WIDGET_MANAGER." should". throw new \LogicException("the service ".self::WIDGET_MANAGER." should".
" be present. It is required by ".self::class); " be present. It is required by ".self::class);
@ -171,7 +172,7 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
// check that the widget is allowed at this place // check that the widget is allowed at this place
if (!$this->isPlaceAllowedForWidget($place, $alias, $container)) { if (!$this->isPlaceAllowedForWidget($place, $alias, $container)) {
throw new \InvalidConfigurationException(sprintf( throw new InvalidConfigurationException(sprintf(
"The widget with alias %s is not allowed at place %s", "The widget with alias %s is not allowed at place %s",
$alias, $alias,
$place $place

View File

@ -1,32 +1,19 @@
<?php <?php
/*
* Chill is a software for social workers declare(strict_types=1);
* Copyright (C) 2018 Champs-Libres Coopérative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Doctrine\DQL; namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
/** /**
* DQL function for OVERLAPS function in postgresql * DQL function for OVERLAPS function in postgresql
* *
* If a value is null in period start, it will be replaced by -infinity. * If a value is null in period start, it will be replaced by -infinity.
* If a value is null in period end, it will be replaced by infinity * If a value is null in period end, it will be replaced by infinity
*
*/ */
class OverlapsI extends FunctionNode class OverlapsI extends FunctionNode
{ {
@ -40,19 +27,17 @@ class OverlapsI extends FunctionNode
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{ {
return '(' return sprintf(
.$this->makeCase($sqlWalker, $this->firstPeriodStart, 'start').', ' '(%s, %s) OVERLAPS (%s, %s)',
.$this->makeCase($sqlWalker, $this->firstPeriodEnd, 'end'). $this->makeCase($sqlWalker, $this->firstPeriodStart, 'start'),
') OVERLAPS (' $this->makeCase($sqlWalker, $this->firstPeriodEnd, 'end'),
.$this->makeCase($sqlWalker, $this->secondPeriodStart, 'start').', ' $this->makeCase($sqlWalker, $this->secondPeriodStart, 'start'),
.$this->makeCase($sqlWalker, $this->secondPeriodEnd, 'end').')' $this->makeCase($sqlWalker, $this->secondPeriodEnd, 'end')
; );
} }
protected function makeCase($sqlWalker, $part, $position) protected function makeCase($sqlWalker, $part, string $position): string
{ {
//return $part->dispatch($sqlWalker);
switch ($position) { switch ($position) {
case 'start' : case 'start' :
$p = '-infinity'; $p = '-infinity';
@ -60,28 +45,28 @@ class OverlapsI extends FunctionNode
case 'end': case 'end':
$p = 'infinity'; $p = 'infinity';
break; break;
default:
throw new \Exception('Unexpected position value.');
} }
if ($part instanceof \Doctrine\ORM\Query\AST\PathExpression) { if ($part instanceof PathExpression) {
return 'CASE WHEN ' return sprintf(
.' '.$part->dispatch($sqlWalker).' IS NOT NULL ' "CASE WHEN %s IS NOT NULL THEN %s ELSE '%s'::date END",
. 'THEN '. $part->dispatch($sqlWalker),
$part->dispatch($sqlWalker) $part->dispatch($sqlWalker),
. ' ELSE '. $p
"'".$p."'::date " );
. 'END';
} else {
return 'CASE WHEN '
.' '.$part->dispatch($sqlWalker).'::date IS NOT NULL '
. 'THEN '.
$part->dispatch($sqlWalker)
. '::date ELSE '.
"'".$p."'::date "
. 'END';
}
} }
public function parse(\Doctrine\ORM\Query\Parser $parser) return sprintf(
"CASE WHEN %s::date IS NOT NULL THEN %s::date ELSE '%s'::date END",
$part->dispatch($sqlWalker),
$part->dispatch($sqlWalker),
$p
);
}
public function parse(Parser $parser): void
{ {
$parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_IDENTIFIER);

View File

@ -4,13 +4,9 @@ namespace Chill\MainBundle\Doctrine\Model;
use \JsonSerializable; use \JsonSerializable;
/**
* Description of Point
*
*/
class Point implements JsonSerializable { class Point implements JsonSerializable {
private ?float $lat = null; private ?float $lat;
private ?float $lon = null; private ?float $lon;
public static string $SRID = '4326'; public static string $SRID = '4326';
private function __construct(?float $lon, ?float $lat) private function __construct(?float $lon, ?float $lat)
@ -22,6 +18,7 @@ class Point implements JsonSerializable {
public function toGeoJson(): string public function toGeoJson(): string
{ {
$array = $this->toArrayGeoJson(); $array = $this->toArrayGeoJson();
return \json_encode($array); return \json_encode($array);
} }
@ -33,60 +30,53 @@ class Point implements JsonSerializable {
public function toArrayGeoJson(): array public function toArrayGeoJson(): array
{ {
return [ return [
"type" => "Point", 'type' => 'Point',
"coordinates" => [ $this->lon, $this->lat ] 'coordinates' => [$this->lon, $this->lat],
]; ];
} }
/**
*
* @return string
*/
public function toWKT(): string public function toWKT(): string
{ {
return 'SRID='.self::$SRID.';POINT('.$this->lon.' '.$this->lat.')'; return sprintf("SRID=%s;POINT(%s %s)", self::$SRID, $this->lon, $this->lat);
} }
/** public static function fromGeoJson(string $geojson): self
*
* @param type $geojson
* @return Point
*/
public static function fromGeoJson(string $geojson): Point
{ {
$a = json_decode($geojson); $a = json_decode($geojson);
//check if the geojson string is correct
if (NULL === $a or !isset($a->type) or !isset($a->coordinates)){ if (null === $a) {
throw PointException::badJsonString($geojson); throw PointException::badJsonString($geojson);
} }
if ($a->type != 'Point'){ if (null === $a->type || null === $a->coordinates) {
throw PointException::badJsonString($geojson);
}
if ($a->type !== 'Point'){
throw PointException::badGeoType(); throw PointException::badGeoType();
} }
$lat = $a->coordinates[1]; [$lon, $lat] = $a->coordinates;
$lon = $a->coordinates[0];
return Point::fromLonLat($lon, $lat); return Point::fromLonLat($lon, $lat);
} }
public static function fromLonLat(float $lon, float $lat): Point public static function fromLonLat(float $lon, float $lat): self
{
if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90))
{ {
if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90)) {
return new Point($lon, $lat); return new Point($lon, $lat);
} else {
throw PointException::badCoordinates($lon, $lat);
}
} }
public static function fromArrayGeoJson(array $array): Point throw PointException::badCoordinates($lon, $lat);
{ }
if ($array['type'] == 'Point' &&
isset($array['coordinates'])) public static function fromArrayGeoJson(array $array): self
{ {
if ($array['type'] === 'Point' && isset($array['coordinates'])) {
return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]); return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]);
} }
throw new \Exception('Unable to build a point from input data.');
} }
public function getLat(): float public function getLat(): float

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\Type; namespace Chill\MainBundle\Doctrine\Type;
use Chill\MainBundle\Doctrine\Model\Point; use Chill\MainBundle\Doctrine\Model\Point;
@ -7,40 +9,32 @@ use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Chill\MainBundle\Doctrine\Model\PointException; use Chill\MainBundle\Doctrine\Model\PointException;
/** /**
* A Type for Doctrine to implement the Geography Point type * A Type for Doctrine to implement the Geography Point type
* implemented by Postgis on postgis+postgresql databases * implemented by Postgis on postgis+postgresql databases
*
*/ */
class PointType extends Type { class PointType extends Type
{
const POINT = 'point'; public const POINT = 'point';
/** /**
*
* @param array $fieldDeclaration
* @param AbstractPlatform $platform
* @return string * @return string
*/ */
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) public function getSQLDeclaration(array $column, AbstractPlatform $platform)
{ {
return 'geometry(POINT,'.Point::$SRID.')'; return 'geometry(POINT,'.Point::$SRID.')';
} }
/** /**
*
* @param type $value
* @param AbstractPlatform $platform
* @return ?Point * @return ?Point
*/ */
public function convertToPHPValue($value, AbstractPlatform $platform) public function convertToPHPValue($value, AbstractPlatform $platform)
{ {
if ($value === NULL){ if ($value === NULL){
return NULL; return NULL;
} else {
return Point::fromGeoJson($value);
} }
return Point::fromGeoJson($value);
} }
public function getName() public function getName()
@ -52,9 +46,9 @@ class PointType extends Type {
{ {
if ($value === NULL){ if ($value === NULL){
return NULL; return NULL;
} else {
return $value->toWKT();
} }
return $value->toWKT();
} }
public function canRequireSQLConversion() public function canRequireSQLConversion()

View File

@ -23,12 +23,11 @@ namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Annotation as Serializer;
/** /**
* @ORM\Entity * @ORM\Entity
* @ORM\Table(name="centers") * @ORM\Table(name="centers")
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class Center implements HasCenterInterface class Center implements HasCenterInterface
{ {
@ -46,8 +45,9 @@ class Center implements HasCenterInterface
* @var string * @var string
* *
* @ORM\Column(type="string", length=255) * @ORM\Column(type="string", length=255)
* @Serializer\Groups({"docgen:read"})
*/ */
private $name; private string $name = '';
/** /**
* @var Collection * @var Collection

View File

@ -1,22 +1,6 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Entity; namespace Chill\MainBundle\Entity;
@ -28,37 +12,29 @@ use Doctrine\Common\Collections\ArrayCollection;
* @ORM\Entity * @ORM\Entity
* @ORM\Table(name="role_scopes") * @ORM\Table(name="role_scopes")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class RoleScope class RoleScope
{ {
/** /**
* @var integer
*
* @ORM\Id * @ORM\Id
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private $id; private ?int $id = null;
/** /**
* @var string
*
* @ORM\Column(type="string", length=255) * @ORM\Column(type="string", length=255)
*/ */
private $role; private ?string $role = null;
/** /**
* @var Scope
*
* @ORM\ManyToOne( * @ORM\ManyToOne(
* targetEntity="Chill\MainBundle\Entity\Scope", * targetEntity="Chill\MainBundle\Entity\Scope",
* inversedBy="roleScopes") * inversedBy="roleScopes")
* @ORM\JoinColumn(nullable=true, name="scope_id") * @ORM\JoinColumn(nullable=true, name="scope_id")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE") * @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/ */
private $scope; private ?Scope $scope = null;
/** /**
* @var Collection * @var Collection
@ -69,55 +45,33 @@ class RoleScope
*/ */
private $permissionsGroups; private $permissionsGroups;
/**
* RoleScope constructor.
*/
public function __construct() { public function __construct() {
$this->new = true;
$this->permissionsGroups = new ArrayCollection(); $this->permissionsGroups = new ArrayCollection();
} }
/** public function getId(): ?int
* @return int
*/
public function getId()
{ {
return $this->id; return $this->id;
} }
/** public function getRole(): ?string
* @return string
*/
public function getRole()
{ {
return $this->role; return $this->role;
} }
/** public function getScope(): ?Scope
* @return Scope
*/
public function getScope()
{ {
return $this->scope; return $this->scope;
} }
/** public function setRole(?string $role = null): self
* @param type $role
* @return RoleScope
*/
public function setRole($role)
{ {
$this->role = $role; $this->role = $role;
return $this; return $this;
} }
/** public function setScope(?Scope $scope = null): self
* @param Scope $scope
* @return RoleScope
*/
public function setScope(Scope $scope = null)
{ {
$this->scope = $scope; $this->scope = $scope;

View File

@ -8,7 +8,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Entity\UserJob;
use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Serializer\Annotation as Serializer;
/** /**
* User * User
@ -16,7 +16,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
* @ORM\Entity * @ORM\Entity
* @ORM\Table(name="users") * @ORM\Table(name="users")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
* @DiscriminatorMap(typeProperty="type", mapping={ * @Serializer\DiscriminatorMap(typeProperty="type", mapping={
* "user"=User::class * "user"=User::class
* }) * })
*/ */
@ -51,6 +51,7 @@ class User implements AdvancedUserInterface {
/** /**
* @ORM\Column(type="string", length=200) * @ORM\Column(type="string", length=200)
* @Serializer\Groups({"docgen:read"})
*/ */
private string $label = ''; private string $label = '';
@ -58,8 +59,9 @@ class User implements AdvancedUserInterface {
* @var string * @var string
* *
* @ORM\Column(type="string", length=150, nullable=true) * @ORM\Column(type="string", length=150, nullable=true)
* @Serializer\Groups({"docgen:read"})
*/ */
private $email; private ?string $email = null;
/** /**
* @var string * @var string
@ -123,6 +125,7 @@ class User implements AdvancedUserInterface {
/** /**
* @var Center|null * @var Center|null
* @ORM\ManyToOne(targetEntity=Center::class) * @ORM\ManyToOne(targetEntity=Center::class)
* @Serializer\Groups({"docgen:read"})
*/ */
private ?Center $mainCenter = null; private ?Center $mainCenter = null;

View File

@ -1,48 +1,25 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Export\Formatter; namespace Chill\MainBundle\Export\Formatter;
use Chill\MainBundle\Export\ExportInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\ExportManager;
use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
// command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff
/** /**
* * Command to get the report with curl:
* * curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @deprecated this formatter is not used any more. * @deprecated this formatter is not used any more.
*/ */
class CSVFormatter implements FormatterInterface class CSVFormatter implements FormatterInterface
{ {
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
protected $result; protected $result;
@ -85,11 +62,7 @@ class CSVFormatter implements FormatterInterface
} }
/** /**
*
* @uses appendAggregatorForm * @uses appendAggregatorForm
* @param FormBuilderInterface $builder
* @param type $exportAlias
* @param array $aggregatorAliases
*/ */
public function buildForm(FormBuilderInterface $builder, $exportAlias, array $aggregatorAliases) public function buildForm(FormBuilderInterface $builder, $exportAlias, array $aggregatorAliases)
{ {
@ -172,31 +145,18 @@ class CSVFormatter implements FormatterInterface
* If two aggregators have the same order, the second given will be placed * If two aggregators have the same order, the second given will be placed
* after. This is not significant for the first ordering. * after. This is not significant for the first ordering.
* *
* @param type $formatterData
* @return type
*/ */
protected function orderingHeaders($formatterData) protected function orderingHeaders(array $formatterData)
{ {
$this->formatterData = $formatterData; $this->formatterData = $formatterData;
uasort($this->formatterData, function($a, $b) { uasort(
$this->formatterData,
return ($a['order'] <= $b['order'] ? -1 : 1); static fn(array $a, array $b): int => ($a['order'] <= $b['order'] ? -1 : 1)
}); );
} }
protected function generateContent() private function findColumnPosition(&$columnHeaders, $columnToFind): int
{ {
$rowKeysNb = count($this->getRowHeaders());
$columnKeysNb = count($this->getColumnHeaders());
$resultsKeysNb = count($this->export->getQueryKeys($this->exportData));
$results = $this->getOrderedResults();
/* @var $columnHeaders string[] the column headers associations */
$columnHeaders = array();
/* @var $data string[] the data of the csv file */
$contentData = array();
$content = array();
function findColumnPosition(&$columnHeaders, $columnToFind) {
$i = 0; $i = 0;
foreach($columnHeaders as $set) { foreach($columnHeaders as $set) {
if ($set === $columnToFind) { if ($set === $columnToFind) {
@ -211,6 +171,19 @@ class CSVFormatter implements FormatterInterface
return $i++; return $i++;
} }
protected function generateContent()
{
$line = null;
$rowKeysNb = count($this->getRowHeaders());
$columnKeysNb = count($this->getColumnHeaders());
$resultsKeysNb = count($this->export->getQueryKeys($this->exportData));
$results = $this->getOrderedResults();
/* @var $columnHeaders string[] the column headers associations */
$columnHeaders = array();
/* @var $data string[] the data of the csv file */
$contentData = array();
$content = array();
// create a file pointer connected to the output stream // create a file pointer connected to the output stream
$output = fopen('php://output', 'w'); $output = fopen('php://output', 'w');
@ -244,7 +217,7 @@ class CSVFormatter implements FormatterInterface
// add the column headers // add the column headers
/* @var $columns string[] the column for this row */ /* @var $columns string[] the column for this row */
$columns = array_slice($row, $rowKeysNb, $columnKeysNb); $columns = array_slice($row, $rowKeysNb, $columnKeysNb);
$columnPosition = findColumnPosition($columnHeaders, $columns); $columnPosition = $this->findColumnPosition($columnHeaders, $columns);
//fill with blank at the position given by the columnPosition + nbRowHeaders //fill with blank at the position given by the columnPosition + nbRowHeaders
for ($i=0; $i < $columnPosition; $i++) { for ($i=0; $i < $columnPosition; $i++) {

View File

@ -229,7 +229,7 @@ class SpreadSheetFormatter implements FormatterInterface
$this->getContentType($this->formatterData['format'])); $this->getContentType($this->formatterData['format']));
$this->tempfile = \tempnam(\sys_get_temp_dir(), ''); $this->tempfile = \tempnam(\sys_get_temp_dir(), '');
$this->generatecontent(); $this->generateContent();
$f = \fopen($this->tempfile, 'r'); $f = \fopen($this->tempfile, 'r');
$response->setContent(\stream_get_contents($f)); $response->setContent(\stream_get_contents($f));

View File

@ -51,8 +51,10 @@ class CenterTransformer implements DataTransformerInterface
} }
} }
$ids = [];
if ($this->multiple) { if ($this->multiple) {
$ids = \explode(',', $id); $ids = explode(',', $id);
} else { } else {
$ids[] = (int) $id; $ids[] = (int) $id;
} }
@ -68,9 +70,9 @@ class CenterTransformer implements DataTransformerInterface
if ($this->multiple) { if ($this->multiple) {
return new ArrayCollection($centers); return new ArrayCollection($centers);
} else {
return $centers[0];
} }
return $centers[0];
} }
public function transform($center) public function transform($center)

View File

@ -1,38 +1,15 @@
<?php <?php
/*
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop> declare(strict_types=1);
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Form\Type\DataTransformer; namespace Chill\MainBundle\Form\Type\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\UnexpectedTypeException;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class DateIntervalTransformer implements DataTransformerInterface class DateIntervalTransformer implements DataTransformerInterface
{ {
/**
*
* @param \DateInterval $value
* @throws UnexpectedTypeException
*/
public function transform($value) public function transform($value)
{ {
if (empty($value)) { if (empty($value)) {
@ -50,31 +27,36 @@ class DateIntervalTransformer implements DataTransformerInterface
'n' => $value->d / 7, 'n' => $value->d / 7,
'unit' => 'W' 'unit' => 'W'
]; ];
} else { }
return [ return [
'n' => $value->d, 'n' => $value->d,
'unit' => 'D' 'unit' => 'D'
]; ];
} }
} elseif ($value->m > 0) {
if ($value->m > 0) {
return [ return [
'n' => $value->m, 'n' => $value->m,
'unit' => 'M' 'unit' => 'M'
]; ];
} elseif ($value->y > 0) { }
if ($value->y > 0) {
return [ return [
'n' => $value->y, 'n' => $value->y,
'unit' => 'Y' 'unit' => 'Y'
]; ];
} }
throw new TransformationFailedException('the date interval does not ' throw new TransformationFailedException(
. 'contains any days, months or years'); 'The date interval does not contains any days, months or years.'
);
} }
public function reverseTransform($value) public function reverseTransform($value)
{ {
if (empty($value) or empty($value['n'])) { if (empty($value) || empty($value['n'])) {
return null; return null;
} }
@ -83,10 +65,11 @@ class DateIntervalTransformer implements DataTransformerInterface
try { try {
return new \DateInterval($string); return new \DateInterval($string);
} catch (\Exception $e) { } catch (\Exception $e) {
throw new TransformationFailedException("Could not transform value " throw new TransformationFailedException(
. "into DateInterval", 1542, $e); 'Could not transform value into DateInterval',
} 1542,
$e
);
}
} }
} }

View File

@ -1,44 +1,17 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
* Copyright (C) 2016 Champs-Libres Coopérative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Pagination; namespace Chill\MainBundle\Pagination;
/** /**
* PageGenerator associated with a Paginator * PageGenerator associated with a Paginator.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/ */
class PageGenerator implements \Iterator class PageGenerator implements \Iterator
{ {
/** protected Paginator $paginator;
*
* @var Paginator
*/
protected $paginator;
/** protected int $current = 1;
*
* @var int
*/
protected $current = 1;
public function __construct(Paginator $paginator) public function __construct(Paginator $paginator)
{ {

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Repository; namespace Chill\MainBundle\Repository;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;

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