mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 01:08:26 +00:00 
			
		
		
		
	Merge branch 'testing' into VSR-issues
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -25,3 +25,5 @@ node_modules/* | ||||
| /.php-cs-fixer.cache | ||||
| /.idea/ | ||||
| /.psalm/ | ||||
|  | ||||
| node_modules/* | ||||
|   | ||||
							
								
								
									
										67
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| { | ||||
|     "name": "chill", | ||||
|     "version": "2.0.0", | ||||
|     "devDependencies": { | ||||
|     "@alexlafroscia/yaml-merge": "^4.0.0", | ||||
|     "@apidevtools/swagger-cli": "^4.0.4", | ||||
|     "@babel/core": "^7.20.5", | ||||
|     "@babel/preset-env": "^7.20.2", | ||||
|     "@ckeditor/ckeditor5-build-classic": "^35.3.2", | ||||
|     "@ckeditor/ckeditor5-dev-utils": "^31.1.13", | ||||
|     "@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13", | ||||
|     "@ckeditor/ckeditor5-markdown-gfm": "^35.3.2", | ||||
|     "@ckeditor/ckeditor5-theme-lark": "^35.3.2", | ||||
|     "@ckeditor/ckeditor5-vue": "^4.0.1", | ||||
|     "@symfony/webpack-encore": "^4.1.0", | ||||
|     "@tsconfig/node14": "^1.0.1", | ||||
|     "bindings": "^1.5.0", | ||||
|     "bootstrap": "^5.0.1", | ||||
|     "chokidar": "^3.5.1", | ||||
|     "fork-awesome": "^1.1.7", | ||||
|     "jquery": "^3.6.0", | ||||
|     "node-sass": "^8.0.0", | ||||
|     "popper.js": "^1.16.1", | ||||
|     "postcss-loader": "^7.0.2", | ||||
|     "raw-loader": "^4.0.2", | ||||
|     "sass-loader": "^13.0.0", | ||||
|     "select2": "^4.0.13", | ||||
|     "select2-bootstrap-theme": "0.1.0-beta.10", | ||||
|     "style-loader": "^3.3.1", | ||||
|     "ts-loader": "^9.3.1", | ||||
|     "typescript": "^4.7.2", | ||||
|     "vue-loader": "^17.0.0", | ||||
|     "webpack": "^5.75.0", | ||||
|     "webpack-cli": "^5.0.1" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@fullcalendar/core": "^5.11.0", | ||||
|     "@fullcalendar/daygrid": "^5.11.0", | ||||
|     "@fullcalendar/interaction": "^5.11.0", | ||||
|     "@fullcalendar/list": "^5.11.0", | ||||
|     "@fullcalendar/timegrid": "^5.11.0", | ||||
|     "@fullcalendar/vue3": "^5.11.1", | ||||
|     "@popperjs/core": "^2.9.2", | ||||
|     "dropzone": "^5.7.6", | ||||
|     "es6-promise": "^4.2.8", | ||||
|     "leaflet": "^1.7.1", | ||||
|     "masonry-layout": "^4.2.2", | ||||
|     "mime": "^3.0.0", | ||||
|     "swagger-ui": "^4.15.5", | ||||
|     "vis-network": "^9.1.0", | ||||
|     "vue": "^3.2.37", | ||||
|     "vue-i18n": "^9.1.6", | ||||
|     "vue-multiselect": "3.0.0-alpha.2", | ||||
|     "vue-toast-notification": "^2.0", | ||||
|     "vuex": "^4.0.0" | ||||
|   }, | ||||
|   "browserslist": [ | ||||
|     "Firefox ESR" | ||||
|   ], | ||||
|   "scripts": { | ||||
|     "dev-server": "encore dev-server", | ||||
|     "dev": "encore dev", | ||||
|     "watch": "encore dev --watch", | ||||
|     "build": "encore production --progress" | ||||
|   }, | ||||
|   "private": true | ||||
| } | ||||
| @@ -44,7 +44,7 @@ class ActivityTypeAggregator implements AggregatorInterface | ||||
|     public function alterQuery(QueryBuilder $qb, $data) | ||||
|     { | ||||
|         if (!in_array('acttype', $qb->getAllAliases(), true)) { | ||||
|             $qb->join('activity.activityType', 'acttype'); | ||||
|             $qb->leftJoin('activity.activityType', 'acttype'); | ||||
|         } | ||||
|  | ||||
|         $qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY)); | ||||
|   | ||||
| @@ -0,0 +1,165 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Export\Export\LinkedToACP; | ||||
|  | ||||
| use Chill\ActivityBundle\Entity\Activity; | ||||
| use Chill\ActivityBundle\Export\Export\ListActivityHelper; | ||||
| use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; | ||||
| use Chill\MainBundle\Entity\Scope; | ||||
| use Chill\MainBundle\Export\GroupedExportInterface; | ||||
| use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper; | ||||
| use Chill\MainBundle\Export\ListInterface; | ||||
| use Chill\PersonBundle\Entity\Person\PersonCenterHistory; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
|  | ||||
| class ListActivity implements ListInterface, GroupedExportInterface | ||||
| { | ||||
|     private EntityManagerInterface $entityManager; | ||||
|  | ||||
|     private ListActivityHelper $helper; | ||||
|  | ||||
|     private TranslatableStringExportLabelHelper $translatableStringExportLabelHelper; | ||||
|  | ||||
|     public function __construct( | ||||
|         ListActivityHelper $helper, | ||||
|         EntityManagerInterface $entityManager, | ||||
|         TranslatableStringExportLabelHelper $translatableStringExportLabelHelper | ||||
|     ) { | ||||
|         $this->helper = $helper; | ||||
|         $this->entityManager = $entityManager; | ||||
|         $this->translatableStringExportLabelHelper = $translatableStringExportLabelHelper; | ||||
|     } | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder) | ||||
|     { | ||||
|         $this->helper->buildForm($builder); | ||||
|     } | ||||
|  | ||||
|     public function getAllowedFormattersTypes() | ||||
|     { | ||||
|         return $this->helper->getAllowedFormattersTypes(); | ||||
|     } | ||||
|  | ||||
|     public function getDescription() | ||||
|     { | ||||
|         return ListActivityHelper::MSG_KEY . 'List activities linked to an accompanying course'; | ||||
|     } | ||||
|  | ||||
|     public function getGroup(): string | ||||
|     { | ||||
|         return 'Exports of activities linked to an accompanying period'; | ||||
|     } | ||||
|  | ||||
|     public function getLabels($key, array $values, $data) | ||||
|     { | ||||
|         switch ($key) { | ||||
|             case 'acpId': | ||||
|                 return static function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return ListActivityHelper::MSG_KEY . 'accompanying course id'; | ||||
|                     } | ||||
|  | ||||
|                     return $value ?? ''; | ||||
|                 }; | ||||
|  | ||||
|             case 'scopesNames': | ||||
|                return $this->translatableStringExportLabelHelper->getLabelMulti($key, $values, ListActivityHelper::MSG_KEY . 'course circles'); | ||||
|  | ||||
|             default: | ||||
|                 return $this->helper->getLabels($key, $values, $data); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function getQueryKeys($data) | ||||
|     { | ||||
|         return | ||||
|             array_merge( | ||||
|                 $this->helper->getQueryKeys($data), | ||||
|                 [ | ||||
|                     'acpId', | ||||
|                     'scopesNames', | ||||
|                 ] | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     public function getResult($query, $data) | ||||
|     { | ||||
|         return $this->helper->getResult($query, $data); | ||||
|     } | ||||
|  | ||||
|     public function getTitle() | ||||
|     { | ||||
|         return ListActivityHelper::MSG_KEY . 'List activity linked to a course'; | ||||
|     } | ||||
|  | ||||
|     public function getType() | ||||
|     { | ||||
|         return $this->helper->getType(); | ||||
|     } | ||||
|  | ||||
|     public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) | ||||
|     { | ||||
|         $centers = array_map(static function ($el) { | ||||
|             return $el['center']; | ||||
|         }, $acl); | ||||
|  | ||||
|         $qb = $this->entityManager->createQueryBuilder(); | ||||
|  | ||||
|         $qb | ||||
|             ->distinct() | ||||
|             ->from(Activity::class, 'activity') | ||||
|             ->join('activity.accompanyingPeriod', 'acp') | ||||
|             ->leftJoin('acp.participations', 'acppart') | ||||
|             ->leftJoin('acppart.person', 'person') | ||||
|             ->andWhere('acppart.startDate != acppart.endDate OR acppart.endDate IS NULL') | ||||
|             ->andWhere( | ||||
|                 $qb->expr()->exists( | ||||
|                     'SELECT 1 | ||||
|                     FROM ' . PersonCenterHistory::class . ' acl_count_person_history | ||||
|                     WHERE acl_count_person_history.person = person | ||||
|                     AND acl_count_person_history.center IN (:authorized_centers) | ||||
|                     ' | ||||
|                 ) | ||||
|             ) | ||||
|             // some grouping are necessary | ||||
|             ->addGroupBy('acp.id') | ||||
|             ->addOrderBy('activity.date') | ||||
|             ->addOrderBy('activity.id') | ||||
|             ->setParameter('authorized_centers', $centers); | ||||
|  | ||||
|         $this->helper->addSelect($qb); | ||||
|  | ||||
|         // add select for this step | ||||
|         $qb | ||||
|             ->addSelect('acp.id AS acpId') | ||||
|             ->addSelect('(SELECT AGGREGATE(acpScope.name) FROM ' . Scope::class . ' acpScope WHERE acpScope MEMBER OF acp.scopes) AS scopesNames') | ||||
|             ->addGroupBy('scopesNames'); | ||||
|  | ||||
|         return $qb; | ||||
|     } | ||||
|  | ||||
|     public function requiredRole(): string | ||||
|     { | ||||
|         return ActivityStatsVoter::LISTS; | ||||
|     } | ||||
|  | ||||
|     public function supportsModifiers() | ||||
|     { | ||||
|         return array_merge( | ||||
|             $this->helper->supportsModifiers(), | ||||
|             [ | ||||
|                 \Chill\PersonBundle\Export\Declarations::ACP_TYPE, | ||||
|             ] | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,269 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Export\Export; | ||||
|  | ||||
| use Chill\ActivityBundle\Export\Declarations; | ||||
| use Chill\ActivityBundle\Repository\ActivityPresenceRepositoryInterface; | ||||
| use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; | ||||
| use Chill\MainBundle\Export\FormatterInterface; | ||||
| use Chill\MainBundle\Export\Helper\DateTimeHelper; | ||||
| use Chill\MainBundle\Export\Helper\TranslatableStringExportLabelHelper; | ||||
| use Chill\MainBundle\Export\Helper\UserHelper; | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelperInterface; | ||||
| use Chill\PersonBundle\Export\Helper\LabelPersonHelper; | ||||
| use Chill\ThirdPartyBundle\Export\Helper\LabelThirdPartyHelper; | ||||
| use Doctrine\ORM\AbstractQuery; | ||||
| use Doctrine\ORM\QueryBuilder; | ||||
| use LogicException; | ||||
| use Symfony\Component\Form\FormBuilderInterface; | ||||
| use Symfony\Contracts\Translation\TranslatorInterface; | ||||
| use const SORT_NUMERIC; | ||||
|  | ||||
| class ListActivityHelper | ||||
| { | ||||
|     public const MSG_KEY = 'export.list.activity.'; | ||||
|  | ||||
|     private ActivityPresenceRepositoryInterface $activityPresenceRepository; | ||||
|  | ||||
|     private ActivityTypeRepositoryInterface $activityTypeRepository; | ||||
|  | ||||
|     private DateTimeHelper $dateTimeHelper; | ||||
|  | ||||
|     private LabelPersonHelper $labelPersonHelper; | ||||
|  | ||||
|     private LabelThirdPartyHelper $labelThirdPartyHelper; | ||||
|  | ||||
|     private TranslatableStringHelperInterface $translatableStringHelper; | ||||
|  | ||||
|     private TranslatableStringExportLabelHelper $translatableStringLabelHelper; | ||||
|  | ||||
|     private TranslatorInterface $translator; | ||||
|  | ||||
|     private UserHelper $userHelper; | ||||
|  | ||||
|     public function __construct( | ||||
|         ActivityPresenceRepositoryInterface $activityPresenceRepository, | ||||
|         ActivityTypeRepositoryInterface $activityTypeRepository, | ||||
|         DateTimeHelper $dateTimeHelper, | ||||
|         LabelPersonHelper $labelPersonHelper, | ||||
|         LabelThirdPartyHelper $labelThirdPartyHelper, | ||||
|         TranslatorInterface $translator, | ||||
|         TranslatableStringHelperInterface $translatableStringHelper, | ||||
|         TranslatableStringExportLabelHelper $translatableStringLabelHelper, | ||||
|         UserHelper $userHelper | ||||
|     ) { | ||||
|         $this->activityPresenceRepository = $activityPresenceRepository; | ||||
|         $this->activityTypeRepository = $activityTypeRepository; | ||||
|         $this->dateTimeHelper = $dateTimeHelper; | ||||
|         $this->labelPersonHelper = $labelPersonHelper; | ||||
|         $this->labelThirdPartyHelper = $labelThirdPartyHelper; | ||||
|         $this->translator = $translator; | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|         $this->translatableStringLabelHelper = $translatableStringLabelHelper; | ||||
|         $this->userHelper = $userHelper; | ||||
|     } | ||||
|  | ||||
|     public function addSelect(QueryBuilder $qb): void | ||||
|     { | ||||
|         $qb | ||||
|             ->addSelect('activity.id AS id') | ||||
|             ->addSelect('activity.date') | ||||
|             ->addSelect('IDENTITY(activity.activityType) AS typeName') | ||||
|             ->leftJoin('activity.reasons', 'reasons') | ||||
|             ->addSelect('AGGREGATE(reasons.name) AS listReasons') | ||||
|             ->leftJoin('activity.persons', 'actPerson') | ||||
|             ->addSelect('AGGREGATE(actPerson.id) AS personsIds') | ||||
|             ->addSelect('AGGREGATE(actPerson.id) AS personsNames') | ||||
|             ->leftJoin('activity.users', 'users_u') | ||||
|             ->addSelect('AGGREGATE(users_u.id) AS usersIds') | ||||
|             ->addSelect('AGGREGATE(users_u.id) AS usersNames') | ||||
|             ->leftJoin('activity.thirdParties', 'thirdparty') | ||||
|             ->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesIds') | ||||
|             ->addSelect('AGGREGATE(thirdparty.id) AS thirdPartiesNames') | ||||
|             ->addSelect('IDENTITY(activity.attendee) AS attendeeName') | ||||
|             ->addSelect('activity.durationTime') | ||||
|             ->addSelect('activity.travelTime') | ||||
|             ->addSelect('activity.emergency') | ||||
|             ->leftJoin('activity.location', 'location') | ||||
|             ->addSelect('location.name AS locationName') | ||||
|             ->addSelect('activity.sentReceived') | ||||
|             ->addSelect('IDENTITY(activity.createdBy) AS createdBy') | ||||
|             ->addSelect('activity.createdAt') | ||||
|             ->addSelect('IDENTITY(activity.updatedBy) AS updatedBy') | ||||
|             ->addSelect('activity.updatedAt') | ||||
|             ->addGroupBy('activity.id') | ||||
|             ->addGroupBy('location.id'); | ||||
|     } | ||||
|  | ||||
|     public function buildForm(FormBuilderInterface $builder) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public function getAllowedFormattersTypes() | ||||
|     { | ||||
|         return [FormatterInterface::TYPE_LIST]; | ||||
|     } | ||||
|  | ||||
|     public function getLabels($key, array $values, $data) | ||||
|     { | ||||
|         switch ($key) { | ||||
|             case 'createdAt': | ||||
|             case 'updatedAt': | ||||
|                 return $this->dateTimeHelper->getLabel($key); | ||||
|  | ||||
|             case 'createdBy': | ||||
|             case 'updatedBy': | ||||
|                 return $this->userHelper->getLabel($key, $values, $key); | ||||
|  | ||||
|             case 'date': | ||||
|                 return $this->dateTimeHelper->getLabel(self::MSG_KEY . $key); | ||||
|  | ||||
|             case 'attendeeName': | ||||
|                 return function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return 'Attendee'; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value || null === $presence = $this->activityPresenceRepository->find($value)) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translatableStringHelper->localize($presence->getName()); | ||||
|                 }; | ||||
|  | ||||
|             case 'listReasons': | ||||
|                 return $this->translatableStringLabelHelper->getLabelMulti($key, $values, 'Activity Reasons'); | ||||
|  | ||||
|             case 'typeName': | ||||
|                 return function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return 'Activity type'; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value || null === $type = $this->activityTypeRepository->find($value)) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translatableStringHelper->localize($type->getName()); | ||||
|                 }; | ||||
|  | ||||
|             case 'usersNames': | ||||
|                 return $this->userHelper->getLabelMulti($key, $values, self::MSG_KEY . 'users name'); | ||||
|  | ||||
|             case 'usersIds': | ||||
|             case 'thirdPartiesIds': | ||||
|             case 'personsIds': | ||||
|                 return static function ($value) use ($key) { | ||||
|                     if ('_header' === $value) { | ||||
|                         switch ($key) { | ||||
|                             case 'usersIds': | ||||
|                                 return self::MSG_KEY . 'users ids'; | ||||
|  | ||||
|                             case 'thirdPartiesIds': | ||||
|                                 return self::MSG_KEY . 'third parties ids'; | ||||
|  | ||||
|                             case 'personsIds': | ||||
|                                 return self::MSG_KEY . 'persons ids'; | ||||
|  | ||||
|                             default: | ||||
|                                 throw new LogicException('key not supported'); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     $decoded = json_decode($value); | ||||
|  | ||||
|                     return implode( | ||||
|                         '|', | ||||
|                         array_unique( | ||||
|                             array_filter($decoded, static fn (?int $id) => null !== $id), | ||||
|                             SORT_NUMERIC | ||||
|                         ) | ||||
|                     ); | ||||
|                 }; | ||||
|  | ||||
|             case 'personsNames': | ||||
|                 return $this->labelPersonHelper->getLabelMulti($key, $values, self::MSG_KEY . 'persons name'); | ||||
|  | ||||
|             case 'thirdPartiesNames': | ||||
|                 return $this->labelThirdPartyHelper->getLabelMulti($key, $values, self::MSG_KEY . 'thirds parties'); | ||||
|  | ||||
|             case 'sentReceived': | ||||
|                 return function ($value) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return self::MSG_KEY . 'sent received'; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translator->trans($value); | ||||
|                 }; | ||||
|  | ||||
|             default: | ||||
|                 return function ($value) use ($key) { | ||||
|                     if ('_header' === $value) { | ||||
|                         return self::MSG_KEY . $key; | ||||
|                     } | ||||
|  | ||||
|                     if (null === $value) { | ||||
|                         return ''; | ||||
|                     } | ||||
|  | ||||
|                     return $this->translator->trans($value); | ||||
|                 }; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function getQueryKeys($data) | ||||
|     { | ||||
|         return [ | ||||
|             'id', | ||||
|             'date', | ||||
|             'typeName', | ||||
|             'listReasons', | ||||
|             'attendeeName', | ||||
|             'durationTime', | ||||
|             'travelTime', | ||||
|             'emergency', | ||||
|             'locationName', | ||||
|             'sentReceived', | ||||
|             'personsIds', | ||||
|             'personsNames', | ||||
|             'usersIds', | ||||
|             'usersNames', | ||||
|             'thirdPartiesIds', | ||||
|             'thirdPartiesNames', | ||||
|             'createdBy', | ||||
|             'createdAt', | ||||
|             'updatedBy', | ||||
|             'updatedAt', | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function getResult($query, $data) | ||||
|     { | ||||
|         return $query->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR); | ||||
|     } | ||||
|  | ||||
|     public function getType(): string | ||||
|     { | ||||
|         return Declarations::ACTIVITY; | ||||
|     } | ||||
|  | ||||
|     public function supportsModifiers() | ||||
|     { | ||||
|         return [ | ||||
|             Declarations::ACTIVITY, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @@ -50,7 +50,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt | ||||
|     { | ||||
|         $where = $qb->getDQLPart('where'); | ||||
|         $join = $qb->getDQLPart('join'); | ||||
|         $clause = $qb->expr()->in('reasons', ':selected_activity_reasons'); | ||||
|         $clause = $qb->expr()->in('actreasons', ':selected_activity_reasons'); | ||||
|  | ||||
|         if (!in_array('actreasons', $qb->getAllAliases(), true)) { | ||||
|             $qb->join('activity.reasons', 'actreasons'); | ||||
| @@ -77,6 +77,7 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt | ||||
|             'class' => ActivityReason::class, | ||||
|             'choice_label' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()), | ||||
|             'group_by' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()), | ||||
|             'attr' => ['class' => 'select2 '], | ||||
|             'multiple' => true, | ||||
|             'expanded' => false, | ||||
|         ]); | ||||
|   | ||||
| @@ -0,0 +1,51 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Repository; | ||||
|  | ||||
| use Chill\ActivityBundle\Entity\ActivityPresence; | ||||
| use Doctrine\ORM\EntityManagerInterface; | ||||
| use Doctrine\ORM\EntityRepository; | ||||
|  | ||||
| class ActivityPresenceRepository implements ActivityPresenceRepositoryInterface | ||||
| { | ||||
|     private EntityRepository $repository; | ||||
|  | ||||
|     public function __construct(EntityManagerInterface $entityManager) | ||||
|     { | ||||
|         $this->repository = $entityManager->getRepository($this->getClassName()); | ||||
|     } | ||||
|  | ||||
|     public function find($id): ?ActivityPresence | ||||
|     { | ||||
|         return $this->repository->find($id); | ||||
|     } | ||||
|  | ||||
|     public function findAll(): array | ||||
|     { | ||||
|         return $this->repository->findAll(); | ||||
|     } | ||||
|  | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?ActivityPresence | ||||
|     { | ||||
|         return $this->findOneBy($criteria); | ||||
|     } | ||||
|  | ||||
|     public function getClassName(): string | ||||
|     { | ||||
|         return ActivityPresence::class; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ActivityBundle\Repository; | ||||
|  | ||||
| use Chill\ActivityBundle\Entity\ActivityPresence; | ||||
|  | ||||
| interface ActivityPresenceRepositoryInterface | ||||
| { | ||||
|     public function find($id): ?ActivityPresence; | ||||
|  | ||||
|     /** | ||||
|      * @return array|ActivityPresence[] | ||||
|      */ | ||||
|     public function findAll(): array; | ||||
|  | ||||
|     /** | ||||
|      * @return array|ActivityPresence[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array; | ||||
|  | ||||
|     public function findOneBy(array $criteria): ?ActivityPresence; | ||||
|  | ||||
|     public function getClassName(): string; | ||||
| } | ||||
| @@ -41,6 +41,12 @@ services: | ||||
|         tags: | ||||
|             - { name: chill.export, alias: 'avg_activity_visit_duration_linked_to_acp' } | ||||
|  | ||||
|     Chill\ActivityBundle\Export\Export\LinkedToACP\ListActivity: | ||||
|         tags: | ||||
|             - { name: chill.export, alias: 'list_activity_acp'} | ||||
|  | ||||
|     Chill\ActivityBundle\Export\Export\ListActivityHelper: ~ | ||||
|  | ||||
|     ## Filters | ||||
|     chill.activity.export.type_filter: | ||||
|         class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter | ||||
| @@ -129,10 +135,9 @@ services: | ||||
|         tags: | ||||
|             - { name: chill.export_aggregator, alias: activity_reason_aggregator } | ||||
|  | ||||
|     chill.activity.export.type_aggregator: | ||||
|         class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator | ||||
|     Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator: | ||||
|         tags: | ||||
|             - { name: chill.export_aggregator, alias: activity_type_aggregator } | ||||
|             - { name: chill.export_aggregator, alias: activity_common_type_aggregator } | ||||
|  | ||||
|     chill.activity.export.user_aggregator: | ||||
|         class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator | ||||
|   | ||||
| @@ -45,6 +45,8 @@ by: 'Par ' | ||||
| location: Lieu | ||||
| Reasons: Sujets | ||||
| Private comment: Commentaire privé | ||||
| sent: Envoyé | ||||
| received: Reçu | ||||
|  | ||||
|  | ||||
| #forms | ||||
| @@ -326,6 +328,27 @@ docgen: | ||||
|     Accompanying period with a list of activities description: Ce contexte reprend les informations du parcours, et tous les activités pour un parcours. Les activités ne sont pas filtrés. | ||||
|  | ||||
| export: | ||||
|     list: | ||||
|         activity: | ||||
|             users name: Nom des utilisateurs | ||||
|             users ids: Identifiant des utilisateurs | ||||
|             third parties ids: Identifiant des tiers | ||||
|             persons ids: Identifiant des personnes | ||||
|             persons name: Nom des personnes | ||||
|             thirds parties: Tiers | ||||
|             date: Date de l'activité | ||||
|             locationName: Localisation | ||||
|             sent received: Envoyé ou reçu | ||||
|             emergency: Urgence | ||||
|             accompanying course id: Identifiant du parcours | ||||
|             course circles: Cercles du parcours | ||||
|             travelTime: Durée de déplacement | ||||
|             durationTime: Durée | ||||
|             id: Identifiant | ||||
|             List activities linked to an accompanying course: Liste les activités liées à un parcours en fonction de différents filtres. | ||||
|             List activity linked to a course: Liste des activités liées à un parcours | ||||
|  | ||||
|  | ||||
|     filter: | ||||
|         activity: | ||||
|             by_usersjob: | ||||
|   | ||||
| @@ -16,8 +16,8 @@ For this type of activity, document is required: Pour ce type d'activité, un do | ||||
| For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" est requis | ||||
| For this type of activity, accompanying period is required: Pour ce type d'activité, le parcours d'accompagnement est requis | ||||
| For this type of activity, you must add at least one social issue: Pour ce type d'activité, vous devez ajouter au moins une problématique sociale | ||||
| For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquez au moins une action sociale | ||||
| For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquer au moins une action sociale | ||||
|  | ||||
| # admin | ||||
| This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales" | ||||
| The socialActionsVisible value is not compatible with the socialIssuesVisible value: Cette valeur du paramètre "Visibilité du champs Actions sociales" n'est pas compatible avec la valeur du paramètre "Visibilité du champs Problématiques sociales" | ||||
| The socialActionsVisible value is not compatible with the socialIssuesVisible value: Cette valeur du paramètre "Visibilité du champs Actions sociales" n'est pas compatible avec la valeur du paramètre "Visibilité du champs Problématiques sociales" | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import App2 from './App2.vue'; | ||||
| import {useI18n} from "vue-i18n"; | ||||
|  | ||||
| futureStore().then((store) => { | ||||
|   const i18n = _createI18n(appMessages, true); | ||||
|   const i18n = _createI18n(appMessages, false); | ||||
|  | ||||
|   const app = createApp({ | ||||
|     template: `<app></app>`, | ||||
|   | ||||
| @@ -37,8 +37,9 @@ class LoadAddressesBEFromBestAddressCommand extends Command | ||||
|     { | ||||
|         $this | ||||
|             ->setName('chill:main:address-ref-from-best-addresses') | ||||
|             ->addArgument('lang', InputArgument::REQUIRED) | ||||
|             ->addArgument('list', InputArgument::IS_ARRAY, 'The list to add'); | ||||
|             ->addArgument('lang', InputArgument::REQUIRED, "Language code, for example 'fr'") | ||||
|             ->addArgument('list', InputArgument::IS_ARRAY, "The list to add, for example 'full', or 'extract' (dev) or '1xxx' (brussel CP)") | ||||
|             ->setDescription('Import BE addresses from BeST Address (see https://osoc19.github.io/best/)'); | ||||
|     } | ||||
|  | ||||
|     protected function execute(InputInterface $input, OutputInterface $output): int | ||||
|   | ||||
| @@ -31,7 +31,7 @@ class LoadAddressesFRFromBANOCommand extends Command | ||||
|     { | ||||
|         $this->setName('chill:main:address-ref-from-bano') | ||||
|             ->addArgument('departementNo', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'a list of departement numbers') | ||||
|             ->setDescription('Import addresses from bano (see https://bano.openstreetmap.fr'); | ||||
|             ->setDescription('Import FR addresses from bano (see https://bano.openstreetmap.fr'); | ||||
|     } | ||||
|  | ||||
|     protected function execute(InputInterface $input, OutputInterface $output): int | ||||
|   | ||||
| @@ -133,8 +133,7 @@ class EntityWorkflowStep | ||||
|         if (!$this->destUser->contains($user)) { | ||||
|             $this->destUser[] = $user; | ||||
|             $this->getEntityWorkflow() | ||||
|                 ->addSubscriberToFinal($user) | ||||
|                 ->addSubscriberToStep($user); | ||||
|                 ->addSubscriberToFinal($user); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
| @@ -145,8 +144,7 @@ class EntityWorkflowStep | ||||
|         if (!$this->destUserByAccessKey->contains($user) && !$this->destUser->contains($user)) { | ||||
|             $this->destUserByAccessKey[] = $user; | ||||
|             $this->getEntityWorkflow() | ||||
|                 ->addSubscriberToFinal($user) | ||||
|                 ->addSubscriberToStep($user); | ||||
|                 ->addSubscriberToFinal($user); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|   | ||||
| @@ -0,0 +1,70 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\MainBundle\Export\Helper; | ||||
|  | ||||
| use Chill\MainBundle\Templating\TranslatableStringHelperInterface; | ||||
|  | ||||
| /** | ||||
|  * This class provides support for showing translatable string into list or exports. | ||||
|  * | ||||
|  * (note: the name of the class contains "ExportLabelHelper" to give a distinction | ||||
|  * with TranslatableStringHelper.) | ||||
|  */ | ||||
| class TranslatableStringExportLabelHelper | ||||
| { | ||||
|     private TranslatableStringHelperInterface $translatableStringHelper; | ||||
|  | ||||
|     public function __construct(TranslatableStringHelperInterface $translatableStringHelper) | ||||
|     { | ||||
|         $this->translatableStringHelper = $translatableStringHelper; | ||||
|     } | ||||
|  | ||||
|     public function getLabel(string $key, array $values, string $header) | ||||
|     { | ||||
|         return function ($value) use ($header) { | ||||
|             if ('_header' === $value) { | ||||
|                 return $header; | ||||
|             } | ||||
|  | ||||
|             if (null === $value) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             return $this->translatableStringHelper->localize(json_decode($value, true)); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public function getLabelMulti(string $key, array $values, string $header) | ||||
|     { | ||||
|         return function ($value) use ($header) { | ||||
|             if ('_header' === $value) { | ||||
|                 return $header; | ||||
|             } | ||||
|  | ||||
|             if (null === $value) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             $decoded = json_decode($value, true); | ||||
|  | ||||
|             return implode( | ||||
|                 '|', | ||||
|                 array_unique( | ||||
|                     array_map( | ||||
|                         fn (array $translatableString) => $this->translatableStringHelper->localize($translatableString), | ||||
|                         array_filter($decoded, static fn ($elem) => null !== $elem) | ||||
|                     ) | ||||
|                 ) | ||||
|             ); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -13,6 +13,8 @@ namespace Chill\MainBundle\Export\Helper; | ||||
|  | ||||
| use Chill\MainBundle\Repository\UserRepositoryInterface; | ||||
| use Chill\MainBundle\Templating\Entity\UserRender; | ||||
| use function count; | ||||
| use const SORT_NUMERIC; | ||||
|  | ||||
| class UserHelper | ||||
| { | ||||
| @@ -40,4 +42,43 @@ class UserHelper | ||||
|             return $this->userRender->renderString($user, []); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public function getLabelMulti($key, array $values, string $header): callable | ||||
|     { | ||||
|         return function ($value) { | ||||
|             if ('_header' === $value) { | ||||
|                 return 'users name'; | ||||
|             } | ||||
|  | ||||
|             if (null === $value) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             $decoded = json_decode($value); | ||||
|  | ||||
|             if (0 === count($decoded)) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             return | ||||
|                 implode( | ||||
|                     '|', | ||||
|                     array_map( | ||||
|                         function (int $userId) { | ||||
|                             $user = $this->userRepository->find($userId); | ||||
|  | ||||
|                             if (null === $user) { | ||||
|                                 return ''; | ||||
|                             } | ||||
|  | ||||
|                             return $this->userRender->renderString($user, []); | ||||
|                         }, | ||||
|                         array_unique( | ||||
|                             array_filter($decoded, static fn (?int $userId) => null !== $userId), | ||||
|                             SORT_NUMERIC | ||||
|                         ) | ||||
|                     ) | ||||
|                 ); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -82,6 +82,7 @@ header { | ||||
|          border-radius: 0; | ||||
|          z-index: 1500; | ||||
|          a.dropdown-item { | ||||
|             padding: 0.5rem 1rem; | ||||
|             width: 120%; | ||||
|             border: 0; | ||||
|             border-bottom: 1px solid $gray-200; | ||||
|   | ||||
| @@ -14,9 +14,11 @@ | ||||
|  | ||||
| // 4. Include any default map overrides here | ||||
| @import "custom/_maps"; | ||||
| @import "bootstrap/scss/maps"; | ||||
|  | ||||
| // 5. Include remainder of required parts | ||||
| @import "bootstrap/scss/mixins"; | ||||
| @import "bootstrap/scss/utilities"; | ||||
| @import "bootstrap/scss/root"; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -2,25 +2,27 @@ | ||||
|    <transition name="modal"> | ||||
|       <div class="modal-mask"> | ||||
|          <!-- :: styles bootstrap :: --> | ||||
|          <div class="modal-dialog" :class="modalDialogClass"> | ||||
|         <div class="modal fade show" style="display: block" aria-modal="true" role="dialog"> | ||||
|           <div class="modal-dialog" :class="modalDialogClass"> | ||||
|             <div class="modal-content"> | ||||
|                <div class="modal-header"> | ||||
|                   <slot name="header"></slot> | ||||
|                   <button class="close btn" @click="$emit('close')"> | ||||
|                      <i class="fa fa-times" aria-hidden="true"></i></button> | ||||
|                </div> | ||||
|                <div class="body-head"> | ||||
|               <div class="modal-header"> | ||||
|                 <slot name="header"></slot> | ||||
|                 <button class="close btn" @click="$emit('close')"> | ||||
|                   <i class="fa fa-times" aria-hidden="true"></i></button> | ||||
|               </div> | ||||
|               <div class="modal-body"> | ||||
|                 <div class="body-head"> | ||||
|                   <slot name="body-head"></slot> | ||||
|                </div> | ||||
|                <div class="modal-body"> | ||||
|                   <slot name="body"></slot> | ||||
|                </div> | ||||
|                <div class="modal-footer" v-if="!hideFooter"> | ||||
|                   <button class="btn btn-cancel" @click="$emit('close')">{{ $t('action.close') }}</button> | ||||
|                   <slot name="footer"></slot> | ||||
|                </div> | ||||
|                 </div> | ||||
|                 <slot name="body"></slot> | ||||
|               </div> | ||||
|               <div class="modal-footer" v-if="!hideFooter"> | ||||
|                 <button class="btn btn-cancel" @click="$emit('close')">{{ $t('action.close') }}</button> | ||||
|                 <slot name="footer"></slot> | ||||
|               </div> | ||||
|             </div> | ||||
|          </div> | ||||
|           </div> | ||||
|         </div> | ||||
|          <!-- :: end styles bootstrap :: --> | ||||
|       </div> | ||||
|    </transition> | ||||
| @@ -33,7 +35,7 @@ import {defineComponent} from "vue"; | ||||
|  *    [+] 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 | ||||
|  *    and Bootstrap 4.6 _modal.scss module | ||||
|  *    and Bootstrap 5 _modal.scss module | ||||
|  *    [+] using bootstrap css classes, the modal have a responsive behaviour, | ||||
|  *    [+] modal design can be configured using css classes (size, scroll) | ||||
|  */ | ||||
| @@ -56,6 +58,9 @@ export default defineComponent({ | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|    /** | ||||
|     * This is a mask behind the modal. | ||||
|     */ | ||||
|    .modal-mask { | ||||
|       position: fixed; | ||||
|       z-index: 9998; | ||||
|   | ||||
| @@ -97,8 +97,8 @@ class PostalCodeBEFromBestAddress | ||||
|             trim($record['postal_info_objectid']), | ||||
|             $record['municipality_objectid'], | ||||
|             'bestaddress', | ||||
|             $record['Y'], | ||||
|             $record['X'], | ||||
|             (float) $record['Y'], | ||||
|             (float) $record['X'], | ||||
|             3812 | ||||
|         ); | ||||
|     } | ||||
|   | ||||
| @@ -26,12 +26,15 @@ buildCKEditor = function(encore) | ||||
|         .addLoader({ | ||||
|             test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/, | ||||
|             loader: 'postcss-loader', | ||||
|             options: styles.getPostCssConfig( { | ||||
|                 themeImporter: { | ||||
|             options: | ||||
|               { | ||||
|                 postcssOptions: styles.getPostCssConfig( { | ||||
|                   themeImporter: { | ||||
|                     themePath: require.resolve('@ckeditor/ckeditor5-theme-lark') | ||||
|                 }, | ||||
|                 minify: true | ||||
|             } ) | ||||
|                   }, | ||||
|                   minify: true | ||||
|                 } ) | ||||
|               } | ||||
|         } ) | ||||
|     ; | ||||
| }; | ||||
|   | ||||
| @@ -56,6 +56,12 @@ Until %date%: Jusqu'au %date% | ||||
| until %date%: jusqu'au %date% | ||||
| Since: Depuis le | ||||
| Until: Jusqu'au | ||||
|  | ||||
| updatedAt: Mise à jour le | ||||
| updatedBy: Mise à jour par | ||||
| createdAt: Créé le | ||||
| createdBy: Créé par | ||||
|  | ||||
| #elements used in software | ||||
| centers: centres | ||||
| Centers: Centres | ||||
| @@ -472,8 +478,8 @@ workflow: | ||||
|     Previous workflow transitionned help: Workflows où vous avez exécuté une action. | ||||
|     For: Pour | ||||
|     You must select a next step, pick another decision if no next steps are available: Il faut une prochaine étape. Choissisez une autre décision si nécessaire. | ||||
|     An access key was also sent to those addresses: Un lien d'accès a été envoyé à ces addresses | ||||
|     Those users are also granted to apply a transition by using an access key: Ces utilisateurs ont obtennu l'accès grâce au lien reçu par email | ||||
|     An access key was also sent to those addresses: Un lien d'accès a été envoyé à ces adresses | ||||
|     Those users are also granted to apply a transition by using an access key: Ces utilisateurs ont obtenu l'accès grâce au lien reçu par email | ||||
|     Access link copied: Lien d'accès copié | ||||
|     This link grant any user to apply a transition: Le lien d'accès suivant permet d'appliquer une transition | ||||
|     The workflow may be accssed through this link: Une transition peut être appliquée sur ce workflow grâce au lien d'accès suivant | ||||
|   | ||||
| @@ -46,7 +46,7 @@ class SocialAction | ||||
|     private $desactivationDate; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\ManyToMany(targetEntity=Evaluation::class, mappedBy="socialActions") | ||||
|      * @ORM\ManyToMany(targetEntity=Evaluation::class, inversedBy="socialActions") | ||||
|      * @ORM\JoinTable(name="chill_person_social_work_evaluation_action") | ||||
|      */ | ||||
|     private Collection $evaluations; | ||||
| @@ -62,7 +62,7 @@ class SocialAction | ||||
|      * @ORM\GeneratedValue | ||||
|      * @ORM\Column(type="integer") | ||||
|      */ | ||||
|     private $id; | ||||
|     private ?int $id = null; | ||||
|  | ||||
|     /** | ||||
|      * @ORM\ManyToOne(targetEntity=SocialIssue::class, inversedBy="socialActions") | ||||
|   | ||||
| @@ -0,0 +1,69 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\PersonBundle\Export\Helper; | ||||
|  | ||||
| use Chill\PersonBundle\Repository\PersonRepository; | ||||
| use Chill\PersonBundle\Templating\Entity\PersonRenderInterface; | ||||
| use function count; | ||||
| use const SORT_NUMERIC; | ||||
|  | ||||
| class LabelPersonHelper | ||||
| { | ||||
|     private PersonRenderInterface $personRender; | ||||
|  | ||||
|     private PersonRepository $personRepository; | ||||
|  | ||||
|     public function __construct(PersonRepository $personRepository, PersonRenderInterface $personRender) | ||||
|     { | ||||
|         $this->personRepository = $personRepository; | ||||
|         $this->personRender = $personRender; | ||||
|     } | ||||
|  | ||||
|     public function getLabelMulti(string $key, array $values, string $header): callable | ||||
|     { | ||||
|         return function ($value) use ($header) { | ||||
|             if ('_header' === $value) { | ||||
|                 return $header; | ||||
|             } | ||||
|  | ||||
|             if (null === $value) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             $decoded = json_decode($value); | ||||
|  | ||||
|             if (0 === count($decoded)) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             return | ||||
|                 implode( | ||||
|                     '|', | ||||
|                     array_map( | ||||
|                         function (int $personId) { | ||||
|                             $person = $this->personRepository->find($personId); | ||||
|  | ||||
|                             if (null === $person) { | ||||
|                                 return ''; | ||||
|                             } | ||||
|  | ||||
|                             return $this->personRender->renderString($person, []); | ||||
|                         }, | ||||
|                         array_unique( | ||||
|                             array_filter($decoded, static fn (?int $id) => null !== $id), | ||||
|                             SORT_NUMERIC | ||||
|                         ) | ||||
|                     ) | ||||
|                 ); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -5,15 +5,12 @@ | ||||
|    <teleport to="#visgraph-legend"> | ||||
|       <div class="post-menu"> | ||||
|          <div class="list-group mt-4"> | ||||
|             <button type="button" class="list-group-item list-group-item-action btn btn-create" @click="createRelationship"> | ||||
|                {{ $t('visgraph.add_link') }} | ||||
|             <button type="button" class="list-group-item list-group-item-action btn btn-misc" @click="createRelationship"> | ||||
|                <i class="fa fa-plus"></i> {{ $t('visgraph.add_link') }} | ||||
|             </button> | ||||
|             <a type="button" class="list-group-item list-group-item-action btn btn-misc" id="exportCanvasBtn" @click="exportCanvasAsImage"> | ||||
|                <i class="fa fa-camera fa-fw"></i> {{ $t('visgraph.screenshot') }} | ||||
|             </a> | ||||
|             <button type="button" class="list-group-item list-group-item-action btn btn-light" @click="refreshNetwork"> | ||||
|                <i class="fa fa-refresh fa-fw"></i> {{ $t('visgraph.refresh') }} | ||||
|             </button> | ||||
|          </div> | ||||
|  | ||||
|          <div v-if="displayHelpMessage" class="alert alert-info mt-3"> | ||||
|   | ||||
| @@ -0,0 +1,69 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\ThirdPartyBundle\Export\Helper; | ||||
|  | ||||
| use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; | ||||
| use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender; | ||||
| use function count; | ||||
| use const SORT_NUMERIC; | ||||
|  | ||||
| class LabelThirdPartyHelper | ||||
| { | ||||
|     private ThirdPartyRender $thirdPartyRender; | ||||
|  | ||||
|     private ThirdPartyRepository $thirdPartyRepository; | ||||
|  | ||||
|     public function __construct(ThirdPartyRender $thirdPartyRender, ThirdPartyRepository $thirdPartyRepository) | ||||
|     { | ||||
|         $this->thirdPartyRender = $thirdPartyRender; | ||||
|         $this->thirdPartyRepository = $thirdPartyRepository; | ||||
|     } | ||||
|  | ||||
|     public function getLabelMulti(string $key, array $values, string $header): callable | ||||
|     { | ||||
|         return function ($value) use ($header) { | ||||
|             if ('_header' === $value) { | ||||
|                 return $header; | ||||
|             } | ||||
|  | ||||
|             if (null === $value) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             $decoded = json_decode($value); | ||||
|  | ||||
|             if (0 === count($decoded)) { | ||||
|                 return ''; | ||||
|             } | ||||
|  | ||||
|             return | ||||
|                 implode( | ||||
|                     '|', | ||||
|                     array_map( | ||||
|                         function (int $tpId) { | ||||
|                             $tp = $this->thirdPartyRepository->find($tpId); | ||||
|  | ||||
|                             if (null === $tp) { | ||||
|                                 return ''; | ||||
|                             } | ||||
|  | ||||
|                             return $this->thirdPartyRender->renderString($tp, []); | ||||
|                         }, | ||||
|                         array_unique( | ||||
|                             array_filter($decoded, static fn (?int $id) => null !== $id), | ||||
|                             SORT_NUMERIC | ||||
|                         ) | ||||
|                     ) | ||||
|                 ); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -6,3 +6,8 @@ services: | ||||
|         tags: | ||||
|             - { name: 'serializer.normalizer', priority: 64 } | ||||
|  | ||||
|     Chill\ThirdPartyBundle\Export\: | ||||
|         autowire: true | ||||
|         autoconfigure: true | ||||
|         resource: '../Export/' | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user