Compare commits

..

965 Commits

Author SHA1 Message Date
Marc Ducobu
8c635c24af Fix test error when no periods 2021-07-23 12:11:58 +02:00
Marc Ducobu
9d478c0f01 Removing var_dump 2021-07-23 10:18:41 +02:00
Marc Ducobu
4646795c2c Automatic styling correction 2021-07-23 10:18:04 +02:00
Marc Ducobu
18369a6c0a Merge branch 'notifications3' into 'master'
Notifications3

See merge request Chill-Projet/chill-bundles!89
2021-07-22 17:44:37 +00:00
Marc Ducobu
0fd9485de5 Avoid creation of services/notification.yaml 2021-07-22 18:15:57 +02:00
c8f139528a Merge branch 'behaviour/do-not-create-accompanying-course-on-person-creation' into 'master'
Remove creation of AccompanyingPeriod on person creation

See merge request Chill-Projet/chill-bundles!100
2021-07-22 15:36:37 +00:00
8030792eb6 Remove creation of AccompanyingPeriod on person creation 2021-07-22 15:36:36 +00:00
Marc Ducobu
50a4df3d0f Notification with paginitation 2021-07-22 17:32:20 +02:00
Marc Ducobu
0907ae1602 Rmq Julien & Pol 2021-07-22 17:32:20 +02:00
Marc Ducobu
673a4761e9 Adding feature for AccompanyingPeriodNotif 2021-07-22 17:32:20 +02:00
Marc Ducobu
282db51f06 Display notification using services (draft) 2021-07-22 17:32:20 +02:00
Marc Ducobu
bdf691a063 Add findAllForAttendee method in NotificationRepository 2021-07-22 17:32:20 +02:00
Marc Ducobu
18ab10dd45 Add center a_social to an activityNotif feature 2021-07-22 17:32:20 +02:00
65198937c0 Merge branch 'tests/fix-tests-after-bootstrap' into 'master'
Fix tests after introduction of bootstrap

See merge request Chill-Projet/chill-bundles!111
2021-07-22 15:20:45 +00:00
2699d48533 Fix tests after introduction of bootstrap 2021-07-22 15:20:45 +00:00
08e396195c Merge branch 'vue_generale' into bootstrap5_replacing_scratch 2021-07-15 15:27:04 +02:00
ab0863a275 new setting margins and breakpoints for person banner 2021-07-15 15:21:33 +02:00
82c79a17dd many corrections in twig templates 2021-07-14 21:01:46 +02:00
d35553a1e2 content bloc: fix margins and breakpoints 2021-07-14 18:16:33 +02:00
030e71d276 activity, content position 2021-07-14 15:51:07 +02:00
4fc3d813c4 bootstrap adapt for activity vue socialIssues component 2021-07-14 15:24:17 +02:00
5f012165d1 fix spinner in addAddresss 2021-07-14 15:23:42 +02:00
61bd5d8ae8 fix spinner in addAddresss 2021-07-14 15:21:38 +02:00
07c464c112 rename vue subfolder _components in components 2021-07-14 14:50:39 +02:00
70a4c34865 move vue AddAddress inside Address component 2021-07-14 14:46:44 +02:00
5a47ebed42 Merge branch 'fix_addresses_issues' into bootstrap5_replacing_scratch 2021-07-14 14:01:08 +02:00
80eb5519bc adapt AddAddress modal to bootstrap: position, responsive, form 2021-07-14 13:36:49 +02:00
50f3ec9064 adapt vue modals styles to bootstrap 2021-07-13 15:35:48 +02:00
bdf0ec63d2 person templates responsive breakpoints in content 2021-07-13 14:07:23 +02:00
15f439b43d divers styles: colors var, table thead,... 2021-07-13 14:07:23 +02:00
30af99f4f0 fix chill theme colors behaviours: chill classes, special buttons variants 2021-07-13 14:07:23 +02:00
c413166866 batch replace .bt- in task scss 2021-07-13 14:07:23 +02:00
3c4c5e29a3 remove ChillMainSass webpack alias (scratch reference) 2021-07-13 14:07:23 +02:00
0224224744 bootstrap tables in vue_accourse 2021-07-13 14:07:23 +02:00
a9a59895b4 rename vue_ entrypoints in webpack 2021-07-13 14:07:23 +02:00
8a859f7885 add margin-top in content (uniformize contexts) 2021-07-13 14:07:23 +02:00
2244c58ec2 better logic: move person layout template in views/Person folder
like others contexts :
* accompanyingCourse
* household
2021-07-13 14:05:36 +02:00
c1ede921ff better twig extends path syntax 2021-07-12 10:32:48 +02:00
17ff80c39c accompanyingCourse, household and person use uniq menu template 2021-07-12 10:23:23 +02:00
f4f747d8d1 put person banner in included file 2021-07-12 10:21:08 +02:00
a740ad29ea replace sc-button + bt- in js and php files 2021-07-08 15:56:00 +02:00
ccee105efb batch replace grid- (scratch) by col- (bootstrap)
hand replace
* push- by offset-
* no-gutter by g-0

add breakpoints md- and sm-
2021-07-08 15:44:32 +02:00
b10012f4da minor swing 2021-07-08 15:03:59 +02:00
4937fd00fc fix form label display inline (with bootstrap5 theme) 2021-07-08 15:03:00 +02:00
0b329a9c9b modify lightly bootstrap5 form theme 2021-07-08 14:52:46 +02:00
4cfc43aaa6 rename collection html classes 2021-07-08 14:49:53 +02:00
1c45770929 wip 2021-07-08 12:27:50 +02:00
198c815052 add classes to person_addresses template 2021-07-08 12:00:59 +02:00
a995adcf0d remove debug discret class 2021-07-08 12:00:07 +02:00
bccda15307 cleaning record_actions scss 2021-07-08 11:59:27 +02:00
75c3df50e0 disable scratch webpack compilation 2021-07-08 11:58:22 +02:00
ce8207ea65 adapt person details page with bootstrap grid 2021-07-08 11:38:19 +02:00
0f6ad3670a add flashbag twig display condition + improve class consistency (main_search) 2021-07-08 11:12:31 +02:00
02a752f20b repair commit "load banner accompanying course everywhere" 2021-07-08 10:20:17 +02:00
1bbce2bb81 person details page: one edit button at bottom of page, fix regression 2021-07-07 19:38:29 +02:00
ca43933163 Merge branch 'fix-vue-warnings' into bootstrap5_replacing_scratch 2021-07-07 19:27:40 +02:00
1392365257 fix most of vue warnings for accompanyingCourse component 2021-07-07 19:27:22 +02:00
3653d7e0b8 fix missing dom selector in stickynav vue 2021-07-07 18:58:11 +02:00
3970bb2644 badge settings in banners 2021-07-07 18:31:05 +02:00
9a1272d350 enabling symfony twig form_theme for bootstrap5
bootstrap5 templates are not supported in symfony 4
see twig.yaml comment and configuration while waiting to upgrade !!
2021-07-07 12:32:40 +02:00
36419cf5f0 fix button colors 2021-07-06 14:17:39 +02:00
c96f407e6a Merge branch 'bootstrap5_replacing_scratch_mat' into bootstrap5_replacing_scratch 2021-07-06 13:50:17 +02:00
690688f5e1 fix buttons classes 2021-07-06 13:49:12 +02:00
4668f657ab button correction if only icon, not text 2021-07-06 13:34:47 +02:00
49253abfb8 custom _record_actions styles 2021-07-06 12:21:52 +02:00
c2122d62c6 button cancel, set icon with before 2021-07-06 12:10:37 +02:00
ca17ca4984 adding forkawesome ::before content unicode 2021-07-06 11:06:32 +02:00
a5d749b882 batch replace sc-button by btn btn-... 2021-07-05 21:55:24 +02:00
53c021b06e Merge branch 'quickfix' into bootstrap5_replacing_scratch_mat 2021-07-05 21:25:33 +02:00
b6e8c64211 fix bootstrap5 + vue modal content scrollable overflow 2021-07-05 21:23:55 +02:00
342fd3e297 batch rename sc-button cancel 2021-07-05 21:22:05 +02:00
05a1f7d041 batch rename class sc-button (scratch) by btn (bootstrap) 2021-07-05 19:02:09 +02:00
2e2eeae4f2 chill colors and buttons with bootstrap5 2021-07-05 18:53:03 +02:00
nobohan
842dfcc69f address: edit household addresses 2021-07-05 17:23:37 +02:00
nobohan
67c31e781d address: back to the page when the address is filled 2021-07-05 15:07:21 +02:00
f32ffc572d badge-pill classes changed to rounded-pill 2021-07-05 12:37:16 +02:00
a44b26da6c badge classes updated from badge-... to bg-... 2021-07-05 12:29:52 +02:00
d016f9be86 fix bootstrap5 + vue modal content scrollable overflow 2021-07-04 14:26:00 +02:00
c36aa22ab2 arrange collapsed header menu 2021-07-03 20:57:28 +02:00
e77c886e3f banner and vertical-menu integration 2021-07-03 17:56:07 +02:00
4ca1618480 bt5, main layout, responsive header 2021-07-03 14:03:30 +02:00
8e8cdfce0a bootstrap5, main layout settings 2021-07-02 18:42:26 +02:00
3694eb5bf2 fix bootstrap import duplicate 2021-07-01 18:49:15 +02:00
e44342ab87 bootstrap5: report variables v4+chill changes in variables v5
--- indigo, purple, teal, cyan
+++ green-dark, beige
2021-07-01 18:25:38 +02:00
a236873919 bootstrap5: swap variables v4+chill 2021-07-01 18:25:38 +02:00
a13766e7d7 wip.. 2021-07-01 18:25:38 +02:00
bc240a6754 bootstrap style in form fields, bootstrap integration for select2 2021-07-01 18:25:35 +02:00
50727fc4b0 bootstrap styles in forms fields 2021-07-01 18:24:48 +02:00
b327a3fbfa fix homepage content cols 2021-07-01 18:24:48 +02:00
2916babe1c bootstrap content with vertical right person menu 2021-07-01 18:24:46 +02:00
fe2f107ddc bootstrap content with vertical right person menu 2021-07-01 18:20:11 +02:00
3da8f89d3c bootstrap footer and homepage 2021-07-01 18:08:00 +02:00
19326ee750 wip.. navbar bootstrap 2021-07-01 18:07:57 +02:00
e0ae5d56f0 import chill colors in bootstrap custom theme 2021-07-01 18:05:25 +02:00
0878767c17 replace class container by container-fluid (full width in bootstrap) 2021-07-01 18:05:25 +02:00
f0232228a3 improve details row for household banner 2021-07-01 17:47:17 +02:00
fc63955205 improve banners render : context person, with common improvements on accompanyingcourse and household context 2021-07-01 16:13:07 +02:00
a78de0f96c improve accompanyingcourse work timeline design 2021-07-01 10:41:13 +02:00
270c0accc5 Merge branch 'parcours/origin-de-la-demande' into 'master'
parcours - origin de la demande

See merge request Chill-Projet/chill-bundles!107
2021-07-01 08:37:46 +00:00
fd94f27eee hide console log, remove unused api endpoint method 2021-07-01 10:30:39 +02:00
f7e3be38a7 Merge branch '51-referent-parcours' into 'master'
parcours référent

See merge request Chill-Projet/chill-bundles!106
2021-07-01 07:48:08 +00:00
5861a86289 cleaning dirty git trace 2021-06-30 19:22:26 +02:00
68c0f9b7d7 accompanyingcourse: lesser space between form fieldsets 2021-06-30 19:02:25 +02:00
52288f7260 fix typo + change component position 2021-06-30 18:44:38 +02:00
nobohan
0b5daa6c33 quick fix: address: add backurl after posting the address 2021-06-30 18:26:44 +02:00
2fe1605385 vue accompanyingCourse, adding an origin sub-component 2021-06-30 17:07:48 +02:00
d8256b0ac5 swagger person: adding origin routes 2021-06-30 14:59:27 +02:00
b5760e82ea swagger person: just sorting yaml tree items 2021-06-30 14:58:24 +02:00
d3ac8d8ceb vue accompanyingcourse: ending referrer subcomponent 2021-06-30 11:59:54 +02:00
196f709065 activity, revert detail, cfr. https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/94#note_614231268 2021-06-30 10:18:57 +02:00
6a8c96cdae referrer get users: preparation 2021-06-30 09:52:15 +02:00
3e83891744 prepare new originDemand sub-component 2021-06-30 09:52:15 +02:00
662e5f967c Merge branch 'frontend/address-to-add-persons-widget' into 'master'
Add address to widget add persons

See merge request Chill-Projet/chill-bundles!105
2021-06-30 07:12:42 +00:00
802125edc6 Add address to widget add persons 2021-06-30 07:50:43 +02:00
028c3e0c31 widget addPersons: fix persons without birthdate 2021-06-29 22:40:23 +02:00
e4adafafc8 remove household search 2021-06-29 22:38:01 +02:00
54316d148c Merge branch 'features/improve-activity' into 'master'
Features/improve activity

See merge request Chill-Projet/chill-bundles!103
2021-06-29 19:18:51 +00:00
3c5a2a65df Merge branch 'features/improve-accompanying-course-summary' into 'master'
Improve accompanying course summary page

See merge request Chill-Projet/chill-bundles!102
2021-06-29 19:16:18 +00:00
741ef7b40d Merge branch 'features/add-suggestion-household-member-editor' into 'master'
Add suggestion household member editor

See merge request Chill-Projet/chill-bundles!97
2021-06-29 19:13:38 +00:00
e7384343b2 Merge remote-tracking branch 'origin/master' into features/improve-accompanying-course-summary 2021-06-29 21:12:21 +02:00
1e2a920200 clean menu builder for activity 2021-06-29 21:03:38 +02:00
b5a78fa341 Merge remote-tracking branch 'origin/master' into features/improve-activity 2021-06-29 20:52:06 +02:00
d9c1f52894 improve activity 2021-06-29 20:51:08 +02:00
nobohan
f05f7415bd household: add household accompanying periods 2021-06-29 19:41:00 +02:00
nobohan
5553c7314c household address: fix conflict on branch merge 2021-06-29 17:47:40 +02:00
7dc70baf57 permet de surcharger le label 'commentaire' des actviités 2021-06-29 17:39:19 +02:00
nobohan
34af401a98 accompanying period: add items in the summary page 2021-06-29 17:37:58 +02:00
5bae8dc5bf Import also scripts tags & css for launching banner 2021-06-29 17:13:57 +02:00
6e277e99ae fix in accompanying period list: thirdparty as requestor + link 2021-06-29 17:09:55 +02:00
2688c0f0ce fix missing div in accompanying course work list 2021-06-29 17:09:38 +02:00
nobohan
0135f5184e accompanying period: wording + minor changes in twig 2021-06-29 17:09:24 +02:00
fd698419e8 Merge branch 'fix-prototypage-details' into 'master'
Fix prototypage details

See merge request Chill-Projet/chill-bundles!94
2021-06-29 15:06:20 +00:00
4a864a0b14 Merge remote-tracking branch 'origin/master' into features/improve-accompanying-course-summary 2021-06-29 16:59:05 +02:00
55dc0d3f9f Ajout informations manquantes dans la page "summary" des
AccompanyingCourse
2021-06-29 16:57:28 +02:00
85835c8b0d Merge branch 'features/api-search' into 'master'
Features/api search

See merge request Chill-Projet/chill-bundles!98
2021-06-29 14:50:28 +00:00
nobohan
ab1edee9fb person menu: add style for submenus 2021-06-29 16:22:58 +02:00
6154e0912b fix in accompanying period list: thirdparty as requestor + link 2021-06-29 16:14:50 +02:00
0388428c6f fix missing div in accompanying course work list 2021-06-29 16:14:30 +02:00
7ac55275c2 Merge remote-tracking branch 'origin/fix_issues_juminet' into features/improve-accompanying-course-summary 2021-06-29 16:06:57 +02:00
1119e20a49 Add minor fixes to summary page:
* add messages when no resources
* add address to person
* replace household link label with household number
2021-06-29 16:03:59 +02:00
ea2870eef8 Merge branch 'features/create-user-endpoint' into 'master'
Feature: create user endpoint

See merge request Chill-Projet/chill-bundles!96
2021-06-29 14:02:16 +00:00
nobohan
93a44d8303 address: automatic return when saving address 2021-06-29 15:06:35 +02:00
nobohan
8109415e05 address: wording button 2021-06-29 14:39:43 +02:00
nobohan
514fe6163a address: format address as the French format 2021-06-29 14:33:51 +02:00
9d9be7f831 vue activity: fix backend when hidden return empty string 2021-06-29 14:31:56 +02:00
nobohan
4cf3cc8353 address: add focus on selectAddress field 2021-06-29 14:25:26 +02:00
2a974e1269 fix socialActions selected visibility if all issues unchecked + cleaning 2021-06-29 12:23:11 +02:00
beca41774e vue activity: fix duplicates and add condition in initial loading 2021-06-29 11:49:23 +02:00
dd991e3572 add test 2021-06-28 23:02:15 +02:00
0640631821 implementation on 3party + quote keys in SearchApiQuery 2021-06-28 22:44:42 +02:00
e845d9ba90 replace search api by a first workin implementation 2021-06-28 22:01:33 +02:00
nobohan
6f8231f6f6 accompanying course: clean controller 2021-06-28 22:01:05 +02:00
nobohan
048161e300 accompanying course summary (WIP) 2021-06-28 22:00:07 +02:00
b705c5910f dispatch action change value of hidden fields, persisted when submited 2021-06-28 20:46:30 +02:00
6f1209eaf5 rename methods, improve logic 2021-06-28 20:20:54 +02:00
020759180b prepare dispatch 2021-06-28 20:07:53 +02:00
3748b4fbf4 vue activity: manage datas in store, not with data() 2021-06-28 19:05:26 +02:00
nobohan
4f49292178 address: fix saving of isNoAddress 2021-06-28 17:18:57 +02:00
6eaffcae49 fix redirection after changing household member 2021-06-28 16:22:17 +02:00
nobohan
f92d710a26 accompanying course summary: add social actions 2021-06-28 16:16:55 +02:00
nobohan
bc6ba88acd menu: fix code indentation 2021-06-28 16:04:24 +02:00
61c2934d64 activity: get social Actions, improve reactivity 2021-06-28 15:31:41 +02:00
28b4d9562c add socialAction checkbox list 2021-06-28 15:21:41 +02:00
e06aded1ec remove from multiselect when adding social issues + disable accompanyingcourse issues loading 2021-06-28 15:21:32 +02:00
3a81124e04 activity vue: list socialIssues checkbox from accompanyingCourse 2021-06-28 15:21:17 +02:00
nobohan
b72d45d9db accompanying period: hide activity entries from the menu if accompanyin period is DRAFT 2021-06-28 13:50:31 +02:00
2a1f5cbad1 add test for suggestion household by accompanying period 2021-06-28 13:18:00 +02:00
e8566fd006 change label 2021-06-28 12:36:19 +02:00
cd6b5c9a39 Add context for household member editor form:
* add context for accompanying period, if indicated in a query
parameter;
* expand automatically household suggestion, if indicated in a query
parameter
2021-06-28 11:23:30 +02:00
9aa3974071 show household suggestion in household members editor 2021-06-28 00:35:40 +02:00
a8bf478ee8 add endpoint for getting suggestion on household by accompanying period 2021-06-27 11:10:17 +02:00
a35f3363b2 Merge branch 'features/edit-accompanying-period-social-work' into 'master'
Features/edit accompanying period social work

See merge request Chill-Projet/chill-bundles!91
2021-06-26 13:15:34 +00:00
0b117e5158 Merge remote-tracking branch 'origin/features/edit-accompanying-period-social-work' into _vue_echanges 2021-06-26 12:14:32 +02:00
7cae9e1769 wip 2021-06-26 12:09:18 +02:00
a43e6c12a0 add tests for UserApiController 2021-06-26 11:08:26 +02:00
abe012de60 add endpoint whoami 2021-06-26 11:08:10 +02:00
aaa9a1ec7b create user _index and _entity endpoint 2021-06-26 11:07:03 +02:00
25f2d17097 documentation for api social actions 2021-06-25 21:34:36 +02:00
4fd43310c0 Merge remote-tracking branch 'origin/master' into features/edit-accompanying-period-social-work 2021-06-25 21:26:21 +02:00
c85ca894b8 layout for list accompanying work 2021-06-25 21:25:27 +02:00
fe22e6c7dc activity: create new vue subcomponent socialIssuesAcc 2021-06-25 15:44:20 +02:00
cb67605bd2 list accompanying course work 2021-06-25 14:59:10 +02:00
d26e08324c load banner accompanying course everywhere 2021-06-25 14:09:47 +02:00
e55a2691b7 move vue activity component app in subcomponent concernedGroups 2021-06-25 14:09:32 +02:00
nobohan
aa5c7f333e fix conflict + error on CommentType 2021-06-25 13:57:49 +02:00
0afe277b04 form acc work edit: save action 2021-06-25 00:06:26 +02:00
981b9299ad layout form 2021-06-24 16:21:52 +02:00
nobohan
36eb247995 address: add maxlength, upd default map center and add loader messages in addresses form 2021-06-24 16:02:57 +02:00
2cda6ceebf improve history details 2021-06-24 15:43:02 +02:00
1ceabec400 redesign timeline with css gridlayout 2021-06-24 15:17:34 +02:00
nobohan
91c5cd74f7 household address: remove group write on member collection 2021-06-24 14:01:15 +02:00
nobohan
b7f2e189dc small fix: use class name instead of string 2021-06-24 14:01:15 +02:00
nobohan
ab8deb036b accompanyingCourse: add activities in the accompanying course summary 2021-06-24 14:01:15 +02:00
nobohan
ac47a75a75 fix bug issue 163 Address JSON string not valid 2021-06-24 14:01:15 +02:00
nobohan
4e6454d7de translation Activity Envoyer/recevoir 2021-06-24 14:01:15 +02:00
92a95d4186 finish form behaviour 2021-06-24 12:44:24 +02:00
nobohan
c23ada3533 person: add show/hide on marital status date 2021-06-24 08:25:55 +02:00
b72b1bd4c7 Merge remote-tracking branch 'origin/master' into features/edit-accompanying-period-social-work 2021-06-23 22:48:09 +02:00
ca9ae3874c Merge branch 'fix/api-crud-improve-loading-for-existing-controller' into 'master'
Fix/api crud improve loading for existing controller

See merge request Chill-Projet/chill-bundles!92
2021-06-23 20:44:25 +00:00
7fb4616aa6 Merge branch 'features/create-social-action' into 'master'
Create social work

See merge request Chill-Projet/chill-bundles!90
2021-06-23 20:43:32 +00:00
ac4cf43753 add goals to work, and add results for each goal 2021-06-23 22:40:11 +02:00
5a4a0a3617 add results for actions in course edit form 2021-06-23 21:26:36 +02:00
2cc1274ee0 fix js alert with dom event listener 2021-06-23 18:04:06 +02:00
154fa4719d add involved persons to accompanying period work 2021-06-23 17:46:51 +02:00
193e7b4c7e cleaning 2021-06-23 13:20:50 +02:00
80c2bd285f vue component html anchor place 2021-06-23 11:50:09 +02:00
133c0ac1ac TOFIX temporary disable js alert that return an error:
## in JS console:

Uncaught ReferenceError: chill is not defined
    <anonymous> http://localhost:8001/fr/activity/1808/edit?person_id=1453:317
2021-06-23 11:25:54 +02:00
c8d5c2c67b resume interlocutors 3 columns 2021-06-23 09:31:26 +02:00
0754d20622 fix form create + WIP form edit for Accompanying Period Work 2021-06-22 22:59:34 +02:00
99d6e030ca ergonomic buttons details 2021-06-22 16:15:05 +02:00
5d38d193e2 add type of activity in title 2021-06-22 16:14:29 +02:00
86f7b116a9 adapt buttons when choosing type of ativity 2021-06-22 16:12:30 +02:00
bcab5a1211 remove old webpack entrypoint definitions 2021-06-22 16:11:24 +02:00
65a6607112 fix translations 2021-06-22 16:10:17 +02:00
1cd376bf86 Merge remote-tracking branch 'origin/master' into features/edit-accompanying-period-social-work 2021-06-22 16:09:58 +02:00
84f6f9b44d fix bug with new activity in context person 2021-06-22 16:09:20 +02:00
b53f6af8d8 add api for getting goal and results by social action and goal 2021-06-22 16:08:53 +02:00
34d6452286 fix: household api 2021-06-22 15:31:56 +02:00
c04ccef4cd improve loading for existing crud cotnroller 2021-06-22 14:40:56 +02:00
nobohan
d8afbc4a40 fix bug on PostalCodeChoiceLoader (not understood) 2021-06-22 11:56:25 +02:00
95edbc673c improve loading for crud controller 2021-06-22 10:08:19 +02:00
07ffdfab86 household banner context colors 2021-06-21 15:58:27 +02:00
50be29308d Merge remote-tracking branch 'origin/master' into features/create-social-action 2021-06-21 14:38:09 +02:00
d1e0d997ac Merge branch 'features/household-edit-members-forms-improve-household' into 'master'
Corrections ménage

See merge request Chill-Projet/chill-bundles!88
2021-06-21 12:25:22 +00:00
nobohan
504b2efacf person: fix death date type as date immutable 2021-06-21 13:58:14 +02:00
4c3c67344a fix merge old css styles 2021-06-21 13:43:15 +02:00
40fcb09082 layout for form 2021-06-21 13:38:43 +02:00
aa4a9e874a add a spinner 2021-06-19 11:15:27 +02:00
3abfdbf6fd first impl for create form 2021-06-18 19:41:58 +02:00
07cc394abd [bugfix] fix font in element ::before
See https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/162

[ci skip]
2021-06-18 14:24:53 +02:00
99337c4aa6 add form edit metadata in summary page 2021-06-18 14:11:02 +02:00
04ccca092b remove links to route 'household members' 2021-06-18 13:53:19 +02:00
nobohan
b3792f6714 person: update person view/show twig 2021-06-18 13:46:46 +02:00
e1f01a47f8 Merge remote-tracking branch 'origin/master' into features/household-edit-members-forms-improve-household 2021-06-18 13:42:37 +02:00
dc79e1a02d remove test for members page 2021-06-18 13:31:19 +02:00
7a6117a264 fix test which randomly failed 2021-06-18 13:30:31 +02:00
nobohan
1a204312f3 person: re-enable the creation of a person 2021-06-18 13:12:27 +02:00
1b1a25edc4 Merge branch 'features/sql-vue-from-household-address-to-person' into 'master'
Features/sql vue from household address to person

See merge request Chill-Projet/chill-bundles!86
2021-06-18 11:01:40 +00:00
5ab7f7a37b Merge remote-tracking branch 'origin/master' into features/sql-vue-from-household-address-to-person 2021-06-18 12:08:13 +02:00
b174397823 Merge branch 'features/household-validation' into 'master'
Validation for household and household members & list for household for a person

See merge request Chill-Projet/chill-bundles!79
2021-06-18 10:07:10 +00:00
9d35e4efbb Merge remote-tracking branch 'origin/master' into features/household-validation 2021-06-18 12:02:34 +02:00
0e9933ca41 improve banner 2021-06-18 11:57:27 +02:00
nobohan
3d14f00cac person: add show hide on some fields + remove unknown genderType 2021-06-18 11:28:02 +02:00
0add757230 remove members page, move to summary 2021-06-18 11:27:25 +02:00
2bf65dfadb Merge branch 'fix-test-accompanying-period' into 'master'
fix data provider which randomly generate invalid data in test

See merge request Chill-Projet/chill-bundles!87
2021-06-18 09:19:29 +00:00
a7ecd08d78 fix data provider which randomly generate invalid data in test 2021-06-18 09:19:28 +00:00
nobohan
bccaf5ad6e person: add createdBY, updatedBy fields on Person + migration 2021-06-18 10:15:30 +02:00
585a19e803 Apply 7 suggestion(s) to 1 file(s) 2021-06-18 07:17:32 +00:00
b801b75eb9 Merge remote-tracking branch 'origin/master' into features/sql-vue-from-household-address-to-person 2021-06-17 23:16:57 +02:00
f1120af59e add 'holder' in list of persons 2021-06-17 23:10:18 +02:00
9d58356b90 remove drag-and-drop behaviour 2021-06-17 22:54:46 +02:00
a7131653c9 finish merge (oups) + layout of household in members editor app 2021-06-17 22:47:33 +02:00
9f3cd943cb Merge branch 'features/household-validation' into features/household-edit-members-forms-improve-household 2021-06-17 22:46:47 +02:00
nobohan
970635dfad Merge branch 'master' of gitlab.com:Chill-Projet/chill-bundles
merge...
2021-06-17 17:03:42 +02:00
nobohan
c8297b2230 fix conflict when merging _77_address_household into master 2021-06-17 16:59:55 +02:00
994cce41e5 Merge branch 'master' into features/household-edit-members-forms-improve-household 2021-06-17 15:41:00 +02:00
86e41fb877 Merge remote-tracking branch 'origin/_77_address_household' into features/household-edit-members-forms-improve-household 2021-06-17 15:05:46 +02:00
f8b97b96f4 do not use arrayAccess for Collection in validator 2021-06-17 14:57:16 +02:00
27907e7558 fix modification of key members in household normalization 2021-06-17 14:02:29 +02:00
Marc Ducobu
38712de462 Merge branch 'notifications_fixtures' into 'master'
LoadNotifications using DependentFixtureInterface

See merge request Chill-Projet/chill-bundles!83
2021-06-17 11:38:47 +00:00
fd7c7388d9 fix prepending configuration of doctrine 2021-06-17 13:31:04 +02:00
ef55d2cf7f create view for current address and apply on Person/Household normalizer 2021-06-17 13:21:55 +02:00
nobohan
8406c30c8e person: Person FormType + edit twig 2021-06-17 12:27:47 +02:00
nobohan
901ae47ce6 person: correct migration + entity 2021-06-17 11:12:40 +02:00
nobohan
951160982d person: add more fields on Person + migration 2021-06-17 10:43:57 +02:00
nobohan
e2633a2a79 addresses: filter out postal code introduced by user 2021-06-16 16:20:37 +02:00
Marc Ducobu
1cfc29caf7 LoadNotifications using DependentFixtureInterface 2021-06-16 15:32:59 +02:00
nobohan
5b72eeb147 addresses: edit address for household (WIP) 2021-06-16 15:05:32 +02:00
Marc Ducobu
1b9d8fab61 Merge branch 'notifications' into 'master'
Notifications

See merge request Chill-Projet/chill-bundles!81
2021-06-16 12:58:57 +00:00
Marc Ducobu
801af209a1 Revert "NotificationRepo as a service"
This reverts commit 84913553e8.
2021-06-16 14:54:33 +02:00
nobohan
06daf35e96 addresses: edit address for person 2021-06-16 14:39:02 +02:00
38bff2e42f add address to household in fixtures 2021-06-16 08:35:47 +02:00
e68a5405a1 Merge branch 'master' into features/sql-vue-from-household-address-to-person 2021-06-15 22:53:21 +02:00
8bd20c9c78 [WIP] add fixtures for household address 2021-06-15 22:52:48 +02:00
54997e5893 add test for household membership sequential validator 2021-06-15 21:31:02 +02:00
nobohan
35d35c9f40 addresses: edit address (WIP) 2021-06-15 21:03:50 +02:00
Marc Ducobu
49d022ef55 NotificationRepository as a service 2021-06-15 18:57:56 +02:00
78ca61c82e fix showing person without birthdate 2021-06-15 17:22:03 +02:00
b68de1f2e9 fix parameters in list 2021-06-15 17:16:35 +02:00
68ecff253a fix validation when leaving any household 2021-06-15 17:15:45 +02:00
Marc Ducobu
db545f9fe6 Adding typehinting for Entity/Notif 2021-06-15 17:14:11 +02:00
Marc Ducobu
86d764c097 Using JSONB for storage in db for attendees in Notifications 2021-06-15 17:14:11 +02:00
Marc Ducobu
cf8b9ec172 Migration for notifications 2021-06-15 17:14:11 +02:00
Marc Ducobu
23528e7a5c Adding some features to load for notifications) 2021-06-15 17:14:11 +02:00
Marc Ducobu
a258905c59 Add unique constraint (class, id) to notifications 2021-06-15 17:14:11 +02:00
Marc Ducobu
84913553e8 NotificationRepo as a service 2021-06-15 17:14:11 +02:00
Marc Ducobu
916209e402 Fix remarks MR - notif 2021-06-15 17:12:40 +02:00
Marc Ducobu
3ec212df93 Creation of Notification Entity 2021-06-15 17:12:40 +02:00
e95d8fbc7a Historique ménage pour une personne 2021-06-15 17:03:38 +02:00
Pol Dellaiera
ce88fe158f Merge branch 'chill-main-update-repositores-and-entities' into 'master'
Chill main update repositores and entities

See merge request Chill-Projet/chill-bundles!82
2021-06-15 14:24:04 +00:00
efdfd10e49 replace comment by commentEmbeddable 2021-06-15 10:17:53 +02:00
nobohan
000ae6c2cb address: style (css) 2021-06-15 08:04:38 +02:00
nobohan
7c26f0a56c address: add a new address to a person 2021-06-15 07:49:35 +02:00
f827e50431 ajout métadonnées membres 2021-06-14 22:30:52 +02:00
41617295c1 fix validation groups and sequential validator msg 2021-06-14 16:39:27 +02:00
b2c1d75fc5 fix parameters in test MaxHolder 2021-06-14 12:58:23 +02:00
17c3ecbabe validation on simultaneous household membership for a person 2021-06-14 12:56:01 +02:00
de024b405f Merge branch 'features/household-editor' into 'master'
[UI] Add page to move members of household

See merge request Chill-Projet/chill-bundles!73
2021-06-14 09:38:17 +00:00
51399b21b9 fix class for Person component 2021-06-14 11:37:20 +02:00
c40019da8f add alert for not-in-household and actions in page
accompanyingCourse/summary

* alert for people not in household for each accompanying course;
* style for action in alert
* form to members editor
2021-06-14 11:34:05 +02:00
1df759e970 fix JS error "chill is not defined"
This happens since js is loaded using "defer" tag
2021-06-14 10:19:18 +02:00
Pol Dellaiera
92b4adc113 Fix DI on other services depending on updated repositories. 2021-06-11 21:56:17 +02:00
807d3674fc implements max holder and validation on UI 2021-06-11 17:58:09 +02:00
af740fd87d Merge branch 'features/household-editor' into features/household-validation 2021-06-11 17:08:38 +02:00
45dc8ed661 apply maxHolder constraint on houehold 2021-06-11 17:08:35 +02:00
ecc8b929ca create max holder validator 2021-06-11 17:03:48 +02:00
nobohan
c378f59f5a addresses: person address history 2021-06-11 16:20:40 +02:00
4fd6d38187 create Util for computing intersection 2021-06-11 15:53:32 +02:00
nobohan
f3a7556bca household address: update twig for household address 2021-06-11 15:44:49 +02:00
nobohan
14db7265fe addresses: fix POST if isNoAddress 2021-06-11 15:06:56 +02:00
nobohan
f22461af1b address: better default zoom when choosing an address 2021-06-11 14:42:08 +02:00
nobohan
1b709d39a4 addresses: enable POSTing Postal Code entities (back + front) 2021-06-11 14:33:22 +02:00
Pol Dellaiera
81e8a4562b Remove obsolete repositories.yaml file. 2021-06-11 12:43:54 +02:00
Pol Dellaiera
1e72247546 Update existing repositories and their corresponding entities. 2021-06-11 12:43:44 +02:00
Pol Dellaiera
670ba1713a Add missing repositories and update corresponding entities. 2021-06-11 12:43:38 +02:00
nobohan
5daf5cbe84 address: write new address (separate street and streetNumber) 2021-06-11 11:12:44 +02:00
nobohan
331cdf13ca household address: add validation on household->getAddresses 2021-06-11 09:34:27 +02:00
f25365f651 Add LICENSE 2021-06-11 07:31:28 +00:00
cbadcb4980 Merge remote-tracking branch 'origin/master' into features/household-validation 2021-06-11 09:05:48 +02:00
b2ce5fca38 household editor: allow to move without any household 2021-06-10 16:17:59 +02:00
38c06977ca add link to household or household editor 2021-06-10 15:18:41 +02:00
nobohan
1551ea796d household address: UI of the adress move form 2021-06-10 14:34:14 +02:00
3e39dd9a1e remove route for testing move 2021-06-10 13:02:35 +02:00
89734c680c backend: allow to remove people from household, or move to a new household 2021-06-10 13:01:42 +02:00
nobohan
4c025184b4 household address: check if address are sequential (WIP) 2021-06-10 12:40:01 +02:00
6fed008ff2 fix creation of new household during move 2021-06-10 11:48:06 +02:00
057bdf6a6a add missing message 2021-06-10 11:47:52 +02:00
nobohan
6f2c219e3b household address: add validTo computation in Address 2021-06-10 11:43:13 +02:00
nobohan
550aaacaab household address: fix POST api chaining 2021-06-10 11:42:39 +02:00
f9758eff5b fix use of context into householdMember::move 2021-06-10 11:16:37 +02:00
abc79249a2 Merge remote-tracking branch 'origin/master' into features/household-editor 2021-06-10 11:01:59 +02:00
f7bb9ac327 Merge branch 'features/household-members-list' into 'master'
Features/household members list

See merge request Chill-Projet/chill-bundles!76
2021-06-10 08:59:51 +00:00
3c727d1c65 fix format for date, after use of html5 date widget 2021-06-10 10:52:37 +02:00
ac211337d6 fix denomination: bold only in list 2021-06-10 10:31:59 +02:00
30668ca67f Merge remote-tracking branch 'origin/master' into features/household-members-list 2021-06-10 10:29:57 +02:00
5da0be24ff change icon for household 2021-06-10 10:20:18 +02:00
nobohan
dd78e9759c household address: show js error messages 2021-06-10 10:11:00 +02:00
nobohan
1b36d9b1ab household address: chain API call 2021-06-10 10:06:23 +02:00
7fddf1d5e0 fix indentation 2021-06-09 22:18:47 +02:00
315fc7f63a set default for Position attributes 2021-06-09 22:12:55 +02:00
3c889db41a style editor when no household nor persons to move 2021-06-09 22:08:10 +02:00
71f794c4d9 add ckeditor for comment 2021-06-09 17:31:55 +02:00
e135b98072 Merge remote-tracking branch 'origin/master' into features/household-editor 2021-06-09 16:27:03 +02:00
e14205ae1d first layout for form edit 2021-06-09 16:13:39 +02:00
nobohan
e14a125bf3 household address: format js date for POSTing 2021-06-09 12:24:15 +02:00
8a5650a705 Merge branch 'features/activity-form' into 'master'
Activity

See merge request Chill-Projet/chill-bundles!58
2021-06-09 06:23:55 +00:00
18217f53e8 Merge branch 'features/household-members-list' into features/household-editor 2021-06-08 22:16:43 +02:00
79ec182ca3 Merge branch 'features/date-type-use-html5' into features/activity-form 2021-06-08 22:01:19 +02:00
1433af8e95 fix format for birthdate in test 2021-06-08 21:57:06 +02:00
e91596ae12 fix callback for comparing birthdate in test 2021-06-08 19:44:31 +00:00
nobohan
9375c2cf86 household address: patch address + add validFrom input 2021-06-08 21:14:09 +02:00
nobohan
db77224b9f address: add swagger documentation 2021-06-08 20:36:20 +02:00
1c42bf6400 Merge branch 'features/date-type-use-html5' into features/activity-form 2021-06-08 19:45:58 +02:00
c9da72fa0d fix test: use format for html5 date 2021-06-08 19:44:55 +02:00
3b3855089c fix social action render 2021-06-08 19:42:29 +02:00
265ace0b4c update dep to app 2021-06-08 19:27:46 +02:00
0e1bbbfee9 Merge remote-tracking branch 'origin/master' into features/household-validation 2021-06-08 19:19:30 +02:00
ebf896ac74 use encore functions to load assets 2021-06-08 19:17:07 +02:00
31befaa339 remove dump 2021-06-08 18:19:24 +02:00
780c14cfbe Merge branch 'features/date-type-use-html5' into features/activity-form 2021-06-08 18:08:23 +02:00
8183c028f8 remove ref to pikaday 2021-06-08 18:07:59 +02:00
97bba861c9 Merge branch 'features/date-type-use-html5' into features/activity-form 2021-06-08 18:03:34 +02:00
8d7d170f11 Use Html5 datetype and remove pikaday and moment.js 2021-06-08 17:58:23 +02:00
c126f680ae Merge remote-tracking branch 'origin/master' into features/activity-form 2021-06-08 17:24:47 +02:00
nobohan
6a42edd460 household address: remove address selection 2021-06-08 17:06:03 +02:00
0aa909f060 fix misc in activity (WIP) 2021-06-08 16:55:29 +02:00
f27957e91b improve banner 2021-06-08 12:36:27 +02:00
ed891b224f allow to distinguish stle for list-with-periods and list household
members in css
2021-06-08 12:36:01 +02:00
nobohan
76d945f2a7 household address: address history : add button 2021-06-08 11:51:30 +02:00
nobohan
7d13bc7cfe household address: address history (twig + css) 2021-06-08 11:35:33 +02:00
nobohan
66b54bad31 household address: add swagger documentation 2021-06-08 08:55:41 +02:00
nobohan
9d32ccbcad address: swagger config for documenting API points 2021-06-08 08:30:54 +02:00
4dc82bc207 add test for Member edition + fix path 2021-06-07 21:52:17 +02:00
2384281532 update test app to new version 2021-06-07 21:23:28 +02:00
7c94824c20 Merge branch 'features/household-members-list' into features/household-editor 2021-06-07 17:36:25 +02:00
a922e397f8 Merge remote-tracking branch 'origin/master' into features/household-editor 2021-06-07 17:32:29 +02:00
be13f8f65b fullfill summary page 2021-06-07 17:27:10 +02:00
12f83abccc add encore to composer.json 2021-06-07 17:26:38 +02:00
nobohan
63c3b5a970 address: add swagger doc on API point for address 2021-06-07 17:24:31 +02:00
1967d6ea4c Merge branch 'features/household-context' into 'master'
Create an household context

See merge request Chill-Projet/chill-bundles!74
2021-06-07 15:04:44 +00:00
5cb076495a finalize members lists 2021-06-07 17:03:45 +02:00
nobohan
03a7ec389b household address: fix POST household address 2021-06-07 16:54:16 +02:00
604e78f35e restore list with period 2021-06-07 15:31:30 +02:00
nobohan
f39fe05dd5 household address: rely on ROLE_USER for household address api point role 2021-06-07 15:26:24 +02:00
eeffa3191e page list members of an household: born date + collpse old members 2021-06-07 15:14:42 +02:00
nobohan
6c126b0581 household address: api POST on address for household (WIP) 2021-06-07 15:13:45 +02:00
84d5fb936e use encore entry tags to load css and js in layout 2021-06-07 14:48:36 +02:00
nobohan
5ee824d1c2 household address: define a custom household-address API point (WIP) 2021-06-07 14:47:22 +02:00
7933aaed1c use MessageFormatter for formatting message with gender 2021-06-07 14:25:15 +02:00
nobohan
6d20476b81 household address: household address history (WIP) 2021-06-07 14:24:03 +02:00
nobohan
2b5ed5e5a3 household address: choose among available address 2021-06-07 12:18:03 +02:00
0fe70d00ec Merge branch 'remove-uneeded-service-definition' into 'master'
[simplification] Remove custom service definitions.

See merge request Chill-Projet/chill-bundles!72
2021-06-07 08:29:55 +00:00
e5905902cc add confirm button for move 2021-06-04 21:24:11 +02:00
48e5809008 add utility for date 2021-06-04 21:23:51 +02:00
a947634f30 remove dump 2021-06-04 19:52:03 +02:00
3e3c9dc894 Merge branch 'features/activity-form' of gitlab.com:Chill-Projet/chill-bundles into features/activity-form 2021-06-04 19:50:50 +02:00
574b5dcbd0 simplify concernedGroups template for bloc/row include 2021-06-04 19:50:00 +02:00
c1ba892811 list activity flex-table design 2021-06-04 18:59:34 +02:00
nobohan
6f68349f57 household address: post address to household (WIP) 2021-06-04 17:45:29 +02:00
nobohan
d513be2fce household address: post address to household (WIP) 2021-06-04 16:23:13 +02:00
Pol Dellaiera
7a33c37b51 Fix path. 2021-06-04 15:52:13 +02:00
Pol Dellaiera
a6c4b4eb55 Remove custom service definitions. 2021-06-04 15:52:12 +02:00
Marc Ducobu
160c7f2c31 Adding fr translation for social issues 2021-06-04 15:47:52 +02:00
nobohan
aff140230c household address: add a button for posting to household 2021-06-04 15:38:28 +02:00
Marc Ducobu
31468aeae0 Using select2 for reason field inside activity form 2021-06-04 15:15:28 +02:00
3e57ff3ffa Merge remote-tracking branch 'origin/master' into features/household-context 2021-06-04 15:11:36 +02:00
6cbbce03c4 Merge branch 'features/household' into 'master'
Manage household

See merge request Chill-Projet/chill-bundles!70
2021-06-04 13:10:42 +00:00
Marc Ducobu
e52c94aabd Use SocialIssueRenderer->renderString for displaying socialIssues 2021-06-04 15:04:36 +02:00
ef98111a2f Merge remote-tracking branch 'origin/master' into features/household 2021-06-04 15:03:00 +02:00
55fa16ce56 fix missing postgresql extension: correct class name 2021-06-04 14:54:14 +02:00
nobohan
7e1b7b7e9f household address: init vue component for household address 2021-06-04 14:50:51 +02:00
Marc Ducobu
39dca2a9ca Form for socialIssues & Actions using expanded 2021-06-04 14:48:07 +02:00
80ccb76794 Merge branch 'master' into 38_modal_on-the-fly 2021-06-04 14:18:54 +02:00
nobohan
878ee5d9c7 household address: correct household api entry point 2021-06-04 12:34:44 +02:00
Marc Ducobu
541fe8f1ad Removing extra line 2021-06-04 12:22:17 +02:00
Marc Ducobu
bb71b9f908 Descendants for socialActions & Issues 2021-06-04 12:22:17 +02:00
nobohan
7b67ef5db2 household address: add household api entry point 2021-06-04 12:13:15 +02:00
330234981c Merge remote-tracking branch 'origin/features/activity-form--marc' into features/activity-form 2021-06-04 11:58:33 +02:00
a323e84357 concerned parties in vue component: display 3 or 4 bloc according to context 2021-06-04 11:53:50 +02:00
c33f577f5a activity show: concerned parties are clickable links 2021-06-04 10:52:07 +02:00
nobohan
0ce814cf52 hotfix: delete duplicate key in ChillPersonBundle messages translation 2021-06-04 09:34:36 +02:00
nobohan
d806a074a7 Merge branch 'master' into _77_address_household
merge master
2021-06-04 09:09:59 +02:00
nobohan
14a9d9c739 address-household: address move (WIP) 2021-06-04 08:48:08 +02:00
502a629dc8 add date for movement editor 2021-06-03 22:09:52 +02:00
4ace2fef99 concerned parties, split in activity model persons associated or not 2021-06-03 20:20:56 +02:00
Marc Ducobu
4a1ebc1c4c Removing dump 2021-06-03 20:18:47 +02:00
Marc Ducobu
4553051271 Review load fixtures for activityType & categories 2021-06-03 20:15:40 +02:00
Marc Ducobu
743d6cd0bf Method setX with return this (and not void) 2021-06-03 20:15:40 +02:00
Marc Ducobu
0f635ca51a SocialAction & Issues in Activity form 2021-06-03 20:15:40 +02:00
987815471c add concerned parties in show activity page (2 contexts) 2021-06-03 19:13:58 +02:00
d9a3e117b2 WIP continue editor 2021-06-03 18:11:05 +02:00
nobohan
f6d4d32ce4 fix conflict when merging 2021-06-03 15:11:09 +02:00
937be1af3a fix html5 birthdate field on modal form OnTheFly 2021-06-03 14:34:52 +02:00
32b3d74a1b fix activity entity addPersons if person is null 2021-06-03 13:48:03 +02:00
nobohan
43fb020272 address: remove serializer config (it is autowired) 2021-06-03 13:01:24 +02:00
nobohan
f26fafb2f2 address: remove comment 2021-06-03 10:35:27 +02:00
nobohan
e1e3051d00 address: correct customizeQuery 2021-06-03 10:33:09 +02:00
nobohan
a659263af6 addresses: translations 2021-06-03 10:27:17 +02:00
nobohan
9333b6d2df address: correct customizeQuery 2021-06-03 10:22:20 +02:00
4d0cfbb396 OnTheFly modal, Person Sub-component: create/edit form, show 2021-06-02 22:29:09 +02:00
e9caa7b4b8 add groups on household serialization 2021-06-02 21:44:49 +02:00
261acdfd24 Merge branch 'features/household' into features/household-context 2021-06-02 16:48:54 +02:00
17481798fb fix duplicate in messages.fr.yml 2021-06-02 16:38:59 +02:00
edb8aa1dfe Merge branch 'master' into features/household 2021-06-02 16:28:24 +02:00
93a67c9ab9 Merge branch 'fix-person-tests'
Conflicts:
	src/Bundle/ChillPersonBundle/translations/messages.fr.yml
2021-06-02 16:25:37 +02:00
980a305456 Merge branch 'dune-risky'
Conflicts:
	src/Bundle/ChillActivityBundle/config/services.yaml
	src/Bundle/ChillPersonBundle/translations/messages.fr.yml
2021-06-02 16:23:45 +02:00
0158c6f2ed add tests for household 2021-06-02 16:21:01 +02:00
ff5b0bc258 add list for addresses 2021-06-02 16:20:46 +02:00
a133f56dce add routes for household addresses, members, and addresses_moves 2021-06-02 15:45:39 +02:00
Marc Ducobu
c4e226d0bd Ajout de SocialIsssue & SocialAction to ActivityType 2021-06-02 12:47:43 +02:00
fa556bbba1 basic context for household 2021-06-02 11:44:36 +02:00
e8f3c499ee Merge branch 'dune-risky' into fix-person-tests 2021-06-02 00:47:14 +02:00
cfd9f1bab1 replace call to entity by class FQDN 2021-06-02 00:46:55 +02:00
c6949490a4 first impl for household editor 2021-06-02 00:32:55 +02:00
nobohan
8011293b28 address form: add the possibility to create a new address 2021-06-01 21:55:34 +02:00
Marc Ducobu
7992f09aea Ajout SocialAction & SocialIssues to Activity 2021-06-01 17:18:00 +02:00
abede56d68 activity vue corrections 2021-06-01 16:18:01 +02:00
9ab032c943 resolve data Transformer in ActivityType (persons/thirdparties/users) 2021-06-01 15:13:21 +02:00
4562ed46db OnTheFly modal: adapt footer button for show/edit cases (bug minor)
[BUG] to reproduce:
* clic first on show item button
* in modal clic edit button
* close modal
* clic again on show item button
2021-06-01 10:48:34 +02:00
cd52f7e6e8 Merge branch 'fix-person-tests' into features/household 2021-05-31 21:40:24 +02:00
126ffc55bf Merge branch 'fix-getParticipationsContainsPerson' into 'master'
Fix `::getParticipationsContainsPerson`.

See merge request Chill-Projet/chill-bundles!50
2021-05-31 19:35:33 +00:00
f49c54d51f fix redirection after creating accompanying course in test 2021-05-31 21:31:02 +02:00
1410213258 Merge remote-tracking branch 'origin/master' into fix-person-tests 2021-05-31 21:17:56 +02:00
35e0b98687 temporarily remove test for person duplicate 2021-05-31 21:16:31 +02:00
8f1091b8a3 Merge branch '50-ajout-problematique-sociale-modele' into 'master'
Add many2many relation between socialIssue and accompanying period + api endpoint

See merge request Chill-Projet/chill-bundles!53
2021-05-31 19:11:15 +00:00
c269bfe278 fix type-hinting for person repository 2021-05-31 21:09:14 +02:00
041b1dfc51 Controller action to move members of an household 2021-05-31 20:42:07 +02:00
718d6c2375 add basic on-the-fly sub-components, to show/edit/create person/thirdparty 2021-05-31 19:25:37 +02:00
158b572879 replace all links and buttons involved by OnTheFly component 2021-05-31 15:52:26 +02:00
68059a9938 add new OnTheFly vue sub-component 2021-05-31 12:59:11 +02:00
543f6b20dd firstname and lastname in same column 2021-05-31 11:39:15 +02:00
e95d756e71 fix socialIssues multiselect with searchable=true option 2021-05-31 09:59:44 +02:00
992734bb72 fix banner toggleFlags regular/occasionnal 'on' style -> stronger 2021-05-31 09:54:28 +02:00
741ed84918 formType transform string id in entities, wip 2021-05-28 22:59:56 +02:00
5822736f19 store action add/remove id values in hidden input fields 2021-05-28 22:29:34 +02:00
66776eed01 activity component split added persons between 'Usagers du parcours' and 'Tiers non pros.' 2021-05-28 19:27:27 +02:00
ace3b1969e Rename membership edition and add more fixtures 2021-05-28 18:26:22 +02:00
edc86af659 add tests for moving houshold 2021-05-28 18:01:20 +02:00
e123ee5d03 activity vue component add and remove persons (in store) 2021-05-28 17:30:11 +02:00
87ba68971c first impl of person Mover + add fixtures 2021-05-28 16:41:37 +02:00
94bcbac06a add extension btree_gist to postgres 2021-05-28 13:55:06 +02:00
74520330b1 add position for household and prefix tables names 2021-05-28 13:25:41 +02:00
666c1e7ae7 replace border by box-shadox in flex-bloc and flex-table
We use box-shadow instead of border
to avoid to manage border double-width
when blocs are resized for small screen !

Then we can simulate border-collapse: collapse (table)
2021-05-28 12:46:04 +02:00
nobohan
935006eae3 addresses form: add default country value 2021-05-28 12:31:08 +02:00
622c254cc4 Activity: vue DisplayPerson component logic 2021-05-28 12:14:46 +02:00
a19fd51600 serialize new activity when id's not yet defined 2021-05-28 12:13:28 +02:00
nobohan
165012b302 address: POST an address 2021-05-28 10:14:54 +02:00
nobohan
057db09847 addresses: improve address multiselect 2021-05-28 09:06:07 +02:00
56242f9b5a adapt requestor to flex-table 2021-05-27 22:55:07 +02:00
549f3a4c78 AddPersons in activity
* modal button dont submit all form
* addNewPersons action mutation loop ready
2021-05-27 22:53:35 +02:00
9ec2a62fb6 controller return json to vue via twig, corrections 2021-05-27 18:41:22 +02:00
65ac9a47b4 add addPersons subcomponent 2021-05-27 17:53:14 +02:00
b1d7e543fc controller return json to vue via twig; init vue App 2021-05-27 17:36:33 +02:00
b89cffce68 add serializer to activityController 2021-05-27 16:13:22 +02:00
nobohan
063076d0cb address: use multiselect for city and address selection 2021-05-27 15:15:20 +02:00
nobohan
bcf2b9d834 address: use multiselect for country selection 2021-05-27 14:49:41 +02:00
968e6914b2 add new webpack vue entrypoint for activity
+ rename existing activity.scss
+ rename webpack vue accompanyingCourse entrypoint
2021-05-27 13:29:01 +02:00
52ee8c5a9a activity: change fields order in form 2021-05-27 13:27:40 +02:00
nobohan
64d28106c8 address: POST a new address: treat the postcode 2021-05-27 12:34:45 +02:00
0a5d20b16f Merge branch 'master' into features/activity-form 2021-05-27 11:43:37 +02:00
85dda8b680 hide flex-table test on page AccompanyingCourse history 2021-05-27 11:34:49 +02:00
2c49afe549 Merge branch 'master' into features/activity-form 2021-05-27 10:44:21 +02:00
2e1201418a Merge branch 'fix-activity-menubuilder-definition' into 'master'
fix activityBundle menuBuilder definition

See merge request Chill-Projet/chill-bundles!69
2021-05-27 08:40:29 +00:00
a9fb916843 fix activityBundle menuBuilder definition 2021-05-27 10:37:24 +02:00
6631e853b4 Merge branch 'master' into features/activity-form 2021-05-27 10:08:40 +02:00
e26e3ac67b Merge branch '59_parcours_resu_2' 2021-05-27 09:28:23 +02:00
562c72f7bb missing comma 2021-05-27 00:06:00 +02:00
6602e1b286 fix wording in timeline accompanying period test 2021-05-27 00:03:22 +02:00
b69aaeafd9 fix tests for search 2021-05-26 23:54:00 +02:00
aa473b5f70 fix errors on tests in person bundle 2021-05-26 23:25:36 +02:00
124e36b9d4 fix declaration of entity rendering 2021-05-26 22:58:28 +02:00
b88765c344 fix tests 2021-05-26 22:57:00 +02:00
f3427d6754 fix declaration of entity rendering 2021-05-26 22:56:35 +02:00
df00ac66f5 Merge remote-tracking branch 'origin/master' into fix-person-tests 2021-05-26 22:44:45 +02:00
2b12e61fbd Merge remote-tracking branch 'origin/fix-getParticipationsContainsPerson' into fix-person-tests 2021-05-26 22:38:25 +02:00
151e8deaeb fix some tests for person bundle 2021-05-26 22:37:37 +02:00
acbe93f9cf Merge remote-tracking branch 'origin/dune-risky' into fix-person-tests 2021-05-26 21:57:09 +02:00
358410cde1 Remove dead code 2021-05-26 19:44:58 +00:00
06c74ed5ed add menu into section 2021-05-26 21:14:42 +02:00
25c986cc61 fix rendering for timeline entries in center context 2021-05-26 18:10:51 +02:00
cad8174333 apply timelineSingleQuery on events 2021-05-26 18:05:02 +02:00
6c8f1f77ff improve flex-table and flex-box 2021-05-26 18:03:54 +02:00
75c586fbf8 fix documentation for timeline 2021-05-26 17:58:58 +02:00
2cb9dfc250 add tasks to global timeline 2021-05-26 17:50:54 +02:00
3b2d4142c1 Merge branch 'master' into 'gitlab-ci-fix-initialization'
# Conflicts:
#   phpunit.xml.dist
2021-05-26 14:33:58 +00:00
9a6bab7ba2 Update phpunit.xml.dist 2021-05-26 14:27:31 +00:00
c2bbee299c remove tests for person bundle 2021-05-26 13:56:42 +00:00
f4db9be557 remove tests for person, which are not fixed 2021-05-26 13:43:41 +00:00
5449efdd97 Increase memory for running phpunit 2021-05-26 13:35:38 +00:00
7896d288e7 Increase memory_limit for some operations 2021-05-26 13:31:25 +00:00
b98d6fa505 launch a bash command for debugging 2021-05-26 13:25:29 +00:00
e4d1b951a3 Merge branch 'fix-missing-dependency' into 'master'
Fix repositories - add typing - add missing methods - remove obsolete phpdoc

See merge request Chill-Projet/chill-bundles!60
2021-05-26 13:22:25 +00:00
ae8e5bc2e3 Merge branch 'master' into 'fix-accompanying-period-opening'
# Conflicts:
#   src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php
2021-05-26 13:11:23 +00:00
9b66f7a83f Merge branch 'fix_load_fixtures' into 'master'
Fix load fixtures

See merge request Chill-Projet/chill-bundles!66
2021-05-26 11:04:43 +00:00
Pol Dellaiera
13d5b7078e Prevent infinite loop and memory leak. 2021-05-26 10:44:35 +02:00
37996651c4 Search list with periods, html/scss refactoring 2021-05-26 00:09:25 +02:00
Marc Ducobu
679665d9db Handle parent deletion in associated tables (ThirdPartyBundle) 2021-05-25 23:47:15 +02:00
Marc Ducobu
1d4edd5b7b Handle parent deletion in associated tables (PersonBundle) 2021-05-25 23:46:05 +02:00
Marc Ducobu
f1c77277f3 Handle parent deletion in associated tables (MainBundle) 2021-05-25 23:45:08 +02:00
6264171c0c Merge branch 'period-in-list-result' into 59_parcours_resu_2 2021-05-25 22:00:58 +02:00
902d8b52d3 Merge branch 'master' into 59_parcours_resu_2 2021-05-25 21:51:06 +02:00
caeb75ce13 vue requestor component, flex-table design 2021-05-25 21:44:15 +02:00
2f27674e05 flex table (row) design 2021-05-25 20:40:05 +02:00
ce9070e641 redirect to resume page after confirm action 2021-05-25 19:09:50 +02:00
5350a09951 apply timeline for report 2021-05-25 19:07:09 +02:00
31252461c9 load vue banner component for each page of AccompanyingCourse context
* vue css and js loaded from layout.html.twig
* rename 'show' template to 'edit' template
* overwrite js block for 'edit' template (load all component, not only banner)
2021-05-25 19:05:51 +02:00
73790db700 Merge branch 'add-doctrine-dbal-configuration-in-the-bundle' into 'master'
Add Doctrine DBAL postgis configuration in the bundle.

See merge request Chill-Projet/chill-bundles!65
2021-05-25 16:52:23 +00:00
nobohan
72795be040 post new address - WIP 2021-05-25 17:54:21 +02:00
fc2a2da75f page blocs design 2021-05-25 15:36:07 +02:00
nobohan
e88e9b1a6f addresses: add groups annotation to Country, postal code & address reference 2021-05-25 15:07:32 +02:00
nobohan
f7dea7f041 address selection: fix leaflet icon anchor + css for the form 2021-05-25 15:07:32 +02:00
nobohan
57a35f88be addresses reference: remove the load Adressess references command (has moved to the Vendee app) 2021-05-25 15:05:52 +02:00
nobohan
1b1eb45d15 address: improve load addresse reference command" 2021-05-25 15:05:52 +02:00
nobohan
65859f62f3 address selection: filter addresses based on cities 2021-05-25 15:05:52 +02:00
nobohan
4cc308c936 address selection: filter cities based on country 2021-05-25 15:05:52 +02:00
nobohan
2f28cb16ef addresses: import address reference: add pagination and error handling 2021-05-25 15:05:52 +02:00
nobohan
73ee77b8b2 addresses: import reference address from WFS using httpClientInterface 2021-05-25 15:05:52 +02:00
nobohan
830cda64e0 addresses: add symfony http-client as a dependency 2021-05-25 15:05:52 +02:00
nobohan
3bc510d116 addresses: add pagination in WFS request (WIP) 2021-05-25 15:05:52 +02:00
nobohan
5f8a506c84 addresses: add postcode in address reference load command 2021-05-25 15:05:52 +02:00
nobohan
bbb9dc2561 address reference: command for loading addresse reference (WIP) 2021-05-25 15:05:52 +02:00
nobohan
b51575fc49 address selection: order preferred countries 2021-05-25 15:05:51 +02:00
nobohan
fee37b5af3 address selection: use API points for Country and PostalCode + remove obsolet Address Controller 2021-05-25 15:05:51 +02:00
nobohan
0afcf3d79e address selection: move marker on the leaflet map on update map 2021-05-25 15:05:51 +02:00
juminet
743b456030 Merge branch 'add-api-for-person' into 'master'
Add api for person

See merge request Chill-Projet/chill-bundles!61
2021-05-25 12:59:59 +00:00
0dbd42ba5b Merge branch '139_demandeur' into 'master'
139 suite et fin

See merge request Chill-Projet/chill-bundles!62
2021-05-25 12:39:00 +00:00
7efbf2fce8 59 résumé, flex person position 2021-05-25 10:49:11 +02:00
9b1a66c992 fix query in timeline in activity and person bundle 2021-05-25 09:48:19 +02:00
Pol Dellaiera
cb897cfef1 Move Doctrine DBAL configuration in the appropriate and already existing code section. 2021-05-25 08:05:18 +02:00
Pol Dellaiera
bafbc2dd74 Add Doctrine DBAL postgis configuration in the bundle.
This can now be removed totally from the user application.
2021-05-25 07:57:12 +02:00
74541f360b fix activity timeline using TimelineSingleQuery 2021-05-24 20:26:33 +02:00
20a14c9ff4 cleaning chillmain.scss 2021-05-24 13:19:37 +02:00
cdade50d76 display person and thirdparty informations in accompanyingCourse index template (twig) 2021-05-24 11:23:03 +02:00
d4f96ee25f add 'with_icon' option in twig address macro 2021-05-24 11:22:27 +02:00
ca33580831 improve how refresh height sum and anchors position 2021-05-23 14:41:53 +02:00
64e37c5235 corrections 2021-05-23 14:03:43 +02:00
bf576e171c corrections 2021-05-23 12:35:47 +02:00
3f2fe6a138 Merge branch '_sticky_nav' into 139_demandeur 2021-05-23 11:51:38 +02:00
f18ccce814 comment console.log 2021-05-23 11:51:02 +02:00
2386a35eb7 fix bottom page exception + listen size changes too in main container 2021-05-23 11:47:01 +02:00
1fbda740a7 stickNav map elements switch active when scrolling 2021-05-23 11:13:21 +02:00
d35e1fe21e stickyNav item in a subcomponent 2021-05-23 10:16:18 +02:00
771b9eb616 anchors wip 2021-05-23 00:49:02 +02:00
4261ddcde4 cleaning 2021-05-23 00:10:26 +02:00
6ee03b7ebb top computed 2021-05-23 00:07:43 +02:00
1217578202 fix absolute / fixed navbar position 2021-05-22 23:42:25 +02:00
c7b6788288 Merge branch '139_demandeur' into _sticky_nav 2021-05-22 09:58:55 +02:00
02f1d2ff8a rename subcomponent 2021-05-22 09:56:09 +02:00
bb677152c9 sticky nav better position 2021-05-21 23:45:48 +02:00
ad6519fb87 minimalist squares navmap 2021-05-21 22:59:51 +02:00
d08f2e0e11 referrer component 2021-05-21 22:59:06 +02:00
73aeca0916 allow to import existing person from normalizer 2021-05-21 20:24:24 +02:00
080a54231f Merge remote-tracking branch 'origin/master' into add-api-for-person 2021-05-21 20:19:38 +02:00
b403569b16 improve and clean socialIssues 2021-05-21 19:47:39 +02:00
3abfb02962 Merge branch '_multiselect_store' into 139_demandeur 2021-05-21 19:23:45 +02:00
11a6d08023 add reactives social issues in banner 2021-05-21 19:16:09 +02:00
69ecc42055 enable fetch post/delete socialIssues 2021-05-21 19:06:16 +02:00
5f74c5297a move subcomponents in subfolder 2021-05-21 19:03:42 +02:00
34fcefa1bd temporary fix to allow creation on persons without centers 2021-05-21 18:31:20 +02:00
c9e6935f15 fix requirements on POST route 2021-05-21 18:30:52 +02:00
21cc0007fb transformValue to payload, body and method 2021-05-21 18:24:32 +02:00
ebe3bc5f7b add route for creating a person, and post api 2021-05-21 18:05:03 +02:00
132f11298e now i have to find id+method from payload 2021-05-21 17:05:14 +02:00
21f75c8a63 dont use mapActions 2021-05-21 16:54:25 +02:00
c1e1f65715 action resolve commit payload, but fetch body+method 2021-05-21 16:44:59 +02:00
Pol Dellaiera
5cc5e6a1f7 Fix missing dependency. 2021-05-21 16:35:26 +02:00
Pol Dellaiera
1f4735caac Fix missing ::find method. 2021-05-21 16:35:13 +02:00
Pol Dellaiera
d672a29dda Remove obsolete documentation, fix typing here and there. 2021-05-21 16:34:42 +02:00
68ebd60bc8 options managed by data, not store 2021-05-21 16:22:33 +02:00
4d12796289 get options and display selected 2021-05-21 16:08:26 +02:00
857298b8b8 add api Method GET on person 2021-05-21 16:04:18 +02:00
220f1ea0eb Merge branch '139_demandeur' into 'master'
139 Demandeur

See merge request Chill-Projet/chill-bundles!43
2021-05-21 12:53:03 +00:00
a88acd34fd design and translations 2021-05-21 11:41:36 +02:00
8ae113c872 person search rendering more reponsive 2021-05-20 19:20:06 +02:00
098a2ea620 improve AccompanyingCourse ux design 2021-05-20 18:42:40 +02:00
6a62b46dec first impl 2021-05-20 17:41:37 +02:00
Jean-Francois Monfort
2bae684df9 Add list of activities in AccompanyingCourse Menu 2021-05-20 17:08:47 +02:00
8bd75429c1 improve AccompanyingCourse ux design 2021-05-20 16:45:47 +02:00
Jean-Francois Monfort
8fe00b4c2b Add / Edit / Delete activity from Accompanying Course 2021-05-20 15:56:34 +02:00
199e5a73d8 confirm modal "are you sure ?" 2021-05-20 15:43:10 +02:00
54d03275cf place html anchors: top, bottom of page + for each form section 2021-05-20 14:35:32 +02:00
8683f8faf3 titles: size and interaction 2021-05-20 13:24:53 +02:00
821b67723c Banner vue component fully manage AccompanyingCourse banner 2021-05-20 12:59:58 +02:00
ae1146c79c Confirm post request, change state step and hide components 2021-05-20 11:45:29 +02:00
050c325195 renaming AccompanyingCourse component in 'Banner' 2021-05-20 11:07:00 +02:00
5e0d869d9b Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-20 09:53:33 +02:00
Jean-Francois Monfort
c59cf3f0df Merge remote-tracking branch 'origin/139_demandeur' into features/activity-form 2021-05-20 08:57:32 +02:00
Jean-Francois Monfort
890b8db5dd Merge branch 'master' into features/activity-form 2021-05-20 08:20:10 +02:00
32b8de8997 implements trackable on accompanying period 2021-05-19 23:08:13 +02:00
9f1f7ad3f7 skeleton for page "index accompanying course" 2021-05-19 22:36:47 +02:00
9da4c1ebeb get SocialIssues List in multiselect 2021-05-19 22:20:16 +02:00
9b7a52064a page 'create a course' for draft accompanying course 2021-05-19 22:15:04 +02:00
faad3f5f47 add menu for creating an accompanying period 2021-05-19 21:48:40 +02:00
Pol Dellaiera
7595d70ada Fix ::getPersons.
1. Add more typing informations.
2021-05-19 19:10:03 +02:00
Pol Dellaiera
484259c8ab Fix ::canBeReOpened.
1. Fix call to `::getOpenParticipationContainsPerson` instead of `::getParticipationsContainsPerson`.
2. Use early returns to reduce cyclomatic complexity.
3. Avoid storing variable that are used only once.
2021-05-19 19:10:03 +02:00
Pol Dellaiera
a6e0b16032 Fix ::getOpenParticipationContainsPerson
1. The filter predicate must return a boolean
2. The $person variable is not needed
2021-05-19 19:10:03 +02:00
Pol Dellaiera
9d34968b88 Fix ::getParticipationsContainsPerson.
1. `::getParticipations()` does not accept any argument.
2. The filter predicate must return a boolean.
2021-05-19 19:10:03 +02:00
f548121312 wip 2021-05-19 18:29:24 +02:00
1ecb1abc80 Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-19 16:22:28 +02:00
28a45992c6 first vue multiselect implementation 2021-05-19 16:18:56 +02:00
c39097f164 removeComment button replaced by link
that allows to keep it both inside <form> and in <ul class="record_actions">
2021-05-19 16:18:56 +02:00
30b127bc88 vue-component dev style more discrete, + disable flashbag for comment 2021-05-19 16:17:57 +02:00
25d7fc36a4 action to create an accompanyinig period 2021-05-19 16:14:36 +02:00
03bd1674e1 fix resource repository 2021-05-19 16:13:19 +02:00
b018a50a7e encore_entry_link_tags allows to use <style scoped> in vue files 2021-05-19 16:07:37 +02:00
4440cf8a24 add missing declaration property 2021-05-19 16:00:06 +02:00
6bd7a0105d Merge branch 'quick-fix-crud' into 'master'
Crud : fix sprintf pbm

See merge request Chill-Projet/chill-bundles!55
2021-05-19 13:15:35 +00:00
Marc Ducobu
51c2408878 Crud : fix sprintf pbm 2021-05-19 15:00:13 +02:00
242c77a30c partially revert 75ba07f18 (17/05) 2021-05-19 13:40:51 +02:00
22aa4afc02 action: confirm accompanying period + create workflow 2021-05-19 13:20:59 +02:00
04e9e30972 quick fix for banner 2021-05-19 11:44:09 +02:00
d536da3581 initialcomment: conditionnal delete button 2021-05-19 10:37:29 +02:00
27f49b2aa3 fix initialComment with patch endpoint 2021-05-19 10:34:17 +02:00
912a8d53af Merge branch 'fix_issue_43_add_entities' into 'master'
LoadFixtures, replacing Array() by []

See merge request Chill-Projet/chill-bundles!54
2021-05-18 18:13:41 +00:00
9ef397e935 fix docblock 2021-05-18 20:12:03 +02:00
eca8172c6d doc for multi-types denormalizer 2021-05-18 20:11:49 +02:00
f3802e36b3 documentation for api 2021-05-18 19:58:29 +02:00
2f9c7c38b5 fix read group on scope 2021-05-18 19:58:16 +02:00
Marc Ducobu
d73fd697dd Array() -> [] 2021-05-18 19:21:52 +02:00
f35889339d remove comment in constructor 2021-05-18 19:20:50 +02:00
8e95166c24 fix replacing an initial comment in accompanying period 2021-05-18 19:19:22 +02:00
30c53b17f7 documentation for get/index social issues api endpoint 2021-05-18 19:13:30 +02:00
2610730219 add initial comment to accompanying period 2021-05-18 19:04:09 +02:00
5dd99d201b Merge remote-tracking branch 'origin/master' into 50-ajout-problematique-sociale-modele 2021-05-18 17:30:28 +02:00
d327dae9fa Merge remote-tracking branch 'origin/139_demandeur' into 139_demandeur 2021-05-18 17:24:28 +02:00
2bdbb20154 Merge remote-tracking branch 'origin/master' into 139_demandeur 2021-05-18 17:24:09 +02:00
14bd211a5f add api endpoint for adding/remove social issue on accompanying period 2021-05-18 17:18:35 +02:00
35627203e6 remove props for ToggleFlags component 2021-05-18 16:23:40 +02:00
f978636d57 add intensity in teleported toggleFlags 2021-05-18 16:14:10 +02:00
e095cac7e0 Merge branch '50-ajout-problematique-sociale-modele' into 139_demandeur 2021-05-18 16:11:18 +02:00
c5b0d6e2bd Merge branch '20-use-fqdn-in-person-creation-form' into 'master'
Use FQDN in PersonCreation form

See merge request Chill-Projet/chill-bundles!52
2021-05-18 14:06:57 +00:00
Pol Dellaiera
905cb66011 Merge branch 'fix-services-repository-loading' into 'master'
Update repositories service discovery.

See merge request Chill-Projet/chill-bundles!34
2021-05-18 12:13:34 +00:00
eaac97221f add many2many relation between socialIssue and accompanying period + api endpoint 2021-05-18 13:48:11 +02:00
Pol Dellaiera
893c38fba4 Fix collateral things. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
f867f4985d Add a note about the custom service definition for the repository. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
aebeefcf80 Use repositories as services. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
3fc6c0c479 refactor: Update entities. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
ce854cb58f refactor: Upgrade repositories. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
ed4f1344c2 Service autodiscovery, autowire and autoconfigure. 2021-05-18 12:02:00 +02:00
Marc Ducobu
86dbe527d8 Adding missing arguments for services 2021-05-18 12:02:00 +02:00
Pol Dellaiera
69a56fb433 Update repositories service discovery. 2021-05-18 12:02:00 +02:00
Pol Dellaiera
a7fad0ca1b tests: Update relevant tests but it seems that it is currently broken. 2021-05-18 12:00:58 +02:00
Pol Dellaiera
9b8c34a9be Symfony form: use FQDN instead of custom constant. 2021-05-18 12:00:58 +02:00
5acc78507e building Confirm component 2021-05-18 10:59:06 +02:00
1722cf721e init SocialIssue, Referrer and Confirm components 2021-05-18 09:57:10 +02:00
75ba07f181 course banner: opening date by user 2021-05-17 22:50:28 +02:00
5b635fbe58 fix input value for radio selection in AddPersons modal
selected value is different for radio or checkbox
for radio value is an object, for checkbox vaue is an array of objects
2021-05-17 22:19:23 +02:00
e0dc0a8fdb add Comment component, make POST comment request 2021-05-17 16:10:36 +02:00
2aa13dceff catchError mutation 2021-05-17 15:56:14 +02:00
ea477a9842 add accompanying period opening/closing to global timeline 2021-05-17 13:24:50 +02:00
73653744d7 Prepare for deprecation of class Role, and add method to filter centers 2021-05-17 13:23:58 +02:00
55264da092 prepare postComment fetch request 2021-05-17 12:05:46 +02:00
38f5854c6d AddPersons, move/rename files 2021-05-17 12:04:22 +02:00
3c6d3f30d2 teleport toggle flags in header 2021-05-17 11:25:20 +02:00
a6d6a962cd Merge branch 'issue_43_add_entities' into 'master'
Add fixtures for social work

See merge request Chill-Projet/chill-bundles!46
2021-05-17 08:24:36 +00:00
6256d6a19e Apply 1 suggestion(s) to 1 file(s) 2021-05-17 08:23:21 +00:00
8841af8d2b remove references to no-static container 2021-05-17 10:07:23 +02:00
0a9b8ba0b0 remove test that concerns old code 2021-05-17 10:05:03 +02:00
9710f8be63 display resources table row 2021-05-14 21:25:30 +02:00
d872bf65dd reactive toggle flags emergency and confidential 2021-05-14 20:42:22 +02:00
c3ef8d112c first impl for global timeline: apply on activities 2021-05-14 16:25:56 +02:00
f2a4347de7 Merge branch 'master' into fix-person-tests 2021-05-14 10:24:35 +02:00
51a4880fdb Merge branch 'fix-gitlab-ci-with-postgis' into 'master'
Update .gitlab-ci.yml - change db image

See merge request Chill-Projet/chill-bundles!51
2021-05-14 08:24:10 +00:00
a4d22b0fcb Update .gitlab-ci.yml - change db image 2021-05-14 08:16:28 +00:00
8d051800a4 Merge branch 'fix-accompagnyingperiod' into 'master'
Make sure the called method has the proper name.

See merge request Chill-Projet/chill-bundles!48
2021-05-14 07:58:33 +00:00
Pol Dellaiera
c0b59162a1 Rename ::participationsContainsPerson($person); in ::getParticipationsContainsPerson($person);. 2021-05-14 08:32:22 +02:00
0e53a081c7 Merge branch 'fix-person-tests' into 139_demandeur 2021-05-13 21:44:22 +02:00
d76f6d716f exclude tests which concerns exports for persons 2021-05-13 21:44:09 +02:00
f1d5d9840e add route for scope on participation 2021-05-13 17:44:54 +02:00
f3eb418409 test sur création et retrait commentaire 2021-05-13 17:31:46 +02:00
3e85529468 add route for comment + track update/creation of entities 2021-05-13 17:25:24 +02:00
05798688d0 refactore method addRemoveSomething, and add test for resources 2021-05-13 16:29:05 +02:00
01f35eed04 rename all interlocutor in resource 2021-05-13 11:09:07 +02:00
aef97cca32 fetch post resource 2021-05-13 10:59:24 +02:00
87e2ac9386 handling multi types and acc-period/repositories endpoint 2021-05-13 00:54:44 +02:00
4a04628d5b adapt payload body to entity convention with type + id 2021-05-12 18:50:18 +02:00
0af78f814c Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-12 18:34:03 +02:00
929d40ff6e add particiaption to openapi 2021-05-12 18:32:15 +02:00
68f6642ff2 Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-12 17:52:49 +02:00
91e4d585ff add a discrimnator type on onbjects 2021-05-12 17:51:37 +02:00
eac42581a6 interlocutors: actions, mutations, fetch request (wip) 2021-05-12 17:40:23 +02:00
Marc Ducobu
4e50d0ace9 Merge branch 'fix-style-stuff2' into 'master'
Fix style stuff2

See merge request Chill-Projet/chill-bundles!47
2021-05-12 14:06:46 +00:00
Marc Ducobu
0b54adeb59 Removing spaces at the end of line 2021-05-12 16:04:42 +02:00
Marc Ducobu
5d23de4862 Removing spaces at the end of line 2021-05-12 16:04:27 +02:00
Marc Ducobu
eda454cb9d Add fixtures for social work 2021-05-12 15:40:40 +02:00
6da8f1c107 when passed option uniq, suggestions are with radio button, not checkbox 2021-05-12 15:26:46 +02:00
4fb487dcef requestor logic, is_anonymous patch request 2021-05-12 14:49:26 +02:00
0d6a339b53 Merge branch '_23_addresses_form_2' into 139_demandeur 2021-05-12 10:45:47 +02:00
c6525be444 get countries when opening modal + fix select placeholders 2021-05-12 10:43:12 +02:00
cb846891d6 add store postAddress fetch request 2021-05-12 09:54:37 +02:00
2aed37757e Merge branch '_23_addresses_form_2' of gitlab.com:Chill-Projet/chill-bundles into _23_addresses_form_2 2021-05-11 23:53:50 +02:00
444159b52a cleaning AddAdress refactor 2021-05-11 23:52:56 +02:00
7aed8e83ea refactoring AddAddress component 2021-05-11 23:41:32 +02:00
f7a807473d send 400 bad request on invalid json 2021-05-11 21:30:24 +02:00
f8e91c325d oups, forget a flush :) 2021-05-11 21:20:30 +02:00
a448405ce5 Add a denormalizer for fetching entities by id 2021-05-11 20:37:56 +02:00
a4989f99d6 Use annoations for serialization 2021-05-11 19:49:41 +02:00
3f64db3b3a remove 'u' from date normalizer 2021-05-11 19:11:22 +02:00
nobohan
7ee5ca0753 address selection: add API points for PostalCode and Country 2021-05-11 16:03:11 +02:00
41254db72f Merge branch '139_demandeur' into _23_addresses_form_2 2021-05-11 15:51:06 +02:00
nobohan
15e301b889 address selection: add more fields 2021-05-11 15:32:02 +02:00
061a7dd537 patch request for accompanying period 2021-05-11 15:05:26 +02:00
nobohan
c3926991ac address selection: fix leaflet icon url + others fix (WIP) 2021-05-11 14:56:56 +02:00
nobohan
ea0b2407df address selection: add leaflet css + add fields for the address extra information (WIP)' 2021-05-11 13:50:11 +02:00
569679238c add InterlocutorItem subcomponent 2021-05-11 13:49:43 +02:00
ed17f78da5 requestor, add checkbox isAnonymous 2021-05-11 13:48:40 +02:00
dfd9230541 Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-11 12:52:03 +02:00
65b751642f documentation for api 2021-05-11 10:33:52 +02:00
d6fd827f8b interlocutors wip 2021-05-10 22:02:21 +02:00
162b0099b2 addpersons modal title from outside component 2021-05-10 21:42:02 +02:00
e0b689174a oups 2021-05-10 19:19:11 +02:00
edf4430fb1 Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-10 19:15:03 +02:00
040884a039 when option uniq is true, display message if you select multiple suggestions 2021-05-10 19:13:50 +02:00
f7c08f02c2 add and remove requestor functions 2021-05-10 18:46:21 +02:00
nobohan
2fe38945d2 Address selection: add a leaflet map 2021-05-10 17:31:22 +02:00
cece152c0b fix test for api requestors 2021-05-10 17:04:34 +02:00
4e31b3e424 Merge branch '139_demandeur' of gitlab.com:Chill-Projet/chill-bundles into 139_demandeur 2021-05-10 16:36:32 +02:00
109bf5ec5d suggestions, flex position for little screens + thirdparty links 2021-05-10 16:33:41 +02:00
4f3f16d9b0 Set requestor for accompanying period 2021-05-10 15:59:58 +02:00
nobohan
fe5745831c Address selection: add selectCountry and selectCity components 2021-05-10 15:21:38 +02:00
3447117742 fix postParticipation with new search endpoint structure 2021-05-10 14:17:48 +02:00
143f8f43fa pass options in search endpoint 2021-05-10 14:02:25 +02:00
36326a2a70 improve suggestions display, with more details, and different according to the entity 2021-05-10 13:27:41 +02:00
52637c2919 rewrite method add participation for new period's methods 2021-05-10 13:24:57 +02:00
f3a8552829 rewrite methods for participation 2021-05-10 13:21:28 +02:00
bfdfd19711 add uniq key property, allow multiple entity in suggestions 2021-05-10 13:11:58 +02:00
nobohan
efb9bc938a Address selection: add store + addressSuggestion 2021-05-10 12:12:04 +02:00
dcd1856ebb adapt api endpoint, resolve id parameter passed in api functions 2021-05-10 10:47:21 +02:00
43f3270171 add requestor, wip 2021-05-09 09:24:02 +02:00
b7fcac8f39 Merge branch 'selectAll' into addPersons_nostore 2021-05-09 09:16:12 +02:00
e521d06702 addpersons better ux with reset and selectall features 2021-05-09 09:11:49 +02:00
a260274549 addpersons better ux with reset features 2021-05-09 00:39:18 +02:00
b37a7d2690 requestor call AddPersons modal, and pass options until api (wip) 2021-05-08 21:14:46 +02:00
242c2b31a3 remove store AddPersons module 2021-05-08 20:59:47 +02:00
57c420e9dd no store for AddPersons, move store in data component
note: this allow to use same addPersons component
to add participations, requestor, or interlocutors.
each addPersons component has his own data()
2021-05-08 20:58:46 +02:00
ac67f56b09 bind options and key inside AddPersons component (wip) 2021-05-08 15:34:15 +02:00
b24eb93c57 addNewPersons() method is called out of addPerson component
note: this allow to use same addPersons component
to add participations, requestor, or interlocutors
2021-05-08 12:12:58 +02:00
0f59be04a7 accompanyingCourse steps, flags, .. translations and pills appearence 2021-05-08 11:42:42 +02:00
54eb15ea35 disable close participation button when is closed 2021-05-08 11:20:53 +02:00
a85f170e2d fix delete route change + fix closeParticipation row position 2021-05-08 10:56:43 +02:00
226f71ab2b requestor, just display datas 2021-05-07 21:37:14 +02:00
a887326611 Merge remote-tracking branch 'origin/136-add-search-endpoint' into 139_demandeur 2021-05-07 19:27:19 +02:00
8ed2e7585d fix random thid party 2021-05-07 19:22:47 +02:00
7a1ad24f0e add endoint /api/1.0/search.json?q=xxx with fake data
See https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/136
2021-05-07 19:11:10 +02:00
nobohan
b934c2eeaf add POC of a vuejs component (opens a modal) for address selection 2021-05-07 17:38:15 +02:00
de0e3f7dfd move test in a test component, clean requestor component 2021-05-07 16:53:29 +02:00
44c9a65505 cleaning console log 2021-05-07 16:22:02 +02:00
038d7ad2e1 load third party fixtures 2021-05-07 16:07:53 +02:00
nobohan
c1b727b1c8 Add API endpoints for Address and AddressReference (again) 2021-05-07 16:02:39 +02:00
a63c38b6aa Merge branch '37_modal_add-persons' 2021-05-07 15:46:38 +02:00
8915c42008 endpoint DELETE participation works ! 2021-05-07 15:44:08 +02:00
503293a359 Merge branch 'master' into '37_modal_add-persons'
# Conflicts:
#   src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php
#   src/Bundle/ChillPersonBundle/chill.webpack.config.js
2021-05-07 13:35:48 +00:00
7bdf71315a move Modal component in ChillMainAssets 2021-05-07 15:28:50 +02:00
6f5d457122 renaming store state dict name 2021-05-07 15:16:27 +02:00
b4274264a7 create addPersons store module, move state/getters/mutations/actions in module 2021-05-07 15:04:36 +02:00
8002725c87 fix doc for api 2021-05-07 12:42:49 +02:00
2c9edf3741 Set Collection normalization to fit into specs from https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/136 2021-05-07 12:13:24 +02:00
3f562449e1 Merge branch 'issue23_addresses' into 'master'
Issue23 addresses

See merge request Chill-Projet/chill-bundles!12
2021-05-07 09:27:56 +00:00
1cce39bcb5 Merge branch 'bootstrap-api' into 'master'
Bootstrap api

See merge request Chill-Projet/chill-bundles!35
2021-05-07 09:14:11 +00:00
c93d5ceb16 remove references to ->getContainer in favor of static:: 2021-05-07 10:56:49 +02:00
ad690db886 display reset link + minor changes 2021-05-07 10:36:50 +02:00
nobohan
1b8462b40d update validto field in chill_main_address for legacy 2021-05-07 10:27:11 +02:00
Pol Dellaiera
8c98f2cf6e Update .gitignore file. 2021-05-07 09:04:29 +02:00
f3260f57a4 fix display elements order
selectAndSuggested method in store getter, is callable in all components,
and make union of two arrays: suggested and selected

* we need to have selected in last position (required for isChecked method to work well)
* but we want to display selected in first position (for better ux)

then, we use double inversion to obtain good behaviour
2021-05-06 19:23:28 +02:00
b4ad0128e4 manage selected and suggested arrays: fix duplicate 2021-05-06 19:15:25 +02:00
e1c8278f71 Merge branch 'fix-return-type' into 'master'
Fix return type of Person::getAddresses().

See merge request Chill-Projet/chill-bundles!39
2021-05-06 15:05:35 +00:00
Pol Dellaiera
ed3f46ce7f Fix return type. 2021-05-06 17:01:11 +02:00
Jean-Francois Monfort
1f838d9c5a Fix Activity fixtures 2021-05-06 16:23:34 +02:00
33457d3cbc Merge branch 'fix-accompanying-period-opening' into bootstrap-api 2021-05-06 16:02:13 +02:00
6df8e6dec8 add person suite to phpunit 2021-05-06 15:55:02 +02:00
f9b8f13dd6 Merge branch 'fix-accompanying-period-opening' into fix-person-tests 2021-05-06 15:50:34 +02:00
e919b4322e fix accompanying period/remove person 2021-05-06 15:49:38 +02:00
7503c845df Merge branch 'dev-undefined-index' into 'master'
fix undefined index in person edit form

See merge request Chill-Projet/chill-bundles!26
2021-05-06 13:47:13 +00:00
Jean-Francois Monfort
c6cd785262 add Translations 2021-05-06 15:09:38 +02:00
Jean-Francois Monfort
e453e24203 Merge branch 'master' into features/activity-form 2021-05-06 14:01:03 +02:00
3686a294d3 fix return type for person::getAddresses 2021-05-06 13:57:44 +02:00
Jean-Francois Monfort
115a14fcba Merge branch 'master' into features/activity-form 2021-05-06 13:52:03 +02:00
Jean-Francois Monfort
fc172fdb1f Add documents to Activity Form 2021-05-06 13:40:25 +02:00
b6131379f9 Merge remote-tracking branch 'origin/master' into bootstrap-api 2021-05-06 13:20:12 +02:00
e1fcc41ace avoiding duplicates between selected and suggested (wip)
see comments in store/index.js
2021-05-06 13:16:26 +02:00
f2a04cebe6 configure origin route into chillMainExtension 2021-05-06 13:12:18 +02:00
c693002ddb documentation for api - prepend config 2021-05-06 13:11:59 +02:00
ee77c8540a fix typos 2021-05-06 13:00:59 +02:00
a536d2780e fix state mutation for closeParticipation 2021-05-06 12:57:53 +02:00
f880598052 documentation for api 2021-05-06 12:56:19 +02:00
e7985ea52f customize controller for origin 2021-05-06 12:55:40 +02:00
f56dc65021 fix argument order 2021-05-06 12:55:12 +02:00
nobohan
4770758aee add migrations for addresse on household + add linkedtothirdparty on address 2021-05-06 12:36:58 +02:00
90fe484d81 fix api for rendering a single item 2021-05-06 12:18:47 +02:00
2b8bbe019d first impl for index action 2021-05-06 12:08:45 +02:00
Jean-Francois Monfort
1f1b9c594f add ordoring field & Display Activity type by Category 2021-05-06 11:53:07 +02:00
9e1c151402 réinitialize suggested, avoiding double with selected (wip) 2021-05-06 10:57:04 +02:00
088e522292 Merge branch 'master' into _31_interface_creation_parcours 2021-05-06 10:55:22 +02:00
Jean-Francois Monfort
f836114d84 Fix travelTime field 2021-05-06 10:51:17 +02:00
b8e6e98a74 fix payload error with add participation 2021-05-06 10:44:15 +02:00
Jean-Francois Monfort
4fd13440c6 Modernize ActivityController 2021-05-06 10:03:49 +02:00
Jean-Francois Monfort
4d8afd53ad Form & save into DB 2021-05-06 09:36:03 +02:00
2db847ada2 Merge branch 'drupol-fix-person-addresses' into 'master'
Fix person addresses

See merge request Chill-Projet/chill-bundles!33
2021-05-06 07:14:54 +00:00
07e0692783 bootstrap api and apply on accompanying period 2021-05-06 00:14:36 +02:00
e78d53064b closeParticipation fetch DELETE request 2021-05-05 21:48:00 +02:00
e6fcb5ff22 Merge branch '_test_closePerson' into _31_interface_creation_parcours 2021-05-05 20:47:39 +02:00
f02e33fda7 first impl for api 2021-05-05 20:33:34 +02:00
1bbec9efae improve addpersons store cycle: init query, selections and suggestions 2021-05-05 19:25:28 +02:00
3b53c4451c fix modal ux counter position 2021-05-05 18:45:51 +02:00
30f490959b for each selected, loop for post participation, then get response and commit state 2021-05-05 18:44:26 +02:00
nobohan
0a894b0db1 add new fields on Address and Household 2021-05-05 18:24:58 +02:00
c20e9507d5 prepare close participation button (wip) 2021-05-05 15:03:58 +02:00
f89c690f1b add scratch fontawesome 'remove' button 2021-05-05 13:36:45 +02:00
Pol Dellaiera
7819c1204c Merge branch '4-remove-unused-main-test-route' into 'master'
Issue #4: Remove obsolete route.

Closes #4

See merge request Chill-Projet/chill-bundles!31
2021-05-05 10:30:03 +00:00
nobohan
f61af9d02a add household and householdmembers entities + migration 2021-05-05 11:44:55 +02:00
Pol Dellaiera
e470a6a97e Merge remote-tracking branch 'tmp/fix-person-last-address' into drupol-fix-person-addresses 2021-05-05 11:24:18 +02:00
Pol Dellaiera
cd8c47449b Issue #4: Remove obsolete route. 2021-05-05 11:11:25 +02:00
120e7cade5 simplify store suggested array 2021-05-05 11:11:13 +02:00
ac550e05e8 improve addPersons modal ux 2021-05-05 09:29:57 +02:00
d6e7fadb4f Merge branch 'issue_43_admin_prosoc' into 'master'
URGENT : Fix namespace pbm

See merge request Chill-Projet/chill-bundles!30
2021-05-05 07:00:05 +00:00
Marc Ducobu
2be1c08c44 Fix namespace pbm 2021-05-04 19:14:50 +02:00
nobohan
86c177bbbb remove vuejs address component 2021-05-04 17:26:47 +02:00
Pol Dellaiera
d426d28ba0 Merge branch 'add-readme' into 'master'
docs: Add root README file.

See merge request Chill-Projet/chill-bundles!29
2021-05-04 13:14:14 +00:00
Pol Dellaiera
72e69fc0b3 docs: Add root README file. 2021-05-04 14:49:36 +02:00
cc8de353d4 moving selected counter + cleaning code 2021-05-04 10:48:58 +02:00
4495a5d33b Union suggested and selected results 2021-05-03 23:15:38 +02:00
9dffe30aad Merge branch '_31_interface_creation_parcours' of gitlab.com:Chill-Projet/chill-bundles into _31_interface_creation_parcours 2021-05-03 22:53:47 +02:00
d393e74896 save checkboxes state in store 2021-05-03 22:44:28 +02:00
daf083dc88 save checkboxes state in store 2021-05-03 21:02:15 +02:00
nobohan
ce859697b5 Use json endpoint for showing address with Vuejs Components (WIP) 2021-05-03 17:16:45 +02:00
nobohan
1587c762f8 better fixture for AddressReference 2021-05-03 14:34:23 +02:00
nobohan
17c01d9b46 fix fixture for address reference 2021-05-03 12:18:21 +02:00
a1bb9ea352 modal addPerson design, search field: focus and position fixed 2021-05-03 11:52:06 +02:00
nobohan
a1895ec65f fixture for addressReference - WIP 2021-05-03 11:18:31 +02:00
nobohan
c5faa0b99d update the address fixture by adding some points 2021-05-03 09:28:05 +02:00
nobohan
e9d142f3e8 define legacy functions for Address 2021-05-03 09:28:05 +02:00
nobohan
91860afd80 check if point value is null for 2 methods in PointType 2021-05-03 09:28:05 +02:00
nobohan
bec0700d39 Point model: better handling of exception 2021-05-03 09:28:05 +02:00
nobohan
05d3d7f5c7 update twig template and AddressType following the changes in Address entity 2021-05-03 09:28:05 +02:00
nobohan
ebff36d257 add unit test for class Point 2021-05-03 09:28:05 +02:00
nobohan
a709b3afb6 add addressReference in Chill Main + migration 2021-05-03 09:28:05 +02:00
nobohan
69a3c6a9b2 refine the migration comment 2021-05-03 09:28:05 +02:00
juminet
8c33d876e8 code formatting in PointType 2021-05-03 09:28:05 +02:00
nobohan
1ec2fbcc16 translated exception messages in English 2021-05-03 09:28:05 +02:00
juminet
bc4e29141b syntax (null -> NULL and == -> ===) 2021-05-03 09:28:05 +02:00
nobohan
e90ea31683 add type hinting in Point and PointException 2021-05-03 09:28:05 +02:00
juminet
7c99f0b3e0 array synatx: array() -> [] 2021-05-03 09:28:05 +02:00
nobohan
c089960707 add type hinting in Point and PointException 2021-05-03 09:28:05 +02:00
nobohan
0b2f29f1e8 add migration for address 2021-05-03 09:28:05 +02:00
nobohan
9a4f50472a add point type + Address: add Point field : fix dependency injection of the Point type 2021-05-03 09:28:05 +02:00
nobohan
7d1a1c4004 #32 add point type + Address: add Point field + add null on nullable fields 2021-05-03 09:28:05 +02:00
nobohan
ebd58d4229 add more fields to Address entity + rename streetAddress1 and streetAddress2 2021-05-03 09:25:41 +02:00
nobohan
dd48795f64 #23 enable postgis in a chil main migration 2021-05-03 09:25:41 +02:00
3d45b6687f adding addPersons component with modal, search field and basic suggestions 2021-04-30 23:18:57 +02:00
35e6d36ce0 fetch postParticipation request, catch fetch error, store mutation+action 2021-04-30 16:33:49 +02:00
4900c81c11 improve inheritance with translations i18n.js files
vue-i18n --> chill main i18n ---( )---> app index
chill bundle i18n --> app i18n --^
2021-04-30 16:32:06 +02:00
52472b0ec3 Merge branch 'fix-tests-main' into 'master'
Fix tests for chill main bundle

See merge request Chill-Projet/chill-bundles!24
2021-04-29 22:35:47 +00:00
ec68e6f761 make inheritance for vue translations i18n.js files
By importing only the app i18n file,
we benefit from the whole inherited chain:

app i18n < chill bundle i18n < chill main bundle i18n
2021-04-29 18:32:22 +02:00
Jean-Francois Monfort
82d8556f24 Activity Form : display field according to the parameters 2021-04-29 16:35:39 +02:00
25bd170f6b improve modal system, test when a modal call next modal 2021-04-29 15:49:25 +02:00
6939b4a313 Merge branch 'master' into _31_interface_creation_parcours 2021-04-29 14:19:02 +02:00
d18922ed98 permit multiple modals in same component 2021-04-29 14:04:40 +02:00
e8bf242c42 Merge branch '_31_interface_creation_parcours' of gitlab.com:Chill-Projet/chill-bundles into _31_interface_creation_parcours 2021-04-29 12:44:29 +02:00
2050460bb3 add modal system, added/removed managed by vue, appearence managed by bootstrap
Modal component is an hybrid solution between :
- Vue3 modal implementation
  => with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
  => with slot we can pass content from parent component
  => some classes are passed from parent component
- Bootstrap 4.4 _modal.scss module
  => using bootstrap css classes, the modal have a responsive behaviour,
  => modal design can be configured using css classes (size, scroll)

See
* https://v3.vuejs.org/examples/modal.html#modal-component
* https://github.com/bootstrap-vue/bootstrap-vue/issues/5196
2021-04-29 12:40:28 +02:00
nobohan
4add30e895 add fixture for parcours: replace createQuery by createQueryBuilder 2021-04-29 12:23:41 +02:00
e1dbfdafd7 test modals with vue and modals with bootstrap 2021-04-28 22:01:05 +02:00
75becb2294 Merge branch '_31_interface_creation_parcours' of gitlab.com:Chill-Projet/chill-bundles into _31_interface_creation_parcours 2021-04-28 21:58:52 +02:00
94e494361f adding show/edit links (prepare modal) + save button 2021-04-28 18:00:46 +02:00
cab3b1059d ChillMainBundle: use localize function 2021-04-28 15:56:50 +02:00
nobohan
d27bdf68fb Merge branch '_31_interface_creation_parcours' of https://gitlab.com/Chill-Projet/chill-bundles into _31_interface_creation_parcours
merge..
2021-04-28 12:24:29 +02:00
nobohan
82b82920e1 add 2 fixtures for parcours 2021-04-28 12:24:25 +02:00
4bb3eadf91 renaming vuejs root dir 2021-04-28 11:41:15 +02:00
4c82e65c1f Merge branch '14-correctif-creation-personne' into 'master'
Use injected EntityManager - fix property visibility.

See merge request Chill-Projet/chill-bundles!25
2021-04-28 08:36:34 +00:00
cf4d7df7ad Merge branch 'bootstrap-serializer' into 'master'
Bootstrap serializer

See merge request Chill-Projet/chill-bundles!17
2021-04-28 08:32:02 +00:00
86d13410c3 Merge branch 'bootstrap-serializer' into fix-tests-main 2021-04-28 10:29:53 +02:00
19fdf2a503 Add test for AccompanyingCourseController 2021-04-28 10:28:10 +02:00
3a0c25c871 fix addPerson feature with vue3+store+i18n 2021-04-28 10:10:16 +02:00
083338da8d Merge branch 'master' into _31_interface_creation_parcours 2021-04-28 08:54:20 +02:00
37e5c9ceaa Merge branch '_31_interface_creation_parcours' of gitlab.com:Chill-Projet/chill-bundles into _31_interface_creation_parcours 2021-04-28 08:49:32 +02:00
Pol Dellaiera
5448238697 Set final keyword - remove redundant information in phpdoc. 2021-04-28 07:21:19 +02:00
Pol Dellaiera
c5250a1059 Use injected EntityManager - fix property visibility. 2021-04-27 23:07:59 +02:00
b2c1a7b8de Merge remote-tracking branch 'origin/master' into fix-tests-main 2021-04-27 22:50:32 +02:00
49c6915c0a Merge branch 'vendee_27' into 'master'
Vendee 27

See merge request Chill-Projet/chill-bundles!21
2021-04-27 20:49:59 +00:00
b4583fc6dc improve serializers 2021-04-27 22:48:48 +02:00
f7c508939c Add test for AccompanyingCourseController 2021-04-27 22:40:00 +02:00
4cf77a9b0e adapt multi components to new store and new api endpoints
* base of i18n (yarn add new deps)
2021-04-27 22:03:39 +02:00
a2160bef7d WIP: first implementation for test 2021-04-27 19:33:34 +02:00
nobohan
c2a4a95eba add a fixture for accompanying period - wip 2021-04-27 18:52:37 +02:00
8641d6bdce try to fix correct values for redis 2021-04-27 18:06:58 +02:00
5f4d513aa6 try to connect to redis in gitlab-ci 2021-04-27 17:57:09 +02:00
f47b15de39 try to fix .gitlab-ci with correct redis parameters 2021-04-27 17:52:12 +02:00
7426dc02cf currently restrict to chill main test suite 2021-04-27 17:18:46 +02:00
a570160aed update chill app to working commit 2021-04-27 17:18:26 +02:00
6e81ef0065 tests: update chill-app subprojet ref 2021-04-27 17:09:41 +02:00
e3cc76c689 tests/ChillPersonBundle: use type casting 2021-04-27 17:03:31 +02:00
b43f43fa0b ChillPersonBundle: persist new Persons 2021-04-27 16:53:57 +02:00
7596bd5a06 fix tests for chill main 2021-04-27 16:33:44 +02:00
f02d6df262 tests/ChillPersonBundle: in sf4 container is a static method of KernelTestCase 2021-04-27 15:15:41 +02:00
e4e2138765 tests/ChillPersonBundle: replace testGenderIsNull with crafted form as html input now prevents user form not selecting a gender 2021-04-27 15:15:41 +02:00
395735e6f7 tests/ChillPersonBundle: remove broken obsolete testFirstnameTooLong, html input and doctrine contrains are working 2021-04-27 15:15:41 +02:00
2c96c02261 tests/ChillPersonBundle: the gender input has three options: man, women and undefined 2021-04-27 15:15:41 +02:00
53813f8f29 tests/ChillPersonBundle: use mutualized getClientAuthenticated() 2021-04-27 15:15:41 +02:00
Marc Ducobu
b8ef0d28f5 Migration for AccompanyingPeriodWork, AccompanyongPeriodWokGoal & SocialWork/Evaluation 2021-04-27 15:15:02 +02:00
Marc Ducobu
e973c4013f Correct namespace 2021-04-27 15:11:31 +02:00
01f9d03b14 init vuex store 2021-04-27 15:11:13 +02:00
Marc Ducobu
0f9a395dfc Entites for AccomanyingPeriodWork, AccomanyingPeriodWorkGoal & Social/WorkEvaluation 2021-04-27 15:10:56 +02:00
Marc Ducobu
38ac3badef Integration rmq Julien 2021-04-27 11:24:26 +02:00
Marc Ducobu
cda32fb925 Pbm migration double 2021-04-26 17:19:10 +02:00
Marc Ducobu
58cb34f39b Creation of entities : SocialIssue / Social Action / Result / Goal 2021-04-26 17:09:54 +02:00
66426f5102 serializer on accompanying course
Two new routes:

* `GET /{_locale}/person/api/1.0/accompanying-course/{parcours_id}/show.json`: get a json representation for a course
* `POST /{_locale}/person/api/1.0/accompanying-course/{parcours_id}/participation.json`:
add a particitipation to course. Usage:

    `curl -v --cookie "PHPSESSID=fed98aa23e40cb36e630f84155aea3bb;" -X
POST --data '{ "id": 481 }'
http://localhost:8001/fr/person/api/1.0/accompanying-course/270/participation.json`

    Will add the person with id "481" to the course.
2021-04-26 17:01:22 +02:00
Jean-Francois Monfort
45671bda52 Merge branch 'features/activity-model' into features/activity-form 2021-04-22 16:26:59 +02:00
Jean-Francois Monfort
934eef4db4 Merge branch 'master' into features/activity-model 2021-04-22 16:13:05 +02:00
Jean-Francois Monfort
31e8dea965 Add missing fields & migrations 2021-04-22 15:33:13 +02:00
Jean-Francois Monfort
05ebdefd47 Add missing fields & migrations 2021-04-22 14:47:00 +02:00
Jean-Francois Monfort
c233c481b6 WIP Activity Model 2021-04-15 17:33:41 +02:00
Jean-Francois Monfort
68d9778c00 Merge branch 'features/activity-type' into features/activity-form 2021-04-15 14:46:08 +02:00
Jean-Francois Monfort
8acd852070 Fix uls 2021-04-15 14:45:52 +02:00
Jean-Francois Monfort
a9420f0339 Merge branch 'features/activity-type' into features/activity-form 2021-04-15 14:10:46 +02:00
Jean-Francois Monfort
207e5bf01d Merge branch 'master' into features/activity-type 2021-04-15 14:06:58 +02:00
Jean-Francois Monfort
cb5cf5763e ActivityType : rename some fields 2021-04-15 13:56:39 +02:00
Jean-Francois Monfort
ff450215c6 Add first step to select Activity Type 2021-04-15 13:08:30 +02:00
Jean-Francois Monfort
dad8fd5378 ActivityType add new fields : add translations 2021-04-08 16:19:54 +02:00
Jean-Francois Monfort
37b395ee52 ActivityType add new fields 2021-04-08 16:10:04 +02:00
Pol Dellaiera
03243605da Remove unrelated code style change. 2021-04-02 11:18:52 +02:00
Pol Dellaiera
48e2d2ceab Do not use DateTimeImmutable. 2021-04-02 11:18:48 +02:00
Pol Dellaiera
777fb25860 tests: Add missing test based on review's feedback. 2021-04-02 11:12:50 +02:00
Pol Dellaiera
03601b9707 Update Person::getLastAddress() based on feedback. 2021-04-02 11:11:24 +02:00
Jean-Francois Monfort
580dc71218 ActivityType replace Admin Conroller with Crud system 2021-04-01 16:22:33 +02:00
Jean-Francois Monfort
24a7d7b34b new entity ActivityTypeCategory + CRUD 2021-04-01 15:44:05 +02:00
c205bbddd3 writing test to reproduce bug 2021-03-08 10:26:12 +01:00
1380 changed files with 90386 additions and 59673 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ docs/build/
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###

View File

@@ -11,14 +11,15 @@ before_script:
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
# Install and run Composer
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install
- php -d memory_limit=2G composer.phar install
- php tests/app/bin/console doctrine:migrations:migrate -n
- php tests/app/bin/console doctrine:fixtures:load -n
- php -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n
- echo "before_script finished"
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
# See http://docs.gitlab.com/ee/ci/services/README.html for examples.
services:
- name: postgres:12
- name: postgis/postgis:12-3.1-alpine
alias: db
- name: redis
alias: redis
@@ -30,8 +31,12 @@ variables:
POSTGRES_PASSWORD: postgres
# fetch the chill-app using git submodules
GIT_SUBMODULE_STRATEGY: recursive
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_URL: redis://redis:6379
# Run our tests
test:
script:
- bin/phpunit --colors=never
- php -d memory_limit=3G bin/phpunit --colors=never

View File

@@ -1,25 +0,0 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
$config = require __DIR__ . '/vendor/drupol/php-conventions/config/php73/php_cs_fixer.config.php';
$config
->getFinder()
->ignoreDotFiles(false)
->name(['.php_cs.dist']);
$rules = $config->getRules();
$rules['header_comment']['header'] = trim(file_get_contents(__DIR__ . '/resource/header.txt'));
return $config->setRules($rules);

View File

@@ -629,12 +629,12 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
chill-bundles
Copyright (C) 2021 Chill Project
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
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,

9
README.md Normal file
View File

@@ -0,0 +1,9 @@
# Chill framework
Documentation of the Chill software.
The online documentation can be found at http://docs.chill.social
See the [`docs`][1] directory for more.
[1]: docs/README.md

View File

@@ -58,13 +58,13 @@
"symfony/css-selector": "^5.2",
"twig/markdown-extra": "^3.3",
"erusev/parsedown": "^1.7",
"symfony/serializer": "^5.2"
"symfony/serializer": "^5.2",
"symfony/webpack-encore-bundle": "^1.11"
},
"conflict": {
"symfony/symfony": "*"
},
"require-dev": {
"drupol/php-conventions": "4.*",
"fakerphp/faker": "^1.13",
"phpunit/phpunit": "^7.0",
"symfony/dotenv": "^5.1",
@@ -74,7 +74,8 @@
"symfony/web-profiler-bundle": "^5.0",
"symfony/var-dumper": "4.*",
"symfony/debug-bundle": "^5.1",
"symfony/phpunit-bridge": "^5.2"
"symfony/phpunit-bridge": "^5.2",
"nelmio/alice": "^3.8"
},
"scripts": {
"auto-scripts": {
@@ -83,6 +84,7 @@
}
},
"config": {
"vendor-dir": "tests/app/vendor",
"bin-dir": "bin"
}
}

View File

@@ -1,128 +1,123 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Constraints;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Symfony\Component\Form\FormError;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
class BirthdateFilter implements ExportElementValidatedInterface, FilterInterface
class BirthdateFilter implements FilterInterface, ExportElementValidatedInterface
{
// add specific role for this filter
// add specific role for this filter
public function addRole()
{
// we do not need any new role for this filter, so we return null
return null;
}
// here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
// we create the clause here
$clause = $qb->expr()->between(
'person.birthdate',
':date_from',
':date_to'
);
// we have to take care **not to** remove previous clauses...
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
// we add parameters from $data. $data contains the parameters from the form
$qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']);
}
// we give information on which type of export this filter applies
public function applyOn()
{
return 'person';
}
// we build a form to collect some parameters from the users
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, [
'label' => 'Born after this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->add('date_to', DateType::class, [
'label' => 'Born before this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]);
}
// here, we create a simple string which will describe the action of
// the filter in the Response
public function describeAction($data, $format = 'string')
{
return ['Filtered by person\'s birtdate: '
. 'between %date_from% and %date_to%', [
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
], ];
}
public function getTitle()
{
return 'Filter by person\'s birthdate';
}
// we build a form to collect some parameters from the users
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, array(
'label' => "Born after this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
));
$builder->add('date_to', DateType::class, array(
'label' => "Born before this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
));
}
// the form created above must be validated. The process of validation
// is executed here. This function is added by the interface
// `ExportElementValidatedInterface`, and can be ignore if there is
// is executed here. This function is added by the interface
// `ExportElementValidatedInterface`, and can be ignore if there is
// no need for a validation
public function validateForm($data, ExecutionContextInterface $context)
{
{
$date_from = $data['date_from'];
$date_to = $data['date_to'];
if (null === $date_from) {
$date_to = $data['date_to'];
if ($date_from === null) {
$context->buildViolation('The "date from" should not be empty')
//->atPath('date_from')
->addViolation();
}
if (null === $date_to) {
if ($date_to === null) {
$context->buildViolation('The "date to" should not be empty')
//->atPath('date_to')
->addViolation();
}
if (
(null !== $date_from && null !== $date_to)
&& $date_from >= $date_to
($date_from !== null && $date_to !== null)
&&
$date_from >= $date_to
) {
$context->buildViolation('The date "date to" should be after the '
. 'date given in "date from" field')
->addViolation();
}
}
// here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
// we create the clause here
$clause = $qb->expr()->between('person.birthdate', ':date_from',
':date_to');
// we have to take care **not to** remove previous clauses...
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
// we add parameters from $data. $data contains the parameters from the form
$qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']);
}
// here, we create a simple string which will describe the action of
// the filter in the Response
public function describeAction($data, $format = 'string')
{
return array('Filtered by person\'s birtdate: '
. 'between %date_from% and %date_to%', array(
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y')
));
}
}

View File

@@ -1,121 +1,118 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Export\Export;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\Query;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Export\Declarations;
use Chill\MainBundle\Export\FormatterInterface;
use Doctrine\ORM\EntityManagerInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountPerson implements ExportInterface
{
/**
*
* @var EntityManagerInterface
*/
protected $entityManager;
public function __construct(
EntityManagerInterface $em
) {
EntityManagerInterface $em
)
{
$this->entityManager = $em;
}
public function buildForm(FormBuilderInterface $builder)
{
// this export does not add any form
}
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
return 'Count peoples by various parameters.';
}
public function getLabels($key, array $values, $data)
{
// the Closure which will be executed by the formatter.
return function ($value) {
switch ($value) {
case '_header':
// we have to process specifically the '_header' string,
// which will be used by the formatter to show a column title
return $this->getTitle();
default:
// for all value, we do not process them and return them
// immediatly
return $value;
}
};
}
public function getQueryKeys($data)
{
// this array match the result keys in the query. We have only
// one column.
return ['export_result'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle()
{
return 'Count peoples';
}
public function getType()
{
return Declarations::PERSON_TYPE;
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
public function getDescription()
{
// we gather all center the user choose.
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb->select('COUNT(person.id) AS export_result')
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
return $qb;
return "Count peoples by various parameters.";
}
public function getTitle()
{
return "Count peoples";
}
public function requiredRole()
{
return new Role(PersonVoter::STATS);
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
// we gather all center the user choose.
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb->select('COUNT(person.id) AS export_result')
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
;
return $qb;
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getQueryKeys($data)
{
// this array match the result keys in the query. We have only
// one column.
return array('export_result');
}
public function getLabels($key, array $values, $data)
{
// the Closure which will be executed by the formatter.
return function($value) {
switch($value) {
case '_header':
// we have to process specifically the '_header' string,
// which will be used by the formatter to show a column title
return $this->getTitle();
default:
// for all value, we do not process them and return them
// immediatly
return $value;
};
}
public function getAllowedFormattersTypes()
{
return array(FormatterInterface::TYPE_TABULAR);
}
public function buildForm(FormBuilderInterface $builder) {
// this export does not add any form
}
public function supportsModifiers()
{
// explain the export manager which formatters and filters are allowed
return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN];
return array(Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN);
}
}

View File

@@ -0,0 +1,747 @@
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
.. _api:
API
###
Chill provides a basic framework to build REST api.
Basic configuration
*******************
Configure a route
=================
Follow those steps to build a REST api:
1. Create your model;
2. Configure the API;
You can also:
* hook into the controller to customize some steps;
* add more route and steps
.. note::
Useful links:
* `How to use annotation to configure serialization <https://symfony.com/doc/current/serializer.html>`_
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
Auto-loading the routes
=======================
Ensure that those lines are present in your file `app/config/routing.yml`:
.. code-block:: yaml
chill_cruds:
resource: 'chill_main_crud_route_loader:load'
type: service
Create your model
=================
Create your model on the usual way:
.. code-block:: php
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=OriginRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_origin")
*/
class Origin
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="json")
*/
private $label;
/**
* @ORM\Column(type="date_immutable", nullable=true)
*/
private $noActiveAfter;
// .. getters and setters
}
Configure api
=============
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
.. code-block:: yaml
# config/packages/chill_main.yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/accompanying-period/origin'
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
name: accompanying_period_origin
base_role: 'ROLE_USER'
actions:
_index:
methods:
GET: true
HEAD: true
_entity:
methods:
GET: true
HEAD: true
.. note::
If you are working on a shared bundle (aka "The chill bundles"), you should define your configuration inside the class :code:`ChillXXXXBundleExtension`, using the "prependConfig" feature:
.. code-block:: php
namespace Chill\PersonBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ChillPersonExtension
* Loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
* @package Chill\PersonBundle\DependencyInjection
*/
class ChillPersonExtension extends Extension implements PrependExtensionInterface
{
public function prepend(ContainerBuilder $container)
{
$this->prependCruds($container);
}
/**
* @param ContainerBuilder $container
*/
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'apis' => [
[
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class,
'name' => 'accompanying_period_origin',
'base_path' => '/api/1.0/person/accompanying-period/origin',
'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
'base_role' => 'ROLE_USER',
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
]
],
]
]
]
]);
}
}
The :code:`_index` and :code:`_entity` action
*********************************************
The :code:`_index` and :code:`_entity` action are default actions:
* they will call a specific method in the default controller;
* they will generate defined routes:
Index:
Name: :code:`chill_api_single_accompanying_period_origin__index`
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
Entity:
Name: :code:`chill_api_single_accompanying_period_origin__entity`
Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}`
Role
****
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
For index action, the role will be called with :code:`NULL` as :code:`$subject`. The retrieved entity will be the subject for single queries.
You can also define a role for each method. In this case, this role is used for the given method, and, if any, the base role is taken into account.
.. code-block:: yaml
# config/packages/chill_main.yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/bla/bla'
class: 'Chill\PersonBundle\Entity\Blah'
name: bla
actions:
_entity:
methods:
GET: true
HEAD: true
roles:
GET: MY_ROLE_SEE
HEAD: MY ROLE_SEE
Customize the controller
************************
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class OpeningApiController extends ApiController
{
protected function customizeQuery(string $action, Request $request, $qb): void
{
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
$qb->setParameter('now', new \DateTime('now'));
}
}
And set your controller in configuration:
.. code-block:: yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/accompanying-period/origin'
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
name: accompanying_period_origin
# add a controller
controller: 'Chill\PersonBundle\Controller\OpeningApiController'
base_role: 'ROLE_USER'
actions:
_index:
methods:
GET: true
HEAD: true
_entity:
methods:
GET: true
HEAD: true
Create your own actions
***********************
You can add your own actions:
.. code-block:: yaml
chill_main:
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
# add a custom participation:
participation:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
single-collection: single
The key :code:`single-collection` with value :code:`single` will add a :code:`/{id}/ + "action name"` (in this example, :code:`/{id}/participation`) into the path, after the base path. If the value is :code:`collection`, no id will be set, but the action name will be append to the path.
Then, create the corresponding action into your controller:
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
class AccompanyingCourseApiController extends ApiController
{
protected EventDispatcherInterface $eventDispatcher;
protected ValidatorInterface $validator;
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
{
$this->eventDispatcher = $eventDispatcher;
$this->validator = $validator;
}
public function participationApi($id, Request $request, $_format)
{
/** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
$person = $this->getSerializer()
->deserialize($request->getContent(), Person::class, $_format, []);
if (NULL === $person) {
throw new BadRequestException('person id not found');
}
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
switch ($request->getMethod()) {
case Request::METHOD_POST:
$participation = $accompanyingPeriod->addPerson($person);
break;
case Request::METHOD_DELETE:
$participation = $accompanyingPeriod->removePerson($person);
break;
default:
throw new BadRequestException("This method is not supported");
}
$errors = $this->validator->validate($accompanyingPeriod);
if ($errors->count() > 0) {
// only format accepted
return $this->json($errors);
}
$this->getDoctrine()->getManager()->flush();
return $this->json($participation);
}
}
Managing association
********************
ManyToOne association
=====================
In ManyToOne association, you can add associated entities using the :code:`PATCH` request. By default, the serializer deserialize entities only with their id and discriminator type, if any.
Example:
.. code-block:: bash
curl -X 'PATCH' \
'http://localhost:8001/api/1.0/person/accompanying-course/2668.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
# see the data sent to the server: \
-d '{
"type": "accompanying_period",
"id": 2668,
"origin": { "id": 11 }
}'
ManyToMany associations
=======================
In OneToMany association, you can easily create route for adding and removing entities, using :code:`POST` and :code:`DELETE` requests.
Prepare your entity, creating the methods :code:`addYourEntity` and :code:`removeYourEntity`:
.. code-block:: php
namespace Chill\PersonBundle\Entity;
use Chill\MainBundle\Entity\Scope;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/**
* AccompanyingPeriod Class
*
* @ORM\Entity
* @ORM\Table(name="chill_person_accompanying_period")
* @DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period"=AccompanyingPeriod::class
* })
*/
class AccompanyingPeriod
{
/**
* @var Collection
* @ORM\ManyToMany(
* targetEntity=Scope::class,
* cascade={}
* )
* @Groups({"read"})
*/
private $scopes;
public function addScope(Scope $scope): self
{
$this->scopes[] = $scope;
return $this;
}
public function removeScope(Scope $scope): void
{
$this->scopes->removeElement($scope);
}
Create your route into the configuration:
.. code-block:: yaml
chill_main:
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
scope:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
PATCH: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
PATCH: null
controller_action: null
path: null
single-collection: single
This will create a new route, which will accept two methods: DELETE and POST:
.. code-block:: raw
+--------------+---------------------------------------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------------------------------------+
| Route Name | chill_api_single_accompanying_course_scope |
| Path | /api/1.0/person/accompanying-course/{id}/scope.{_format} |
| Path Regex | {^/api/1\.0/person/accompanying\-course/(?P<id>[^/]++)/scope\.(?P<_format>[^/]++)$}sD |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | POST|DELETE |
| Requirements | {id}: \d+ |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: csapi_accompanying_course_controller:scopeApi |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
+--------------+---------------------------------------------------------------------------------------+
Then, create the controller action. Call the method:
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Entity\Scope;
class MyController extends ApiController
{
public function scopeApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, [ 'groups' => [ 'read' ] ]);
}
}
This will allow to add a scope by his id, and delete them.
Curl requests:
.. code-block:: bash
# add a scope with id 5
curl -X 'POST' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"type": "scope",
"id": 5
}'
# remove a scope with id 5
curl -X 'DELETE' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"id": 5,
"type": "scope"
}'
Deserializing an association where multiple types are allowed
=============================================================
Sometimes, multiples types are allowed as association to one entity:
.. code-block:: php
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM;
class Resource
{
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @ORM\JoinColumn(nullable=true)
*/
private $thirdParty;
/**
* @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\JoinColumn(nullable=true)
*/
private $person;
/**
*
* @param $resource Person|ThirdParty
*/
public function setResource($resource): self
{
// ...
}
/**
* @return ThirdParty|Person
* @Groups({"read", "write"})
*/
public function getResource()
{
return $this->person ?? $this->thirdParty;
}
}
This is not well taken into account by the Symfony serializer natively.
You must, then, create your own CustomNormalizer. You can help yourself using this:
.. code-block:: php
namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use Symfony\Component\Serializer\Exception;
use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer;
class AccompanyingPeriodResourceNormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
use DenormalizerAwareTrait;
use ObjectToPopulateTrait;
public function __construct(ResourceRepository $repository)
{
$this->repository = $repository;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
// .. snipped for brevity
if ($resource === NULL) {
$resource = new Resource();
}
if (\array_key_exists('resource', $data)) {
$res = $this->denormalizer->denormalize(
$data['resource'],
// call for a "multiple type"
DiscriminatedObjectDenormalizer::TYPE,
$format,
// into the context, we add the list of allowed types:
[
DiscriminatedObjectDenormalizer::ALLOWED_TYPES =>
[
Person::class, ThirdParty::class
]
]
);
$resource->setResource($res);
}
return $resource;
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $type === Resource::class;
}
}
Serialization for collection
****************************
A specific model has been defined for returning collection:
.. code-block:: json
{
"count": 49,
"results": [
],
"pagination": {
"more": true,
"next": "/api/1.0/search.json&q=xxxx......&page=2",
"previous": null,
"first": 0,
"items_per_page": 1
}
}
Where this is relevant, this model should be re-used in custom controller actions.
In custom actions, this can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`).
.. code-block:: php
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\MainBundle\Pagination\PaginatorInterface;
class MyController extends AbstractController
{
protected function serializeCollection(PaginatorInterface $paginator, $entities): Response
{
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], $context);
}
}
.. _api_full_configuration:
Full configuration example
**************************
.. code-block:: yaml
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
_entity:
roles:
GET: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
HEAD: null
POST: null
DELETE: null
PUT: null
controller_action: null
path: null
single-collection: single
methods:
GET: true
HEAD: true
POST: false
DELETE: false
PUT: false
participation:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
controller_action: null
# the requirements for the route. Will be set to `[ 'id' => '\d+' ]` if left empty.
requirements: []
path: null
single-collection: single
base_role: null

View File

@@ -16,6 +16,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
Instructions to create a new bundle <create-a-new-bundle.rst>
CRUD (Create - Update - Delete) for one entity <crud.rst>
Helpers for building a REST API <api.rst>
Routing <routing.rst>
Menus <menus.rst>
Forms <forms.rst>

View File

@@ -7,6 +7,8 @@
Free Documentation License".
.. _pagination-ref:
Pagination
##########
@@ -15,7 +17,7 @@ The Bundle :code:`Chill\MainBundle` provides a **Pagination** api which allow yo
A simple example
****************
In the controller, get the :class:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance.
In the controller, get the :code:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance.
.. literalinclude:: pagination/example.php

View File

@@ -1,51 +1,42 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class example extends Controller
{
public function yourAction()
class ItemController extends Controller {
public function yourAction()
{
$em = $this->getDoctrine()->getManager();
// first, get the number of total item are available
$total = $em
->createQuery('SELECT COUNT (item.id) FROM ChillMyBundle:Item item')
->getSingleScalarResult();
->createQuery("SELECT COUNT (item.id) FROM ChillMyBundle:Item item")
->getSingleScalarResult();
// get the PaginatorFactory
$paginatorFactory = $this->get('chill_main.paginator_factory');
// create a pagination instance. This instance is only valid for
// create a pagination instance. This instance is only valid for
// the current route and parameters
$paginator = $paginatorFactory->create($total);
// launch your query on item. Limit the query to the results
// for the current page using the paginator
$items = $em->createQuery('SELECT item FROM ChillMyBundle:Item item WHERE <your clause>')
$items = $em->createQuery("SELECT item FROM ChillMyBundle:Item item WHERE <your clause>")
// use the paginator to get the first item number
->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
// use the paginator to get the number of items to display
->setMaxResults($paginator->getItemsPerPage());
return $this->render(
'ChillMyBundle:Item:list.html.twig',
[
return $this->render('ChillMyBundle:Item:list.html.twig', array(
'items' => $items,
'paginator' => $paginator,
]
);
'paginator' => $paginator
);
}
}

View File

@@ -97,7 +97,7 @@ The has the following signature :
*
* @param string $context
* @param mixed[] $args the argument to the context.
* @return string[]
* @return TimelineSingleQuery
* @throw \LogicException if the context is not supported
*/
public function fetchQuery($context, array $args);
@@ -163,18 +163,16 @@ The has the following signature :
The `fetchQuery` function
^^^^^^^^^^^^^^^^^^^^^^^^^
The fetchQuery function help to build the UNION query to gather events. This function should return an associative array MUST have the following key :
The fetchQuery function help to build the UNION query to gather events. This function should return an instance of :code:`TimelineSingleQuery`. For you convenience, this object may be build using an associative array with the following keys:
* `id` : the name of the id column
* `type`: a string to indicate the type
* `date`: the name of the datetime column, used to order entities by date
* `FROM` (in capital) : the FROM clause. May contains JOIN instructions
* `FROM`: the FROM clause. May contains JOIN instructions
* `WHERE`: the WHERE clause;
* `parameters`: the parameters to pass to the query
Those key are optional:
* `WHERE` (in capital) : the WHERE clause.
Where relevant, the data must be quoted to avoid SQL injection.
The parameters should be replaced into the query by :code:`?`. They will be replaced into the query using prepared statements.
`$context` and `$args` are defined by the bundle which will call the timeline rendering. You may use them to build a different query depending on this context.
@@ -186,6 +184,15 @@ For instance, if the context is `'person'`, the args will be this array :
'person' => $person //a \Chill\PersonBundle\Entity\Person entity
);
For the context :code:`center`, the args will be:
.. code-block:: php
array(
'centers' => [ ] // an array of \Chill\MainBundle\Entity\Center entities
);
You should find in the bundle documentation which contexts are arguments the bundle defines.
.. note::
@@ -199,13 +206,12 @@ Example of an implementation :
namespace Chill\ReportBundle\Timeline;
use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Doctrine\ORM\EntityManager;
/**
* Provide report for inclusion in timeline
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/
class TimelineReportProvider implements TimelineProviderInterface
{
@@ -227,16 +233,17 @@ Example of an implementation :
$metadata = $this->em->getClassMetadata('ChillReportBundle:Report');
return array(
return TimelineSingleQuery::fromArray([
'id' => $metadata->getColumnName('id'),
'type' => 'report',
'date' => $metadata->getColumnName('date'),
'FROM' => $metadata->getTableName(),
'WHERE' => sprintf('%s = %d',
'WHERE' => sprintf('%s = ?',
$metadata
->getAssociationMapping('person')['joinColumns'][0]['name'],
$args['person']->getId())
);
->getAssociationMapping('person')['joinColumns'][0]['name'])
)
'parameters' => [ $args['person']->getId() ]
]);
}
//....

View File

@@ -1,55 +1,43 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\HealthBundle\Controller;
use Chill\HealthBundle\Security\Authorization\ConsultationVoter;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Role\Role;
class ConsultationController extends Controller
{
/**
*
* @param int $id personId
*
* @throws type
*
* @return \Symfony\Component\HttpFoundation\Response
* @throws type
*/
public function listAction($id)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
/* @var $person \Chill\PersonBundle\Entity\Person */
$person = $this->get('chill.person.repository.person')
->find($id);
if (null === $person) {
throw $this->createNotFoundException('The person is not found');
if ($person === null) {
throw $this->createNotFoundException("The person is not found");
}
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
/** @var \Chill\MainBundle\Security\Authorization\AuthorizationHelper $authorizationHelper */
/* @var $authorizationHelper \Chill\MainBundle\Security\Authorization\AuthorizationHelper */
$authorizationHelper = $this->get('chill.main.security.'
. 'authorization.helper');
$circles = $authorizationHelper->getReachableCircles(
$this->getUser(),
new Role(ConsultationVoter::SEE),
$this->getUser(),
new Role(ConsultationVoter::SEE),
$person->getCenter()
);
// create a query which take circles into account
);
// create a query which take circles into account
$consultations = $this->getDoctrine()->getManager()
->createQuery('SELECT c FROM ChillHealthBundle:Consultation c '
. 'WHERE c.patient = :person AND c.circle IN(:circles) '
@@ -57,10 +45,11 @@ class ConsultationController extends Controller
->setParameter('person', $person)
->setParameter('circles', $circles)
->getResult();
return $this->render('ChillHealthBundle:Consultation:list.html.twig', [
'person' => $person,
'consultations' => $consultations,
]);
return $this->render('ChillHealthBundle:Consultation:list.html.twig', array(
'person' => $person,
'consultations' => $consultations
));
}
}

View File

@@ -1,70 +1,64 @@
<?php
# Chill\MainBundle\DependencyInjection\Configuration.php
namespace Chill\MainBundle\DependencyInjection;
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill\MainBundle\DependencyInjection\Configuration.php
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Configure the main bundle.
*/
class ChillMainConfiguration implements ConfigurationInterface
{
use AddWidgetConfigurationTrait;
/**
* Configure the main bundle
*/
class Configuration implements ConfigurationInterface
{
use AddWidgetConfigurationTrait;
/**
*
* @var ContainerBuilder
*/
private $containerBuilder;
/**
* @var ContainerBuilder
*/
private $containerBuilder;
public function __construct(array $widgetFactories = array(),
ContainerBuilder $containerBuilder)
{
// we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories);
// we will need the container builder later...
$this->containerBuilder = $containerBuilder;
}
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_main');
public function __construct(
array $widgetFactories,
ContainerBuilder $containerBuilder
) {
// we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories);
// we will need the container builder later...
$this->containerBuilder = $containerBuilder;
}
$rootNode
->children()
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_main');
// ...
$rootNode
->children()
->arrayNode('widgets')
->canBeDisabled()
->children()
// we declare here all configuration for homepage place
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->end() // end of root/children
->end() // end of root
;
return $treeBuilder;
}
}
// ...
->arrayNode('widgets')
->canBeDisabled()
->children()
// we declare here all configuration for homepage place
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->end() // end of root/children
->end() // end of root
;
return $treeBuilder;
}
}

View File

@@ -1,23 +1,16 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
//Chill\MainBundle\DependencyInjection\ChillMainExtension.php
#Chill\MainBundle\DependencyInjection\ChillMainExtension.php
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Chill\MainBundle\DependencyInjection\Configuration;
/**
* This class load config for chillMainExtension.
@@ -25,42 +18,42 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesExtensionInterface
{
/**
* widget factory.
*
* widget factory
*
* @var WidgetFactoryInterface[]
*/
protected $widgetFactories = [];
protected $widgetFactories = array();
public function addWidgetFactory(WidgetFactoryInterface $factory)
{
$this->widgetFactories[] = $factory;
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
/**
*
* @return WidgetFactoryInterface[]
*/
public function getWidgetFactories()
{
return $this->widgetFactories;
}
public function load(array $configs, ContainerBuilder $container)
{
// configuration for main bundle
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
// add the key 'widget' without the key 'enable'
$container->setParameter(
'chill_main.widgets',
['homepage' => $config['widgets']['homepage']]
);
$container->setParameter('chill_main.widgets',
array('homepage' => $config['widgets']['homepage']));
// ...
// ...
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
}

View File

@@ -1,77 +1,69 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/Widget/PersonListWidgetFactory
# Chill/PersonBundle/Widget/PersonListWidgetFactory
namespace Chill\PersonBundle\Widget;
use Chill\MainBundle\DependencyInjection\Widget\Factory\AbstractWidgetFactory;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
/**
* add configuration for the person_list widget.
*/
class ChillPersonAddAPersonListWidgetFactory extends AbstractWidgetFactory
class PersonListWidgetFactory extends AbstractWidgetFactory
{
/*
* append the option to the configuration
* see http://symfony.com/doc/current/components/config/definition.html
*
*/
/*
* append the option to the configuration
* see http://symfony.com/doc/current/components/config/definition.html
*
*/
public function configureOptions($place, NodeBuilder $node)
{
$node->booleanNode('only_active')
->defaultTrue()
->end();
->defaultTrue()
->end();
$node->integerNode('number_of_items')
->defaultValue(50)
->end();
$node->scalarNode('filtering_class')
->defaultNull()
->end();
->defaultNull()
->end();
}
/**
* return an array with the allowed places where the widget can be rendered.
*
* @return string[]
*/
/*
* return an array with the allowed places where the widget can be rendered
*
* @return string[]
*/
public function getAllowedPlaces()
{
return ['homepage'];
return array('homepage');
}
/*
* return the widget alias
*
* @return string
*/
public function getWidgetAlias()
{
return 'person_list';
}
/*
* return the service id for the service which will render the widget.
*
* this service must implements `Chill\MainBundle\Templating\Widget\WidgetInterface`
*
* the service must exists in the container, and it is not required that the service
*
* the service must exists in the container, and it is not required that the service
* has the `chill_main` tag.
*/
public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config)
{
return 'chill_person.widget.person_list';
}
/**
* return the widget alias.
*
* @return string
*/
public function getWidgetAlias()
{
return 'person_list';
}
}

View File

@@ -1,77 +1,66 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/Widget/PersonListWidget.php
# Chill/PersonBundle/Widget/PersonListWidget.php
namespace Chill\PersonBundle\Widget;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\Widget\WidgetInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\DBAL\Types\Type;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\User\UserInterface;
use Twig_Environment;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\EntityManager;
/**
* add a widget with person list.
*
* add a widget with person list.
*
* The configuration is defined by `PersonListWidgetFactory`
*/
class ChillPersonAddAPersonWidget implements WidgetInterface
class PersonListWidget implements WidgetInterface
{
/**
* the authorization helper.
*
* @var AuthorizationHelper;
* Repository for persons
*
* @var EntityRepository
*/
protected $authorizationHelper;
protected $personRepository;
/**
* The entity manager.
* The entity manager
*
* @var EntityManager
*/
protected $entityManager;
/**
* Repository for persons.
*
* @var EntityRepository
* the authorization helper
*
* @var AuthorizationHelper;
*/
protected $personRepository;
protected $authorizationHelper;
/**
*
* @var TokenStorage
*/
protected $tokenStorage;
/**
*
* @var UserInterface
*/
protected $user;
public function __construct(
EntityRepository $personRepostory,
EntityManager $em,
AuthorizationHelper $authorizationHelper,
TokenStorage $tokenStorage
) {
EntityRepository $personRepostory,
EntityManager $em,
AuthorizationHelper $authorizationHelper,
TokenStorage $tokenStorage
) {
$this->personRepository = $personRepostory;
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
@@ -79,24 +68,27 @@ class ChillPersonAddAPersonWidget implements WidgetInterface
}
/**
*
* @param type $place
*
* @param array $context
* @param array $config
* @return string
*/
public function render(Twig_Environment $env, $place, array $context, array $config)
{
public function render(\Twig_Environment $env, $place, array $context, array $config)
{
$qb = $this->personRepository
->createQueryBuilder('person');
->createQueryBuilder('person');
// show only the person from the authorized centers
$and = $qb->expr()->andX();
$centers = $this->authorizationHelper
->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE));
->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE));
$and->add($qb->expr()->in('person.center', ':centers'));
$qb->setParameter('centers', $centers);
// add the "only active" where clause
if (true === $config['only_active']) {
if ($config['only_active'] === true) {
$qb->join('person.accompanyingPeriods', 'ap');
$or = new Expr\Orx();
// add the case where closingDate IS NULL
@@ -106,30 +98,32 @@ class ChillPersonAddAPersonWidget implements WidgetInterface
$or->add($andWhenClosingDateIsNull);
// add the case when now is between opening date and closing date
$or->add(
(new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate')
);
(new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate')
);
$and->add($or);
$qb->setParameter('now', new DateTime(), Type::DATE);
$qb->setParameter('now', new \DateTime(), Type::DATE);
}
// adding the where clause to the query
$qb->where($and);
$qb->setFirstResult(0)->setMaxResults($config['number_of_items']);
$persons = $qb->getQuery()->getResult();
return $env->render(
'ChillPersonBundle:Widget:homepage_person_list.html.twig',
['persons' => $persons]
);
array('persons' => $persons)
);
}
/**
*
* @return UserInterface
*/
private function getUser()
{
// return a user
}
}

View File

@@ -1,55 +1,51 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/DependencyInjection/ChillPersonExtension.php
# Chill/PersonBundle/DependencyInjection/ChillPersonExtension.php
namespace Chill\PersonBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\MissingBundleException;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
/**
* This is the class that loads and manages your bundle configuration.
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class ChillPersonExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
// ...
// ...
}
/**
* Add a widget "add a person" on the homepage, automatically.
*
*
* Add a widget "add a person" on the homepage, automatically
*
* @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container
*/
public function prepend(ContainerBuilder $container)
public function prepend(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'widgets' => [
'homepage' => [
[
$container->prependExtensionConfig('chill_main', array(
'widgets' => array(
'homepage' => array(
array(
'widget_alias' => 'add_person',
'order' => 2,
],
],
],
]);
'order' => 2
)
)
)
));
}
}

View File

@@ -82,7 +82,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
.. code-block:: bash
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load --purge-with-truncate
There are several users available:

View File

@@ -1,8 +0,0 @@
imports:
- { resource: vendor/drupol/php-conventions/config/php73/grumphp.yml }
parameters:
tasks.phpcsfixer.config: .php_cs.dist
tasks.license.name: AGPL-3.0
tasks.license.holder: Champs-Libres
tasks.license.date_from: 2001

3
package.json.txt Normal file
View File

@@ -0,0 +1,3 @@
add npm/yarn dependency in package.json :
"select2-bootstrap-theme": "0.1.0-beta.10",

View File

@@ -18,12 +18,20 @@
<testsuite name="MainBundle">
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
</testsuite>
<testsuite name="PersonBundle">
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
<!-- test for export will be runned later -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
<!-- we are rewriting accompanying periods... Work in progress -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php</exclude>
<!-- we are rewriting address, Work in progress -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php</exclude>
<!-- find a solution to create multiple configs -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php</exclude>
<!-- temporarily removed, the time to find a fix -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
</testsuite>
</testsuites>
</testsuites>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />

View File

@@ -1,6 +0,0 @@
Chill is a software for social workers.
For the full copyright and license information, please view
the LICENSE file that was distributed with this source code.
@see https://www.champs-libres.coop/

View File

@@ -1,16 +1,5 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;

View File

@@ -1,468 +1,481 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Form\ActivityType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use DateTime;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Serializer\SerializerInterface;
/**
* Class ActivityController
*
* @package Chill\ActivityBundle\Controller
*/
class ActivityController extends AbstractController
{
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected EventDispatcherInterface $eventDispatcher;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
protected AuthorizationHelper $authorizationHelper;
/**
* @var LoggerInterface
*/
protected $logger;
protected LoggerInterface $logger;
protected SerializerInterface $serializer;
/**
* ActivityController constructor.
*/
public function __construct(
EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger
LoggerInterface $logger,
SerializerInterface $serializer
) {
$this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
$this->logger = $logger;
$this->serializer = $serializer;
}
/**
* Creates a new Activity entity.
*
* @param mixed $person_id
* Lists all Activity entities.
*/
public function createAction($person_id, Request $request)
public function listAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
$view = null;
// TODO: add pagination
if (null === $person) {
throw $this->createNotFoundException('person not found');
}
[$person, $accompanyingPeriod] = $this->getEntity($request);
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
if ($person instanceof Person) {
$reachableScopes = $this->authorizationHelper
->getReachableCircles($this->getUser(), new Role('CHILL_ACTIVITY_SEE'),
$person->getCenter());
$entity = new Activity();
$entity->setPerson($person);
$form = $this->createCreateForm($entity, $person);
$form->handleRequest($request);
$activities = $em->getRepository(Activity::class)
->findByPersonImplied($person, $reachableScopes)
;
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'action' => 'list'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$this->denyAccessUnlessGranted(
'CHILL_ACTIVITY_CREATE',
$entity,
'creation of this activity not allowed'
$view = 'ChillActivityBundle:Activity:listPerson.html.twig';
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
$activities = $em->getRepository('ChillActivityBundle:Activity')->findBy(
['accompanyingPeriod' => $accompanyingPeriod],
['date' => 'DESC'],
);
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
}
return $this->render($view, array(
'activities' => $activities,
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
));
}
public function selectTypeAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:selectTypeAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:selectTypePerson.html.twig';
}
$data = [];
$activityTypeCategories = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityTypeCategory::class)
->findBy(['active' => true], ['ordering' => 'ASC']);
foreach ($activityTypeCategories as $activityTypeCategory) {
$activityTypes = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']);
$data[] = [
'activityTypeCategory' => $activityTypeCategory,
'activityTypes' => $activityTypes,
];
}
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'data' => $data,
]);
}
public function newAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:newPerson.html.twig';
}
$activityType_id = $request->get('activityType_id', 0);
$activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
->find($activityType_id);
if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType ||
!$activityType->isActive()) {
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
return $this->redirectToRoute('chill_activity_activity_select_type', $params);
}
$entity = new Activity();
$entity->setUser($this->getUser());
if ($person instanceof Person) {
$entity->setPerson($person);
}
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$entity->setAccompanyingPeriod($accompanyingPeriod);
}
$entity->setType($activityType);
$entity->setDate(new \DateTime('now'));
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_CREATE'),
'activityType' => $entity->getType(),
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity);
$em->flush();
$this->get('session')
->getFlashBag()
->add(
'success',
$this->get('translator')
->trans('Success : activity created!')
);
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
return $this->redirect(
$this->generateUrl(
'chill_activity_activity_show',
['id' => $entity->getId(), 'person_id' => $person_id]
)
);
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $entity->getId();
return $this->redirectToRoute('chill_activity_activity_show', $params);
}
$this->get('session')
->getFlashBag()->add(
'danger',
$this->get('translator')
->trans('The form is not valid. The activity has not been created !')
);
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render('ChillActivityBundle:Activity:new.html.twig', [
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, [
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'form' => $form->createView(),
'person' => $person,
'activity_json' => $activity_array
]);
}
/**
* Deletes a Activity entity.
*
* @param mixed $id
* @param mixed $person_id
*/
public function deleteAction(Request $request, $id, $person_id)
public function showAction(Request $request, $id): Response
{
$em = $this->getDoctrine()->getManager();
/** @var Activity $activity */
$activity = $em->getRepository('ChillActivityBundle:Activity')
->find($id);
$person = $activity->getPerson();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if (!$activity) {
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:showPerson.html.twig';
}
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
$form = $this->createDeleteForm($id, $person);
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->notice('An activity has been removed', [
'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(),
'person_id' => $activity->getPerson()->getId(),
'comment' => $activity->getComment()->getComment(),
'scope_id' => $activity->getScope()->getId(),
'reasons_ids' => $activity->getReasons()
->map(static function ($ar) {
return $ar->getId();
})
->toArray(),
'type_id' => $activity->getType()->getId(),
'duration' => $activity->getDurationTime()->format('U'),
'date' => $activity->getDate()->format('Y-m-d'),
'attendee' => $activity->getAttendee(),
]);
$em->remove($activity);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans('The activity has been successfully removed.'));
return $this->redirect($this->generateUrl(
'chill_activity_activity_list',
[
'person_id' => $person_id,
]
));
}
if (null !== $accompanyingPeriod) {
$entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated();
}
return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', [
'activity' => $activity,
'delete_form' => $form->createView(),
]);
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod);
// TODO
/*
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'show'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, array(
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function editAction($person_id, $id)
public function editAction($id, Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (!$person) {
throw $this->createNotFoundException('person not found');
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:editPerson.html.twig';
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
// TODO
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id, $person);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
'activityType' => $entity->getType(),
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'edit',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
'person' => $person,
]);
}
/**
* Lists all Activity entities.
*
* @param mixed $person_id
*/
public function listAction($person_id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (null === $person) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$reachableScopes = $this->authorizationHelper
->getReachableScopes(
$this->getUser(),
new Role('CHILL_ACTIVITY_SEE'),
$person->getCenter()
);
$activities = $em->getRepository('ChillActivityBundle:Activity')
->findBy(
['person' => $person, 'scope' => $reachableScopes],
['date' => 'DESC']
);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'action' => 'list',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:list.html.twig', [
'activities' => $activities,
'person' => $person,
]);
}
/**
* Displays a form to create a new Activity entity.
*
* @param mixed $person_id
*/
public function newAction($person_id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (null === $person) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$entity = new Activity();
$entity->setUser($this->get('security.token_storage')->getToken()->getUser());
$entity->setPerson($person);
$entity->setDate(new DateTime('now'));
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
$form = $this->createCreateForm($entity, $person);
return $this->render('ChillActivityBundle:Activity:new.html.twig', [
'person' => $person,
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function showAction($person_id, $id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (!$person) {
throw $this->createNotFoundException('person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$deleteForm = $this->createDeleteForm($id, $person);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'show',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:show.html.twig', [
'person' => $person,
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
]);
}
/**
* Edits an existing Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function updateAction(Request $request, $person_id, $id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$deleteForm = $this->createDeleteForm($id, $person);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'update',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
if ($editForm->isValid()) {
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity);
$em->flush();
$this->get('session')
->getFlashBag()
->add(
'success',
$this->get('translator')
->trans('Success : activity updated!')
);
$this->addFlash('success', $this->get('translator')->trans('Success : activity updated!'));
return $this->redirect($this->generateUrl('chill_activity_activity_show', ['id' => $id, 'person_id' => $person_id]));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id;
return $this->redirectToRoute('chill_activity_activity_show', $params);
}
$this->get('session')
->getFlashBag()
->add(
'error',
$this->get('translator')
->trans('This form contains errors')
);
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod);
return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'person' => $entity->getPerson(),
'entity' => $entity,
'edit_form' => $editForm->createView(),
/*
* TODO
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'edit'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, array(
'entity' => $entity,
'edit_form' => $form->createView(),
'delete_form' => $deleteForm->createView(),
]);
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'activity_json' => $activity_array
));
}
/**
* Creates a form to create a Activity entity.
* Deletes a Activity entity.
*
* @param Activity $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Activity $entity)
public function deleteAction(Request $request, $id)
{
return $this->createForm(
ActivityType::class,
$entity,
[
'action' => $this->generateUrl('chill_activity_activity_create', [
'person_id' => $entity->getPerson()->getId(),
]),
'method' => 'POST',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_CREATE'),
]
);
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
}
/* @var $activity Activity */
$activity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$activity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
// TODO
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
$form = $this->createDeleteForm($id, $person, $accompanyingPeriod);
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->notice("An activity has been removed", array(
'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(),
'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null,
'comment' => $activity->getComment()->getComment(),
'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null,
'reasons_ids' => $activity->getReasons()
->map(function ($ar) { return $ar->getId(); })
->toArray(),
'type_id' => $activity->getType()->getId(),
'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null,
'date' => $activity->getDate()->format('Y-m-d'),
'attendee' => $activity->getAttendee()
));
$em->remove($activity);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans("The activity has been successfully removed."));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
return $this->redirectToRoute('chill_activity_activity_list', $params);
}
}
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, array(
'activity' => $activity,
'delete_form' => $form->createView(),
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
));
}
/**
* Creates a form to delete a Activity entity by id.
*
* @param mixed $id The entity id
* @param mixed $person
*
* @return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm($id, $person)
private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form
{
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id;
return $this->createFormBuilder()
->setAction($this->generateUrl(
'chill_activity_activity_delete',
['id' => $id, 'person_id' => $person->getId()]
))
->setAction($this->generateUrl('chill_activity_activity_delete', $params))
->setMethod('DELETE')
->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm();
->add('submit', SubmitType::class, array('label' => 'Delete'))
->getForm()
;
}
/**
* Creates a form to edit a Activity entity.
*
* @param Activity $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Activity $entity)
private function getEntity(Request $request): array
{
return $this->createForm(ActivityType::class, $entity, [
'action' => $this->generateUrl(
'chill_activity_activity_update',
[
'id' => $entity->getId(),
'person_id' => $entity->getPerson()->getId(),
]
),
'method' => 'PUT',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
]);
$em = $this->getDoctrine()->getManager();
$person = $accompanyingPeriod = null;
if ($request->query->has('person_id')) {
$person_id = $request->get('person_id');
$person = $em->getRepository(Person::class)->find($person_id);
if ($person === null) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} elseif ($request->query->has('accompanying_period_id')) {
$accompanying_period_id = $request->get('accompanying_period_id');
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id);
if ($accompanyingPeriod === null) {
throw $this->createNotFoundException('Accompanying Period not found');
}
// TODO Add permission
// $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} else {
throw $this->createNotFoundException("Person or Accompanying Period not found");
}
return [
$person, $accompanyingPeriod
];
}
private function buildParamsToUrl(
?Person $person,
?AccompanyingPeriod $accompanyingPeriod
): array {
$params = [];
if ($person) {
$params['person_id'] = $person->getId();
}
if ($accompanyingPeriod) {
$params['accompanying_period_id'] = $accompanyingPeriod->getId();
}
return $params;
}
}

View File

@@ -1,28 +1,38 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Chill\ActivityBundle\Form\ActivityReasonCategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* ActivityReasonCategory controller.
*
*/
class ActivityReasonCategoryController extends AbstractController
{
/**
* Lists all ActivityReasonCategory entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll();
return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', array(
'entities' => $entities,
));
}
/**
* Creates a new ActivityReasonCategory entity.
*
*/
public function createAction(Request $request)
{
@@ -35,19 +45,71 @@ class ActivityReasonCategoryController extends AbstractController
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', ['id' => $entity->getId()]));
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', array('id' => $entity->getId())));
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
]);
'form' => $form->createView(),
));
}
/**
* Creates a form to create a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new ActivityReasonCategory entity.
*
*/
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a ActivityReasonCategory entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', array(
'entity' => $entity,
));
}
/**
* Displays a form to edit an existing ActivityReasonCategory entity.
*
* @param mixed $id
*/
public function editAction($id)
{
@@ -61,64 +123,33 @@ class ActivityReasonCategoryController extends AbstractController
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
/**
* Lists all ActivityReasonCategory entities.
*/
public function indexAction()
* Creates a form to edit a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReasonCategory $entity)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll();
$form->add('submit', SubmitType::class, array('label' => 'Update'));
return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', [
'entities' => $entities,
]);
return $form;
}
/**
* Displays a form to create a new ActivityReasonCategory entity.
*/
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityReasonCategory entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', [
'entity' => $entity,
]);
}
/**
* Edits an existing ActivityReasonCategory entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
@@ -136,50 +167,12 @@ class ActivityReasonCategoryController extends AbstractController
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', ['id' => $id]));
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', array('id' => $id)));
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to create a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
}

View File

@@ -1,28 +1,38 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Form\ActivityReasonType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* ActivityReason controller.
*
*/
class ActivityReasonController extends AbstractController
{
/**
* Lists all ActivityReason entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll();
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', array(
'entities' => $entities,
));
}
/**
* Creates a new ActivityReason entity.
*
*/
public function createAction(Request $request)
{
@@ -35,19 +45,71 @@ class ActivityReasonController extends AbstractController
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $entity->getId()]));
return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $entity->getId())));
}
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
]);
'form' => $form->createView(),
));
}
/**
* Creates a form to create a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreason_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new ActivityReason entity.
*
*/
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a ActivityReason entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', array(
'entity' => $entity,
));
}
/**
* Displays a form to edit an existing ActivityReason entity.
*
* @param mixed $id
*/
public function editAction($id)
{
@@ -61,64 +123,33 @@ class ActivityReasonController extends AbstractController
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView()
));
}
/**
* Lists all ActivityReason entities.
*/
public function indexAction()
* Creates a form to edit a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReason $entity)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(ActivityReasonType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreason_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll();
$form->add('submit', SubmitType::class, array('label' => 'Update'));
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [
'entities' => $entities,
]);
return $form;
}
/**
* Displays a form to create a new ActivityReason entity.
*/
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityReason entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', [
'entity' => $entity,
]);
}
/**
* Edits an existing ActivityReason entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
@@ -136,50 +167,12 @@ class ActivityReasonController extends AbstractController
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $id]));
return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $id)));
}
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to create a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView()
));
}
}

View File

@@ -1,185 +0,0 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Form\ActivityTypeType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
class ActivityTypeController extends AbstractController
{
/**
* Creates a new ActivityType entity.
*/
public function createAction(Request $request)
{
$entity = new ActivityType();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_show', ['id' => $entity->getId()]));
}
return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Displays a form to edit an existing ActivityType entity.
*
* @param mixed $id
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Lists all ActivityType entities.
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll();
return $this->render('ChillActivityBundle:ActivityType:index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new ActivityType entity.
*/
public function newAction()
{
$entity = new ActivityType();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityType entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
return $this->render('ChillActivityBundle:ActivityType:show.html.twig', [
'entity' => $entity,
]);
}
/**
* Edits an existing ActivityType entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', ['id' => $id]));
}
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to create a ActivityType entity.
*
* @param ActivityType $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityType $entity)
{
$form = $this->createForm(ActivityTypeType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activitytype_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityType entity.
*
* @param ActivityType $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityType $entity)
{
$form = $this->createForm(ActivityTypeType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activitytype_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityPresenceController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.id', 'ASC');
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityTypeCategoryController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC');
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityTypeController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC');
}
}

View File

@@ -1,22 +1,33 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Controller for activity configuration.
* Controller for activity configuration
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/
class AdminController extends AbstractController
{
@@ -24,7 +35,7 @@ class AdminController extends AbstractController
{
return $this->render('ChillActivityBundle:Admin:layout_activity.html.twig');
}
public function redirectToAdminIndexAction()
{
return $this->redirectToRoute('chill_main_admin_central');

View File

@@ -1,33 +1,44 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory as FakerFactory;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use function in_array;
/**
* Load reports into DB.
* Load reports into DB
*
* @author Champs-Libres Coop
*/
class LoadActivity extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
@@ -46,22 +57,54 @@ class LoadActivity extends AbstractFixture implements ContainerAwareInterface, O
return 16400;
}
public function load(ObjectManager $manager)
/**
* Return a random scope
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope()
{
$persons = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillPersonBundle:Person')
->findAll();
$scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)];
return $this->getReference($scopeRef);
}
foreach ($persons as $person) {
$activityNbr = mt_rand(0, 3);
/**
* Return a random activityType
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)];
return $this->getReference($typeRef);
}
for ($i = 0; $i < $activityNbr; ++$i) {
echo 'Creating an activity type for : ' . $person . "\n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
}
/**
* Return a random activityReason
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludingIds)
{
$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);
}
$manager->flush();
return $this->getReference($reasonRef);
}
/**
* Return a random user
*
* @return \Chill\MainBundle\Entity\User
*/
private function getRandomUser()
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
}
public function newRandomActivity($person)
@@ -73,11 +116,12 @@ class LoadActivity extends AbstractFixture implements ContainerAwareInterface, O
->setDurationTime($this->faker->dateTime(36000))
->setType($this->getRandomActivityType())
->setScope($this->getRandomScope())
->setAttendee($this->faker->boolean());
;
$usedId = [];
// ->setAttendee($this->faker->boolean())
for ($i = 0; mt_rand(0, 4) > $i; ++$i) {
$usedId = array();
for ($i = 0; $i < rand(0, 4); $i++) {
$reason = $this->getRandomActivityReason($usedId);
$usedId[] = $reason->getId();
$activity->addReason($reason);
@@ -86,56 +130,24 @@ class LoadActivity extends AbstractFixture implements ContainerAwareInterface, O
return $activity;
}
/**
* Return a random activityReason.
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludingIds)
public function load(ObjectManager $manager)
{
$reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)];
$persons = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillPersonBundle:Person')
->findAll();
if (in_array($this->getReference($reasonRef)->getId(), $excludingIds, true)) {
// we have a reason which should be excluded. Find another...
return $this->getRandomActivityReason($excludingIds);
foreach($persons as $person) {
$activityNbr = rand(0,3);
$ref = 'activity_'.$person->getFullnameCanonical();
for($i = 0; $i < $activityNbr; $i ++) {
print "Creating an activity type for : ".$person." (ref: ".$ref.") \n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
}
$this->setReference($ref, $activity);
}
return $this->getReference($reasonRef);
}
/**
* Return a random activityType.
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)];
return $this->getReference($typeRef);
}
/**
* Return a random scope.
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope()
{
$scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)];
return $this->getReference($scopeRef);
}
/**
* Return a random user.
*
* @return \Chill\MainBundle\Entity\User
*/
private function getRandomUser()
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
$manager->flush();
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadAbstractNotificationsTrait;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivity;
/**
* Load notififications into database
*/
class LoadActivityNotifications extends AbstractFixture implements DependentFixtureInterface
{
use LoadAbstractNotificationsTrait;
public $notifs = [
[
'message' => 'Hello !',
'entityClass' => Activity::class,
'entityRef' => 'activity_gerard depardieu',
'sender' => 'center a_social',
'addressees' => [
'center a_social',
'center a_administrative',
'center a_direction',
'multi_center'
],
]
];
public function getDependencies()
{
return [
LoadActivity::class,
];
}
}

View File

@@ -1,70 +1,81 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
/*
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityReason;
/**
* Description of LoadActivityReason.
* Description of LoadActivityReason
*
* @author Champs-Libres Coop
*/
class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterface
{
public static $references = [];
public function getOrder()
{
return 16300;
}
public static $references = array();
public function load(ObjectManager $manager)
{
$reasons = [
[
'name' => ['fr' => 'Recherche logement', 'en' => 'Housing research', 'nl' => 'Woning zoektoch'],
'category' => 'cat_Housing', ],
'category' => 'cat_Housing'],
[
'name' => ['fr' => 'Problème avec propriétaire', 'en' => 'Landlord problems', 'nl' => 'Huisbaas problemen'],
'category' => 'cat_Housing', ],
'category' => 'cat_Housing'],
[
'name' => ['fr' => 'Retard de payement', 'en' => 'Payement problems', 'nl' => 'Betalings vertragingen'],
'category' => 'cat_Housing', ],
'category' => 'cat_Housing'],
[
'name' => ['fr' => 'Explication législation', 'en' => 'Legislation explanation', 'nl' => 'Legislative uitleg'],
'category' => 'cat_Unemployment procedure', ],
'category' => 'cat_Unemployment procedure'],
[
'name' => ['fr' => 'Coaching entretien d\'activation', 'en' => 'Interview coaching', 'nl' => 'Interview coaching'],
'category' => 'cat_Unemployment procedure', ],
'category' => 'cat_Unemployment procedure'],
[
'name' => ['fr' => 'Récupération des allocations', 'en' => 'Allowance recovery', 'nl' => 'Terugwinning van de uitkeringen'],
'category' => 'cat_Unemployment procedure', ],
'category' => 'cat_Unemployment procedure']
];
foreach ($reasons as $r) {
echo 'Creating activity reason : ' . $r['name']['en'] . "\n";
print "Creating activity reason : " . $r['name']['en'] . "\n";
$activityReason = (new ActivityReason())
->setName(($r['name']))
->setActive(true)
->setCategory($this->getReference($r['category']));
$manager->persist($activityReason);
$reference = 'activity_reason_' . $r['name']['en'];
$reference = 'activity_reason_'.$r['name']['en'];
$this->addReference($reference, $activityReason);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,25 +1,35 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
/*
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
/**
* Description of LoadActivityReasonCategory.
* Description of LoadActivityReasonCategory
*
* @author Champs-Libres Coop
*/
class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtureInterface
{
@@ -27,26 +37,27 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu
{
return 16200;
}
public function load(ObjectManager $manager)
{
$categs = [
['name' => ['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']],
['name' => ['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']],
['name' =>
['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']],
['name' =>
['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']],
];
foreach ($categs as $c) {
echo 'Creating activity reason category : ' . $c['name']['en'] . "\n";
print "Creating activity reason category : " . $c['name']['en'] . "\n";
$activityReasonCategory = (new ActivityReasonCategory())
->setName(($c['name']))
->setActive(true);
$manager->persist($activityReasonCategory);
$this->addReference(
'cat_' . $c['name']['en'],
$activityReasonCategory
);
'cat_'.$c['name']['en'],
$activityReasonCategory);
}
$manager->flush();
}
}

View File

@@ -1,49 +1,86 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityType;
/**
* Description of LoadActivityType.
* Description of LoadActivityType
*
* @author Champs-Libres Coop
*/
class LoadActivityType extends AbstractFixture implements OrderedFixtureInterface
class LoadActivityType extends Fixture implements OrderedFixtureInterface
{
public static $references = [];
public function getOrder()
{
return 16100;
}
public static $references = array();
public function load(ObjectManager $manager)
{
$types = [
['name' => ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']],
['name' => ['fr' => 'Entretien', 'en' => 'Interview', 'nl' => 'Vraaggesprek']],
['name' => ['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']],
# Exange
[
'name' =>
['fr' => 'Entretien physique avec l\'usager'],
'category' => 'exchange' ],
[
'name' =>
['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel'],
'category' => 'exchange' ],
[
'name' =>
['fr' => 'Courriel', 'en' => 'Email', 'nl' => 'Email'],
'category' => 'exchange' ],
# Meeting
[
'name' =>
['fr' => 'Point technique encadrant'],
'category' => 'meeting' ],
[
'name' =>
['fr' => 'Réunion avec des partenaires'],
'category' => 'meeting' ],
[
'name' =>
['fr' => 'Commission pluridisciplinaire et pluri-institutionnelle'],
'category' => 'meeting' ],
];
foreach ($types as $t) {
echo 'Creating activity type : ' . $t['name']['en'] . "\n";
print "Creating activity type : " . $t['name']['fr'] . " (cat:". $t['category'] . " \n";
$activityType = (new ActivityType())
->setName(($t['name']));
->setName(($t['name']))
->setCategory($this->getReference('activity_type_cat_'.$t['category']))
->setSocialIssuesVisible(1)
->setSocialActionsVisible(1);
$manager->persist($activityType);
$reference = 'activity_type_' . $t['name']['en'];
$reference = 'activity_type_'.$t['name']['fr'];
$this->addReference($reference, $activityType);
static::$references[] = $reference;
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2014-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\DataFixtures\ORM;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
/**
* Fixtures for ActivityTypeCategory
*
* @author Champs-Libres Coop
*/
class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterface
{
public static $references = array();
public function getOrder()
{
return 16050;
}
public function load(ObjectManager $manager)
{
$categories = [
[
'name' => ['fr' => 'Échange avec usager', 'en' => 'Exchange with user'],
'ref' => 'exchange',
],
[
'name' => ['fr' => 'Réunion', 'en' => 'Meeting'],
'ref' => 'meeting',
],
];
foreach ($categories as $cat) {
print "Creating activity type category : " . $cat['ref'] . "\n";
$newCat = (new ActivityTypeCategory())
->setName(($cat['name']));
$manager->persist($newCat);
$reference = 'activity_type_cat_'.$cat['ref'];
$this->addReference($reference, $newCat);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,16 +1,22 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
@@ -21,7 +27,12 @@ use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
/**
* Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except administrative,
* and a role CHILL_ACTIVITY_SEE for administrative
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterface
{
public function getOrder()
@@ -29,12 +40,12 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
return 16000;
}
public function load(ObjectManager $manager)
{
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
$permissionsGroup = $this->getReference($permissionsGroupRef);
foreach (LoadScopes::$references as $scopeRef) {
foreach (LoadScopes::$references as $scopeRef){
$scope = $this->getReference($scopeRef);
//create permission group
switch ($permissionsGroup->getName()) {
@@ -42,48 +53,47 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
if ($scope->getName()['en'] === 'administrative') {
break 2; // we do not want any power on administrative
}
break;
case 'administrative':
case 'direction':
if (\in_array($scope->getName()['en'], ['administrative', 'social'], true)) {
if (in_array($scope->getName()['en'], array('administrative', 'social'))) {
break 2; // we do not want any power on social or administrative
}
}
break;
}
printf(
'Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s '
. "permission group, scope '%s' \n",
$permissionsGroup->getName(),
$scope->getName()['en']
);
printf("Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s "
. "permission group, scope '%s' \n",
$permissionsGroup->getName(), $scope->getName()['en']);
$roleScopeUpdate = (new RoleScope())
->setRole('CHILL_ACTIVITY_UPDATE')
->setScope($scope);
->setRole('CHILL_ACTIVITY_UPDATE')
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeUpdate);
$roleScopeCreate = (new RoleScope())
->setRole('CHILL_ACTIVITY_CREATE')
->setScope($scope);
->setRole('CHILL_ACTIVITY_CREATE')
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeCreate);
$roleScopeDelete = (new RoleScope())
->setRole('CHILL_ACTIVITY_DELETE')
->setScope($scope);
->setRole('CHILL_ACTIVITY_DELETE')
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeDelete);
$roleScopeList = (new RoleScope())
->setRole(ActivityStatsVoter::LISTS);
->setRole(ActivityStatsVoter::LISTS)
;
$permissionsGroup->addRoleScope($roleScopeList);
$roleScopeStat = (new RoleScope())
->setRole(ActivityStatsVoter::STATS);
->setRole(ActivityStatsVoter::STATS)
;
$permissionsGroup->addRoleScope($roleScopeStat);
$manager->persist($roleScopeUpdate);
$manager->persist($roleScopeCreate);
$manager->persist($roleScopeDelete);
}
}
$manager->flush();
}
}

View File

@@ -1,27 +1,37 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DependencyInjection;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
/**
* This is the class that loads and manages your bundle configuration.
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
@@ -37,12 +47,11 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml');
$loader->load('services/export.yaml');
$loader->load('services/repositories.yaml');
$loader->load('services/fixtures.yaml');
$loader->load('services/menu.yaml');
$loader->load('services/controller.yaml');
$loader->load('services/form.yaml');
$loader->load('services/templating.yaml');
@@ -52,32 +61,104 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
{
$this->prependRoutes($container);
$this->prependAuthorization($container);
$this->prependCruds($container);
}
public function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', [
'role_hierarchy' => [
ActivityVoter::UPDATE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::CREATE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::DELETE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::SEE_DETAILS => [ActivityVoter::SEE],
],
]);
}
/** (non-PHPdoc).
/* (non-PHPdoc)
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
*/
public function prependRoutes(ContainerBuilder $container)
{
//add routes for custom bundle
$container->prependExtensionConfig('chill_main', array(
'routing' => array(
'resources' => array(
'@ChillActivityBundle/config/routes.yaml'
)
)
));
}
public function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', array(
'role_hierarchy' => array(
ActivityVoter::UPDATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::CREATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::DELETE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE)
)
));
}
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillActivityBundle/config/routes.yaml',
'cruds' => [
[
'class' => \Chill\ActivityBundle\Entity\ActivityType::class,
'name' => 'activity_type',
'base_path' => '/admin/activity/type',
'form_class' => \Chill\ActivityBundle\Form\ActivityTypeType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityType/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityType/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityType/edit.html.twig',
]
]
],
],
[
'class' => \Chill\ActivityBundle\Entity\ActivityTypeCategory::class,
'name' => 'activity_type_category',
'base_path' => '/admin/activity/type_category',
'form_class' => \Chill\ActivityBundle\Form\ActivityTypeCategoryType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeCategoryController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityTypeCategory/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityTypeCategory/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityTypeCategory/edit.html.twig',
]
]
],
[
'class' => \Chill\ActivityBundle\Entity\ActivityPresence::class,
'name' => 'activity_presence',
'base_path' => '/admin/activity/presence',
'form_class' => \Chill\ActivityBundle\Form\ActivityPresenceType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityPresenceController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityPresence/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityPresence/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityPresence/edit.html.twig',
]
]
],
]
]);
}
}

View File

@@ -1,25 +1,12 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use function is_int;
/**
* This is the class that validates and merges configuration from your app/config files.
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/
@@ -32,51 +19,53 @@ class Configuration implements ConfigurationInterface
{
$treeBuilder = new TreeBuilder('chill_activity');
$rootNode = $treeBuilder->getRootNode('chill_activity');
$rootNode
->children()
->arrayNode('form')
->canBeEnabled()
->children()
->arrayNode('time_duration')
->isRequired()
->requiresAtLeastOneElement()
->defaultValue(
[
['label' => '5 minutes', 'seconds' => 300],
['label' => '10 minutes', 'seconds' => 600],
['label' => '15 minutes', 'seconds' => 900],
['label' => '20 minutes', 'seconds' => 1200],
['label' => '25 minutes', 'seconds' => 1500],
['label' => '30 minutes', 'seconds' => 1800],
['label' => '45 minutes', 'seconds' => 2700],
['label' => '1 hour', 'seconds' => 3600],
['label' => '1 hour 15', 'seconds' => 4500],
['label' => '1 hour 30', 'seconds' => 5400],
['label' => '1 hour 45', 'seconds' => 6300],
['label' => '2 hours', 'seconds' => 7200],
]
)
->info('The intervals of time to show in activity form')
->prototype('array')
->children()
->scalarNode('seconds')
->info('The number of seconds of this duration. Must be an integer.')
->cannotBeEmpty()
->validate()
->ifTrue(static function ($data) {
return !is_int($data);
})->thenInvalid('The value %s is not a valid integer')
->end()
->end()
->scalarNode('label')
->cannotBeEmpty()
->info('The label to show into fields')
->end()
->end()
->end()
->children()
->arrayNode('form')
->canBeEnabled()
->children()
->arrayNode('time_duration')
->isRequired()
->requiresAtLeastOneElement()
->defaultValue(
array(
[ 'label' => '5 minutes', 'seconds' => 300],
[ 'label' => '10 minutes', 'seconds' => 600],
[ 'label' => '15 minutes', 'seconds' => 900],
[ 'label' => '20 minutes', 'seconds' => 1200],
[ 'label' => '25 minutes', 'seconds' => 1500],
[ 'label' => '30 minutes', 'seconds' => 1800],
[ 'label' => '45 minutes', 'seconds' => 2700],
[ 'label' => '1 hour', 'seconds' => 3600],
[ 'label' => '1 hour 15', 'seconds' => 4500],
[ 'label' => '1 hour 30', 'seconds' => 5400],
[ 'label' => '1 hour 45', 'seconds' => 6300],
[ 'label' => '2 hours', 'seconds' => 7200],
)
)
->info('The intervals of time to show in activity form')
->prototype('array')
->children()
->scalarNode('seconds')
->info("The number of seconds of this duration. Must be an integer.")
->cannotBeEmpty()
->validate()
->ifTrue(function($data) {
return !is_int($data);
})->thenInvalid("The value %s is not a valid integer")
->end()
->end()
->scalarNode('label')
->cannotBeEmpty()
->info("The label to show into fields")
->end()
->end()
->end()
// ->validate()
//
//
// ->ifTrue(function ($data) {
// // test this is an array
// if (!is_array($data)) {
@@ -95,10 +84,11 @@ class Configuration implements ConfigurationInterface
// })
// ->thenInvalid("The data are invalid. The keys must be a string and the value integers")
// ->end()
->end()
->end()
->end()
->end();
->end()
->end()
->end()
->end();
return $treeBuilder;
}

View File

@@ -1,333 +1,556 @@
<?php
/**
* Chill is a software for social workers.
/*
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Chill\MainBundle\Entity\Center;
use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/**
* @ORM\Entity
* Class Activity
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository")
* @ORM\Table(name="activity")
* @ORM\HasLifecycleCallbacks
* @UserCircleConsistency(
* "CHILL_ACTIVITY_SEE_DETAILS",
* getUserFunction="getUser",
* path="scope")
* @ORM\HasLifecycleCallbacks()
* @DiscriminatorMap(typeProperty="type", mapping={
* "activity"=Activity::class
* })
*/
/*
* TODO : revoir
* @UserCircleConsistency(
* "CHILL_ACTIVITY_SEE_DETAILS",
* getUserFunction="getUser",
* path="scope")
*/
class Activity implements HasCenterInterface, HasScopeInterface
{
const SENTRECEIVED_SENT = 'sent';
const SENTRECEIVED_RECEIVED = 'received';
/**
* @var bool
* @ORM\Column(type="boolean")
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
* @Groups({"read"})
*/
private $attendee;
private ?int $id = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private User $user;
/**
* @ORM\Column(type="datetime")
*/
private \DateTime $date;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?\DateTime $durationTime = null;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?\DateTime $travelTime = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityPresence")
*/
private ?ActivityPresence $attendee = null;
/**
* @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason")
*/
private Collection $reasons;
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialIssue")
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialissue")
* @Groups({"read"})
*/
private Collection $socialIssues;
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialAction")
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialaction")
* @Groups({"read"})
*/
private Collection $socialActions;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/
private ActivityType $type;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
*/
private ?Scope $scope = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
*/
private ?Person $person = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
* @Groups({"read"})
*/
private ?AccompanyingPeriod $accompanyingPeriod = null;
/**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_")
*/
private $comment;
private CommentEmbeddable $comment;
/**
* @var DateTime
* @ORM\Column(type="datetime")
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person")
* @Groups({"read"})
*/
private $date;
private ?Collection $persons = null;
/**
* @var DateTime
* @ORM\Column(type="time")
* @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
* @Groups({"read"})
*/
private $durationTime;
private ?Collection $thirdParties = null;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject")
*/
private $id;
private Collection $documents;
/**
* @var Person
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
* @Groups({"read"})
*/
private $person;
private ?Collection $users = null;
/**
* @var ActivityReason
* @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason")
* @ORM\Column(type="boolean", options={"default"=false})
*/
private $reasons;
private bool $emergency = false;
/**
* @var Scope
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
* @ORM\Column(type="string", options={"default"=""})
*/
private $scope;
private string $sentReceived = '';
/**
* @var ActivityType
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/
private $type;
/**
* @var User
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private $user;
/**
* Activity constructor.
*/
public function __construct()
{
$this->reasons = new ArrayCollection();
$this->comment = new CommentEmbeddable();
$this->persons = new ArrayCollection();
$this->thirdParties = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->users = new ArrayCollection();
$this->socialIssues = new ArrayCollection();
$this->socialActions = new ArrayCollection();
}
/**
* Add a reason.
*
* @return Activity
*/
public function addReason(ActivityReason $reason)
{
$this->reasons[] = $reason;
return $this;
}
/**
* Get attendee.
*
* @return bool
*/
public function getAttendee()
{
return $this->attendee;
}
/**
* get the center
* center is extracted from person.
*
* @return Center
*/
public function getCenter()
{
return $this->person->getCenter();
}
/**
* @return \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable
*/
public function getComment()
{
return $this->comment;
}
/**
* Get date.
*
* @return DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Get durationTime.
*
* @return DateTime
*/
public function getDurationTime()
{
return $this->durationTime;
}
/**
* Get id.
*
* @return int
*/
public function getId()
public function getId(): ?int
{
return $this->id;
}
/**
* Get person.
*
* @return Person
*/
public function getPerson()
public function setUser(User $user): self
{
return $this->person;
}
/**
* Get reasons.
*
* @return Collection
*/
public function getReasons()
{
return $this->reasons;
}
/**
* Get scope.
*
* @return Scope
*/
public function getScope()
{
return $this->scope;
}
/**
* Get type.
*
* @return ActivityType
*/
public function getType()
{
return $this->type;
}
/**
* Get user.
*
* @return User
*/
public function getUser()
{
return $this->user;
}
public function removeReason(ActivityReason $reason)
{
$this->reasons->removeElement($reason);
}
/**
* Set attendee.
*
* @param bool $attendee
*
* @return Activity
*/
public function setAttendee($attendee)
{
$this->attendee = $attendee;
$this->user = $user;
return $this;
}
/**
* @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment
*/
public function setComment($comment)
public function getUser(): User
{
$this->comment = $comment;
return $this->user;
}
/**
* Set date.
*
* @param DateTime $date
*
* @return Activity
*/
public function setDate($date)
public function setDate(\DateTime $date): self
{
$this->date = $date;
return $this;
}
/**
* Set durationTime.
*
* @param DateTime $durationTime
*
* @return Activity
*/
public function setDurationTime($durationTime)
public function getDate(): \DateTime
{
return $this->date;
}
public function setDurationTime(?\DateTime $durationTime): self
{
$this->durationTime = $durationTime;
return $this;
}
/**
* Set person.
*
* @return Activity
*/
public function setPerson(Person $person)
public function getDurationTime(): ?\DateTime
{
$this->person = $person;
return $this->durationTime;
}
public function setTravelTime(\DateTime $travelTime): self
{
$this->travelTime = $travelTime;
return $this;
}
/**
* Set scope.
*
* @return Activity
*/
public function setScope(Scope $scope)
public function getTravelTime(): ?\DateTime
{
$this->scope = $scope;
return $this->travelTime;
}
public function setAttendee(ActivityPresence $attendee): self
{
$this->attendee = $attendee;
return $this;
}
/**
* Set type.
*
* @return Activity
*/
public function setType(ActivityType $type)
public function getAttendee(): ?ActivityPresence
{
return $this->attendee;
}
public function addReason(ActivityReason $reason): self
{
$this->reasons->add($reason);
return $this;
}
public function removeReason(ActivityReason $reason): void
{
$this->reasons->removeElement($reason);
}
public function getReasons(): Collection
{
return $this->reasons;
}
public function setReasons(?ArrayCollection $reasons): self
{
$this->reasons = $reasons;
return $this;
}
public function getSocialIssues(): Collection
{
return $this->socialIssues;
}
public function addSocialIssue(SocialIssue $socialIssue): self
{
if (!$this->socialIssues->contains($socialIssue)) {
$this->socialIssues[] = $socialIssue;
}
return $this;
}
public function removeSocialIssue(SocialIssue $socialIssue): self
{
$this->socialIssues->removeElement($socialIssue);
return $this;
}
public function getSocialActions(): Collection
{
return $this->socialActions;
}
public function addSocialAction(SocialAction $socialAction): self
{
if (!$this->socialActions->contains($socialAction)) {
$this->socialActions[] = $socialAction;
}
return $this;
}
public function removeSocialAction(SocialAction $socialAction): self
{
$this->socialActions->removeElement($socialAction);
return $this;
}
public function setType(ActivityType $type): self
{
$this->type = $type;
return $this;
}
/**
* Set user.
*
* @return Activity
*/
public function setUser(User $user)
public function getType(): ActivityType
{
$this->user = $user;
return $this->type;
}
public function setScope(Scope $scope): self
{
$this->scope = $scope;
return $this;
}
public function getScope(): ?Scope
{
return $this->scope;
}
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
public function getPerson(): ?Person
{
return $this->person;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
$this->accompanyingPeriod = $accompanyingPeriod;
return $this;
}
/**
* get the center
* center is extracted from person
*/
public function getCenter(): ?Center
{
if ($this->person instanceof Person) {
return $this->person->getCenter();
}
return null;
}
public function getComment(): CommentEmbeddable
{
return $this->comment;
}
public function setComment(CommentEmbeddable $comment): self
{
$this->comment = $comment;
return $this;
}
/**
* Add a person to the person list
*/
public function addPerson(?Person $person): self
{
if (null !== $person) {
$this->persons[] = $person;
}
return $this;
}
public function removePerson(Person $person): void
{
$this->persons->removeElement($person);
}
public function getPersons(): Collection
{
return $this->persons;
}
public function getPersonsAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsAssociated = [];
foreach ($this->accompanyingPeriod->getParticipations() as $participation) {
if ($this->persons->contains($participation->getPerson())) {
$personsAssociated[] = $participation->getPerson();
}
}
return $personsAssociated;
}
return [];
}
public function getPersonsNotAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsNotAssociated = [];
foreach ($this->persons as $person) {
if (!in_array($person, $this->getPersonsAssociated())) {
$personsNotAssociated[] = $person;
}
}
return $personsNotAssociated;
}
return [];
}
public function setPersons(?Collection $persons): self
{
$this->persons = $persons;
return $this;
}
public function addThirdParty(?ThirdParty $thirdParty): self
{
if (null !== $thirdParty) {
$this->thirdParties[] = $thirdParty;
}
return $this;
}
public function removeThirdParty(ThirdParty $thirdParty): void
{
$this->thirdParties->removeElement($thirdParty);
}
public function getThirdParties(): Collection
{
return $this->thirdParties;
}
public function setThirdParties(?Collection $thirdParties): self
{
$this->thirdParties = $thirdParties;
return $this;
}
public function addDocument(Document $document): self
{
$this->documents[] = $document;
return $this;
}
public function removeDocument(Document $document): void
{
$this->documents->removeElement($document);
}
public function getDocuments(): Collection
{
return $this->documents;
}
public function setDocuments(Collection $documents): self
{
$this->documents = $documents;
return $this;
}
public function addUser(?User $user): self
{
if (null !== $user) {
$this->users[] = $user;
}
return $this;
}
public function removeUser(User $user): void
{
$this->users->removeElement($user);
}
public function getUsers(): Collection
{
return $this->users;
}
public function setUsers(?Collection $users): self
{
$this->users = $users;
return $this;
}
public function isEmergency(): bool
{
return $this->getEmergency();
}
public function getEmergency(): bool
{
return $this->emergency;
}
public function setEmergency(bool $emergency): self
{
$this->emergency = $emergency;
return $this;
}
public function getSentReceived(): string
{
return $this->sentReceived;
}
public function setSentReceived(?string $sentReceived): self
{
$this->sentReceived = (string) $sentReceived;
return $this;
}

View File

@@ -0,0 +1,97 @@
<?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;
use Doctrine\ORM\Mapping as ORM;
/**
* Class ActivityPresence
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytpresence")
* @ORM\HasLifecycleCallbacks()
*/
class ActivityPresence
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private ?int $id;
/**
* @ORM\Column(type="json")
*/
private array $name = [];
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
public function getId(): int
{
return $this->id;
}
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
public function getName(): array
{
return $this->name;
}
/**
* Get active
* return true if the category type is active.
*/
public function getActive(): bool
{
return $this->active;
}
/**
* Is active
* return true if the category type is active
*/
public function isActive(): bool
{
return $this->getActive();
}
/**
* Set active
* set to true if the category type is active
*/
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
}

View File

@@ -1,43 +1,40 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
/*
*
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
/**
* @ORM\Entity
* Class ActivityReason
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activityreason")
* @ORM\HasLifecycleCallbacks
* @ORM\HasLifecycleCallbacks()
*/
class ActivityReason
{
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @var ActivityReasonCategory
* @ORM\ManyToOne(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory",
* inversedBy="reasons")
*/
private $category;
/**
* @var int
* @var integer
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
@@ -52,17 +49,86 @@ class ActivityReason
private $name;
/**
* Get active.
*
* @return bool
* @var ActivityReasonCategory
* @ORM\ManyToOne(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory",
* inversedBy="reasons")
*/
public function getActive()
private $category;
/**
* @var boolean
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->active;
return $this->id;
}
/**
* Get category.
* Set name
*
* @param array $name
* @return ActivityReason
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return array | string
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
} else {
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
}
return '';
} else {
return $this->name;
}
}
/**
* Set category of the reason. If you set to the reason an inactive
* category, the reason will become inactive
*
* @param ActivityReasonCategory $category
* @return ActivityReason
*/
public function setCategory(ActivityReasonCategory $category)
{
if($this->category !== $category && ! $category->getActive()) {
$this->setActive(False);
}
$this->category = $category;
return $this;
}
/**
* Get category
*
* @return ActivityReasonCategory
*/
@@ -72,46 +138,9 @@ class ActivityReason
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array | string
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this->name;
}
/**
* Set active.
*
* @param bool $active
* Set active
*
* @param boolean $active
* @return ActivityReason
*/
public function setActive($active)
@@ -122,33 +151,13 @@ class ActivityReason
}
/**
* Set category of the reason. If you set to the reason an inactive
* category, the reason will become inactive.
* Get active
*
* @return ActivityReason
* @return boolean
*/
public function setCategory(ActivityReasonCategory $category)
public function getActive()
{
if ($this->category !== $category && !$category->getActive()) {
$this->setActive(false);
}
$this->category = $category;
return $this;
}
/**
* Set name.
*
* @param array $name
*
* @return ActivityReason
*/
public function setName($name)
{
$this->name = $name;
return $this;
return $this->active;
}
}

View File

@@ -1,36 +1,39 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
/*
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity
* Class ActivityReasonCategory
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activityreasoncategory")
* @ORM\HasLifecycleCallbacks
* @ORM\HasLifecycleCallbacks()
*/
class ActivityReasonCategory
{
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @var int
* @var integer
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
@@ -45,15 +48,20 @@ class ActivityReasonCategory
private $name;
/**
* Array of ActivityReason.
*
* @var boolean
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* Array of ActivityReason
* @var ArrayCollection
* @ORM\OneToMany(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReason",
* mappedBy="category")
* mappedBy="category")
*/
private $reasons;
/**
* ActivityReasonCategory constructor.
*/
@@ -61,29 +69,19 @@ class ActivityReasonCategory
{
$this->reasons = new ArrayCollection();
}
/**
* @return string
*/
public function __toString()
{
return 'ActivityReasonCategory(' . $this->getName('x') . ')';
return 'ActivityReasonCategory('.$this->getName('x').')';
}
/**
* Get active.
* Get id
*
* @return bool
*/
public function getActive()
{
return $this->active;
}
/**
* Get id.
*
* @return int
* @return integer
*/
public function getId()
{
@@ -91,58 +89,9 @@ class ActivityReasonCategory
}
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this->name;
}
/**
* Declare a category as active (or not). When a category is set
* as unactive, all the reason have this entity as category is also
* set as unactive.
*
* @param bool $active
*
* @return ActivityReasonCategory
*/
public function setActive($active)
{
if ($this->active !== $active && !$active) {
foreach ($this->reasons as $reason) {
$reason->setActive($active);
}
}
$this->active = $active;
return $this;
}
/**
* Set name.
* Set name
*
* @param array $name
*
* @return ActivityReasonCategory
*/
public function setName($name)
@@ -151,4 +100,59 @@ class ActivityReasonCategory
return $this;
}
/**
* Get name
*
* @return array
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
} else {
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
}
return '';
} else {
return $this->name;
}
}
/**
* Declare a category as active (or not). When a category is set
* as unactive, all the reason have this entity as category is also
* set as unactive
*
* @param boolean $active
* @return ActivityReasonCategory
*/
public function setActive($active)
{
if($this->active !== $active && !$active) {
foreach ($this->reasons as $reason) {
$reason->setActive($active);
}
}
$this->active = $active;
return $this;
}
/**
* Get active
*
* @return boolean
*/
public function getActive()
{
return $this->active;
}
}

View File

@@ -1,131 +1,822 @@
<?php
/**
* Chill is a software for social workers.
/*
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* Class ActivityType
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytype")
* @ORM\HasLifecycleCallbacks
* @ORM\HasLifecycleCallbacks()
*/
class ActivityType
{
/**
* @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
const FIELD_INVISIBLE = 0;
const FIELD_OPTIONAL = 1;
const FIELD_REQUIRED = 2;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private ?int $id;
/**
* @var array
* @ORM\Column(type="json_array")
*/
private $name;
private array $name = [];
/**
* Get active
* return true if the type is active.
*
* @return bool
* @ORM\Column(type="boolean")
*/
public function getActive()
{
return $this->active;
}
private bool $active = true;
/**
* Get id.
*
* @return int
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityTypeCategory")
*/
public function getId()
private ?ActivityTypeCategory $category = null;
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $personVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $personLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $userVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $userLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $dateVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $dateLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $placeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $placeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $personsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $personsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $thirdPartiesVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $thirdPartiesLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $durationTimeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $durationTimeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $travelTimeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $travelTimeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $attendeeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $attendeeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $reasonsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $reasonsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $commentVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $commentLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $sentReceivedVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $sentReceivedLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $documentsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $documentsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $usersVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $usersLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $emergencyVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $emergencyLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $accompanyingPeriodLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialDataVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialDataLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialIssuesVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialIssuesLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialActionsVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialActionsLabel = '';
/**
* @ORM\Column(type="float", options={"default"="0.0"})
*/
private float $ordering = 0.0;
/**
* Get id
*/
public function getId(): int
{
return $this->id;
}
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array | string
* Set name
*/
public function getName($locale = null)
public function setName(array $name): self
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
$this->name = $name;
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this;
}
/**
* Get name
*/
public function getName(): array
{
return $this->name;
}
/**
* Is active
* Get active
* return true if the type is active.
*
* @return bool
*/
public function isActive()
public function getActive(): bool
{
return $this->active;
}
/**
* Is active
* return true if the type is active
*/
public function isActive(): bool
{
return $this->getActive();
}
/**
* Set active
* set to true if the type is active.
*
* @param bool $active
*
* @return ActivityType
* set to true if the type is active
*/
public function setActive($active)
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
/**
* Set name.
*
* @param array $name
*
* @return ActivityType
*/
public function setName($name)
public function getCategory(): ?ActivityTypeCategory
{
$this->name = $name;
return $this->category;
}
public function setCategory(?ActivityTypeCategory $category): self
{
$this->category = $category;
return $this;
}
public function getPersonVisible(): int
{
return $this->personVisible;
}
public function setPersonVisible(int $personVisible): self
{
$this->personVisible = $personVisible;
return $this;
}
public function getPersonLabel(): string
{
return $this->personLabel;
}
public function setPersonLabel(string $personLabel): self
{
$this->personLabel = $personLabel;
return $this;
}
public function getUserVisible(): int
{
return $this->userVisible;
}
public function setUserVisible(int $userVisible): self
{
$this->userVisible = $userVisible;
return $this;
}
public function getUserLabel(): string
{
return $this->userLabel;
}
public function setUserLabel(string $userLabel): self
{
$this->userLabel = $userLabel;
return $this;
}
public function getDateVisible(): int
{
return $this->dateVisible;
}
public function setDateVisible(int $dateVisible): self
{
$this->dateVisible = $dateVisible;
return $this;
}
public function getDateLabel(): string
{
return $this->dateLabel;
}
public function setDateLabel(string $dateLabel): self
{
$this->dateLabel = $dateLabel;
return $this;
}
public function getPlaceVisible(): int
{
return $this->placeVisible;
}
public function setPlaceVisible(int $placeVisible): self
{
$this->placeVisible = $placeVisible;
return $this;
}
public function getPlaceLabel(): string
{
return $this->placeLabel;
}
public function setPlaceLabel(string $placeLabel): self
{
$this->placeLabel = $placeLabel;
return $this;
}
public function getPersonsVisible(): int
{
return $this->personsVisible;
}
public function setPersonsVisible(int $personsVisible): self
{
$this->personsVisible = $personsVisible;
return $this;
}
public function getPersonsLabel(): string
{
return $this->personsLabel;
}
public function setPersonsLabel(string $personsLabel): self
{
$this->personsLabel = $personsLabel;
return $this;
}
public function getThirdPartiesVisible(): int
{
return $this->thirdPartiesVisible;
}
public function setThirdPartiesVisible(int $thirdPartiesVisible): self
{
$this->thirdPartiesVisible = $thirdPartiesVisible;
return $this;
}
public function getThirdPartiesLabel(): string
{
return $this->thirdPartiesLabel;
}
public function setThirdPartiesLabel(string $thirdPartiesLabel): self
{
$this->thirdPartiesLabel = $thirdPartiesLabel;
return $this;
}
public function getDurationTimeVisible(): int
{
return $this->durationTimeVisible;
}
public function setDurationTimeVisible(int $durationTimeVisible): self
{
$this->durationTimeVisible = $durationTimeVisible;
return $this;
}
public function getDurationTimeLabel(): string
{
return $this->durationTimeLabel;
}
public function setDurationTimeLabel(string $durationTimeLabel): self
{
$this->durationTimeLabel = $durationTimeLabel;
return $this;
}
public function getTravelTimeVisible(): int
{
return $this->travelTimeVisible;
}
public function setTravelTimeVisible(int $TravelTimeVisible): self
{
$this->travelTimeVisible = $TravelTimeVisible;
return $this;
}
public function getTravelTimeLabel(): string
{
return $this->travelTimeLabel;
}
public function setTravelTimeLabel(string $TravelTimeLabel): self
{
$this->travelTimeLabel = $TravelTimeLabel;
return $this;
}
public function getAttendeeVisible(): int
{
return $this->attendeeVisible;
}
public function setAttendeeVisible(int $attendeeVisible): self
{
$this->attendeeVisible = $attendeeVisible;
return $this;
}
public function getAttendeeLabel(): string
{
return $this->attendeeLabel;
}
public function setAttendeeLabel(string $attendeeLabel): self
{
$this->attendeeLabel = $attendeeLabel;
return $this;
}
public function getReasonsVisible(): int
{
return $this->reasonsVisible;
}
public function setReasonsVisible(int $reasonsVisible): self
{
$this->reasonsVisible = $reasonsVisible;
return $this;
}
public function getReasonsLabel(): string
{
return $this->reasonsLabel;
}
public function setReasonsLabel(string $reasonsLabel): self
{
$this->reasonsLabel = $reasonsLabel;
return $this;
}
public function getCommentVisible(): int
{
return $this->commentVisible;
}
public function setCommentVisible(int $commentVisible): self
{
$this->commentVisible = $commentVisible;
return $this;
}
public function getCommentLabel(): string
{
return $this->commentLabel;
}
public function setCommentLabel(string $commentLabel): self
{
$this->commentLabel = $commentLabel;
return $this;
}
public function getSentReceivedVisible(): int
{
return $this->sentReceivedVisible;
}
public function setSentReceivedVisible(int $sentReceivedVisible): self
{
$this->sentReceivedVisible = $sentReceivedVisible;
return $this;
}
public function getSentReceivedLabel(): string
{
return $this->sentReceivedLabel;
}
public function setSentReceivedLabel(string $sentReceivedLabel): self
{
$this->sentReceivedLabel = $sentReceivedLabel;
return $this;
}
public function getDocumentsVisible(): int
{
return $this->documentsVisible;
}
public function setDocumentsVisible(int $documentsVisible): self
{
$this->documentsVisible = $documentsVisible;
return $this;
}
public function getDocumentsLabel(): string
{
return $this->documentsLabel;
}
public function setDocumentsLabel(string $documentsLabel): self
{
$this->documentsLabel = $documentsLabel;
return $this;
}
public function getUsersVisible(): int
{
return $this->usersVisible;
}
public function setUsersVisible(int $usersVisible): self
{
$this->usersVisible = $usersVisible;
return $this;
}
public function getUsersLabel(): string
{
return $this->usersLabel;
}
public function setUsersLabel(string $usersLabel): self
{
$this->usersLabel = $usersLabel;
return $this;
}
public function getEmergencyVisible(): int
{
return $this->emergencyVisible;
}
public function setEmergencyVisible(int $emergencyVisible): self
{
$this->emergencyVisible = $emergencyVisible;
return $this;
}
public function getEmergencyLabel(): string
{
return $this->emergencyLabel;
}
public function setEmergencyLabel(string $emergencyLabel): self
{
$this->emergencyLabel = $emergencyLabel;
return $this;
}
public function getAccompanyingPeriodVisible(): int
{
return $this->accompanyingPeriodVisible;
}
public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self
{
$this->accompanyingPeriodVisible = $accompanyingPeriodVisible;
return $this;
}
public function getAccompanyingPeriodLabel(): string
{
return $this->accompanyingPeriodLabel;
}
public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self
{
$this->accompanyingPeriodLabel = $accompanyingPeriodLabel;
return $this;
}
public function getSocialDataVisible(): int
{
return $this->socialDataVisible;
}
public function setSocialDataVisible(int $socialDataVisible): self
{
$this->socialDataVisible = $socialDataVisible;
return $this;
}
public function getSocialDataLabel(): string
{
return $this->socialDataLabel;
}
public function setSocialDataLabel(string $socialDataLabel): self
{
$this->socialDataLabel = $socialDataLabel;
return $this;
}
public function isVisible(string $field): bool
{
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return self::FIELD_INVISIBLE !== $this->$property;
}
public function isRequired(string $field): bool
{
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return self::FIELD_REQUIRED === $this->$property;
}
public function getLabel(string $field): ?string
{
$property = $field.'Label';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return $this->$property;
}
public function getOrdering(): float
{
return $this->ordering;
}
public function setOrdering(float $ordering): self
{
$this->ordering = $ordering;
return $this;
}
public function getSocialIssuesVisible(): ?int
{
return $this->socialIssuesVisible;
}
public function setSocialIssuesVisible(int $socialIssuesVisible): self
{
$this->socialIssuesVisible = $socialIssuesVisible;
return $this;
}
public function getSocialIssuesLabel(): ?string
{
return $this->socialIssuesLabel;
}
public function setSocialIssuesLabel(string $socialIssuesLabel): self
{
$this->socialIssuesLabel = $socialIssuesLabel;
return $this;
}
public function getSocialActionsVisible(): ?int
{
return $this->socialActionsVisible;
}
public function setSocialActionsVisible(int $socialActionsVisible): self
{
$this->socialActionsVisible = $socialActionsVisible;
return $this;
}
public function getSocialActionsLabel(): ?string
{
return $this->socialActionsLabel;
}
public function setSocialActionsLabel(string $socialActionsLabel): self
{
$this->socialActionsLabel = $socialActionsLabel;
return $this;
}

View File

@@ -0,0 +1,123 @@
<?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;
use Doctrine\ORM\Mapping as ORM;
/**
* Class ActivityTypeCateogry
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytypecategory")
* @ORM\HasLifecycleCallbacks()
*/
class ActivityTypeCategory
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private ?int $id;
/**
* @ORM\Column(type="json_array")
*/
private array $name = [];
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
/**
* @ORM\Column(type="float", options={"default"="0.0"})
*/
private float $ordering = 0.0;
/**
* Get id
*/
public function getId(): int
{
return $this->id;
}
/**
* Set name
*/
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
/**
* Get name
*/
public function getName(): array
{
return $this->name;
}
/**
* Get active
* return true if the category type is active.
*/
public function getActive(): bool
{
return $this->active;
}
/**
* Is active
* return true if the category type is active
*/
public function isActive(): bool
{
return $this->getActive();
}
/**
* Set active
* set to true if the category type is active
*/
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
public function getOrdering(): float
{
return $this->ordering;
}
public function setOrdering(float $ordering): self
{
$this->ordering = $ordering;
return $this;
}
}

View File

@@ -1,103 +1,107 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use function array_key_exists;
use function count;
class ActivityReasonAggregator implements
AggregatorInterface,
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonAggregator implements AggregatorInterface,
ExportElementValidatedInterface
{
/**
*
* @var EntityRepository
*/
protected $categoryRepository;
/**
*
* @var EntityRepository
*/
protected $reasonRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
public function __construct(
EntityRepository $categoryRepository,
EntityRepository $reasonRepository,
TranslatableStringHelper $stringHelper
EntityRepository $categoryRepository,
EntityRepository $reasonRepository,
TranslatableStringHelper $stringHelper
) {
$this->categoryRepository = $categoryRepository;
$this->reasonRepository = $reasonRepository;
$this->stringHelper = $stringHelper;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
$this->reasonRepository = $reasonRepository;
$this->stringHelper = $stringHelper;
}
public function alterQuery(QueryBuilder $qb, $data)
{
// add select element
if ('reasons' === $data['level']) {
if ($data['level'] === 'reasons') {
$elem = 'reasons.id';
$alias = 'activity_reasons_id';
} elseif ('categories' === $data['level']) {
} elseif ($data['level'] === 'categories') {
$elem = 'category.id';
$alias = 'activity_categories_id';
} else {
throw new RuntimeException('the data provided are not recognized');
throw new \RuntimeException('the data provided are not recognized');
}
$qb->addSelect($elem . ' as ' . $alias);
$qb->addSelect($elem.' as '.$alias);
// make a jointure only if needed
$join = $qb->getDQLPart('join');
if (
(
array_key_exists('activity', $join)
&& !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
(array_key_exists('activity', $join)
&&
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
)
|| (!array_key_exists('activity', $join))
OR
(! array_key_exists('activity', $join))
) {
$qb->add(
'join',
['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons'),
],
true
);
'join',
array('activity' =>
new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')
),
true);
}
// join category if necessary
if ('activity_categories_id' === $alias) {
if ($alias === 'activity_categories_id') {
// add join only if needed
if (!$this->checkJoinAlreadyDefined($qb->getDQLPart('join')['activity'], 'category')) {
$qb->join('reasons.category', 'category');
@@ -114,107 +118,12 @@ class ActivityReasonAggregator implements
}
}
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('level', ChoiceType::class, [
'choices' => [
'By reason' => 'reasons',
'By category of reason' => 'categories',
],
'multiple' => false,
'expanded' => true,
'label' => 'Reason\'s level',
]);
}
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
switch ($data['level']) {
case 'reasons':
$this->reasonRepository->findBy(['id' => $values]);
break;
case 'categories':
$this->categoryRepository->findBy(['id' => $values]);
break;
default:
throw new RuntimeException(sprintf(
"the level data '%s' is invalid",
$data['level']
));
}
return function ($value) use ($data) {
if ('_header' === $value) {
return 'reasons' === $data['level'] ?
'Group by reasons'
:
'Group by categories of reason';
}
switch ($data['level']) {
case 'reasons':
/** @var \Chill\ActivityBundle\Entity\ActivityReason $r */
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName())
. ' > '
. $this->stringHelper->localize($r->getName());
break;
case 'categories':
$c = $this->categoryRepository->find($value);
return $this->stringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
}
};
}
public function getQueryKeys($data)
{
// add select element
if ('reasons' === $data['level']) {
return ['activity_reasons_id'];
}
if ('categories' === $data['level']) {
return ['activity_categories_id'];
}
throw new RuntimeException('the data provided are not recognised');
}
public function getTitle()
{
return 'Aggregate by activity reason';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['level']) {
$context->buildViolation("The reasons's level should not be empty")
->addViolation();
}
}
/**
* Check if a join between Activity and another alias.
* Check if a join between Activity and another alias
*
* @param Join[] $joins
* @param string $alias the alias to search for
*
* @return bool
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
@@ -226,4 +135,99 @@ class ActivityReasonAggregator implements
return false;
}
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('level', ChoiceType::class, array(
'choices' => array(
'By reason' => 'reasons',
'By category of reason' => 'categories'
),
'multiple' => false,
'expanded' => true,
'label' => 'Reason\'s level'
));
}
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['level'] === null) {
$context->buildViolation("The reasons's level should not be empty")
->addViolation();
}
}
public function getTitle()
{
return "Aggregate by activity reason";
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
switch ($data['level']) {
case 'reasons':
$this->reasonRepository->findBy(array('id' => $values));
break;
case 'categories':
$this->categoryRepository->findBy(array('id' => $values));
break;
default:
throw new \RuntimeException(sprintf("the level data '%s' is invalid",
$data['level']));
}
return function($value) use ($data) {
if ($value === '_header') {
return $data['level'] === 'reasons' ?
'Group by reasons'
:
'Group by categories of reason'
;
}
switch ($data['level']) {
case 'reasons':
/* @var $r \Chill\ActivityBundle\Entity\ActivityReason */
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName())
." > "
. $this->stringHelper->localize($r->getName());
;
break;
case 'categories':
$c = $this->categoryRepository->find($value);
return $this->stringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
}
};
}
public function getQueryKeys($data)
{
// add select element
if ($data['level'] === 'reasons') {
return array('activity_reasons_id');
} elseif ($data['level'] === 'categories') {
return array ('activity_categories_id');
} else {
throw new \RuntimeException('the data provided are not recognised');
}
}
}

View File

@@ -1,62 +1,89 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityTypeAggregator implements AggregatorInterface
{
public const KEY = 'activity_type_aggregator';
/**
* @var TranslatableStringHelper
*/
protected $stringHelper;
/**
*
* @var EntityRepository
*/
protected $typeRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
const KEY = 'activity_type_aggregator';
public function __construct(
EntityRepository $typeRepository,
TranslatableStringHelper $stringHelper
EntityRepository $typeRepository,
TranslatableStringHelper $stringHelper
) {
$this->typeRepository = $typeRepository;
$this->stringHelper = $stringHelper;
$this->typeRepository = $typeRepository;
$this->stringHelper = $stringHelper;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data)
{
// add select element
// add select element
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
// add the "group by" part
$groupBy = $qb->addGroupBy(self::KEY);
}
/**
* Check if a join between Activity and another alias
*
* @param Join[] $joins
* @param string $alias the alias to search for
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn()
{
@@ -68,49 +95,37 @@ class ActivityTypeAggregator implements AggregatorInterface
// no form required for this aggregator
}
public function getTitle()
{
return "Aggregate by activity type";
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
$this->typeRepository->findBy(['id' => $values]);
return function ($value) {
if ('_header' === $value) {
$this->typeRepository->findBy(array('id' => $values));
return function($value) use ($data) {
if ($value === '_header') {
return 'Activity type';
}
/** @var \Chill\ActivityBundle\Entity\ActivityType $r */
/* @var $r \Chill\ActivityBundle\Entity\ActivityType */
$t = $this->typeRepository->find($value);
return $this->stringHelper->localize($t->getName());
};
}
public function getQueryKeys($data)
{
return [self::KEY];
return array(self::KEY);
}
public function getTitle()
{
return 'Aggregate by activity type';
}
/**
* Check if a join between Activity and another alias.
*
* @param Join[] $joins
* @param string $alias the alias to search for
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
}

View File

@@ -1,41 +1,51 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2019 Champs Libres Cooperative <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\AggregatorInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query\Expr\Join;
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
{
public const KEY = 'activity_user_id';
/**
*
* @var EntityManagerInterface
*/
protected $em;
public function __construct(EntityManagerInterface $em)
const KEY = 'activity_user_id';
function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
@@ -43,9 +53,9 @@ class ActivityUserAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data)
{
// add select element
// add select element
$qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY));
// add the "group by" part
$qb->addGroupBy(self::KEY);
}
@@ -60,17 +70,16 @@ class ActivityUserAggregator implements AggregatorInterface
// nothing to add
}
public function getLabels($key, $values, $data): Closure
public function getLabels($key, $values, $data): \Closure
{
// preload users at once
$this->em->getRepository(User::class)
->findBy(['id' => $values]);
return function ($value) {
return function($value) {
switch ($value) {
case '_header':
return 'activity user';
default:
return $this->em->getRepository(User::class)->find($value)
->getUsername();
@@ -80,11 +89,11 @@ class ActivityUserAggregator implements AggregatorInterface
public function getQueryKeys($data)
{
return [self::KEY];
return [ self::KEY ];
}
public function getTitle(): string
{
return 'Aggregate by activity user';
return "Aggregate by activity user";
}
}

View File

@@ -1,79 +1,64 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use LogicException;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountActivity implements ExportInterface
{
/**
*
* @var EntityManagerInterface
*/
protected $entityManager;
public function __construct(
EntityManagerInterface $em
) {
EntityManagerInterface $em
)
{
$this->entityManager = $em;
}
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
}
public function getAllowedFormattersTypes()
{
return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
return 'Count activities by various parameters.';
}
public function getLabels($key, array $values, $data)
{
if ('export_count_activity' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
return static function ($value) {
return '_header' === $value ?
'Number of activities'
:
$value;
};
}
public function getQueryKeys($data)
{
return ['export_count_activity'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
return "Count activities by various parameters.";
}
public function getTitle()
{
return 'Count activities';
return "Count activities";
}
public function getType()
@@ -81,30 +66,61 @@ class CountActivity implements ExportInterface
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
$qb = $this->entityManager->createQueryBuilder();
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb->select('COUNT(activity.id) as export_count_activity')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person');
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
;
$qb->where($qb->expr()->in('person.center', ':centers'))
->setParameter('centers', $centers);
->setParameter('centers', $centers)
;
return $qb;
}
public function supportsModifiers()
{
return array('person', 'activity');
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers()
public function getAllowedFormattersTypes()
{
return ['person', 'activity'];
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR);
}
public function getLabels($key, array $values, $data)
{
if ($key !== 'export_count_activity') {
throw new \LogicException("the key $key is not used by this export");
}
return function($value) {
return $value === '_header' ?
'Number of activities'
:
$value
;
};
}
public function getQueryKeys($data)
{
return array('export_count_activity');
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
}

View File

@@ -1,48 +1,69 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Doctrine\ORM\Query;
use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function array_key_exists;
use function count;
use function in_array;
/**
* Create a list for all activities.
* Create a list for all activities
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ListActivity implements ListInterface
{
/**
*
* @var EntityManagerInterface
*/
protected $entityManager;
protected $fields = [
/**
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $fields = array(
'id',
'date',
'durationTime',
@@ -53,132 +74,115 @@ class ListActivity implements ListInterface
'type_name',
'person_firstname',
'person_lastname',
'person_id',
];
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* @var TranslatorInterface
*/
protected $translator;
'person_id'
);
public function __construct(
EntityManagerInterface $em,
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper
) {
EntityManagerInterface $em,
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper
)
{
$this->entityManager = $em;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
}
/**
* {@inheritdoc}
* {@inheritDoc}
*
* @param FormBuilderInterface $builder
*/
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('fields', ChoiceType::class, [
$builder->add('fields', ChoiceType::class, array(
'multiple' => true,
'expanded' => true,
'choices' => array_combine($this->fields, $this->fields),
'label' => 'Fields to include in export',
'constraints' => [new Callback([
'callback' => static function ($selected, ExecutionContextInterface $context) {
'label' => 'Fields to include in export',
'constraints' => [new Callback(array(
'callback' => function($selected, ExecutionContextInterface $context) {
if (count($selected) === 0) {
$context->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
},
])],
]);
}
))]
));
}
/**
* {@inheritdoc}
* {@inheritDoc}
*
* @return type
*/
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_LIST];
return array(FormatterInterface::TYPE_LIST);
}
public function getDescription()
{
return 'List activities';
return "List activities";
}
public function getLabels($key, array $values, $data)
{
switch ($key) {
case 'date':
return static function ($value) {
if ('_header' === $value) {
return 'date';
}
switch ($key)
{
case 'date' :
return function($value) {
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');
};
case 'attendee':
return static function ($value) {
if ('_header' === $value) {
return 'attendee';
}
return function($value) {
if ($value === '_header') return 'attendee';
return $value ? 1 : 0;
};
case 'list_reasons':
/** @var EntityRepository $activityReasonsRepository */
case 'list_reasons' :
/* @var $activityReasonsRepository EntityRepository */
$activityRepository = $this->entityManager
->getRepository('ChillActivityBundle:Activity');
return function ($value) use ($activityRepository) {
if ('_header' === $value) {
return 'activity reasons';
}
return function($value) use ($activityRepository) {
if ($value === '_header') return 'activity reasons';
$activity = $activityRepository
->find($value);
->find($value);
return implode(', ', array_map(function (ActivityReason $r) {
return '"' .
return implode(", ", array_map(function(ActivityReason $r) {
return '"'.
$this->translatableStringHelper->localize($r->getCategory()->getName())
. ' > ' .
.' > '.
$this->translatableStringHelper->localize($r->getName())
. '"';
.'"';
}, $activity->getReasons()->toArray()));
};
case 'circle_name':
return function ($value) {
if ('_header' === $value) {
return 'circle';
}
case 'circle_name' :
return function($value) {
if ($value === '_header') return 'circle';
return $this->translatableStringHelper
->localize(json_decode($value, true));
->localize(json_decode($value, true));
};
case 'type_name':
return function ($value) {
if ('_header' === $value) {
return 'activity type';
}
case 'type_name' :
return function($value) {
if ($value === '_header') return 'activity type';
return $this->translatableStringHelper
->localize(json_decode($value, true));
->localize(json_decode($value, true));
};
default:
return static function ($value) use ($key) {
if ('_header' === $value) {
return $key;
}
return function($value) use ($key) {
if ($value === '_header') return $key;
return $value;
};
@@ -205,76 +209,68 @@ class ListActivity implements ListInterface
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(function($el) { return $el['center']; }, $acl);
// throw an error if any fields are present
if (!array_key_exists('fields', $data)) {
throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields '
. 'have been checked');
if (!\array_key_exists('fields', $data)) {
throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields "
. "have been checked");
}
$qb = $this->entityManager->createQueryBuilder();
$qb
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
;
foreach ($this->fields as $f) {
if (in_array($f, $data['fields'], true)) {
if (in_array($f, $data['fields'])) {
switch ($f) {
case 'id':
$qb->addSelect('activity.id AS id');
break;
case 'person_firstname':
$qb->addSelect('person.firstName AS person_firstname');
break;
case 'person_lastname':
$qb->addSelect('person.lastName AS person_lastname');
break;
case 'person_id':
$qb->addSelect('person.id AS person_id');
break;
case 'user_username':
$qb->join('activity.user', 'user');
$qb->addSelect('user.username AS user_username');
break;
case 'circle_name':
$qb->join('activity.scope', 'circle');
$qb->addSelect('circle.name AS circle_name');
break;
case 'type_name':
$qb->join('activity.type', 'type');
$qb->addSelect('type.name AS type_name');
break;
case 'list_reasons':
// this is a trick... The reasons is filled with the
// activity id which will be used to load reasons
$qb->addSelect('activity.id AS list_reasons');
break;
default:
$qb->addSelect(sprintf('activity.%s as %s', $f, $f));
break;
}
}
}
return $qb;
}
@@ -285,6 +281,7 @@ class ListActivity implements ListInterface
public function supportsModifiers()
{
return ['activity', 'person'];
return array('activity', 'person');
}
}

View File

@@ -1,109 +1,89 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use LogicException;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/**
* This export allow to compute stats on activity duration.
*
*
* The desired stat must be given in constructor.
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class StatActivityDuration implements ExportInterface
{
public const SUM = 'sum';
/**
*
* @var EntityManagerInterface
*/
protected $entityManager;
const SUM = 'sum';
/**
* The action for this report.
*
* @var string
*/
protected $action;
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* constructor.
*
* constructor
*
* @param EntityManagerInterface $em
* @param string $action the stat to perform
*/
public function __construct(
EntityManagerInterface $em,
$action = 'sum'
) {
EntityManagerInterface $em,
$action = 'sum'
)
{
$this->entityManager = $em;
$this->action = $action;
}
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
}
public function getAllowedFormattersTypes()
{
return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
if (self::SUM === $this->action) {
return 'Sum activities duration by various parameters.';
if ($this->action === self::SUM) {
return "Sum activities duration by various parameters.";
}
}
public function getLabels($key, array $values, $data)
{
if ('export_stat_activity' !== $key) {
throw new LogicException("the key {$key} is not used by this export");
}
switch ($this->action) {
case self::SUM:
$header = 'Sum of activities duration';
}
return static function ($value) use ($header) {
return '_header' === $value ?
$header
:
$value;
};
}
public function getQueryKeys($data)
{
return ['export_stat_activity'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle()
{
if (self::SUM === $this->action) {
return 'Sum activity duration';
if ($this->action === self::SUM) {
return "Sum activity duration";
}
}
public function getType()
@@ -111,34 +91,69 @@ class StatActivityDuration implements ExportInterface
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb = $this->entityManager->createQueryBuilder();
if (self::SUM === $this->action) {
$select = 'SUM(activity.durationTime) AS export_stat_activity';
if ($this->action === self::SUM) {
$select = "SUM(activity.durationTime) AS export_stat_activity";
}
$qb->select($select)
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers'))
->setParameter(':centers', $centers);
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers'))
->setParameter(':centers', $centers)
;
return $qb;
}
public function supportsModifiers()
{
return array('person', 'activity');
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers()
public function getAllowedFormattersTypes()
{
return ['person', 'activity'];
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR);
}
public function getLabels($key, array $values, $data)
{
if ($key !== 'export_stat_activity') {
throw new \LogicException("the key $key is not used by this export");
}
switch ($this->action) {
case self::SUM:
$header = "Sum of activities duration";
}
return function($value) use ($header) {
return $value === '_header' ?
$header
:
$value
;
};
}
public function getQueryKeys($data)
{
return array('export_stat_activity');
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
}

View File

@@ -1,40 +1,52 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Export\FilterType;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityDateFilter implements FilterInterface
{
/**
*
* @var TranslatorInterface
*/
protected $translator;
public function __construct(TranslatorInterface $translator)
function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public function addRole()
{
return null;
@@ -43,18 +55,15 @@ class ActivityDateFilter implements FilterInterface
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->between(
'activity.date',
':date_from',
':date_to'
);
$clause = $qb->expr()->between('activity.date', ':date_from',
':date_to');
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']);
@@ -67,58 +76,55 @@ class ActivityDateFilter implements FilterInterface
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, [
'label' => 'Activities after this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
$builder->add('date_from', DateType::class, array(
'label' => "Activities after this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->add('date_to', DateType::class, [
'label' => 'Activities before this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
));
$builder->add('date_to', DateType::class, array(
'label' => "Activities before this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/** @var \Symfony\Component\Form\FormInterface $filterForm */
));
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */
$filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if (true === $enabled) {
if ($enabled === true) {
// if the filter is enabled, add some validation
$form = $event->getForm();
$form = $event->getForm();
$date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData();
$date_to = $form->get('date_to')->getData();
// check that fields are not empty
if (null === $date_from) {
if ($date_from === null) {
$form->get('date_from')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
. 'should not be empty')));
}
if (null === $date_to) {
if ($date_to === null) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
}
. 'should not be empty')));
}
// check that date_from is before date_to
if (
(null !== $date_from && null !== $date_to)
&& $date_from >= $date_to
($date_from !== null && $date_to !== null)
&&
$date_from >= $date_to
) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This date should be after '
. 'the date given in "Implied in an activity after '
. 'this date" field')
));
. 'this date" field')));
}
}
});
@@ -126,16 +132,17 @@ class ActivityDateFilter implements FilterInterface
public function describeAction($data, $format = 'string')
{
return [
'Filtered by date of activity: only between %date_from% and %date_to%',
[
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
], ];
return array(
"Filtered by date of activity: only between %date_from% and %date_to%",
array(
"%date_from%" => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y')
));
}
public function getTitle()
{
return 'Filtered by date activity';
return "Filtered by date activity";
}
}

View File

@@ -1,83 +1,88 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use function array_key_exists;
use function count;
class ActivityReasonFilter implements
ExportElementValidatedInterface,
FilterInterface
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonFilter implements FilterInterface,
ExportElementValidatedInterface
{
/**
* The repository for activity reasons.
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $reasonRepository;
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct(
TranslatableStringHelper $helper,
EntityRepository $reasonRepository
TranslatableStringHelper $helper,
EntityRepository $reasonRepository
) {
$this->translatableStringHelper = $helper;
$this->reasonRepository = $reasonRepository;
$this->reasonRepository = $reasonRepository;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
$join = $qb->getDQLPart('join');
$join = $qb->getDQLPart('join');
$clause = $qb->expr()->in('reasons', ':selected_activity_reasons');
//dump($join);
// add a join to reasons only if needed
if (
(
array_key_exists('activity', $join)
&& !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
(array_key_exists('activity', $join)
&&
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
)
|| (!array_key_exists('activity', $join))
OR
(! array_key_exists('activity', $join))
) {
$qb->add(
'join',
['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')],
true
);
'join',
array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')),
true
);
}
if ($where instanceof Expr\Andx) {
@@ -85,10 +90,27 @@ class ActivityReasonFilter implements
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('selected_activity_reasons', $data['reasons']);
}
/**
* Check if a join between Activity and Reason is already defined
*
* @param Join[] $joins
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn()
{
@@ -99,63 +121,49 @@ class ActivityReasonFilter implements
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('reasons', EntityType::class, [
$builder->add('reasons', EntityType::class, array(
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => static function (ActivityReason $reason) use ($helper) {
'choice_label' => function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getName());
},
'group_by' => static function (ActivityReason $reason) use ($helper) {
'group_by' => function(ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getCategory()->getName());
},
'multiple' => true,
'expanded' => false,
]);
'expanded' => false
));
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function (ActivityReason $r) {
return '"' . $this->translatableStringHelper->localize($r->getName()) . '"';
},
$this->reasonRepository->findBy(['id' => $data['reasons']->toArray()])
);
return ['Filtered by reasons: only %list%',
['%list%' => implode(', ', $reasonsNames)], ];
}
public function getTitle()
{
return 'Filter by reason';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
$context->buildViolation('At least one reason must be choosen')
if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen")
->addViolation();
}
}
/**
* Check if a join between Activity and Reason is already defined.
*
* @param Join[] $joins
* @param mixed $alias
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
public function getTitle()
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
return 'Filter by reason';
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function(ActivityReason $r) {
return "\"".$this->translatableStringHelper->localize($r->getName())."\"";
},
$this->reasonRepository->findBy(array('id' => $data['reasons']->toArray()))
);
return array("Filtered by reasons: only %list%",
["%list%" => implode(", ", $reasonsNames)]);
}
}

View File

@@ -1,63 +1,67 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\ActivityBundle\Entity\ActivityType;
use function count;
class ActivityTypeFilter implements
ExportElementValidatedInterface,
FilterInterface
/**
*
*
*/
class ActivityTypeFilter implements FilterInterface,
ExportElementValidatedInterface
{
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* The repository for activity reasons.
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $typeRepository;
public function __construct(
TranslatableStringHelper $helper,
EntityRepository $typeRepository
TranslatableStringHelper $helper,
EntityRepository $typeRepository
) {
$this->translatableStringHelper = $helper;
$this->typeRepository = $typeRepository;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
@@ -68,10 +72,27 @@ class ActivityTypeFilter implements
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter('selected_activity_types', $data['types']);
}
/**
* Check if a join between Activity and Reason is already defined
*
* @param Join[] $joins
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn()
{
@@ -82,60 +103,46 @@ class ActivityTypeFilter implements
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('types', EntityType::class, [
$builder->add('types', EntityType::class, array(
'class' => ActivityType::class,
'choice_label' => static function (ActivityType $type) use ($helper) {
'choice_label' => function (ActivityType $type) use ($helper) {
return $helper->localize($type->getName());
},
'multiple' => true,
'expanded' => false,
]);
'expanded' => false
));
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function (ActivityType $t) {
return '"' . $this->translatableStringHelper->localize($t->getName()) . '"';
},
$this->typeRepository->findBy(['id' => $data['types']->toArray()])
);
return ['Filtered by activity type: only %list%',
['%list%' => implode(', ', $reasonsNames)], ];
}
public function getTitle()
{
return 'Filter by activity type';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['types'] || count($data['types']) === 0) {
$context->buildViolation('At least one type must be choosen')
if ($data['types'] === null || count($data['types']) === 0) {
$context->buildViolation("At least one type must be choosen")
->addViolation();
}
}
/**
* Check if a join between Activity and Reason is already defined.
*
* @param Join[] $joins
* @param mixed $alias
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
public function getTitle()
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
return 'Filter by activity type';
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function(ActivityType $t) {
return "\"".$this->translatableStringHelper->localize($t->getName())."\"";
},
$this->typeRepository->findBy(array('id' => $data['types']->toArray()))
);
return array("Filtered by activity type: only %list%",
["%list%" => implode(", ", $reasonsNames)]);
}
}

View File

@@ -1,66 +1,79 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Chill\PersonBundle\Export\Declarations;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use function count;
class PersonHavingActivityBetweenDateFilter implements
ExportElementValidatedInterface,
FilterInterface
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonHavingActivityBetweenDateFilter implements FilterInterface,
ExportElementValidatedInterface
{
/**
* @var EntityRepository
*/
protected $activityReasonRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* @var TranslatorInterface
*
* @var EntityRepository
*/
protected $activityReasonRepository;
/**
*
* @var TranslatorInterface
*/
protected $translator;
public function __construct(
TranslatableStringHelper $translatableStringHelper,
EntityRepository $activityReasonRepository,
TranslatorInterface $translator
TranslatableStringHelper $translatableStringHelper,
EntityRepository $activityReasonRepository,
TranslatorInterface $translator
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->activityReasonRepository = $activityReasonRepository;
$this->translator = $translator;
$this->translator = $translator;
}
public function addRole()
{
return null;
@@ -70,26 +83,24 @@ class PersonHavingActivityBetweenDateFilter implements
{
// create a query for activity
$sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select('person_person_having_activity.id')
->from('ChillActivityBundle:Activity', 'activity_person_having_activity')
->join('activity_person_having_activity.person', 'person_person_having_activity');
$sqb->select("person_person_having_activity.id")
->from("ChillActivityBundle:Activity", "activity_person_having_activity")
->join("activity_person_having_activity.person", "person_person_having_activity")
;
// add clause between date
$sqb->where('activity_person_having_activity.date BETWEEN '
. ':person_having_activity_between_date_from'
. ' AND '
. ':person_having_activity_between_date_to');
$sqb->where("activity_person_having_activity.date BETWEEN "
. ":person_having_activity_between_date_from"
. " AND "
. ":person_having_activity_between_date_to");
// add clause activity reason
$sqb->join(
'activity_person_having_activity.reasons',
'reasons_person_having_activity'
);
$sqb->join('activity_person_having_activity.reasons',
'reasons_person_having_activity');
$sqb->andWhere(
$sqb->expr()->in(
'reasons_person_having_activity',
':person_having_activity_reasons'
)
);
$sqb->expr()->in(
'reasons_person_having_activity',
":person_having_activity_reasons")
);
$where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('person.id', $sqb->getDQL());
@@ -98,16 +109,12 @@ class PersonHavingActivityBetweenDateFilter implements
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
$qb->setParameter(
'person_having_activity_between_date_from',
$data['date_from']
);
$qb->setParameter(
'person_having_activity_between_date_to',
$data['date_to']
);
$qb->setParameter('person_having_activity_between_date_from',
$data['date_from']);
$qb->setParameter('person_having_activity_between_date_to',
$data['date_to']);
$qb->setParameter('person_having_activity_reasons', $data['reasons']);
}
@@ -118,107 +125,104 @@ class PersonHavingActivityBetweenDateFilter implements
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, [
'label' => 'Implied in an activity after this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
$builder->add('date_from', DateType::class, array(
'label' => "Implied in an activity after this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->add('date_to', DateType::class, [
'label' => 'Implied in an activity before this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
));
$builder->add('date_to', DateType::class, array(
'label' => "Implied in an activity before this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->add('reasons', EntityType::class, [
));
$builder->add('reasons', EntityType::class, array(
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $reason) {
return $this->translatableStringHelper
->localize($reason->getName());
->localize($reason->getName());
},
'group_by' => function (ActivityReason $reason) {
'group_by' => function(ActivityReason $reason) {
return $this->translatableStringHelper
->localize($reason->getCategory()->getName());
->localize($reason->getCategory()->getName());
},
'data' => $this->activityReasonRepository->findAll(),
'multiple' => true,
'expanded' => false,
'label' => 'Activity reasons for those activities',
]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/** @var \Symfony\Component\Form\FormInterface $filterForm */
'label' => "Activity reasons for those activities"
));
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */
$filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if (true === $enabled) {
if ($enabled === true) {
// if the filter is enabled, add some validation
$form = $event->getForm();
$form = $event->getForm();
$date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData();
$date_to = $form->get('date_to')->getData();
// check that fields are not empty
if (null === $date_from) {
if ($date_from === null) {
$form->get('date_from')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
. 'should not be empty')));
}
if (null === $date_to) {
if ($date_to === null) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This field '
. 'should not be empty')
));
}
. 'should not be empty')));
}
// check that date_from is before date_to
if (
(null !== $date_from && null !== $date_to)
&& $date_from >= $date_to
($date_from !== null && $date_to !== null)
&&
$date_from >= $date_to
) {
$form->get('date_to')->addError(new FormError(
$this->translator->trans('This date '
. 'should be after the date given in "Implied in an '
. 'activity after this date" field')
));
. 'activity after this date" field')));
}
}
});
}
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen")
->addViolation();
}
}
public function describeAction($data, $format = 'string')
{
return [
'Filtered by person having an activity between %date_from% and '
. '%date_to% with reasons %reasons_name%',
[
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
'%reasons_name%' => implode(', ', array_map(
function (ActivityReason $r) {
return '"' . $this->translatableStringHelper->
localize($r->getName()) . '"';
},
$data['reasons']
)),
], ];
return array(
"Filtered by person having an activity between %date_from% and "
. "%date_to% with reasons %reasons_name%",
array(
"%date_from%" => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
"%reasons_name%" => implode(", ", array_map(
function (ActivityReason $r) {
return '"'.$this->translatableStringHelper->
localize($r->getName()).'"';
},
$data['reasons']))
));
}
public function getTitle()
{
return 'Filtered by person having an activity in a period';
return "Filtered by person having an activity in a period";
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
$context->buildViolation('At least one reason must be choosen')
->addViolation();
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\ActivityPresence;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityPresenceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true
));
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(array(
'data_class' => ActivityPresence::class
));
}
}

View File

@@ -1,31 +1,25 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityReasonCategoryType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', CheckboxType::class, ['required' => false]);
->add('active', CheckboxType::class, array('required' => false))
;
}
/**
@@ -33,9 +27,9 @@ class ActivityReasonCategoryType extends AbstractType
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory',
]);
$resolver->setDefaults(array(
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory'
));
}
/**

View File

@@ -1,40 +1,37 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory;
class ActivityReasonType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', CheckboxType::class, ['required' => false])
->add('category', TranslatableActivityReasonCategory::class);
->add('active', CheckboxType::class, array('required' => false))
->add('category', TranslatableActivityReasonCategory::class)
;
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason',
]);
$resolver->setDefaults(array(
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason'
));
}
/**

View File

@@ -1,87 +1,81 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Chill\ActivityBundle\Form\Type\TranslatableActivityType;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityPresence;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\DocStoreBundle\Form\StoredObjectType;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Form\Type\UserPickerType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use DateInterval;
use DateTime;
use DateTimeZone;
use Doctrine\Persistence\ObjectManager;
use RuntimeException;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use function in_array;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\UserPickerType;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Form\Type\ChillDateType;
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
{
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected User $user;
/**
* @var ObjectManager
*/
protected $om;
protected AuthorizationHelper $authorizationHelper;
protected $timeChoices;
protected ObjectManager $om;
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected TranslatableStringHelper $translatableStringHelper;
/**
* the user running this form.
*
* @var User
*/
protected $user;
protected SocialIssueRender $socialIssueRender;
public function __construct(
protected SocialActionRender $socialActionRender;
protected array $timeChoices;
public function __construct (
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
ObjectManager $om,
TranslatableStringHelper $translatableStringHelper,
array $timeChoices
array $timeChoices,
SocialIssueRender $socialIssueRender,
SocialActionRender $socialActionRender
) {
if (!$tokenStorage->getToken()->getUser() instanceof User) {
throw new RuntimeException('you should have a valid user');
throw new \RuntimeException("you should have a valid user");
}
$this->user = $tokenStorage->getToken()->getUser();
$this->authorizationHelper = $authorizationHelper;
$this->om = $om;
$this->translatableStringHelper = $translatableStringHelper;
$this->timeChoices = $timeChoices;
$this->socialIssueRender = $socialIssueRender;
$this->socialActionRender = $socialActionRender;
}
public function buildForm(FormBuilderInterface $builder, array $options)
public function buildForm(FormBuilderInterface $builder, array $options): void
{
// handle times choices
$timeChoices = [];
@@ -96,104 +90,301 @@ class ActivityType extends AbstractType
'placeholder' => 'Choose the duration',
];
$builder
->add('date', ChillDateType::class, [
'required' => true,
])
->add('durationTime', ChoiceType::class, $durationTimeOptions)
->add('attendee', ChoiceType::class, [
'expanded' => true,
'required' => false,
'choices' => [
'present' => true,
'not present' => false,
],
])
->add('user', UserPickerType::class, [
/** @var \Chill\ActivityBundle\Entity\ActivityType $activityType */
$activityType = $options['activityType'];
if (!$activityType->isActive()) {
throw new \InvalidArgumentException('Activity type must be active');
}
// TODO revoir la gestion des center au niveau du form des activité.
if ($options['center']) {
$builder->add('scope', ScopePickerType::class, [
'center' => $options['center'],
'role' => $options['role'],
])
->add('scope', ScopePickerType::class, [
'center' => $options['center'],
'role' => $options['role'],
])
->add('reasons', TranslatableActivityReason::class, [
'multiple' => true,
'required' => false,
])
->add('type', TranslatableActivityType::class, [
'placeholder' => 'Choose a type',
'active_only' => true,
])
->add('comment', CommentType::class, [
'required' => false,
'role' => $options['role']
]);
}
$builder->get('durationTime')
->addModelTransformer($durationTimeTransformer);
/** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = NULL;
if ($options['accompanyingPeriod']) {
$accompanyingPeriod = $options['accompanyingPeriod'];
}
$builder->get('durationTime')
->addEventListener(
FormEvents::PRE_SET_DATA,
static function (FormEvent $formEvent) use (
if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) {
$builder->add('socialIssues', HiddenType::class);
$builder->get('socialIssues')
->addModelTransformer(new CallbackTransformer(
function (iterable $socialIssuesAsIterable): string {
$socialIssueIds = [];
foreach ($socialIssuesAsIterable as $value) {
$socialIssueIds[] = $value->getId();
}
return implode(',', $socialIssueIds);
},
function (?string $socialIssuesAsString): array {
if (null === $socialIssuesAsString) {
return [];
}
return array_map(
fn(string $id): ?SocialIssue => $this->om->getRepository(SocialIssue::class)->findOneBy(['id' => (int) $id]),
explode(',', $socialIssuesAsString)
);
}
))
;
}
if ($activityType->isVisible('socialActions') && $accompanyingPeriod) {
$builder->add('socialActions', HiddenType::class);
$builder->get('socialActions')
->addModelTransformer(new CallbackTransformer(
function (iterable $socialActionsAsIterable): string {
$socialActionIds = [];
foreach ($socialActionsAsIterable as $value) {
$socialActionIds[] = $value->getId();
}
return implode(',', $socialActionIds);
},
function (?string $socialActionsAsString): array {
if (null === $socialActionsAsString) {
return [];
}
return array_map(
fn(string $id): ?SocialAction => $this->om->getRepository(SocialAction::class)->findOneBy(['id' => (int) $id]),
explode(',', $socialActionsAsString)
);
}
))
;
}
if ($activityType->isVisible('date')) {
$builder->add('date', ChillDateType::class, [
'label' => $activityType->getLabel('date'),
'required' => $activityType->isRequired('date'),
]);
}
if ($activityType->isVisible('durationTime')) {
$durationTimeOptions['label'] = $activityType->getLabel('durationTime');
$durationTimeOptions['required'] = $activityType->isRequired('durationTime');
$builder->add('durationTime', ChoiceType::class, $durationTimeOptions);
}
if ($activityType->isVisible('travelTime')) {
$durationTimeOptions['label'] = $activityType->getLabel('travelTime');
$durationTimeOptions['required'] = $activityType->isRequired('travelTime');
$builder->add('travelTime', ChoiceType::class, $durationTimeOptions);
}
if ($activityType->isVisible('attendee')) {
$builder->add('attendee', EntityType::class, [
'label' => $activityType->getLabel('attendee'),
'required' => $activityType->isRequired('attendee'),
'expanded' => true,
'class' => ActivityPresence::class,
'choice_label' => function (ActivityPresence $activityPresence) {
return $this->translatableStringHelper->localize($activityPresence->getName());
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('a')
->where('a.active = true');
},
]);
}
if ($activityType->isVisible('user') && $options['center']) {
$builder->add('user', UserPickerType::class, [
'label' => $activityType->getLabel('user'),
'required' => $activityType->isRequired('user'),
'center' => $options['center'],
'role' => $options['role']
]);
}
if ($activityType->isVisible('reasons')) {
$builder->add('reasons', EntityType::class, [
'label' => $activityType->getLabel('reasons'),
'required' => $activityType->isRequired('reasons'),
'class' => ActivityReason::class,
'multiple' => true,
'choice_label' => function (ActivityReason $activityReason) {
return $this->translatableStringHelper->localize($activityReason->getName());
},
'attr' => array('class' => 'select2 '),
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('a')
->where('a.active = true');
},
]);
}
if ($activityType->isVisible('comment')) {
$builder->add('comment', CommentType::class, [
'label' => empty($activityType->getLabel('comment'))
? 'activity.comment' : $activityType->getLabel('comment'),
'required' => $activityType->isRequired('comment'),
]);
}
if ($activityType->isVisible('persons')) {
$builder->add('persons', HiddenType::class);
$builder->get('persons')
->addModelTransformer(new CallbackTransformer(
function (iterable $personsAsIterable): string {
$personIds = [];
foreach ($personsAsIterable as $value) {
$personIds[] = $value->getId();
}
return implode(',', $personIds);
},
function (?string $personsAsString): array {
return array_map(
fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]),
explode(',', $personsAsString)
);
}
))
;
}
if ($activityType->isVisible('thirdParties')) {
$builder->add('thirdParties', HiddenType::class);
$builder->get('thirdParties')
->addModelTransformer(new CallbackTransformer(
function (iterable $thirdpartyAsIterable): string {
$thirdpartyIds = [];
foreach ($thirdpartyAsIterable as $value) {
$thirdpartyIds[] = $value->getId();
}
return implode(',', $thirdpartyIds);
},
function (?string $thirdpartyAsString): array {
return array_map(
fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]),
explode(',', $thirdpartyAsString)
);
}
))
;
}
if ($activityType->isVisible('documents')) {
$builder->add('documents', ChillCollectionType::class, [
'entry_type' => StoredObjectType::class,
'label' => $activityType->getLabel('documents'),
'required' => $activityType->isRequired('documents'),
'allow_add' => true,
'button_add_label' => 'activity.Insert a document',
'button_remove_label' => 'activity.Remove a document'
]);
}
if ($activityType->isVisible('users')) {
$builder->add('users', HiddenType::class);
$builder->get('users')
->addModelTransformer(new CallbackTransformer(
function (iterable $usersAsIterable): string {
$userIds = [];
foreach ($usersAsIterable as $value) {
$userIds[] = $value->getId();
}
return implode(',', $userIds);
},
function (?string $usersAsString): array {
return array_map(
fn(string $id): ?User => $this->om->getRepository(User::class)->findOneBy(['id' => (int) $id]),
explode(',', $usersAsString)
);
}
))
;
}
if ($activityType->isVisible('emergency')) {
$builder->add('emergency', CheckboxType::class, [
'label' => $activityType->getLabel('emergency'),
'required' => $activityType->isRequired('emergency'),
]);
}
if ($activityType->isVisible('sentReceived')) {
$builder->add('sentReceived', ChoiceType::class, [
'label' => $activityType->getLabel('sentReceived'),
'required' => $activityType->isRequired('sentReceived'),
'choices' => [
'Sent' => Activity::SENTRECEIVED_SENT,
'Received' => Activity::SENTRECEIVED_RECEIVED,
],
]);
}
foreach (['durationTime', 'travelTime'] as $fieldName) {
if (!$activityType->isVisible($fieldName)) {
continue;
}
$builder->get($fieldName)
->addModelTransformer($durationTimeTransformer);
$builder->get($fieldName)
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use (
$timeChoices,
$builder,
$durationTimeTransformer,
$durationTimeOptions
$durationTimeOptions,
$fieldName
) {
// set the timezone to GMT, and fix the difference between current and GMT
// the datetimetransformer will then handle timezone as GMT
$timezoneUTC = new DateTimeZone('GMT');
/** @var DateTime $data */
$data = $formEvent->getData() === null ?
DateTime::createFromFormat('U', 300) :
$formEvent->getData();
$timezoneUTC = new \DateTimeZone('GMT');
/* @var $data \DateTime */
$data = $formEvent->getData() === NULL ?
\DateTime::createFromFormat('U', 300) :
$formEvent->getData();
$seconds = $data->getTimezone()->getOffset($data);
$data->setTimeZone($timezoneUTC);
$data->add(new DateInterval('PT' . $seconds . 'S'));
$data->add(new \DateInterval('PT'.$seconds.'S'));
// test if the timestamp is in the choices.
// If not, recreate the field with the new timestamp
if (!in_array($data->getTimestamp(), $timeChoices, true)) {
if (!in_array($data->getTimestamp(), $timeChoices)) {
// the data are not in the possible values. add them
$timeChoices[$data->format('H:i')] = $data->getTimestamp();
$form = $builder->create(
'durationTime',
ChoiceType::class,
array_merge(
$durationTimeOptions,
[
'choices' => $timeChoices,
'auto_initialize' => false,
]
)
);
$form = $builder->create($fieldName, ChoiceType::class, array_merge(
$durationTimeOptions, [
'choices' => $timeChoices,
'auto_initialize' => false
]
));
$form->addModelTransformer($durationTimeTransformer);
$formEvent->getForm()->getParent()->add($form->getForm());
}
}
);
});
}
}
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver)
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\Activity',
'data_class' => Activity::class
]);
$resolver
->setRequired(['center', 'role'])
->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center')
->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role');
->setRequired(['center', 'role', 'activityType', 'accompanyingPeriod'])
->setAllowedTypes('center', ['null', 'Chill\MainBundle\Entity\Center'])
->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role')
->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class)
->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null'])
;
}
/**
* @return string
*/
public function getBlockPrefix()
public function getBlockPrefix(): string
{
return 'chill_activitybundle_activity';
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityTypeCategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true
))
->add('ordering', NumberType::class, [
'required' => true,
'scale' => 5
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(array(
'data_class' => ActivityTypeCategory::class
));
}
}

View File

@@ -1,26 +1,28 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Chill\ActivityBundle\Form\Type\ActivityFieldPresence;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityTypeType extends AbstractType
{
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
@@ -28,27 +30,42 @@ class ActivityTypeType extends AbstractType
->add('active', ChoiceType::class, [
'choices' => [
'Yes' => true,
'No' => false,
'No' => false
],
'expanded' => true,
]);
'expanded' => true
])
->add('category', EntityType::class, [
'class' => ActivityTypeCategory::class,
'choice_label' => function (ActivityTypeCategory $activityTypeCategory) {
return $this->translatableStringHelper->localize($activityTypeCategory->getName());
},
])
->add('ordering', NumberType::class, [
'required' => true,
'scale' => 5
])
;
$fields = [
'persons', 'user', 'date', 'place', 'persons',
'thirdParties', 'durationTime', 'travelTime', 'attendee',
'reasons', 'comment', 'sentReceived', 'documents',
'emergency', 'accompanyingPeriod', 'socialData', 'users'
];
foreach ($fields as $field) {
$builder
->add($field.'Visible', ActivityFieldPresence::class)
->add($field.'Label', TextType::class, [
'required' => false,
'empty_data' => '',
]);
}
}
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityType',
]);
}
/**
* @return string
*/
public function getBlockPrefix()
{
return 'chill_activitybundle_activitytype';
$resolver->setDefaults(array(
'data_class' => \Chill\ActivityBundle\Entity\ActivityType::class
));
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ActivityFieldPresence extends AbstractType
{
public function getParent()
{
return ChoiceType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'choices' => [
'Invisible' => ActivityType::FIELD_INVISIBLE,
'Optional' => ActivityType::FIELD_OPTIONAL,
'Required' => ActivityType::FIELD_REQUIRED,
],
)
);
}
}

View File

@@ -1,40 +1,53 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2020, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender;
/**
* FormType to choose amongst activity reasons.
* FormType to choose amongst activity reasons
*
*/
class TranslatableActivityReason extends AbstractType
{
/**
* @var ActivityReasonRender
*/
protected $reasonRender;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
*
* @var ActivityReasonRender
*/
protected $reasonRender;
public function __construct(
TranslatableStringHelper $translatableStringHelper,
@@ -44,30 +57,6 @@ class TranslatableActivityReason extends AbstractType
$this->reasonRender = $reasonRender;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []);
},
'group_by' => function (ActivityReason $choice): ?string {
if (null !== $category = $choice->getCategory()) {
return $this->translatableStringHelper->localize($category->getName());
}
return null;
},
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.active = true');
},
'attr' => ['class' => ' select2 '],
]
);
}
public function getBlockPrefix()
{
return 'translatable_activity_reason';
@@ -77,4 +66,28 @@ class TranslatableActivityReason extends AbstractType
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function(ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []);
},
'group_by' => function(ActivityReason $choice): ?string {
if (null !== $category = $choice->getCategory()) {
return $this->translatableStringHelper->localize($category->getName());
}
return null;
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.active = true');
},
'attr' => [ 'class' => ' select2 ']
)
);
}
}

View File

@@ -1,27 +1,40 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form\Type;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
/**
* Description of TranslatableActivityReasonCategory.
* Description of TranslatableActivityReasonCategory
*
* @author Champs-Libres Coop
*/
class TranslatableActivityReasonCategory extends AbstractType
{
/**
@@ -34,21 +47,6 @@ class TranslatableActivityReasonCategory extends AbstractType
$this->requestStack = $requestStack;
}
public function configureOptions(OptionsResolver $resolver)
{
$locale = $this->requestStack->getCurrentRequest()->getLocale();
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityReasonCategory',
'choice_label' => 'name[' . $locale . ']',
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.active = true');
},
]
);
}
public function getBlockPrefix()
{
return 'translatable_activity_reason_category';
@@ -58,4 +56,19 @@ class TranslatableActivityReasonCategory extends AbstractType
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$locale = $this->requestStack->getCurrentRequest()->getLocale();
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityReasonCategory',
'choice_label' => 'name['.$locale.']',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.active = true');
}
)
);
}
}

View File

@@ -1,71 +1,60 @@
<?php
/**
* Chill is a software for social workers.
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* @see https://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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityType;
/**
* Description of TranslatableActivityType.
* Description of TranslatableActivityType
*
* @author Champs-Libres Coop
*/
class TranslatableActivityType extends AbstractType
{
protected $activityTypeRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $activityTypeRepository;
public function __construct(
TranslatableStringHelper $helper,
EntityRepository $activityTypeRepository
) {
TranslatableStringHelper $helper,
EntityRepository $activityTypeRepository
)
{
$this->translatableStringHelper = $helper;
$this->activityTypeRepository = $activityTypeRepository;
}
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options)
{
/** @var \Doctrine\ORM\QueryBuilder $qb */
$qb = $options['query_builder'];
if (true === $options['active_only']) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityType',
'active_only' => true,
'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
},
]
);
}
public function getBlockPrefix()
{
return 'translatable_activity_type';
@@ -75,4 +64,30 @@ class TranslatableActivityType extends AbstractType
{
return EntityType::class;
}
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) {
/* @var $qb \Doctrine\ORM\QueryBuilder */
$qb = $options['query_builder'];
if ($options['active_only'] === true) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityType',
'active_only' => true,
'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
}
)
);
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Chill\ActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
{
protected TokenStorageInterface $tokenStorage;
protected AuthorizationHelper $authorizationHelper;
protected TranslatorInterface $translator;
public function __construct(
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
TranslatorInterface $translator
) {
$this->translator = $translator;
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
}
public static function getMenuIds(): array
{
return ['accompanyingCourse'];
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
$period = $parameters['accompanyingCourse'];
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
$menu->addChild($this->translator->trans('Activity list'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => [
'accompanying_period_id' => $period->getId(),
]])
->setExtras(['order' => 40]);
}
}
}

View File

@@ -1,88 +0,0 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Translation\TranslatorInterface;
class MenuBuilder implements LocalMenuBuilderInterface
{
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct(
TokenStorageInterface $tokenStorage,
TranslatorInterface $translator,
AuthorizationHelper $authorizationHelper
) {
$this->tokenStorage = $tokenStorage;
$this->translator = $translator;
$this->authorizationHelper = $authorizationHelper;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
$person = $parameters['person'];
$user = $this->tokenStorage->getToken()->getUser();
$roleSee = new Role(ActivityVoter::SEE);
$roleAdd = new Role(ActivityVoter::CREATE);
if ($this->authorizationHelper->userHasAccess($user, $person, $roleSee)) {
$menu->addChild($this->translator->trans('Activity list'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => [
'person_id' => $person->getId(),
],
])
->setExtras([
'order' => 201,
]);
}
if ($this->authorizationHelper->userHasAccess($user, $person, $roleAdd)) {
$menu->addChild($this->translator->trans('Add a new activity'), [
'route' => 'chill_activity_activity_new',
'routeParameters' => [
'person_id' => $person->getId(),
],
])
->setExtras([
'order' => 200,
]);
}
}
public static function getMenuIds(): array
{
return ['person'];
}
}

View File

@@ -1,69 +1,68 @@
<?php
/**
* Chill is a software for social workers.
/*
* Copyright (C) 2018 Julien Fastré <julien.fastre@champs-libres.coop>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
* 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.
*
* @see https://www.champs-libres.coop/
* 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/>.
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
namespace Chill\ActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonMenuBuilder implements LocalMenuBuilderInterface
{
/**
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
/**
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
TranslatorInterface $translator
) {
TranslatorInterface $translator)
{
$this->translator = $translator;
$this->authorizationChecker = $authorizationChecker;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
/* @var $person \Chill\PersonBundle\Entity\Person */
$person = $parameters['person'];
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
$menu->addChild(
$this->translator->trans('Activity list'),
[
$this->translator->trans('Activity list'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => ['person_id' => $person->getId()],
]
)
->setExtra('order', 201);
}
if ($this->authorizationChecker->isGranted(ActivityVoter::CREATE, $person)) {
$menu->addChild(
$this->translator->trans('Add a new activity'),
[
'route' => 'chill_activity_activity_new',
'routeParameters' => ['person_id' => $person->getId()],
]
)
->setExtra('order', 200);
'routeParameters' => [ 'person_id' => $person->getId() ],
])
->setExtra('order', 201)
;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Chill\ActivityBundle\Notification;
use Chill\MainBundle\Entity\Notification;
use Chill\ActivityBundle\Entity\Activity;
final class ActivityNotificationRenderer
{
public function supports(Notification $notification, array $options = []): bool
{
return $notification->getRelatedEntityClass() == Activity::class;
}
public function getTemplate()
{
return '@ChillActivity/Activity/showInNotification.html.twig';
}
public function getTemplateData(Notification $notification)
{
return ['notification' => $notification];
}
}

View File

@@ -0,0 +1,169 @@
<?php
/*
* 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;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\Person;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Scope;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\Orx;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\EntityManagerInterface;
final class ActivityACLAwareRepository
{
private AuthorizationHelper $authorizationHelper;
private TokenStorageInterface $tokenStorage;
private ActivityRepository $repository;
private EntityManagerInterface $em;
public function __construct(
AuthorizationHelper $authorizationHelper,
TokenStorageInterface $tokenStorage,
ActivityRepository $repository,
EntityManagerInterface $em
) {
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
$this->repository = $repository;
$this->em = $em;
}
public function queryTimelineIndexer(string $context, array $args = []): array
{
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$from = $this->getFromClauseCenter($args);
[$where, $parameters] = $this->getWhereClause($context, $args);
return [
'id' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('id'),
'type' => 'activity',
'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'),
'FROM' => $from,
'WHERE' => $where,
'parameters' => $parameters
];
}
private function getFromClauseCenter(array $args): string
{
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class);
$associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName().' JOIN '
.$metadataPerson->getTableName().' ON '
.$metadataPerson->getTableName().'.'.
$associationMapping['joinColumns'][0]['referencedColumnName']
.' = '
.$associationMapping['joinColumns'][0]['name']
;
}
private function getWhereClause(string $context, array $args): array
{
$where = '';
$parameters = [];
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class);
$activityToPerson = $metadataActivity->getAssociationMapping('person')['joinColumns'][0]['name'];
$activityToScope = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'];
$personToCenter = $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'];
// acls:
$role = new Role(ActivityVoter::SEE);
$reachableCenters = $this->authorizationHelper->getReachableCenters($this->tokenStorage->getToken()->getUser(),
$role);
if (count($reachableCenters) === 0) {
// insert a dummy condition
return 'FALSE = TRUE';
}
if ($context === 'person') {
// we start with activities having the person_id linked to person
$where .= sprintf('%s = ? AND ', $activityToPerson);
$parameters[] = $person->getId();
}
// we add acl (reachable center and scopes)
$where .= '('; // first loop for the for centers
$centersI = 0; // like centers#i
foreach ($reachableCenters as $center) {
// we pass if not in centers
if (!\in_array($center, $args['centers'])) {
continue;
}
// we get all the reachable scopes for this center
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), $role, $center);
// we get the ids for those scopes
$reachablesScopesId = array_map(
function(Scope $scope) { return $scope->getId(); },
$reachableScopes
);
// if not the first center
if ($centersI > 0) {
$where .= ') OR (';
}
// condition for the center
$where .= sprintf(' %s.%s = ? ', $metadataPerson->getTableName(), $personToCenter);
$parameters[] = $center->getId();
// begin loop for scopes
$where .= ' AND (';
$scopesI = 0; //like scope#i
foreach ($reachablesScopesId as $scopeId) {
if ($scopesI > 0) {
$where .= ' OR ';
}
$where .= sprintf(' %s.%s = ? ', $metadataActivity->getTableName(), $activityToScope);
$parameters[] = $scopeId;
$scopesI ++;
}
// close loop for scopes
$where .= ') ';
$centersI++;
}
// close loop for centers
$where .= ')';
return [$where, $parameters];
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* 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;
use Chill\ActivityBundle\Entity\Activity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
* @method AccompanyingPeriodParticipation[] findAll()
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Activity::class);
}
public function findByPersonImplied($person, array $scopes, $orderBy = [ 'date' => 'DESC'], $limit = 100, $offset = 0)
{
$qb = $this->createQueryBuilder('a');
$qb->select('a');
$qb
// TODO add acl
//->where($qb->expr()->in('a.scope', ':scopes'))
//->setParameter('scopes', $scopes)
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('a.person', ':person'),
':person MEMBER OF a.persons'
)
)
->setParameter('person', $person)
;
foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir);
}
return $qb->getQuery()
->getResult();
}
}

View File

@@ -1,10 +0,0 @@
@import '~ChillMainSass/custom/config/colors';
@import '~ChillMainSass/custom/mixins/entity';
.chill-entity.chill-entity__activity-reason {
@include entity($chill-pink, white);
}
.activity {
color: $chill-green;
}

View File

@@ -1 +1 @@
require('./activity/activity.scss');
require('./scss/chillactivity.scss');

View File

@@ -0,0 +1,130 @@
@import '~ChillMainAssets/modules/bootstrap/bootstrap';
//@import '~ChillMainSass/custom/mixins/entity';
//.chill-entity.chill-entity__activity-reason {
// @include entity($chill-pink, white);
//}
.activity {
color: $chill-green;
}
// exceptions for flex-bloc in concerned-groups
div.flex-bloc.concerned-groups {
margin-top: 1em;
div.item-bloc {
flex-grow: 0; flex-shrink: 0; flex-basis: 25%; //4 blocs
ul.list-content {
list-style-type: none;
padding-left: 0;
li {
margin-bottom: 0.2em;
a {
color: white;
cursor: pointer;
&:hover {
color: #ffffffab;
}
}
}
}
}
&.person div.item-bloc {
flex-basis: 33%; //3 blocs
}
}
// exceptions for flex-table in list-records
div.flex-table.list-records {
div.item-bloc {
div.item-row.main {
div.item-col {
&:first-child {
flex-basis: 27%;
}
ul.list-content {
li.social-issues, li.social-actions {
.badge-primary {
font-variant: small-caps;
font-weight: bold;
font-size: 88%;
margin-bottom: 0.2em;
}
}
li.social-issues .badge-primary {
background-color: var(--chill-orange);
}
li.social-actions .badge-primary {
background-color: var(--chill-green);
}
}
}
}
div.item-row.details {
flex-direction: row;
& > div.item-col {
justify-content: flex-start;
align-self: center;
&:nth-child(1) {
flex-grow: 1; flex-shrink: 0; flex-basis: 30%;
}
&:nth-child(2) {
flex-grow: 0; flex-shrink: 1; flex-basis: 70%;
}
&:only-child {
flex-grow: 0; flex-shrink: 0; flex-basis: 100%;
& > div.concerned-groups {
flex-grow: 0; flex-shrink: 0; flex-basis: 100%;
display: flex;
flex-direction: column; // TODO pas fini
div.group {
flex-grow: 1; flex-shrink: 0; flex-basis: 30%;
h4 {}
ul.list-content {
li {
display: inline;
}
}
}
}
}
}
div.concerned-groups {
font-size: 85%;
h4 {
text-transform: uppercase;
}
}
}
ul.list-content {
list-style-type: none;
padding-left: 1em;
margin: 0 0;
li {
margin-bottom: 0.2em;
}
}
}
div.duration {
font-size: smaller;
padding-left: 1em;
margin-top: 1em;
}
}
div.activity-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
div.bloc {
width: 200px;
align-self: flex-end;
height: 140px;
display: flex;
justify-content: center;
align-items: center;
}
}

View File

@@ -0,0 +1,17 @@
<template>
<concerned-groups></concerned-groups>
<social-issues-acc></social-issues-acc>
</template>
<script>
import ConcernedGroups from './components/ConcernedGroups.vue';
import SocialIssuesAcc from './components/SocialIssuesAcc.vue';
export default {
name: "App",
components: {
ConcernedGroups,
SocialIssuesAcc
}
}
</script>

View File

@@ -0,0 +1,18 @@
import { getSocialIssues } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api.js';
/*
* Load socialActions by socialIssue (id)
*/
const getSocialActionByIssue = (id) => {
const url = `/api/1.0/person/social/social-action/by-social-issue/${id}.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
export {
getSocialIssues,
getSocialActionByIssue
};

View File

@@ -0,0 +1,170 @@
<template>
<teleport to="#add-persons">
<div class="flex-bloc concerned-groups" :class="getContext">
<persons-bloc
v-for="bloc in contextPersonsBlocs"
v-bind:key="bloc.key"
v-bind:bloc="bloc"
v-bind:setPersonsInBloc="setPersonsInBloc">
</persons-bloc>
</div>
<add-persons
buttonTitle="activity.add_persons"
modalTitle="activity.add_persons"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons">
</add-persons>
</teleport>
</template>
<script>
import { mapState } from 'vuex';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import PersonsBloc from './ConcernedGroups/PersonsBloc.vue';
export default {
name: "ConcernedGroups",
components: {
AddPersons,
PersonsBloc
},
data() {
return {
personsBlocs: [
{ key: 'persons',
title: 'activity.bloc_persons',
persons: [],
included: false
},
{ key: 'personsAssociated',
title: 'activity.bloc_persons_associated',
persons: [],
included: false
},
{ key: 'personsNotAssociated',
title: 'activity.bloc_persons_not_associated',
persons: [],
included: false
},
{ key: 'thirdparty',
title: 'activity.bloc_thirdparty',
persons: [],
included: true
},
{ key: 'users',
title: 'activity.bloc_users',
persons: [],
included: true
},
],
addPersons: {
key: 'activity',
options: {
type: ['person', 'thirdparty', 'user'], // TODO add 'user'
priority: null,
uniq: false,
}
}
}
},
computed: {
...mapState({
persons: state => state.activity.persons,
thirdParties: state => state.activity.thirdParties,
users: state => state.activity.users,
accompanyingCourse: state => state.activity.accompanyingPeriod
}),
getContext() {
return (this.accompanyingCourse) ? "accompanyingCourse" : "person";
},
contextPersonsBlocs() {
return this.personsBlocs.filter(bloc => bloc.included !== false);
}
},
mounted() {
this.setPersonsInBloc();
},
methods: {
setPersonsInBloc() {
let groups;
if (this.accompanyingCourse) {
groups = this.splitPersonsInGroups();
}
this.personsBlocs.forEach(bloc => {
if (this.accompanyingCourse) {
switch (bloc.key) {
case 'personsAssociated':
bloc.persons = groups.personsAssociated;
bloc.included = true;
break;
case 'personsNotAssociated':
bloc.persons = groups.personsNotAssociated;
bloc.included = true;
break;
}
} else {
switch (bloc.key) {
case 'persons':
bloc.persons = this.persons;
bloc.included = true;
break;
}
}
switch (bloc.key) {
case 'thirdparty':
bloc.persons = this.thirdParties;
break;
case 'users':
bloc.persons = this.users;
break;
}
}, groups);
},
splitPersonsInGroups() {
let personsAssociated = [];
let personsNotAssociated = this.persons;
let participations = this.getCourseParticipations();
this.persons.forEach(person => {
participations.forEach(participation => {
if (person.id === participation.id) {
//console.log(person.id);
personsAssociated.push(person);
personsNotAssociated = personsNotAssociated.filter(p => p !== person);
}
});
});
return {
'personsAssociated': personsAssociated,
'personsNotAssociated': personsNotAssociated
};
},
getCourseParticipations() {
let participations = [];
this.accompanyingCourse.participations.forEach(participation => {
if (!participation.endDate) {
participations.push(participation.person);
}
});
return participations;
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addPersonsInvolved', item);
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
this.setPersonsInBloc();
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,29 @@
<template>
<li>
<span class="badge bg-primary" :title="person.text">
<span class="chill_denomination">
{{ textCutted }}
</span>
<a class="fa fa-fw fa-times"
@click.prevent="$emit('remove', person)">
</a>
</span>
</li>
</template>
<script>
export default {
name: "PersonBadge",
props: ['person'],
computed: {
textCutted() {
let more = (this.person.text.length > 15) ?'…' : '';
return this.person.text.slice(0,15) + more;
}
},
emits: ['remove'],
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,41 @@
<template>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<h4>{{ $t(bloc.title) }}</h4>
</div>
<div class="item-col">
<ul class="list-content">
<person-badge
v-for="person in bloc.persons"
v-bind:key="person.id"
v-bind:person="person"
@remove="removePerson">
</person-badge>
</ul>
</div>
</div>
</div>
</template>
<script>
import PersonBadge from './PersonBadge.vue';
export default {
name:"PersonsBloc",
components: {
PersonBadge
},
props: ['bloc', 'setPersonsInBloc'],
methods: {
removePerson(item) {
console.log('@@ CLICK remove person: item', item);
this.$store.dispatch('removePersonInvolved', item);
this.setPersonsInBloc();
}
}
}
</script>
<style lang="scss">
</style>

View File

@@ -0,0 +1,214 @@
<template>
<teleport to="#social-issues-acc">
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_issues') }}</label>
</div>
<div class="col-8">
<check-social-issue
v-for="issue in socialIssuesList"
v-bind:key="issue.id"
v-bind:issue="issue"
v-bind:selection="socialIssuesSelected"
@updateSelected="updateIssuesSelected">
</check-social-issue>
<div class="my-3">
<VueMultiselect
name="otherIssues"
label="text"
track-by="id"
open-direction="bottom"
v-bind:close-on-select="true"
v-bind:preserve-search="false"
v-bind:reset-after="true"
v-bind:hide-selected="true"
v-bind:taggable="false"
v-bind:multiple="false"
v-bind:searchable="true"
v-bind:allow-empty="true"
v-bind:show-labels="false"
v-bind:loading="issueIsLoading"
v-bind:placeholder="$t('activity.choose_other_social_issue')"
v-bind:options="socialIssuesOther"
v-model="value"
@select="addIssueInList">
</VueMultiselect>
</div>
</div>
</div>
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_actions') }}</label>
</div>
<div class="col-8">
<div v-if="actionIsLoading === true">
<i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
</div>
<check-social-action
v-if="socialIssuesSelected.length || socialActionsSelected.length"
v-for="action in socialActionsList"
v-bind:key="action.id"
v-bind:action="action"
v-bind:selection="socialActionsSelected"
@updateSelected="updateActionsSelected">
</check-social-action>
<span v-else class="inline-choice chill-no-data-statement mt-3">
{{ $t('activity.select_first_a_social_issue') }}
</span>
</div>
</div>
</teleport>
</template>
<script>
import { readonly } from 'vue';
import VueMultiselect from 'vue-multiselect';
import CheckSocialIssue from './SocialIssuesAcc/CheckSocialIssue.vue';
import CheckSocialAction from './SocialIssuesAcc/CheckSocialAction.vue';
import { getSocialIssues, getSocialActionByIssue } from '../api.js';
export default {
name: "SocialIssuesAcc",
components: {
CheckSocialIssue,
CheckSocialAction,
VueMultiselect
},
data() {
return {
issueIsLoading: false,
actionIsLoading: false
}
},
computed: {
socialIssuesList() {
return this.$store.state.activity.accompanyingPeriod.socialIssues;
},
socialIssuesSelected() {
return this.$store.state.activity.socialIssues;
},
socialIssuesOther() {
return this.$store.state.socialIssuesOther;
},
socialActionsList() {
return this.$store.state.socialActionsList;
},
socialActionsSelected() {
return this.$store.state.activity.socialActions;
}
},
mounted() {
/* Load others issues in multiselect
*/
this.issueIsLoading = true;
getSocialIssues().then(response => new Promise((resolve, reject) => {
this.$store.commit('updateIssuesOther', response.results);
/* Add in list the issues already associated (if not yet listed)
*/
this.socialIssuesSelected.forEach(issue => {
if (this.socialIssuesList.filter(i => i.id === issue.id).length !== 1) {
this.$store.commit('addIssueInList', issue);
}
}, this);
/* Remove from multiselect the issues that are not yet in checkbox list
*/
this.socialIssuesList.forEach(issue => {
this.$store.commit('removeIssueInOther', issue);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'issues');
/* Add in list the actions already associated (if not yet listed)
*/
this.socialActionsSelected.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'actions');
this.issueIsLoading = false;
resolve();
}));
},
methods: {
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
remove it from multiselect, and add socialActions concerned
*/
addIssueInList(value) {
//console.log('addIssueInList', value);
this.$store.commit('addIssueInList', value);
this.$store.commit('removeIssueInOther', value);
this.$store.dispatch('addIssueSelected', value);
this.updateActionsList();
},
/* Update value for selected issues checkboxes
*/
updateIssuesSelected(issues) {
//console.log('updateIssuesSelected', issues);
this.$store.dispatch('updateIssuesSelected', issues);
this.updateActionsList();
},
/* Update value for selected actions checkboxes
*/
updateActionsSelected(actions) {
//console.log('updateActionsSelected', actions);
this.$store.dispatch('updateActionsSelected', actions);
},
/* Add socialActions concerned: after reset, loop on each issue selected
to get social actions concerned
*/
updateActionsList() {
//console.log('updateActionsList');
this.resetActionsList();
this.socialIssuesSelected.forEach(item => {
this.actionIsLoading = true;
getSocialActionByIssue(item.id)
.then(actions => new Promise((resolve, reject) => {
actions.results.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
this.$store.commit('filterList', 'actions');
this.actionIsLoading = false;
resolve();
}));
}, this);
},
/* Reset socialActions List: flush list and restore selected actions
*/
resetActionsList() {
this.$store.commit('resetActionsList');
this.socialActionsSelected.forEach(item => {
this.$store.commit('addActionInList', item);
}, this);
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="scss">
span.multiselect__single {
display: none !important;
}
</style>

View File

@@ -0,0 +1,36 @@
<template>
<span class="inline-choice">
<div class="form-check">
<input class="form-check-input"
type="checkbox"
v-model="selected"
name="action"
v-bind:id="action.id"
v-bind:value="action"
/>
<label class="form-check-label" v-bind:for="action.id">
{{ action.text }}
</label>
</div>
</span>
</template>
<script>
export default {
name: "CheckSocialAction",
props: [ 'action', 'selection' ],
emits: [ 'updateSelected' ],
computed: {
selected: {
set(value) {
this.$emit('updateSelected', value);
},
get() {
return this.selection;
}
}
}
}
</script>

View File

@@ -0,0 +1,36 @@
<template>
<span class="inline-choice">
<div class="form-check">
<input class="form-check-input"
type="checkbox"
v-model="selected"
name="issue"
v-bind:id="issue.id"
v-bind:value="issue"
/>
<label class="form-check-label" v-bind:for="issue.id">
{{ issue.text }}
</label>
</div>
</span>
</template>
<script>
export default {
name: "CheckSocialIssue",
props: [ 'issue', 'selection' ],
emits: [ 'updateSelected' ],
computed: {
selected: {
set(value) {
this.$emit('updateSelected', value);
},
get() {
return this.selection;
}
}
}
}
</script>

View File

@@ -0,0 +1,27 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
const appMessages = {
fr: {
activity: {
//
social_issues: "Problématiques sociales",
choose_other_social_issue: "Ajouter une autre problématique sociale...",
social_actions: "Actions d'accompagnement",
select_first_a_social_issue: "Sélectionnez d'abord une problématique sociale",
//
add_persons: "Ajouter des personnes concernées",
bloc_persons: "Usagers",
bloc_persons_associated: "Usagers du parcours",
bloc_persons_not_associated: "Tiers non-pro.",
bloc_thirdparty: "Tiers professionnels",
bloc_users: "T(M)S",
}
}
}
Object.assign(appMessages.fr, personMessages.fr);
export {
appMessages
};

View File

@@ -0,0 +1,16 @@
import { createApp } from 'vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { appMessages } from './i18n'
import store from './store'
import App from './App.vue';
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
.use(store)
.use(i18n)
.component('app', App)
.mount('#activity');

View File

@@ -0,0 +1,170 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
const debug = process.env.NODE_ENV !== 'production';
//console.log('window.activity', window.activity);
const addIdToValue = (string, id) => {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
};
const removeIdFromValue = (string, id) => {
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
return str;
};
const store = createStore({
strict: debug,
state: {
activity: window.activity,
socialIssuesOther: [],
socialActionsList: [],
},
mutations: {
// SocialIssueAcc
addIssueInList(state, issue) {
//console.log('add issue list', issue.id);
state.activity.accompanyingPeriod.socialIssues.push(issue);
},
addIssueSelected(state, issue) {
//console.log('add issue selected', issue.id);
state.activity.socialIssues.push(issue);
},
updateIssuesSelected(state, issues) {
//console.log('update issues selected', issues);
state.activity.socialIssues = issues;
},
updateIssuesOther(state, payload) {
//console.log('update issues other');
state.socialIssuesOther = payload;
},
removeIssueInOther(state, issue) {
//console.log('remove issue other', issue.id);
state.socialIssuesOther = state.socialIssuesOther.filter(i => i.id !== issue.id);
},
resetActionsList(state) {
//console.log('reset list actions');
state.socialActionsList = [];
},
addActionInList(state, action) {
//console.log('add action list', action.id);
state.socialActionsList.push(action);
},
updateActionsSelected(state, actions) {
//console.log('update actions selected', actions);
state.activity.socialActions = actions;
},
filterList(state, list) {
const filterList = (list) => {
// remove duplicates entries
list = list.filter((value, index) => list.findIndex(array => array.id === value.id) === index);
// alpha sort
list.sort((a,b) => (a.text > b.text) ? 1 : ((b.text > a.text) ? -1 : 0));
return list;
};
if (list === 'issues') {
state.activity.accompanyingPeriod.socialIssues = filterList(state.activity.accompanyingPeriod.socialIssues);
}
if (list === 'actions') {
state.socialActionsList = filterList(state.socialActionsList);
}
},
// ConcernedGroups
addPersonsInvolved(state, payload) {
//console.log('### mutation addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
state.activity.persons.push(payload.result);
break;
case 'thirdparty':
state.activity.thirdParties.push(payload.result);
break;
case 'user':
state.activity.users.push(payload.result);
break;
};
},
removePersonInvolved(state, payload) {
//console.log('### mutation removePersonInvolved', payload.type);
switch (payload.type) {
case 'person':
state.activity.persons = state.activity.persons.filter(person => person !== payload);
break;
case 'thirdparty':
state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload);
break;
case 'user':
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
};
}
},
actions: {
addIssueSelected({ commit }, issue) {
let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues");
aSocialIssues.value = addIdToValue(aSocialIssues.value, issue.id);
commit('addIssueSelected', issue);
},
updateIssuesSelected({ commit }, payload) {
let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues");
aSocialIssues.value = '';
payload.forEach(item => {
aSocialIssues.value = addIdToValue(aSocialIssues.value, item.id);
});
commit('updateIssuesSelected', payload);
},
updateActionsSelected({ commit }, payload) {
let aSocialActions = document.getElementById("chill_activitybundle_activity_socialActions");
aSocialActions.value = '';
payload.forEach(item => {
aSocialActions.value = addIdToValue(aSocialActions.value, item.id);
});
commit('updateActionsSelected', payload);
},
addPersonsInvolved({ commit }, payload) {
//console.log('### action addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
let aPersons = document.getElementById("chill_activitybundle_activity_persons");
aPersons.value = addIdToValue(aPersons.value, payload.result.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties");
aThirdParties.value = addIdToValue(aThirdParties.value, payload.result.id);
break;
case 'user':
let aUsers = document.getElementById("chill_activitybundle_activity_users");
aUsers.value = addIdToValue(aUsers.value, payload.result.id);
break;
};
commit('addPersonsInvolved', payload);
},
removePersonInvolved({ commit }, payload) {
//console.log('### action removePersonInvolved', payload);
switch (payload.type) {
case 'person':
let aPersons = document.getElementById("chill_activitybundle_activity_persons");
aPersons.value = removeIdFromValue(aPersons.value, payload.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties");
aThirdParties.value = removeIdFromValue(aThirdParties.value, payload.id);
break;
case 'user':
let aUsers = document.getElementById("chill_activitybundle_activity_users");
aUsers.value = removeIdFromValue(aUsers.value, payload.id);
break;
};
commit('removePersonInvolved', payload);
}
}
});
export default store;

View File

@@ -1,40 +1,13 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel
{
/**
* @return string
*/
public function getCacheDir()
{
return sys_get_temp_dir() . '/ActivityBundle/cache';
}
/**
* @return string
*/
public function getLogDir()
{
return sys_get_temp_dir() . '/ActivityBundle/logs';
}
public function registerBundles()
{
return [
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
@@ -47,12 +20,28 @@ class AppKernel extends Kernel
new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
//add here all the required bundle (some bundle are not required)
];
#add here all the required bundle (some bundle are not required)
);
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml');
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
/**
* @return string
*/
public function getCacheDir()
{
return sys_get_temp_dir().'/ActivityBundle/cache';
}
/**
* @return string
*/
public function getLogDir()
{
return sys_get_temp_dir().'/ActivityBundle/logs';
}
}

View File

@@ -1,22 +1,11 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
use Composer\Autoload\ClassLoader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Composer\Autoload\ClassLoader;
/** @var ClassLoader $loader */
$loader = require __DIR__ . '/../../../../../vendor/autoload.php';
$loader = require __DIR__.'/../../../../../vendor/autoload.php';
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
return $loader;

File diff suppressed because one or more lines are too long

View File

@@ -1,18 +1,7 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
@@ -20,20 +9,18 @@ use Symfony\Component\HttpFoundation\Request;
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (
isset($_SERVER['HTTP_CLIENT_IP'])
if (isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| !(\in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', 'fe80::1', '::1'], true) || \PHP_SAPI === 'cli-server')
|| !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server')
) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check ' . basename(__FILE__) . ' for more information.');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
$loader = require_once __DIR__ . '/../app/bootstrap.php.cache';
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
Debug::enable();
require_once __DIR__ . '/../app/AppKernel.php';
require_once __DIR__.'/../app/AppKernel.php';
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();

View File

@@ -0,0 +1,97 @@
{% macro href(pathname, key, value) %}
{% set parms = { (key): value } %}
{{ path(pathname, parms) }}
{% endmacro %}
{% if context == 'person' %}
{% set blocs = [
{ 'title': 'Others persons'|trans,
'items': entity.persons,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third parties'|trans,
'items': entity.thirdParties,
'path' : 'chill_3party_3party_show',
'key' : 'thirdparty_id'
},
{ 'title': 'Users concerned'|trans,
'items': entity.users,
'path' : 'admin_user_show',
'key' : 'id'
},
] %}
{% else %}
{% set blocs = [
{ 'title': 'Persons in accompanying course'|trans,
'items': entity.personsAssociated,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third persons'|trans,
'items': entity.personsNotAssociated,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third parties'|trans,
'items': entity.thirdParties,
'path' : 'chill_3party_3party_show',
'key' : 'thirdparty_id'
},
{ 'title': 'Users concerned'|trans,
'items': entity.users,
'path' : 'admin_user_show',
'key' : 'id'
},
] %}
{% endif %}
{% if (with_display == 'bloc') %}
<div class="{{ context }} flex-bloc concerned-groups">
{% for bloc in blocs %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<h4>{{ bloc.title }}</h4>
</div>
<div class="item-col">
<ul class="list-content">
{% for item in bloc.items %}
<li>
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="badge bg-primary">
{{ item|chill_entity_render_box({'only_denomination': true}) }}
</span>
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% if (with_display == 'row') %}
<div class="concerned-groups">
{% for bloc in blocs %}
<div class="group">
{% if bloc.items|length > 0 %}
<h4>{{ bloc.title }}</h4>
<ul class="list-content">
{% for item in bloc.items %}
<li>
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="badge bg-primary">
{{ item|chill_entity_render_box({'only_denomination': true}) }}
</span>
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,16 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title 'Remove activity'|trans %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove activity'|trans,
'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : accompanyingCourse.id } ),
'cancel_route' : 'chill_activity_activity_list',
'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : activity.id },
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "@ChillPerson/layout.html.twig" %}
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% set person = activity.person %}
@@ -6,7 +6,6 @@
{% block title 'Remove activity'|trans %}
{% block personcontent %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove activity'|trans,
@@ -15,5 +14,4 @@
'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id },
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -1,59 +1,104 @@
{#
* 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/>.
#}
{% extends "@ChillPerson/layout.html.twig" %}
<h1>{{ "Update activity"|trans }}</h1>
<h2 class="chill-green mb-4">{{ entity.type.name|localize_translatable_string }}</h2>
{% set activeRouteKey = 'chill_activity_activity_list' %}
{{ form_start(edit_form) }}
{{ form_errors(edit_form) }}
{% block title 'Update activity'|trans %}
{%- if edit_form.emergency is defined -%}
{{ form_row(edit_form.emergency) }}
{% endif %}
{% block personcontent %}
<h1>{{ "Update activity"|trans }}</h1>
{{ form_start(edit_form) }}
{%- if edit_form.sentReceived is defined -%}
{{ form_row(edit_form.sentReceived) }}
{% endif %}
{%- if edit_form.user is defined -%}
{{ form_row(edit_form.user) }}
{% endif %}
{%- if edit_form.scope is defined -%}
{{ form_row(edit_form.scope) }}
{% endif %}
<h2>{{ 'Activity data'|trans }}</h2>
{{ form_row(edit_form.date) }}
{{ form_row(edit_form.durationTime) }}
{{ form_row(edit_form.type) }}
{{ form_row(edit_form.attendee) }}
{%- if edit_form.socialIssues is defined -%}
{{ form_row(edit_form.socialIssues) }}
{% endif %}
{%- if edit_form.socialActions is defined -%}
{{ form_row(edit_form.socialActions) }}
{% endif %}
<div id="social-issues-acc"></div>
{%- if edit_form.reasons is defined -%}
{{ form_row(edit_form.reasons) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if edit_form.persons is defined -%}
{{ form_widget(edit_form.persons) }}
{% endif %}
{%- if edit_form.thirdParties is defined -%}
{{ form_widget(edit_form.thirdParties) }}
{% endif %}
{%- if edit_form.users is defined -%}
{{ form_widget(edit_form.users) }}
{% endif %}
<div id="add-persons"></div>
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
{%- if edit_form.date is defined -%}
{{ form_row(edit_form.date) }}
{% endif %}
.. location
{%- if edit_form.durationTime is defined -%}
{{ form_row(edit_form.durationTime) }}
{% endif %}
{%- if edit_form.travelTime is defined -%}
{{ form_row(edit_form.travelTime) }}
{% endif %}
{%- if edit_form.comment is defined -%}
.. public and private
{{ form_row(edit_form.comment) }}
{% endif %}
{{ form_widget(edit_form) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_activity_activity_show', { 'id': entity.id, 'person_id': entity.person.id } ) }}" class="sc-button bt-cancel">
{{ 'Cancel'|trans }}
</a>
</li>
<li>
<button class="sc-button bt-update" type="submit">{{ 'Save activity'|trans }}</button>
</li>
</ul>
{{ form_end(edit_form) }}
{%- if edit_form.documents is defined -%}
{{ form_row(edit_form.documents) }}
{% endif %}
{# {{ form(delete_form) }} #}
{% endblock %}
{%- if edit_form.attendee is defined -%}
{{ form_row(edit_form.attendee) }}
{% endif %}
{% block js %}
<script type="text/javascript">
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]', '{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
</script>
{% endblock %}
.. status
{% set person_id = null %}
{% if entity.person %}
{% set person_id = entity.person.id %}
{% endif %}
{% set accompanying_course_id = null %}
{% if accompanyingCourse %}
{% set accompanying_course_id = accompanyingCourse.id %}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_activity_activity_show', { 'id': entity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-cancel">
{{ 'Cancel'|trans }}
</a>
</li>
<li>
<button class="btn btn-update" type="submit">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(edit_form) }}
{# {{ form(delete_form) }} #}

View File

@@ -0,0 +1,37 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title 'Update activity'|trans %}
{% block content %}
<div class="activity-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_link_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -0,0 +1,51 @@
{#
* 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/>.
#}
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title 'Update activity'|trans %}
{% block personcontent %}
<div class="activity-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ encore_entry_link_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -1,87 +1,197 @@
{#
* 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/>.
#}
{% extends "@ChillPerson/layout.html.twig" %}
{% set person_id = null %}
{% if person %}
{% set person_id = person.id %}
{% endif %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% set accompanying_course_id = null %}
{% if accompanyingCourse %}
{% set accompanying_course_id = accompanyingCourse.id %}
{% endif %}
{% block title %}{{ 'Activity list' |trans }}{% endblock title %}
<h2>{{ 'Activity list' |trans }}</h2>
{% block personcontent %}
<h2>{{ 'Activity list' |trans }}</h2>
{% if activities|length == 0 %}
<p class="chill-no-data-statement">
{{ "There isn't any activities."|trans }}
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create button-small"></a>
</p>
{% else %}
{% if activities|length == 0 %}
<p class="chill-no-data-statement">
{{ "There isn't any activities."|trans }}
<a href="{{ path('chill_activity_activity_new', {'person_id': person.id}) }}" class="sc-button bt-create button-small"></a>
</p>
{% else %}
<table class="records_list">
<thead>
<tr>
<th class="chill-red">{{'Date' | trans }}</th>
<th class="chill-green">{{'Duration Time' | trans }}</th>
<th class="chill-orange">{{'Reasons' | trans}}</th>
<th>{{'Type' | trans}}</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for activity in activities %}
<tr>
<td>{% if activity.date %}{{ activity.date|format_date('long') }}{% endif %}</td>
<td>{{ activity.durationTime|date('H:i') }}</td>
<td>
{% if activity.comment.comment is not empty %}
{{ activity.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
<div class="flex-table list-records context-{{ context }}">
<!--
<thead>
<tr>
<th class="chill-red">{{'Date' | trans }}</th>
<th class="chill-green">{{'Duration Time' | trans }}</th>
<th class="chill-orange">{{'Reasons' | trans}}</th>
<th>{{'Type' | trans}}</th>
<th>&nbsp;</th>
</tr>
</thead>
-->
{% for activity in activities %}
{% set t = activity.type %}
<div class="item-bloc">
<div class="item-row main">
<div class="item-col">
{% if activity.date %}
<h3>{{ activity.date|format_date('long') }}</h3>
{% endif %}
{%- if activity.reasons is empty -%}
{{ 'No reason associated'|trans }}
{%- else -%}
{% for r in activity.reasons %}{{ r|chill_entity_render_box }} {% endfor %}
{%- endif -%}
</td>
<td>{{ activity.type.name | localize_translatable_string }}</td>
<td>
<div class="duration">
{% if t.durationTimeVisible > 0 %}
<p>
<i class="fa fa-fw fa-hourglass-end"></i>
{{ activity.durationTime|date('H:i') }}
</p>
{% endif %}
{% if activity.travelTime and t.travelTimeVisible %}
<p>
<i class="fa fa-fw fa-car"></i>
{{ activity.travelTime|date('H:i') }}
</p>
{% endif %}
</div>
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
<div class="accompanyingPeriodLink" style="margin-top: 1rem">
<a
href="{{ chill_path_add_return_path(
"chill_person_accompanying_course_index",
{ 'accompanying_period_id': activity.accompanyingPeriod.id }
) }}"
>
<i class="fa fa-random"></i>
{{ activity.accompanyingPeriod.id }}
</a>
</div>
{% endif %}
</div>
<div class="item-col">
<ul class="list-content">
{% if activity.user and t.userVisible %}
<li>
<b>{{ 'by'|trans }}{{ activity.user.usernameCanonical }}</b>
</li>
{% endif %}
<li>
<b>{{ activity.type.name | localize_translatable_string }}</b>
{% if activity.attendee is not null and t.attendeeVisible %}
{% if activity.attendee %}
{{ '→ ' ~ 'present'|trans|capitalize }}
{% else %}
{{ '→ ' ~ 'not present'|trans|capitalize }}
{% endif %}
{% endif %}
</li>
<li>
<b>{{ 'location'|trans ~ ': ' }}</b>
Domicile de l'usager
{#
{% if activity.location %}{{ activity.location }}{% endif %}
#}
</li>
{%- if t.reasonsVisible -%}
<li>
{%- if activity.reasons is empty -%}
<span class="chill-no-data-statement">{{ 'No reason associated'|trans }}</span>
{%- else -%}
{% for r in activity.reasons %}
{{ r|chill_entity_render_box }}
{% endfor %}
{%- endif -%}
</li>
{% endif %}
{%- if t.socialIssuesVisible %}
<li class="social-issues">
{%- if activity.socialIssues is empty -%}
<span class="chill-no-data-statement">{{ 'No social issues associated'|trans }}</span>
{%- else -%}
{% for r in activity.socialIssues %}
{{ r|chill_entity_render_box }}
{% endfor %}
{%- endif -%}
</li>
{% endif %}
{%- if t.socialActionsVisible -%}
<li class="social-actions">
{%- if activity.socialActions is empty -%}
<span class="chill-no-data-statement">{{ 'No social actions associated'|trans }}</span>
{%- else -%}
{% for r in activity.socialActions %}
<span class="badge bg-primary">{{ r.title|localize_translatable_string }}</span>
{% endfor %}
{%- endif -%}
</li>
{% endif %}
</ul>
<ul class="record_actions">
<li>
<a href="{{ path('chill_activity_activity_show', { 'id': activity.id, 'person_id': person.id }) }}" class="sc-button bt-show "></a>
<a href="{{ path('chill_activity_activity_show', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-show "></a>
</li>
{# TOOD
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
#}
<li>
<a href="{{ path('chill_activity_activity_edit', { 'id': activity.id, 'person_id': person.id }) }}" class="sc-button bt-update "></a>
<a href="{{ path('chill_activity_activity_edit', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-update "></a>
</li>
{# TOOD
{% endif %}
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
#}
<li>
<a href="{{ path('chill_activity_activity_delete', { 'id': activity.id, 'person_id' : person.id } ) }}" class="sc-button bt-delete "></a>
<a href="{{ path('chill_activity_activity_delete', { 'id': activity.id, 'person_id' : person_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete "></a>
</li>
{#
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
#}
</ul>
</div>
</div>
{%
if activity.comment.comment is not empty
or activity.persons|length > 0
or activity.thirdParties|length > 0
or activity.users|length > 0
%}
<div class="item-row details">
<div class="item-col">
<ul class="record_actions">
<li>
<a href="{{ path('chill_activity_activity_new', {'person_id': person.id}) }}" class="sc-button bt-create">
{{ 'Add a new activity' | trans }}
</a>
</li>
</ul>
{% endblock %}
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'row', 'entity': activity } %}
</div>
{% if activity.comment.comment is not empty %}
<div class="item-col comment">
{{ activity.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
</div>
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% if context != 'person' %}
{# TODO set this condition in configuration #}
<ul class="record_actions">
<li>
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create">
{{ 'Add a new activity' | trans }}
</a>
</li>
</ul>
{% endif %}

View File

@@ -0,0 +1,9 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title %}{{ 'Activity list' |trans }}{% endblock title %}
{% block content %}
{% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %}
{% endblock %}

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