diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 55c68972e..221de2e5d 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -35,6 +35,7 @@ use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\CallbackTransformer; use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; use Chill\PersonBundle\Templating\Entity\SocialIssueRender; +use Chill\PersonBundle\Templating\Entity\SocialActionRender; class ActivityType extends AbstractType { @@ -46,6 +47,10 @@ class ActivityType extends AbstractType protected TranslatableStringHelper $translatableStringHelper; + protected SocialIssueRender $socialIssueRender; + + protected SocialActionRender $socialActionRender; + protected array $timeChoices; public function __construct ( @@ -54,7 +59,8 @@ class ActivityType extends AbstractType ObjectManager $om, TranslatableStringHelper $translatableStringHelper, array $timeChoices, - SocialIssueRender $socialIssueRender + SocialIssueRender $socialIssueRender, + SocialActionRender $socialActionRender ) { if (!$tokenStorage->getToken()->getUser() instanceof User) { throw new \RuntimeException("you should have a valid user"); @@ -66,6 +72,7 @@ class ActivityType extends AbstractType $this->translatableStringHelper = $translatableStringHelper; $this->timeChoices = $timeChoices; $this->socialIssueRender = $socialIssueRender; + $this->socialActionRender = $socialActionRender; } public function buildForm(FormBuilderInterface $builder, array $options): void @@ -133,7 +140,7 @@ class ActivityType extends AbstractType 'required' => $activityType->isRequired('socialActions'), 'class' => SocialAction::class, 'choice_label' => function (SocialAction $socialAction) { - return $this->translatableStringHelper->localize($socialAction->getTitle()); + return $this->socialActionRender->renderString($socialAction, []); }, 'multiple' => true, 'choices' => $accompanyingPeriod->getRecursiveSocialActions(), diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index 3da20cce5..fd034b2da 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -32,6 +32,7 @@ services: - "@chill.main.helper.translatable_string" - "%chill_activity.form.time_duration%" - '@Chill\PersonBundle\Templating\Entity\SocialIssueRender' + - '@Chill\PersonBundle\Templating\Entity\SocialActionRender' tags: - { name: form.type, alias: chill_activitybundle_activity } diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index dc2894499..3f3f8ff45 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -38,7 +38,7 @@ Required: Obligatoire Persons: Personnes Users: Utilisateurs Emergency: Urgent -Sent received: Envoyer / Recevoir +Sent received: Entrant / Sortant Sent: Envoyer Received: Recevoir by: 'Par ' diff --git a/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php b/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php index d8a46837c..11b3c34fd 100644 --- a/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php +++ b/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php @@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Reference; use Chill\MainBundle\Routing\MenuComposer; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Alias; /** * @@ -49,29 +50,32 @@ class CRUDControllerCompilerPass implements CompilerPassInterface private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void { $controllerClass = $crudEntry['controller']; - $controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller'; - if ($container->hasDefinition($controllerClass)) { - $controller = $container->getDefinition($controllerClass); - $container->removeDefinition($controllerClass); - $alreadyDefined = true; - } else { - $controller = new Definition($controllerClass); - $alreadyDefined = false; - } - - $controller->addTag('controller.service_arguments'); - if (FALSE === $alreadyDefined) { - $controller->setAutoconfigured(true); - $controller->setPublic(true); - } - + // create config parameter in container $param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name']; $container->setParameter($param, $crudEntry); - $controller->addMethodCall('setCrudConfig', ['%'.$param.'%']); - $container->setDefinition($controllerServiceName, $controller); + if ($container->hasDefinition($controllerClass)) { + // create an alias to not to re-create the service + $alias = new Alias($controllerClass, true); + $container->setAlias($controllerServiceName, $alias); + + // add the "addMethodCall" + $container->getDefinition($controllerClass) + ->addMethodCall('setCrudConfig', ['%'.$param.'%']); + + } else { + $controller = new Definition($controllerClass); + + $controller->addTag('controller.service_arguments'); + $controller->setAutoconfigured(true); + $controller->setPublic(true); + + $controller->addMethodCall('setCrudConfig', ['%'.$param.'%']); + + $container->setDefinition($controllerServiceName, $controller); + } } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php index 71476fb78..a1d28483d 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -8,6 +8,11 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Validator\ValidatorInterface; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\CRUD\Resolver\Resolver; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Translation\TranslatorInterface; class AbstractCRUDController extends AbstractController { @@ -248,4 +253,24 @@ class AbstractCRUDController extends AbstractController { return $this->get('validator'); } + + /** + * @return array + */ + public static function getSubscribedServices(): array + { + return \array_merge( + parent::getSubscribedServices(), + [ + 'chill_main.paginator_factory' => PaginatorFactory::class, + + 'translator' => TranslatorInterface::class, + AuthorizationHelper::class => AuthorizationHelper::class, + EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, + SerializerInterface::class => SerializerInterface::class, + 'validator' => ValidatorInterface::class, + ] + ); + } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php index 9686a7b98..cab0bcdcb 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php @@ -359,9 +359,10 @@ class ApiController extends AbstractCRUDController * 6. validate the base entity (not the deserialized one). Groups are fetched from getValidationGroups, validation is perform by `validate` * 7. run onAfterValidation * 8. if errors, return a 422 response with errors - * 9. flush the data - * 10. run onAfterFlush - * 11. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity + * 9. if $forcePersist === true, persist the entity + * 10. flush the data + * 11. run onAfterFlush + * 12. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity * * @param string action * @param mixed id @@ -370,11 +371,12 @@ class ApiController extends AbstractCRUDController * @param string $property the name of the property. This will be used to make a `add+$property` and `remove+$property` method * @param string $postedDataType the type of the posted data (the content) * @param string $postedDataContext a context to deserialize posted data (the content) + * @param bool $forcePersist force to persist the created element (only for POST request) * @throw BadRequestException if unable to deserialize the posted data * @throw BadRequestException if the method is not POST or DELETE * */ - protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, $postedDataContext = []): Response + protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, array $postedDataContext = [], bool $forcePersist = false): Response { $entity = $this->getEntity($action, $id, $request); @@ -429,6 +431,10 @@ class ApiController extends AbstractCRUDController return $this->json($errors, 422); } + if ($forcePersist && $request->getMethod() === Request::METHOD_POST) { + $this->getDoctrine()->getManager()->persist($postedData); + } + $this->getDoctrine()->getManager()->flush(); diff --git a/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php b/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php index 9d61d6233..36aadb8b7 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php +++ b/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php @@ -142,11 +142,11 @@ class CRUDRoutesLoader extends Loader protected function loadApi(array $crudConfig): RouteCollection { $collection = new RouteCollection(); - $controller ='csapi_'.$crudConfig['name'].'_controller'; + $controller = 'csapi_'.$crudConfig['name'].'_controller'; foreach ($crudConfig['actions'] as $name => $action) { // filter only on single actions - $singleCollection = $action['single-collection'] ?? $name === '_entity' ? 'single' : NULL; + $singleCollection = $action['single_collection'] ?? $name === '_entity' ? 'single' : NULL; if ('collection' === $singleCollection) { // continue; } @@ -171,7 +171,7 @@ class CRUDRoutesLoader extends Loader // path are rewritten // if name === 'default', we rewrite it to nothing :-) $localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name; - if ('collection' === $action['single-collection'] || '_index' === $name) { + if ('collection' === $action['single_collection'] || '_index' === $name) { $localPath = $action['path'] ?? $localName.'.{_format}'; } else { $localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}'; diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index 4c90aaabb..c711f911f 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -205,7 +205,7 @@ class Configuration implements ConfigurationInterface ->ignoreExtraKeys(false) ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.') ->end() - ->enumNode('single-collection') + ->enumNode('single_collection') ->values(['single', 'collection']) ->defaultValue('single') ->info('indicates if the returned object is a single element or a collection. '. diff --git a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php index a6e664769..2e9a19717 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php @@ -51,7 +51,7 @@ class CommentType extends AbstractType $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getForm()->getData(); - $comment = $event->getData(); + $comment = $event->getData() ?? ['comment' => '']; if ($data->getComment() !== $comment['comment']) { $data->setDate(new \DateTime()); diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/date.js b/src/Bundle/ChillMainBundle/Resources/public/js/date.js index 7b9bf88a2..ec66da770 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/date.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/date.js @@ -11,13 +11,16 @@ * * Do not take time into account * - * **Experimental** */ const dateToISO = (date) => { + if (null === date) { + return null; + } + return [ - this.$store.state.startDate.getFullYear(), - (this.$store.state.startDate.getMonth() + 1).toString().padStart(2, '0'), - this.$store.state.startDate.getDate().toString().padStart(2, '0') + date.getFullYear(), + (date.getMonth() + 1).toString().padStart(2, '0'), + date.getDate().toString().padStart(2, '0') ].join('-'); }; @@ -36,15 +39,17 @@ const ISOToDate = (str) => { /** * Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00 * - * **Experimental** */ const ISOToDatetime = (str) => { - console.log(str); + if (null === str) { + return null; + } + let [cal, times] = str.split('T'), [year, month, date] = cal.split('-'), - [time, timezone] = cal.split(times.charAt(9)), - [hours, minutes, seconds] = cal.split(':') + [time, timezone] = times.split(times.charAt(8)), + [hours, minutes, seconds] = time.split(':') ; return new Date(year, month-1, date, hours, minutes, seconds); diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/App.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/App.vue index c0d3271ef..438e94892 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/App.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/App.vue @@ -26,6 +26,12 @@
{{ errors }}
+
+ {{ $t('loading') }} +
+
+ {{ $t('person_address_creation_success') }} +
@@ -68,6 +74,12 @@ export default { }, errors() { return this.$store.state.errorMsg; + }, + loading() { + return this.$store.state.loading; + }, + success() { + return this.$store.state.success; } }, methods: { diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/js/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/js/i18n.js index b6f483894..d0e43266a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/js/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/js/i18n.js @@ -26,7 +26,9 @@ const addressMessages = { date: 'Date de la nouvelle adresse', add_an_address_to_person: 'Ajouter l\'adresse à la personne', validFrom: 'Date de la nouvelle adresse', - back_to_the_list: 'Retour à la liste' + back_to_the_list: 'Retour à la liste', + person_address_creation_success: 'La nouvelle adresse de la personne est enregistrée', + loading: 'chargement en cours...' } }; diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/store/index.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/store/index.js index acbf4dcbb..9db2a7298 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/store/index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/store/index.js @@ -11,7 +11,9 @@ const store = createStore({ address: {}, editAddress: {}, //TODO or should be address? person: {}, - errorMsg: [] + errorMsg: [], + loading: false, + success: false }, getters: { }, @@ -39,11 +41,17 @@ const store = createStore({ console.log('@M getEditAddress address', address); state.editAddress = address; }, + setLoading(state, b) { + state.loading = b; + }, + setSuccess(state, b) { + state.success = b; + } }, actions: { addAddress({ commit }, payload) { console.log('@A addAddress payload', payload); - + commit('setLoading', true); if('newPostalCode' in payload){ let postalCodeBody = payload.newPostalCode; postalCodeBody = Object.assign(postalCodeBody, {'origin': 3}); @@ -55,9 +63,11 @@ const store = createStore({ .then(address => new Promise((resolve, reject) => { commit('addAddress', address); resolve(); + commit('setLoading', false); })) .catch((error) => { commit('catchError', error); + commit('setLoading', false); }); }) @@ -66,15 +76,17 @@ const store = createStore({ .then(address => new Promise((resolve, reject) => { commit('addAddress', address); resolve(); + commit('setLoading', false); })) .catch((error) => { commit('catchError', error); + commit('setLoading', false); }); } }, addDateToAddressAndAddressToPerson({ commit }, payload) { console.log('@A addDateToAddressAndAddressToPerson payload', payload); - + commit('setLoading', true); patchAddress(payload.addressId, payload.body) .then(address => new Promise((resolve, reject) => { commit('addDateToAddress', address.validFrom); @@ -84,13 +96,17 @@ const store = createStore({ .then(person => new Promise((resolve, reject) => { commit('addAddressToPerson', person); resolve(); + commit('setLoading', false); + commit('setSuccess', true); })) .catch((error) => { commit('catchError', error); + commit('setLoading', false); }) )) .catch((error) => { commit('catchError', error); + commit('setLoading', false); }); }, updateAddress({ commit }, payload) { diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddAddress.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddAddress.vue index 3417a2d0d..e8bb3700b 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddAddress.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/AddAddress.vue @@ -19,6 +19,10 @@