Compare commits

..

10 Commits

Author SHA1 Message Date
c0f9e953fb Update to v4.11.0 2025-12-17 16:56:35 +01:00
a49ea2b6b9 Fix translation syntax
Cannot start with %, wrap translation value in double quotes
2025-12-17 16:54:33 +01:00
a30232d3ce Merge branch '478-admin-list-filters' into 'master'
Resolve "Add filters to admin lists"

Closes #478

See merge request Chill-Projet/chill-bundles!941
2025-12-15 16:49:39 +00:00
aae55e6f8c Merge branch '466-fix-migrations' into 'master'
Fix migration to exclude null `user_id` in `activity_user` population

Closes #466

See merge request Chill-Projet/chill-bundles!943
2025-12-15 13:43:20 +00:00
c9513f2f6c Fix migration to exclude null user_id in activity_user population 2025-12-15 13:43:20 +00:00
11d7425883 php cs fixes 2025-12-15 10:48:20 +01:00
08897e0981 Fix count of total items for correct paginator display 2025-12-15 10:48:00 +01:00
98cbfed054 Add filtering methods to controllers 2025-12-15 10:48:00 +01:00
9af4d19744 Add repository methods for filtering 2025-12-15 10:48:00 +01:00
c1cf5a8bb2 Start implementation of filter within admin index pages 2025-12-15 10:48:00 +01:00
2641 changed files with 36475 additions and 62539 deletions

View File

@@ -1,6 +0,0 @@
kind: Feature
body: |
Upgrade import of address list to the last version of compiled addresses of belgian-best-address
time: 2024-05-30T16:00:03.440767606+02:00
custom:
Issue: ""

View File

@@ -1,6 +0,0 @@
kind: Feature
body: |
Upgrade CKEditor and refactor configuration with use of typescript
time: 2024-05-31T19:02:42.776662753+02:00
custom:
Issue: ""

View File

@@ -1,6 +0,0 @@
kind: Feature
body: Create invitation list in user menu
time: 2025-08-08T12:08:02.446361367+02:00
custom:
Issue: "385"
SchemaChange: No schema change

View File

@@ -1,6 +0,0 @@
kind: Feature
body: Admin interface for Motive entity
time: 2025-10-07T15:59:45.597029709+02:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@@ -1,6 +0,0 @@
kind: Feature
body: Add an admin interface for Motive entity
time: 2025-10-22T11:15:52.13937955+02:00
custom:
Issue: ""
SchemaChange: Add columns or tables

View File

@@ -1,6 +0,0 @@
kind: Fixed
body: Fix suggestion of referrer when creating notification for accompanyingPeriodWorkDocument
time: 2025-11-06T16:16:05.861813041+01:00
custom:
Issue: "428"
SchemaChange: No schema change

9
.changes/v4.11.0.md Normal file
View File

@@ -0,0 +1,9 @@
## v4.11.0 - 2025-12-17
### Feature
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
### Fixed
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
* Fix translation key/value
Cannot start with % and should be wrapped in "".

View File

@@ -19,11 +19,11 @@ max_line_length = 80
[COMMIT_EDITMSG]
max_line_length = 0
[*.{js,vue,ts}]
[*.{js, vue, ts}]
indent_size = 2
indent_style = space
[*.rst]
indent_size = 3
indent_style = space
[.rst]
ident_size = 3
ident_style = space

2
.env
View File

@@ -86,7 +86,7 @@ ADD_ADDRESS_MAP_CENTER_Z=15
## Redis Cache & redis database
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_URL="redis://${REDIS_HOST}:${REDIS_PORT}"
REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}
###< chill-project/chill-bundles ###
###> symfony/ovh-cloud-notifier ###

View File

@@ -1,4 +0,0 @@
###> symfony/framework-bundle ###
APP_SECRET=72759e571285ef25677c88f967a73386
###< symfony/framework-bundle ###

View File

@@ -1,5 +1,39 @@
# define your env variables for the test env here
# variables for .env environement
# those variables suits for gitlab-ci
# Run tests from root to adapt your own environment
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
DEFAULT_CARRIER_CODE=TEST
ADMIN_PASSWORD=password
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=2a30f6ba26521a2613821da35f28386e
TWILIO_SID=~
TWILIO_SECRET=~
DEFAULT_CARRIER_CODE=BE
ADD_ADDRESS_DEFAULT_COUNTRY=BE
ADD_ADDRESS_MAP_CENTER_X=50.8443
ADD_ADDRESS_MAP_CENTER_Y=4.3523
ADD_ADDRESS_MAP_CENTER_Z=15
SHORT_MESSAGE_DSN=null://null
MESSENGER_TRANSPORT_DSN=sync://
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5454/test?serverVersion=14&charset=utf8"
###< doctrine/doctrine-bundle ###
ASYNC_UPLOAD_TEMP_URL_KEY=
ASYNC_UPLOAD_TEMP_URL_BASE_PATH=
ASYNC_UPLOAD_TEMP_URL_CONTAINER=
MAILER_DSN=null://null
REDIS_HOST=127.0.0.1
REDIS_PORT=6363

3
.gitignore vendored
View File

@@ -33,7 +33,7 @@ config/packages/dev/*
###> phpunit/phpunit ###
/phpunit.xml
/.phpunit.cache/
.phpunit.result.cache
###< phpunit/phpunit ###
/.php-cs-fixer.cache
@@ -62,4 +62,3 @@ yarn-error.log
/.php-cs-fixer.php
/.php-cs-fixer.cache
###< friendsofphp/php-cs-fixer ###
/config/reference.php

View File

@@ -3,7 +3,7 @@
# Select what we should cache between builds
cache:
paths:
- vendor/
- /vendor/
- .cache
- node_modules/
@@ -23,7 +23,6 @@ services:
variables:
APP_ENV: test
GIT_DEPTH: 1
ADMIN_PASSWORD: admin
# Configure postgres environment variables (https://hub.docker.com/r/_/postgres/)
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -43,7 +42,6 @@ variables:
# this is required to work with packages
# see https://getcomposer.org/doc/articles/troubleshooting.md#dependencies-on-the-root-package
COMPOSER_ROOT_VERSION: dev-master
MAILER_DSN: 'null://null'
stages:
- mirror
@@ -99,7 +97,8 @@ mirror_chill_zimbra_bundle:
build:
stage: Composer install
image: chill/base-image:8.4-edge
image: chill/base-image:8.3-edge
variables:
before_script:
- composer config -g cache-dir "$(pwd)/.cache"
script:
@@ -114,7 +113,7 @@ build:
code_style:
stage: Tests
image: chill/base-image:8.4-edge
image: chill/base-image:8.3-edge
script:
- php-cs-fixer fix --dry-run -v --show-progress=none
cache:
@@ -127,25 +126,35 @@ code_style:
phpstan_tests:
stage: Tests
image: chill/base-image:8.4-edge
dependencies:
- build
image: chill/base-image:8.3-edge
variables:
COMPOSER_MEMORY_LIMIT: 3G
before_script:
- bin/console cache:clear --env=dev
script:
- composer exec phpstan -- analyze --memory-limit=3G
cache:
paths:
- .cache/
artifacts:
expire_in: 1 day
paths:
- vendor/
rector_tests:
stage: Tests
image: chill/base-image:8.4-edge
dependencies:
- build
image: chill/base-image:8.3-edge
before_script:
- bin/console cache:clear --env=dev
script:
- composer exec rector -- process --dry-run
cache:
paths:
- .cache/
artifacts:
expire_in: 1 day
paths:
- vendor/
lint:
stage: Tests
@@ -175,9 +184,7 @@ lint:
unit_tests:
stage: Tests
image: chill/base-image:8.4-edge
dependencies:
- build
image: chill/base-image:8.3-edge
variables:
COMPOSER_MEMORY_LIMIT: 3G
before_script:

View File

@@ -234,17 +234,17 @@ This must be a decision made by a human, not by an AI. Every AI task must abort
#### Running Tests
The tests are run from the project's root (not from the bundle's root: so, do not change the directory to any bundle directory before running tests).
Tests must be run using the `symfony` command:
The tests are run from the project's root (not from the bundle's root).
```bash
# Run all tests
vendor/bin/phpunit
# Run a specific test file
symfony composer exec phpunit -- path/to/TestFile.php
vendor/bin/phpunit path/to/TestFile.php
# Run a specific test method
symfony composer exec phpunit -- --filter methodName path/to/TestFile.php
vendor/bin/phpunit --filter methodName path/to/TestFile.php
```
When writing tests, only test specific files. Do not run all tests or the full
@@ -363,8 +363,6 @@ The project can be deployed in a production environment following Symfony's depl
Comprehensive documentation is available in the `/docs/` directory, including installation instructions, configuration guides, and operational procedures.
This documentation is written using the mkdocs tool.
## Development Workflow
1. **Create a Feature Branch**: Always create a new branch for your feature or bugfix

View File

@@ -1,4 +0,0 @@
{
"tabWidth": 2,
"useTabs": false
}

30
.vscode/launch.json vendored
View File

@@ -1,30 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Chill Debug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"preLaunchTask": "symfony"
},
{
"name": "Yarn Encore Dev (Watch)",
"type": "node-terminal",
"request": "launch",
"command": "yarn encore dev --watch",
"cwd": "${workspaceFolder}"
}
],
"compounds": [
{
"name": "Chill Debug + Yarn Encore Dev (Watch)",
"configurations": ["Chill Debug", "Yarn Encore Dev (Watch)"]
}
]
}

23
.vscode/tasks.json vendored
View File

@@ -1,23 +0,0 @@
{
"tasks": [
{
"type": "shell",
"command": "symfony",
"args": [
"server:start",
"--allow-http",
"--no-tls",
"--port=8000",
"--allow-all-ip",
"-d"
],
"label": "symfony"
},
{
"type": "shell",
"command": "yarn",
"args": ["encore", "dev", "--watch"],
"label": "webpack"
}
]
}

View File

@@ -6,6 +6,16 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
and is generated by [Changie](https://github.com/miniscruff/changie).
## v4.11.0 - 2025-12-17
### Feature
* ([#478](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/478)) Add filtering to admin lists: social actions, social issues, goals, results, and evaluations
### Fixed
* ([#466](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/466)) Fix migration query after previous fix
* Fix translation key/value
Cannot start with % and should be wrapped in "".
## v4.10.1 - 2025-12-11
### Fixed
* Fix missing translation variable in NewLocation component

View File

@@ -54,7 +54,7 @@ Arborescence:
- person
- personvendee
- household_edit_metadata
- index.ts
- index.js
```
## Organisation des feuilles de styles

View File

@@ -1,12 +1,7 @@
import {
trans,
setLocale,
getLocale,
setLocaleFallbacks,
} from "./ux-translator";
import { trans, setLocale, setLocaleFallbacks } from "./ux-translator";
setLocaleFallbacks({ en: "fr", nl: "fr", fr: "en" });
setLocale("fr");
setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"});
setLocale('fr');
export { trans, getLocale };
export * from "../var/translations";
export { trans };
export * from '../var/translations';

View File

@@ -2,7 +2,7 @@ services:
###> doctrine/doctrine-bundle ###
database:
ports:
- "127.0.0.1:5455:5432"
- "127.0.0.1:5454:5432"
###< doctrine/doctrine-bundle ###
###> symfony/mailer ###
@@ -14,20 +14,20 @@ services:
environment:
MP_SMTP_AUTH_ACCEPT_ANY: 1
MP_SMTP_AUTH_ALLOW_INSECURE: 1
###< symfony/mailer ###
###< symfony/mailer ###
redis:
ports:
- 127.0.0.1:6364:6379
- 127.0.0.1:6363:6379
relatorio:
ports:
- 8888
rabbitmq:
ports:
- 127.0.0.1:5690:5672
- 127.0.0.1:15690:15672
- 127.0.0.1:5689:5672
- 127.0.0.1:15689:15672
# required to make data persistent
hostname: my-rabbit
volumes:

View File

@@ -15,78 +15,78 @@
}
}],
"require": {
"php": "^8.4",
"php": "^8.2",
"ext-dom": "*",
"ext-json": "*",
"ext-openssl": "*",
"ext-redis": "*",
"ext-zlib": "*",
"champs-libres/wopi-bundle": "1.0.0",
"champs-libres/wopi-lib": "1.0.0",
"champs-libres/wopi-bundle": "dev-symfony-v5@dev",
"champs-libres/wopi-lib": "dev-master@dev",
"doctrine/data-fixtures": "^1.8",
"doctrine/doctrine-bundle": "^2.1",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^3.5.2",
"doctrine/orm": "^2.13.0",
"erusev/parsedown": "^1.7",
"knplabs/knp-menu-bundle": "^3.0",
"knplabs/knp-time-bundle": "^2.4",
"knplabs/knp-time-bundle": "^1.12",
"knpuniversity/oauth2-client-bundle": "^2.10",
"league/csv": "^9.7.1",
"lexik/jwt-authentication-bundle": "^3.1.1",
"lexik/jwt-authentication-bundle": "^2.16",
"nyholm/psr7": "^1.4",
"ocramius/package-versions": "^1.10 || ^2",
"odolbeau/phone-number-bundle": "^3.6",
"ovh/ovh": "^3.0",
"phpoffice/phpspreadsheet": "^1.16",
"ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5",
"smalot/pdfparser": "^2.10",
"spomky-labs/base64url": "^2.0",
"symfony/amqp-messenger": "^7.3",
"symfony/asset": "^7.2",
"symfony/browser-kit": "^7.2",
"symfony/cache": "^7.2",
"symfony/clock": "^7.2",
"symfony/config": "^7.2",
"symfony/console": "^7.2",
"symfony/css-selector": "^7.2",
"symfony/dom-crawler": "^7.2",
"symfony/error-handler": "^7.2",
"symfony/event-dispatcher": "^7.2",
"symfony/event-dispatcher-contracts": "^3.0",
"symfony/expression-language": "^7.2",
"symfony/filesystem": "^7.2",
"symfony/finder": "^7.2",
"symfony/form": "^7.2",
"symfony/framework-bundle": "^7.2",
"symfony/http-client": "^7.2",
"symfony/http-foundation": "^7.2",
"symfony/intl": "^7.2",
"symfony/mailer": "^7.2",
"symfony/messenger": "^7.2",
"symfony/mime": "^7.2",
"symfony/asset": "^5.4",
"symfony/browser-kit": "^5.4",
"symfony/cache": "^5.4",
"symfony/clock": "^6.2",
"symfony/config": "^5.4",
"symfony/console": "^5.4",
"symfony/css-selector": "^5.4",
"symfony/dom-crawler": "^5.4",
"symfony/error-handler": "^5.4",
"symfony/event-dispatcher": "^5.4",
"symfony/event-dispatcher-contracts": "^2.4",
"symfony/expression-language": "^5.4",
"symfony/filesystem": "^5.4",
"symfony/finder": "^5.4",
"symfony/form": "^5.4",
"symfony/framework-bundle": "^5.4",
"symfony/http-client": "^5.4",
"symfony/http-foundation": "^5.4",
"symfony/intl": "^5.4",
"symfony/mailer": "^5.4",
"symfony/messenger": "^5.4",
"symfony/mime": "^5.4",
"symfony/monolog-bundle": "^3.5",
"symfony/notifier": "^7.2",
"symfony/options-resolver": "^7.2",
"symfony/ovh-cloud-notifier": "^7.2",
"symfony/polyfill-intl-messageformatter": "^1.32",
"symfony/process": "^7.2",
"symfony/property-access": "^7.2",
"symfony/property-info": "^7.2",
"symfony/routing": "^7.2",
"symfony/security-bundle": "^7.3",
"symfony/security-core": "^7.2",
"symfony/security-csrf": "^7.2",
"symfony/security-http": "^7.2",
"symfony/serializer": "^7.2",
"symfony/string": "^7.2",
"symfony/translation": "^7.3",
"symfony/twig-bundle": "^7.3",
"symfony/notifier": "^5.4",
"symfony/options-resolver": "^5.4",
"symfony/ovh-cloud-notifier": "^5.4",
"symfony/process": "^5.4",
"symfony/property-access": "^5.4",
"symfony/property-info": "^5.4",
"symfony/routing": "^5.4",
"symfony/security-bundle": "^5.4",
"symfony/security-core": "^5.4",
"symfony/security-csrf": "^5.4",
"symfony/security-guard": "^5.4",
"symfony/security-http": "^5.4",
"symfony/serializer": "^5.4",
"symfony/string": "^5.4",
"symfony/templating": "^5.4",
"symfony/translation": "^5.4",
"symfony/twig-bundle": "^5.4",
"symfony/ux-translator": "^2.22",
"symfony/validator": "^7.2",
"symfony/var-exporter": "^7.0",
"symfony/webpack-encore-bundle": "^2.0",
"symfony/workflow": "^7.2",
"symfony/yaml": "^7.2",
"symfony/validator": "^5.4",
"symfony/webpack-encore-bundle": "^1.11",
"symfony/workflow": "^5.4",
"symfony/yaml": "^5.4",
"thenetworg/oauth2-azure": "^2.0",
"twig/extra-bundle": "^3.0",
"twig/intl-extra": "^3.0",
@@ -97,27 +97,27 @@
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3",
"fakerphp/faker": "^1.13",
"friendsofphp/php-cs-fixer": "3.88.2",
"jangregor/phpstan-prophecy": "^2.2",
"friendsofphp/php-cs-fixer": "3.65.0",
"jangregor/phpstan-prophecy": "^1.0",
"nelmio/alice": "^3.8",
"nikic/php-parser": "^4.15",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^2.1.30",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-doctrine": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0.7",
"phpstan/phpstan-symfony": "^2.0",
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^10.5.24",
"rector/rector": "^2.2",
"symfony/debug-bundle": "^7.2",
"symfony/dotenv": "^7.2",
"rector/rector": "^1.1.0",
"symfony/amqp-messenger": "^5.4.45",
"symfony/debug-bundle": "^5.4",
"symfony/dotenv": "^5.4",
"symfony/flex": "^2.4",
"symfony/maker-bundle": "^1.20",
"symfony/phpunit-bridge": "^7.1",
"symfony/runtime": "^7.2",
"symfony/stopwatch": "^7.2",
"symfony/var-dumper": "^7.2",
"symfony/web-profiler-bundle": "^7.2",
"symfony/runtime": "^5.4",
"symfony/stopwatch": "^5.4",
"symfony/var-dumper": "^5.4",
"symfony/web-profiler-bundle": "^5.4",
"symfony/loco-translation-provider": "^6.0"
},
"conflict": {
@@ -141,7 +141,6 @@
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle",
"Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src",
"Chill\\TicketBundle\\": "src/Bundle/ChillTicketBundle/src",
"Chill\\Utils\\Rector\\": "utils/rector/src"
}
},

View File

@@ -13,6 +13,7 @@ return [
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'test' => true],
Misd\PhoneNumberBundle\MisdPhoneNumberBundle::class => ['all' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
@@ -33,7 +34,6 @@ return [
Chill\ThirdPartyBundle\ChillThirdPartyBundle::class => ['all' => true],
Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
Chill\TicketBundle\ChillTicketBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],

View File

@@ -1,5 +1,5 @@
chill_doc_store:
use_driver: local_storage
use_driver: openstack
local_storage:
storage_path: '%kernel.project_dir%/var/storage'
openstack:

View File

@@ -1,5 +0,0 @@
chill_ticket:
ticket:
person_per_ticket: one # One of "one"; "many"
response_time_exceeded_delay: PT12H

View File

@@ -1,11 +0,0 @@
# Enable stateless CSRF protection for forms and logins/logouts
framework:
form:
csrf_protection:
token_id: submit
csrf_protection:
stateless_token_ids:
- submit
- authenticate
- logout

View File

@@ -7,7 +7,6 @@ doctrine:
#server_version: '16'
use_savepoints: true
orm:
enable_lazy_ghost_objects: true
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.default
auto_mapping: true

View File

@@ -14,7 +14,6 @@ doctrine_migrations:
'Chill\Migrations\Calendar': '@ChillCalendarBundle/migrations'
'Chill\Migrations\Budget': '@ChillBudgetBundle/migrations'
'Chill\Migrations\Report': '@ChillReportBundle/migrations'
'Chill\Migrations\Ticket': '@ChillTicketBundle/migrations'
all_or_nothing:
true

View File

@@ -4,16 +4,6 @@ framework:
#csrf_protection: true
http_method_override: false
# Enable EntityValueResolver for automatic entity injection in controllers
# This replaces the functionality previously provided by SensioFrameworkExtraBundle
http_client:
enabled: true
request:
formats:
json: ['application/json']
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:

View File

@@ -1,5 +1,7 @@
framework:
messenger:
# reset services after consuming messages
reset_on_message: true
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
failure_transport: failed
@@ -64,7 +66,6 @@ framework:
'Chill\MainBundle\Export\Messenger\ExportRequestGenerationMessage': priority
'Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage': async
'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage': async
'Chill\TicketBundle\Messenger\PostTicketUpdateMessage': async
# end of routes added by chill-bundles recipes
# Route your messages to the transports
# 'App\Message\YourMessage': async

View File

@@ -1,8 +1,8 @@
framework:
notifier:
texter_transports:
#ovhcloud: '%env(OVHCLOUD_DSN)%'
#ovhcloud: '%env(SHORT_MESSAGE_DSN)%'
#ovhcloud: '%env(OVHCLOUD_DSN)%'
#ovhcloud: '%env(SHORT_MESSAGE_DSN)%'
channel_policy:
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
urgent: ['email']

View File

@@ -1,3 +0,0 @@
framework:
property_info:
enabled: true

View File

@@ -1,4 +1,5 @@
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
@@ -27,13 +28,16 @@ security:
pattern: ^/wopi
provider: chill_chain_provider
stateless: true
jwt: ~
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
dav:
pattern: ^/dav
provider: chill_chain_provider
stateless: true
custom_authenticator:
- Chill\DocStoreBundle\Security\Authenticator\JWTOnDavUrlAuthenticator
guard:
authenticators:
- Chill\DocStoreBundle\Security\Guard\JWTOnDavUrlAuthenticator
# this firewall is the main firewall for chill. It should be the last one in the stack,
# unless you have specific needs
chill_main:
@@ -59,7 +63,7 @@ security:
# Note: Only the *first* access control that matches will be used
access_control:
# those lines are added by chill-bundles recipes, and are requires to make chill-bundles working
- { path: ^/(login|logout), roles: PUBLIC_ACCESS }
- { path: ^/(login|logout), roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/public, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/wopi, roles: IS_AUTHENTICATED_FULLY }
# access for homepage, the homepage redirect admin to admin section

View File

@@ -0,0 +1,3 @@
sensio_framework_extra:
router:
annotations: false

View File

@@ -1,4 +0,0 @@
framework:
serializer:
enabled: true
enable_attributes: true

View File

@@ -7,8 +7,7 @@ framework:
- Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument
- Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork
- Chill\DocStoreBundle\Entity\AccompanyingCourseDocument
label: Suivi
translated_labels:
label:
fr: 'Suivi'
support_strategy: Chill\MainBundle\Workflow\RelatedEntityWorkflowSupportsStrategy
marking_store:
@@ -17,13 +16,11 @@ framework:
places:
initial:
metadata:
label: Étape initiale
translated_labels:
label:
fr: Étape initiale
attenteModification:
metadata:
label: En attente de modification du document
translated_labels:
label:
fr: En attente de modification du document
validationFilterInputLabels:
forward: {fr: Modification effectuée}
@@ -31,8 +28,7 @@ framework:
neutral: {fr: Autre}
attenteMiseEnForme:
metadata:
label: En attente de mise en forme
translated_labels:
label:
fr: En attente de mise en forme
validationFilterInputLabels:
forward: {fr: Mise en forme terminée}
@@ -40,8 +36,7 @@ framework:
neutral: {fr: Autre}
attenteVisa:
metadata:
label: En attente de visa
translated_labels:
label:
fr: En attente de visa
validationFilterInputLabels:
forward: {fr: Visa accordé}
@@ -52,8 +47,7 @@ framework:
isSignature: ['user', 'person']
onSignatureCompleted:
transitionName: signatureApplied
label: En attente de signature
translated_labels:
label:
fr: En attente de signature
validationFilterInputLabels:
forward: {fr: Signature accordée}
@@ -61,8 +55,7 @@ framework:
neutral: {fr: Autre}
postSignature:
metadata:
label: Signatures traitées
translated_labels:
label:
fr: Signatures traitées
validationFilterInputLabels:
forward: {fr: Poursuite du traitement}
@@ -70,8 +63,7 @@ framework:
neutral: {fr: Autre}
attenteTraitement:
metadata:
label: En attente de traitement
translated_labels:
label:
fr: En attente de traitement
validationFilterInputLabels:
forward: {fr: Traitement terminé favorablement}
@@ -79,8 +71,7 @@ framework:
neutral: {fr: Autre}
attenteEnvoi:
metadata:
label: En attente d'envoi
translated_labels:
label:
fr: En attente d'envoi
validationFilterInputLabels:
forward: {fr: Document envoyé}
@@ -88,8 +79,7 @@ framework:
neutral: {fr: Autre}
attenteValidationMiseEnForme:
metadata:
label: En attente de validation de la mise en forme
translated_labels:
label:
fr: En attente de validation de la mise en forme
validationFilterInputLabels:
forward: {fr: Validation de la mise en forme}
@@ -99,8 +89,7 @@ framework:
metadata:
isSentExternal: true
onExternalView: clotureApresLectureEnvoiExterne
label: En attente d'ouverture par un destinataire externe
translated_labels:
label:
fr: En attente d'ouverture par un destinataire externe
validationFilterInputLabels:
forward: {fr: Document reçu par un destinataire externe}
@@ -110,15 +99,13 @@ framework:
metadata:
isFinal: true
isFinalPositive: false
label: Annulé
translated_labels:
label:
fr: Annulé
final:
metadata:
isFinal: true
isFinalPositive: true
label: Finalisé
translated_labels:
label:
fr: Finalisé
transitions:
# transition qui avancent
@@ -127,8 +114,7 @@ framework:
- initial
to: attenteModification
metadata:
label: Demande de modification du document
translated_labels:
label:
fr: Demande de modification du document
isForward: true
demandeMiseEnForme:
@@ -137,8 +123,7 @@ framework:
- attenteModification
to: attenteMiseEnForme
metadata:
label: Demande de mise en forme
translated_labels:
label:
fr: Demande de mise en forme
isForward: true
demandeValidationMiseEnForme:
@@ -146,8 +131,7 @@ framework:
- attenteMiseEnForme
to: attenteValidationMiseEnForme
metadata:
label: Demande de validation de la mise en forme
translated_labels:
label:
fr: Demande de validation de la mise en forme
isForward: true
demandeVisa:
@@ -160,8 +144,7 @@ framework:
- attenteTraitement
to: attenteVisa
metadata:
label: Demande de visa
translated_labels:
label:
fr: Demande de visa
isForward: true
demandeSignature:
@@ -174,18 +157,14 @@ framework:
- attenteTraitement
to: attenteSignature
metadata:
label: Demande de signature
translated_labels:
fr: Demande de signature
label: {fr: Demande de signature}
isForward: true
signatureApplied:
from:
- attenteSignature
to: postSignature
metadata:
label: Signatures appliquées
translated_labels:
fr: Signatures appliquées
label: {fr: Signatures appliquées}
isForward: true
transitionGuard: 'system' # can be 'system+only-dest' or 'only-dest' (only-dest is default)
demandeTraitement:
@@ -198,9 +177,7 @@ framework:
- postSignature
to: attenteTraitement
metadata:
label: Demande de traitement
translated_labels:
fr: Demande de traitement
label: {fr: Demande de traitement}
isForward: true
demandeEnvoi:
from:
@@ -213,9 +190,7 @@ framework:
- attenteTraitement
to: attenteEnvoi
metadata:
label: Demande d'envoi
translated_labels:
fr: Demande d'envoi
label: {fr: Demande d'envoi}
isForward: true
demandeEnvoiExterne:
from:
@@ -228,9 +203,7 @@ framework:
- attenteTraitement
to: attenteReceptionExternal
metadata:
label: Envoi sécurisé par courrier électronique
translated_labels:
fr: Envoi sécurisé par courrier électronique
label: {fr: Envoi sécurisé par courrier électronique}
isForward: true
clotureApresLectureEnvoiExterne:
from:
@@ -240,9 +213,7 @@ framework:
metadata:
transitionGuard: system
isForward: true
label: Consultation de l'envoi sécurisé
translated_labels:
fr: Consultation de l'envoi sécurisé
label: {fr: Consultation de l'envoi sécurisé}
annulation:
from:
- initial
@@ -256,9 +227,7 @@ framework:
- attenteEnvoi
to: annule
metadata:
label: Annulation
translated_labels:
fr: Annulation
label: {fr: Annulation}
isForward: false
transitionGuard: 'system+only-dest' # can be 'system+only-dest' or 'only-dest' (only-dest is default)
# transitions qui répètent l'étape
@@ -268,35 +237,27 @@ framework:
- attenteValidationMiseEnForme
to: attenteMiseEnForme
metadata:
label: Demande de mise en forme supplémentaire
translated_labels:
fr: Demande de mise en forme supplémentaire
label: {fr: Demande de mise en forme supplémentaire}
demandeVisaSupplementaire:
from:
- attenteVisa
to: attenteVisa
metadata:
label: Demande de visa supplémentaire
translated_labels:
fr: Demande de visa supplémentaire
label: {fr: Demande de visa supplémentaire}
isForward: true
demandeSignatureSupplementaire:
from:
- postSignature
to: attenteSignature
metadata:
label: Demande de signature supplémentaire
translated_labels:
fr: Demande de signature supplémentaire
label: {fr: Demande de signature supplémentaire}
isForward: true
demandeTraitementSupplementaire:
from:
- attenteTraitement
to: attenteTraitement
metadata:
label: Demande de traitement supplémentaire
translated_labels:
fr: Demande de traitement supplémentaire
label: {fr: Demande de traitement supplémentaire}
# transitions qui renvoient vers une étape précédente
refusEtModificationDocument:
from:
@@ -306,8 +267,7 @@ framework:
- attenteEnvoi
to: attenteModification
metadata:
label: Refus et demande de modification du document
translated_labels:
label:
fr: Refus et demande de modification du document
isForward: false
refusEtDemandeMiseEnForme:
@@ -317,9 +277,7 @@ framework:
- attenteEnvoi
to: attenteMiseEnForme
metadata:
label: Refus et demande de mise en forme
translated_labels:
fr: Refus et demande de mise en forme
label: {fr: Refus et demande de mise en forme}
isForward: false
refusEtDemandeVisa:
from:
@@ -327,27 +285,21 @@ framework:
- attenteEnvoi
to: attenteVisa
metadata:
label: Refus et demande de visa
translated_labels:
fr: Refus et demande de visa
label: {fr: Refus et demande de visa}
isForward: false
refusEtDemandeSignature:
from:
- attenteEnvoi
to: attenteSignature
metadata:
label: Refus et demande de signature
translated_labels:
fr: Refus et demande de signature
label: {fr: Refus et demande de signature}
isForward: false
refusEtDemandeTraitement:
from:
- attenteEnvoi
to: attenteTraitement
metadata:
label: Refus et demande de traitement
translated_labels:
fr: Refus et demande de traitement
label: {fr: Refus et demande de traitement}
isForward: false
# transition vers final
initialToFinal:
@@ -355,9 +307,7 @@ framework:
- initial
to: final
metadata:
label: Clotûre immédiate et cloture positive
translated_labels:
fr: Clotûre immédiate et cloture positive
label: {fr: Clotûre immédiate et cloture positive}
isForward: true
attenteMiseEnFormeToFinal:
from:
@@ -365,43 +315,33 @@ framework:
- attenteValidationMiseEnForme
to: final
metadata:
label: Mise en forme terminée et cloture positive
translated_labels:
fr: Mise en forme terminée et cloture positive
label: {fr: Mise en forme terminée et cloture positive}
isForward: true
attenteVisaToFinal:
from:
- attenteVisa
to: final
metadata:
label: Accorde le visa et cloture positive
translated_labels:
fr: Accorde le visa et cloture positive
label: {fr: Accorde le visa et cloture positive}
isForward: true
postSignatureToFinal:
from:
- postSignature
to: final
metadata:
label: Cloture positive
translated_labels:
fr: Cloture positive
label: {fr: Cloture positive}
isForward: true
attenteTraitementToFinal:
from:
- attenteTraitement
to: final
metadata:
label: Traitement terminé et cloture positive
translated_labels:
fr: Traitement terminé et cloture positive
label: {fr: Traitement terminé et cloture positive}
isForward: true
attenteEnvoiToFinal:
from:
- attenteEnvoi
to: final
metadata:
label: Envoyé et cloture positive
translated_labels:
fr: Envoyé et cloture positive
label: {fr: Envoyé et cloture positive}
isForward: true

View File

@@ -0,0 +1,3 @@
kernel:
resource: ../../src/app/Kernel.php
type: annotation

View File

@@ -1,2 +0,0 @@
chill_ticket_bundle:
resource: '@ChillTicketBundle/config/routes.yaml'

View File

@@ -1,3 +0,0 @@
_security_logout:
resource: security.route_loader.logout
type: service

View File

@@ -6,23 +6,11 @@
parameters:
services:
#alias to inject container into AbstractController::setContainer
Psr\Container\ContainerInterface: '@service_container'
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# Custom entity value resolver to replace SensioFrameworkExtraBundle functionality
Chill\MainBundle\ArgumentResolver\EntityValueResolver:
tags:
- { name: controller.argument_value_resolver, priority: 50 }
Chill\MainBundle\Serializer\CircularReferenceHandler:
public: false
tags:
- { name: 'serializer.circular_reference_handler' }
when@dev:
services:
ChampsLibres\WopiLib\Contract\Service\ProofValidatorInterface: '@Chill\WopiBundle\Service\Wopi\NullProofValidator'

View File

@@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Export\Filter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\ExportGenerationContext;
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;
@@ -21,7 +22,6 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
class BirthdateFilter implements ExportElementValidatedInterface, FilterInterface
{
use \Chill\MainBundle\Export\ExportDataNormalizerTrait;
// add specific role for this filter
public function addRole(): ?string
{
@@ -30,7 +30,7 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac
}
// here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data, \Chill\MainBundle\Export\ExportGenerationContext $exportGenerationContext): void
{
$where = $qb->getDQLPart('where');
// we create the clause here
@@ -76,25 +76,21 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac
'format' => 'dd-MM-yyyy',
]);
}
public function getNormalizationVersion(): int
{
return 1;
}
public function normalizeFormData(array $formData): array
{
return ['date_from' => $this->normalizeDate($formData['date_from']), 'date_to' => $this->normalizeDate($formData['date_to'])];
}
public function denormalizeFormData(array $formData, int $fromVersion): array
{
return ['date_from' => $this->denormalizeDate($formData['date_from']), 'date_to' => $this->denormalizeDate($formData['date_to'])];
}
public function getFormDefaultData(): array
{
return ['date_from' => new \DateTime(), 'date_to' => new \DateTime()];
return ['date_from' => new DateTime(), 'date_to' => new DateTime()];
}
// here, we create a simple string which will describe the action of
@@ -102,7 +98,7 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac
public function describeAction($data, ExportGenerationContext $context): string|\Symfony\Contracts\Translation\TranslatableInterface|array
{
return ['Filtered by person\'s birtdate: '
.'between %date_from% and %date_to%', [
. 'between %date_from% and %date_to%', [
'%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'),
], ];
@@ -124,13 +120,13 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac
if (null === $date_from) {
$context->buildViolation('The "date from" should not be empty')
// ->atPath('date_from')
//->atPath('date_from')
->addViolation();
}
if (null === $date_to) {
$context->buildViolation('The "date to" should not be empty')
// ->atPath('date_to')
//->atPath('date_to')
->addViolation();
}
@@ -139,7 +135,7 @@ class BirthdateFilter implements ExportElementValidatedInterface, FilterInterfac
&& $date_from >= $date_to
) {
$context->buildViolation('The date "date to" should be after the '
.'date given in "date from" field')
. 'date given in "date from" field')
->addViolation();
}
}

View File

@@ -32,7 +32,7 @@ class CountPerson implements ExportInterface
$this->entityManager = $em;
}
public function buildForm(FormBuilderInterface $builder): void
public function buildForm(FormBuilderInterface $builder)
{
// this export does not add any form
}

View File

@@ -101,7 +101,7 @@ In twig template, resolve the scope:
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Security;
class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{
@@ -422,7 +422,7 @@ This is an example of implementation:
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Security;
class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{

View File

@@ -1,90 +1,23 @@
# Create a new bundle {#create-new-bundle}
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".
:::: warning
::: title
Warning
:::
###### Create a new bundle
This part of the doc is not yet tested
::::
Create your own bundle is not a trivial task.
## Create a new directory with Bundle class
The easiest way to achieve this is seems to be :
``` bash
mkdir -p src/Bundle/ChillSomeBundle/src/config
mkdir -p src/Bundle/ChillSomeBundle/src/Controller
```
1. Prepare a fresh installation of the chill project, in a new directory
2. Create a new bundle in this project, in the src directory
3. Initialize a git repository **at the root bundle**, and create your initial commit.
4. Register the bundle with composer/packagist. If you do not plan to distribute your bundle with packagist, you may use a custom repository for achieve this [#f1]_
5. Move to a development installation, made as described in the [installation-for-development` section, and add your new repository to the composer.json file
6. Work as :ref:`usual ](editing-code-and-commiting.md)
Add a bundle file
This part of the doc is not yet tested
``` php
<?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\SomeBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillSomeBundle extends Bundle {}
```
And a route file:
``` yaml
chill_ticket_controller:
resource: '@ChillTicketBundle/Controller/'
type: annotation
```
## Register the new psr-4 namespace
In composer.json, add the new psr4 namespace
``` diff
{
"autoload": {
"psr-4": {
+ "Chill\\SomeBundle\\": "src/Bundle/ChillSomeBundle/src",
}
}
}
```
## Register the bundle
Register in the file `config/bundles.php`:
``` php
Vendor\Bundle\YourBundle\YourBundle::class => ['all' => true],
```
And import routes in `config/routes/chill_some_bundle.yaml`:
``` yaml
chill_ticket_bundle:
resource: '@ChillSomeBundle/config/routes.yaml'
```
## Add the doctrine_migration namespace
Add the namespace to `config/packages/doctrine_migrations_chill.yaml`
``` diff
doctrine_migrations:
migrations_paths:
+ 'Chill\Some\Ticket': '@ChillSomeBundle/migrations'
```
## Dump autoloading
``` bash
symfony composer dump-autoload
```
TODO

View File

@@ -1,130 +1,87 @@
###### Menus
This document explains how to use and create menus in Chill.
Chill has created his own menu system
[Routes dans Chill [specification] ](https://redmine.champs-libres.coop/issues/179)
The issue wich discussed the implementation of routes.
## Concepts
to be written
## Add a menu in a template
In your twig template, use the `chill_menu` function:
In your twig template, use the `chill_menu` function :
```twig
{{ chill_menu('person', {
'layout': '@ChillPerson/menu.html.twig',
'args' : {'person_id': person.id, 'person': person },
'activeRouteKey': activeRouteKey
}) }}
```php
{{ chill_menu('person', {
'layout': 'ChillPersonBundle::menu.html.twig',
'args': {'id': person.id },
'activeRouteKey': 'chill_person_view'
}) }}
```
The available arguments are:
* `layout`: a custom layout for KNP Menu.
* `args`: an array of parameters that will be passed to the `MenuBuilder`.
* `activeRouteKey`: the route key name that should be marked as active.
* `layout` : a custom layout. Default to `ChillMainBundle:Menu:defaultMenu.html.twig`
* `args` : those arguments will be passed through the url generator.
* `activeRouteKey` must be the route key name.
## Building a menu
The argument `activeRouteKey` may be a twig variable, defined elsewhere in your template, even in child templates.
To build a menu, you must create a class that implements `\Chill\MainBundle\Routing\LocalMenuBuilderInterface`.
## Create an entry in an existing menu
### The `getMenuIds` method
If a route belongs to a menu, you simply add this to his definition in routing.yml :
This static method returns an array of menu keys that this builder supports. For example, if you want to add items to the "person" menu:
```php
public static function getMenuIds(): array
{
return ['person'];
}
```yaml
chill_person_history_list:
pattern: /person/{person_id}/history
defaults: { _controller: ChillPersonBundle:History:list }
options:
#declare menus
menus:
# the route should be in the 'person' menu :
person:
#and have those arguments :
order: 100
label: menu.person.history
```
### The `buildMenu` method
* `order` (mandatory): the order in the menu. It is preferrable to increment by far more than 1.
* `label` (mandatory): a translatable string.
* `helper` (optional): a text to help people to understand what does the menu do. Not used in default implementation.
* `condition` (optional): an `Expression Language <http://symfony.com/doc/current/components/expression_language/index.html> `_ which will make the menu appears or not. Typically, it may be used to say "show this menu only if the person concerned is more than 18". **Not implemented yet**.
* `access` (optional): an Expression Language to evalute the possibility, for the user, to show this menu according to Access Control Model. **Not implemented yet.**
The `buildMenu` method is called when a menu with one of the supported keys is rendered.
You may add additional keys, but should not use the keys described above.
```php
public function buildMenu($menuId, MenuItem $menu, array $parameters): void
{
// ...
}
You may add the same route to multiple menus :
```yaml
chill_person_history_list:
pattern: /person/{person_id}/history
defaults: { _controller: ChillPersonBundle:History:list }
options:
menus:
menu1:
order: 100
label: menu.person.history
menu2:
order: 100
label: another.label
```
* `$menuId`: the key of the menu being built (e.g., 'person').
* `$menu`: the KNP Menu item representing the parent menu.
* `$parameters`: the arguments passed from the `chill_menu` call in the template (the `args` key).
## Customize menu rendering
#### Example
You may customize menu rendering by using the `layout` option.
```php
public function buildMenu($menuId, MenuItem $menu, array $parameters): void
{
/** @var \Chill\PersonBundle\Entity\Person $person */
$person = $parameters['person'];
$menu->addChild('My Menu Entry', [
'route' => 'my_route_name',
'routeParameters' => [
'id' => $person->getId(),
],
])
->setExtras([
'order' => 100,
]);
}
```
TODO: this part should be written.
### Ordering items
## Caveats
You can order menu items using the `order` extra. In case of duplicate orders, the entry is kept, but the order between items with the same weight is random.
Currently, you may pass arguments globally to each menu, and they will be all passed to route url. This means that :
```php
$menu->addChild('Ordered Item', [/* ... */])
->setExtras(['order' => 50]);
```
### Adding a counter
You can add a counter to a menu item by setting the `counter` extra:
```php
$menu->addChild('Tickets', [/* ... */])
->setExtras([
'counter' => $this->ticketRepository->countOpenedByPerson($person),
'order' => 150
]);
```
### Adding an icon
You can add an icon to a menu item by setting the `icon` extra. The icon name corresponds to a [Fork Awesome](https://forkaweso.me/Fork-Awesome/icons/) icon name (without the `fa-` prefix).
```php
$menu->addChild('My tasks', [
'route' => 'chill_task_singletask_my_tasks',
])
->setExtras([
'order' => -10,
'icon' => 'tasks',
]);
```
Currently, icons are extracted from Fork Awesome, but this might change in the future.
## Existing Menus
Here are some common menus used in Chill and the parameters they receive:
* `person`: Parameter `person` (instance of `Chill\PersonBundle\Entity\Person`). Used in the person file.
* `accompanyingCourse`: Parameter `accompanyingCourse` (instance of `Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriod`). Used in the accompanying course file.
* `admin`: The main administration menu.
* `section`: The "sections" menu (top navigation).
* `user`: The "my menu" (user profile/actions).
* `household`: Parameter `household` (instance of `Chill\PersonBundle\Entity\Household\Household`). Used in the household file.
## Good Examples
For more complex implementations, you can refer to:
* `src/Bundle/ChillTicketBundle/src/Menu/PersonMenuBuilder.php`
* `src/Bundle/ChillTicketBundle/src/Menu/SectionMenuBuilder.php`
* `src/Bundle/ChillDocGeneratorBundle/Menu/AdminMenuBuilder.php`
* `src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php`
* `src/Bundle/ChillPersonBundle/Menu/UserMenuBuilder.php`
* `src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php`
* the argument name in the route entry must match the argument key in the menu declaration in the twig template
* if an argument is missing to generate an url, the url generator will throw a `Symfony\Component\Routing\Exception\MissingMandatoryParametersException`
* if the argument name is not declared in route entry, it will be added to the url, (example: `/my/route?additional=foo`)

View File

@@ -1,188 +0,0 @@
# Normalizing for DocGen
In Chill, some entities can be normalized in the `docgen` format, which is specifically used for document generation.
## The `docgen` Format Requirements
This format has specific requirements regarding `null` values. When serializing a `null` value, it must not be serialized as a literal `null`. Instead, it must be serialized as an object (or array) containing all the keys that would be present if the object were not null.
Each key must have, as value:
- An empty string value (for scalars).
- A boolean
- An empty array (for collections).
- Or, if the expected type is another object, it must contain all the keys for that object, recursively.
This ensures that the document generator always finds the expected keys, even if the data is missing.
Additionally, every normalized form must include an `isNull` key (boolean). This helps the document template distinguish between an actual object and its "null" representation.
## Attribute-Based Normalization
The simplest way to support `docgen` normalization is to use Symfony Serializer attributes.
- Use the group `docgen:read` on properties that should be included.
- For translatable fields (stored as JSON/array of translations), you must also add the context `is-translatable => true`.
### Example: `Country.php`
The `Country` entity demonstrates this approach:
```php
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName;
#[ORM\Entity]
class Country
{
#[Groups(['read', 'docgen:read'])]
#[SerializedName('code')]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 3)]
private string $countryCode = '';
#[Groups(['read', 'docgen:read'])]
#[ORM\Id]
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
private ?int $id = null;
#[Groups(['read', 'docgen:read'])]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
#[Context(['is-translatable' => true], groups: ['docgen:read'])]
private array $name = [];
// ...
}
```
For working properly, the property or return type must be properly set.
## Custom Normalizer
For more complex entities, you may need to implement a custom normalizer.
### Requirements for `docgen` Normalizers
1. **Handle `null` in `supportsNormalization`**:
The normalizer must return `true` if the data is `null` AND the context contains a `docgen:expects` key matching the class the normalizer handles.
```php
public function supportsNormalization($data, $format = null, array $context = []): bool
{
if ('docgen' === $format) {
return $data instanceof MyEntity
|| (null === $data && MyEntity::class === ($context['docgen:expects'] ?? null));
}
return false;
}
```
2. **Implementation of `getSupportedTypes`**:
To avoid side effects and optimize performance, you must return `'*' => false` along with the specific class.
```php
public function getSupportedTypes(?string $format): array
{
if ('docgen' === $format) {
return [
MyEntity::class => true,
'*' => false,
];
}
return [];
}
```
3. **Handle `null` in `normalize`**:
The `normalize` method must detect when the input is `null` and return the "empty" structure with all keys.
### Using `NormalizeNullValueHelper`
To help with normalizing `null` values recursively, you can use the `\Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper` class.
This helper takes an array defining the keys and their expected types. If a type is a class-string, it will call the serializer again to normalize a `null` value for that class.
### Example: `AddressNormalizer.php`
The `AddressNormalizer` is a good example of a custom normalizer handling `docgen`:
```php
class AddressNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
private const array NULL_VALUE = [
'address_id' => 'int',
'text' => 'string',
'street' => 'string',
// ...
'validFrom' => \DateTimeInterface::class,
'postcode' => PostalCode::class,
];
public function normalize($address, $format = null, array $context = []): array
{
if ($address instanceof Address) {
// ... normal normalization logic
if ('docgen' === $format) {
$data['postcode'] = $this->normalizer->normalize(
$address->getPostcode(),
$format,
[...$context, 'docgen:expects' => PostalCode::class]
);
}
return $data;
}
if (null === $address && 'docgen' === $format) {
$helper = new NormalizeNullValueHelper($this->normalizer);
return $helper->normalize(self::NULL_VALUE, $format, $context);
}
// ...
}
// ... supportsNormalization and getSupportedTypes as described above
}
```
## Testing `docgen` Normalization
To ensure that your normalizer strictly follows the `docgen` requirements, you should extend `\Chill\DocGeneratorBundle\Test\DocGenNormalizerTestAbstract`.
This abstract test class performs several critical checks:
- It ensures that the normalized form of a non-null object and a `null` value have **exactly the same keys** (same array shape).
- It verifies that the `isNull` key is present and correctly set (`false` for objects, `true` for `null`).
- It recursively checks that sub-objects also have consistent keys.
- It ensures that `null` values are never returned (they should be empty strings, empty arrays, etc.).
### Example Test: `AddressDocGenNormalizerTest.php`
You need to implement two methods: `provideNotNullObject()` and `provideDocGenExpectClass()`.
```php
namespace Chill\MainBundle\Tests\Serializer\Normalizer;
use Chill\DocGeneratorBundle\Test\DocGenNormalizerTestAbstract;
use Chill\MainBundle\Entity\Address;
class AddressDocGenNormalizerTest extends DocGenNormalizerTestAbstract
{
public function provideNotNullObject(): object
{
// Return a fully populated instance of the entity
return new Address()
->setStreet('Rue de la Loi')
// ...
;
}
public function provideDocGenExpectClass(): string
{
return Address::class;
}
}
```

View File

@@ -15,10 +15,10 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class example extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
{
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, private readonly \Chill\MainBundle\Pagination\PaginatorFactoryInterface $paginatorFactory)
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry)
{
}
public function yourAction(): \Symfony\Component\HttpFoundation\Response
public function yourAction()
{
$em = $this->managerRegistry->getManager();
// first, get the number of total item are available
@@ -27,7 +27,7 @@ class example extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractControl
->getSingleScalarResult();
// get the PaginatorFactory
$paginatorFactory = $this->paginatorFactory;
$paginatorFactory = $this->get('chill_main.paginator_factory');
// create a pagination instance. This instance is only valid for
// the current route and parameters

View File

@@ -18,7 +18,7 @@ use Symfony\Component\Security\Core\Role\Role;
class ConsultationController extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
{
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, private readonly \Chill\PersonBundle\Repository\PersonRepository $personRepository)
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry)
{
}
/**
@@ -28,10 +28,10 @@ class ConsultationController extends \Symfony\Bundle\FrameworkBundle\Controller\
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function listAction($id): \Symfony\Component\HttpFoundation\Response
public function listAction($id)
{
/** @var \Chill\PersonBundle\Entity\Person $person */
$person = $this->personRepository
$person = $this->get('chill.person.repository.person')
->find($id);
if (null === $person) {

View File

@@ -31,7 +31,7 @@ class ChillMainConfiguration implements ConfigurationInterface
$this->setWidgetFactories($widgetFactories);
}
public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_main');
$rootNode = $treeBuilder->getRootNode();

View File

@@ -27,13 +27,12 @@ class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesE
*/
protected $widgetFactories = [];
public function addWidgetFactory(WidgetFactoryInterface $factory): void
public function addWidgetFactory(WidgetFactoryInterface $factory)
{
$this->widgetFactories[] = $factory;
}
#[\Override]
public function getConfiguration(array $config, ContainerBuilder $container): ?\Symfony\Component\Config\Definition\ConfigurationInterface
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
@@ -46,7 +45,7 @@ class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesE
return $this->widgetFactories;
}
public function load(array $configs, ContainerBuilder $container): void
public function load(array $configs, ContainerBuilder $container)
{
// configuration for main bundle
$configuration = $this->getConfiguration($configs, $container);

View File

@@ -25,7 +25,7 @@ class ChillPersonAddAPersonListWidgetFactory extends AbstractWidgetFactory
* see http://symfony.com/doc/current/components/config/definition.html
*
*/
public function configureOptions($place, NodeBuilder $node): void
public function configureOptions($place, NodeBuilder $node)
{
$node->booleanNode('only_active')
->defaultTrue()

View File

@@ -97,12 +97,12 @@ class ChillPersonAddAPersonWidget implements WidgetInterface
$or = new Expr\Orx();
// add the case where closingDate IS NULL
$andWhenClosingDateIsNull = new Expr\Andx();
$andWhenClosingDateIsNull->add(new Expr()->isNull('ap.closingDate'));
$andWhenClosingDateIsNull->add(new Expr()->gte(':now', 'ap.openingDate'));
$andWhenClosingDateIsNull->add((new Expr())->isNull('ap.closingDate'));
$andWhenClosingDateIsNull->add((new Expr())->gte(':now', 'ap.openingDate'));
$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);
@@ -124,7 +124,7 @@ class ChillPersonAddAPersonWidget implements WidgetInterface
/**
* @return UserInterface
*/
private function getUser(): void
private function getUser()
{
// return a user
}

View File

@@ -22,7 +22,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
*/
class ChillPersonExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container): void
public function load(array $configs, ContainerBuilder $container)
{
// ...
}
@@ -32,7 +32,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
*
* @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container
*/
public function prepend(ContainerBuilder $container): void
public function prepend(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'widgets' => [

View File

@@ -11,7 +11,6 @@
"@hotwired/stimulus": "^3.0.0",
"@luminateone/eslint-baseline": "^1.0.9",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
"@symfony/webpack-encore": "^4.1.0",
"@tsconfig/node20": "^20.1.4",
"@types/dompurify": "^3.0.5",
@@ -42,7 +41,6 @@
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0",
"vue-loader": "^17.0.0",
"vue-tsc": "^3.1.3",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
@@ -82,12 +80,12 @@
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress",
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml src/Bundle/ChillTicketBundle/chill.api.specs.yaml> templates/api/specs.yaml",
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml> templates/api/specs.yaml",
"specs-validate": "swagger-cli validate templates/api/specs.yaml",
"specs-create-dir": "mkdir -p templates/api",
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
"version": "node --version",
"eslint": "eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
"eslint": "npx eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
},
"private": true
}

File diff suppressed because it is too large Load Diff

View File

@@ -21,10 +21,6 @@ parameters:
- src/Bundle/*/src/migrations/*
- src/Bundle/*/src/translations/*
- src/Bundle/*/src/Resources/*
- utils/rector/src/Rector/*
symfony:
containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml
includes:
- phpstan-baseline.neon

View File

@@ -1,14 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
failOnNotice="true"
failOnWarning="true"
bootstrap="tests/bootstrap.php"
cacheDirectory="var/cache/.phpunit.cache"
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
>
<php>
<ini name="display_errors" value="1" />
@@ -61,10 +58,6 @@
<!-- temporarily removed, the time to find a fix -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
</testsuite>
<testsuite name="TicketBundle">
<directory suffix="Test.php">src/Bundle/ChillTicketBundle/tests/</directory>
</testsuite>
<!--
<testsuite name="ReportBundle">
<directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory>

View File

@@ -13,16 +13,78 @@ use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonySetList;
return RectorConfig::configure()
->withPaths(['./src', './docs', './rector.php'])
->withComposerBased(twig: true, doctrine: true, symfony: true)
->withSymfonyContainerXml(__DIR__.'/var/cache/dev/App_KernelDevDebugContainer.xml')
->withSymfonyContainerPhp(__DIR__.'/var/cache/dev/App_KernelDevDebugContainer.php')
->withDeadCodeLevel(0)
->withCodeQualityLevel(0)
->withTypeCoverageLevel(0)
->withTypeCoverageDocblockLevel(0)
->withCodingStyleLevel(0);
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->paths([
__DIR__ . '/docs',
__DIR__ . '/src',
__DIR__ . '/rector.php',
]);
$rectorConfig->skip([
\Rector\Php55\Rector\String_\StringClassNameToClassConstantRector::class => __DIR__ . 'src/Bundle/ChillMainBundle/Service/Notifier/LegacyOvhCloudFactory.php'
]);
//$rectorConfig->symfonyContainerXml(__DIR__ . '/var/cache/dev/test/App_KernelTestDebugContainer.xml ');
//$rectorConfig->symfonyContainerPhp(__DIR__ . '/tests/symfony-container.php');
//$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
//$rectorConfig->cacheDirectory(__DIR__ . '/.cache/rector');
// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\ClassMethod\AddParamTypeFromPropertyTypeRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\Class_\MergeDateTimePropertyTypeDeclarationRector::class);
$rectorConfig->rule(Rector\TypeDeclaration\Rector\ClassMethod\AddReturnTypeDeclarationBasedOnParentClassMethodRector::class);
// part of the symfony 54 rules
$rectorConfig->rule(\Rector\Symfony\Symfony53\Rector\StaticPropertyFetch\KernelTestCaseContainerPropertyDeprecationRector::class);
$rectorConfig->rule(\Rector\Symfony\Symfony60\Rector\MethodCall\GetHelperControllerToServiceRector::class);
//$rectorConfig->disableParallel();
//define sets of rules
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_82,
\Rector\Doctrine\Set\DoctrineSetList::DOCTRINE_CODE_QUALITY,
\Rector\PHPUnit\Set\PHPUnitSetList::PHPUNIT_90,
]);
$rectorConfig->ruleWithConfiguration(\Rector\Php80\Rector\Class_\AnnotationToAttributeRector::class, [
new \Rector\Php80\ValueObject\AnnotationToAttribute('Symfony\Component\Serializer\Annotation\Context'),
]);
// migrate for phpunit
$rectorConfig->rules([
\Rector\PHPUnit\PHPUnit100\Rector\Class_\StaticDataProviderClassMethodRector::class,
\Rector\PHPUnit\PHPUnit100\Rector\Class_\PublicDataProviderClassMethodRector::class
]);
// some routes are added twice if it remains activated
// $rectorConfig->rule(\Rector\Symfony\Configs\Rector\ClassMethod\AddRouteAnnotationRector::class);
// skip some path...
$rectorConfig->skip([
// waiting for fixing this bug: https://github.com/rectorphp/rector-doctrine/issues/342
\Rector\Doctrine\CodeQuality\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector::class,
]);
$rectorConfig->ruleWithConfiguration(AnnotationToAttributeRector::class, [
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\AccompanyingPeriodValidity'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\Household\HouseholdMembershipSequential'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\Household\MaxHolder'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ConfidentialCourseMustHaveReferrer'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\LocationValidity'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\Person\Birthdate'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\PersonBundle\Validator\Constraints\Relationship\RelationshipNoDuplicate'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\ActivityBundle\Validator\Constraints\ActivityValidity'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\DocStoreBundle\Validator\Constraints\AsyncFileExists'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\MainBundle\Validation\Constraint\PhonenumberConstraint'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency'),
new \Rector\Php80\ValueObject\AnnotationToAttribute('Chill\MainBundle\Workflow\Validator\EntityWorkflowCreation'),
]);
};

View File

@@ -1,8 +0,0 @@
In this directory, you find an example of file for the command `chill:main:ticket_motives_import`.
This file contains a list of ticket motives to import into the system. Each entry is a dictionary with two keys: `code` and `label`. The `code` key contains the unique code for the ticket motive, and the `label` key contains the human-readable label for the ticket motive.
The `stored_objects` key contains the documents that will be associated with the tickets. They must be found in the same directory.
The command `chill:main:ticket_motives_import` uses this file to import the specified ticket motives into the system.

View File

@@ -1,136 +0,0 @@
- label:
fr: Appel famille pour annonce de décès
urgent: false
supplementary_informations:
- label:
fr: Date du décès
- label:
fr: lieu du décès (domicile ou hôpital)
- label:
fr: nom de lhôpital
- label:
fr: service concerné
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 2_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 3_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 4_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 'Appel famille pour annonce absence : hospitalisation ou consultation'
urgent: false
supplementary_informations:
- label:
fr: Quel hôpital
- label:
fr: quel service
- label:
fr: pour quelles raisons
- label:
fr: 'consultation : date et heure'
- label:
fr: hospitalisation complète ou HDJ
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 5_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 6_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 7_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 'Appel famille pour annonce absence : interruption de prise en charge'
urgent: false
supplementary_informations:
- label:
fr: Pour quelles raisons ? Date
- label:
fr: durée
- label:
fr: accord médical ?
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 8_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 9_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 10_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 'Appel famille pour annonce absence : changement dadresse'
urgent: false
supplementary_informations:
- label:
fr:
- label:
fr: Pourquoi ? Pour combien de temps ? Besoin dun relais des soins ? Nouvelle adresse ?
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 11_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 12_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 13_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: Appel famille pour altération de létat général du patient
urgent: true
supplementary_informations:
- label:
fr: Recherche des symptômes
- label:
fr: Attentes par rapport à la demande
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 14_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 15_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 16_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: Appel famille pour prise en charge de la douleur
urgent: true
supplementary_informations:
- label:
fr: Localisation douleur
- label:
fr: Horaire dernier passage
- label:
fr: Traitements en cours
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 17_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 18_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 19_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: Appel famille pour information sur la date de prise en charge
urgent: false
supplementary_informations: []
stored_objects:
- label:
fr: ☀️ De 07h à 21h
filename: 20_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🌙 De 21h à 07h du matin
filename: 21_doc_20250402_Pelotons flux externes consolidés.pdf
- label:
fr: 🗓️ Dimanches et jours fériés
filename: 22_doc_20250402_Pelotons flux externes consolidés.pdf

View File

@@ -1,6 +0,0 @@
In this directory, you find an example of file for the command `chill:main:override_translation`.
This file contains a list of translations to override in the translation catalogue. Each entry is a dictionary with two keys: `from` and `to`. The `from` key contains the original translation string, and the `to` key contains the replacement string.
The command `chill:main:override_translation` uses this file to generate a new translation catalogue with the specified overrides applied.

View File

@@ -1,8 +0,0 @@
- {from: "de l'usager", to: "du patient"}
- {from: "l'usager", to: "le patient"}
- {from: "L'usager", to: "Le patient"}
- {from: "d'usagers", to: "de patients"}
- {from: "usagers", to: "patients"}
- {from: "Usagers", to: "Patients"}
- {from: "usager", to: "patient"}
- {from: "Usager", to: "Patient"}

View File

@@ -74,8 +74,8 @@ final class ActivityController extends AbstractController
/**
* Deletes a Activity entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/{id}/delete', name: 'chill_activity_activity_delete', methods: ['GET', 'POST', 'DELETE'])]
public function deleteAction(Request $request, mixed $id): \Symfony\Component\HttpFoundation\RedirectResponse|Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/{id}/delete', name: 'chill_activity_activity_delete', methods: ['GET', 'POST', 'DELETE'])]
public function deleteAction(Request $request, mixed $id)
{
$view = null;
@@ -83,7 +83,7 @@ final class ActivityController extends AbstractController
$activity = $this->activityRepository->find($id);
if (null === $activity) {
if (!$activity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
@@ -104,11 +104,11 @@ final class ActivityController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$this->logger->notice('An activity has been removed', [
'by_user' => $this->getUser()->getUserIdentifier(),
'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(),
'person_id' => null === $activity->getPerson() ? $activity->getPerson()->getId() : null,
'comment' => null === $activity->getComment()->getComment(),
'scope_id' => null === $activity->getScope() ? $activity->getScope()->getId() : null,
'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(
static fn (ActivityReason $ar): int => $ar->getId()
@@ -134,7 +134,7 @@ final class ActivityController extends AbstractController
return $this->render($view, [
'activity' => $activity,
'delete_form' => $form,
'delete_form' => $form->createView(),
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
]);
@@ -143,7 +143,7 @@ final class ActivityController extends AbstractController
/**
* Displays a form to edit an existing Activity entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/{id}/edit', name: 'chill_activity_activity_edit', methods: ['GET', 'POST', 'PUT'])]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/{id}/edit', name: 'chill_activity_activity_edit', methods: ['GET', 'POST', 'PUT'])]
public function editAction(int $id, Request $request): Response
{
$view = null;
@@ -226,8 +226,8 @@ final class ActivityController extends AbstractController
return $this->render($view, [
'entity' => $entity,
'edit_form' => $form,
'delete_form' => $deleteForm,
'edit_form' => $form->createView(),
'delete_form' => $deleteForm->createView(),
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'activity_json' => $activity_array,
@@ -237,7 +237,7 @@ final class ActivityController extends AbstractController
/**
* Lists all Activity entities.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/', name: 'chill_activity_activity_list')]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/', name: 'chill_activity_activity_list')]
public function listAction(Request $request): Response
{
$view = null;
@@ -341,7 +341,7 @@ final class ActivityController extends AbstractController
return $filterBuilder->build();
}
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/new', name: 'chill_activity_activity_new', methods: ['POST', 'GET'])]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/new', name: 'chill_activity_activity_new', methods: ['POST', 'GET'])]
public function newAction(Request $request): Response
{
$view = null;
@@ -364,7 +364,7 @@ final class ActivityController extends AbstractController
$activityData = null;
if ($request->query->has('activityData')) {
$activityData = $request->query->all('activityData');
$activityData = $request->query->get('activityData');
}
if (
@@ -517,13 +517,13 @@ final class ActivityController extends AbstractController
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'form' => $form,
'form' => $form->createView(),
'activity_json' => $activity_array,
'default_location' => $defaultLocation,
]);
}
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/select-type', name: 'chill_activity_activity_select_type')]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/select-type', name: 'chill_activity_activity_select_type')]
public function selectTypeAction(Request $request): Response
{
$view = null;
@@ -568,7 +568,7 @@ final class ActivityController extends AbstractController
]);
}
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/activity/{id}/show', name: 'chill_activity_activity_show')]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/activity/{id}/show', name: 'chill_activity_activity_show')]
public function showAction(Request $request, int $id): Response
{
$entity = $this->activityRepository->find($id);
@@ -612,7 +612,7 @@ final class ActivityController extends AbstractController
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'delete_form' => $deleteForm,
'delete_form' => $deleteForm->createView(),
]);
}

View File

@@ -15,7 +15,6 @@ 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\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -28,8 +27,8 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Creates a new ActivityReasonCategory entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreasoncategory/create', name: 'chill_activity_activityreasoncategory_create', methods: ['POST'])]
public function createAction(Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreasoncategory/create', name: 'chill_activity_activityreasoncategory_create', methods: ['POST'])]
public function createAction(Request $request)
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
@@ -45,15 +44,15 @@ class ActivityReasonCategoryController extends AbstractController
return $this->render('@ChillActivity/ActivityReasonCategory/new.html.twig', [
'entity' => $entity,
'form' => $form,
'form' => $form->createView(),
]);
}
/**
* Lists all ActivityReasonCategory entities.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreasoncategory/', name: 'chill_activity_activityreasoncategory')]
public function indexAction(): \Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreasoncategory/', name: 'chill_activity_activityreasoncategory')]
public function indexAction()
{
$em = $this->managerRegistry->getManager();
@@ -67,29 +66,29 @@ class ActivityReasonCategoryController extends AbstractController
/**
* Displays a form to create a new ActivityReasonCategory entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreasoncategory/new', name: 'chill_activity_activityreasoncategory_new')]
public function newAction(): \Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreasoncategory/new', name: 'chill_activity_activityreasoncategory_new')]
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('@ChillActivity/ActivityReasonCategory/new.html.twig', [
'entity' => $entity,
'form' => $form,
'form' => $form->createView(),
]);
}
/**
* Edits an existing ActivityReasonCategory entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreasoncategory/{id}/update', name: 'chill_activity_activityreasoncategory_update', methods: ['POST', 'PUT'])]
public function updateAction(Request $request, mixed $id): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreasoncategory/{id}/update', name: 'chill_activity_activityreasoncategory_update')]
public function updateAction(Request $request, mixed $id)
{
$em = $this->managerRegistry->getManager();
$entity = $em->getRepository(ActivityReasonCategory::class)->find($id);
if (null === $entity) {
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
@@ -104,7 +103,7 @@ class ActivityReasonCategoryController extends AbstractController
return $this->render('@ChillActivity/ActivityReasonCategory/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm,
'edit_form' => $editForm->createView(),
]);
}
@@ -112,8 +111,10 @@ class ActivityReasonCategoryController extends AbstractController
* 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): FormInterface
private function createCreateForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'),
@@ -129,8 +130,10 @@ class ActivityReasonCategoryController extends AbstractController
* 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): FormInterface
private function createEditForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', ['id' => $entity->getId()]),

View File

@@ -16,8 +16,6 @@ use Chill\ActivityBundle\Form\ActivityReasonType;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -30,8 +28,8 @@ class ActivityReasonController extends AbstractController
/**
* Creates a new ActivityReason entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreason/create', name: 'chill_activity_activityreason_create', methods: ['POST'])]
public function createAction(Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreason/create', name: 'chill_activity_activityreason_create', methods: ['POST'])]
public function createAction(Request $request)
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
@@ -47,15 +45,15 @@ class ActivityReasonController extends AbstractController
return $this->render('@ChillActivity/ActivityReason/new.html.twig', [
'entity' => $entity,
'form' => $form,
'form' => $form->createView(),
]);
}
/**
* Lists all ActivityReason entities.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreason/', name: 'chill_activity_activityreason')]
public function indexAction(): \Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreason/', name: 'chill_activity_activityreason')]
public function indexAction()
{
$em = $this->managerRegistry->getManager();
@@ -69,29 +67,29 @@ class ActivityReasonController extends AbstractController
/**
* Displays a form to create a new ActivityReason entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreason/new', name: 'chill_activity_activityreason_new')]
public function newAction(): \Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreason/new', name: 'chill_activity_activityreason_new')]
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('@ChillActivity/ActivityReason/new.html.twig', [
'entity' => $entity,
'form' => $form,
'form' => $form->createView(),
]);
}
/**
* Edits an existing ActivityReason entity.
*/
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activityreason/{id}/update', name: 'chill_activity_activityreason_update', methods: ['POST', 'PUT'])]
public function updateAction(Request $request, mixed $id): \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activityreason/{id}/update', name: 'chill_activity_activityreason_update')]
public function updateAction(Request $request, mixed $id)
{
$em = $this->managerRegistry->getManager();
$entity = $em->getRepository(ActivityReason::class)->find($id);
if (null === $entity) {
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
@@ -106,7 +104,7 @@ class ActivityReasonController extends AbstractController
return $this->render('@ChillActivity/ActivityReason/edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm,
'edit_form' => $editForm->createView(),
]);
}
@@ -114,8 +112,10 @@ class ActivityReasonController extends AbstractController
* 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): FormInterface
private function createCreateForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_create'),
@@ -131,8 +131,10 @@ class ActivityReasonController extends AbstractController
* 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): FormInterface
private function createEditForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_update', ['id' => $entity->getId()]),

View File

@@ -22,7 +22,6 @@ class AdminActivityPresenceController extends CRUDController
*
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
#[\Override]
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/* @var \Doctrine\ORM\QueryBuilder $query */

View File

@@ -22,7 +22,6 @@ class AdminActivityTypeCategoryController extends CRUDController
*
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
#[\Override]
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/* @var \Doctrine\ORM\QueryBuilder $query */

View File

@@ -22,7 +22,6 @@ class AdminActivityTypeController extends CRUDController
*
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
#[\Override]
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/* @var \Doctrine\ORM\QueryBuilder $query */

View File

@@ -18,15 +18,15 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
*/
class AdminController extends AbstractController
{
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activity', name: 'chill_activity_admin_index')]
public function indexActivityAction(): \Symfony\Component\HttpFoundation\Response
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activity', name: 'chill_activity_admin_index')]
public function indexActivityAction()
{
return $this->render('@ChillActivity/Admin/layout_activity.html.twig');
}
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activity_redirect_to_main', name: 'chill_admin_aside_activity_redirect_to_admin_index', options: [null])]
#[\Symfony\Component\Routing\Attribute\Route(path: '/{_locale}/admin/activity_redirect_to_main', name: 'chill_admin_activity_redirect_to_admin_index')]
public function redirectToAdminIndexAction(): \Symfony\Component\HttpFoundation\RedirectResponse
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activity_redirect_to_main', name: 'chill_admin_aside_activity_redirect_to_admin_index', options: [null])]
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/admin/activity_redirect_to_main', name: 'chill_admin_activity_redirect_to_admin_index')]
public function redirectToAdminIndexAction()
{
return $this->redirectToRoute('chill_main_admin_central');
}

View File

@@ -27,6 +27,8 @@ use Faker\Factory as FakerFactory;
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
{
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
private readonly \Faker\Generator $faker;
public function __construct(private readonly EntityManagerInterface $em)
@@ -61,7 +63,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
public function newRandomActivity($person): ?Activity
{
$activity = new Activity()
$activity = (new Activity())
->setUser($this->getRandomUser())
->setPerson($person)
->setDate($this->faker->dateTimeThisYear())

View File

@@ -54,7 +54,7 @@ class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterf
foreach ($reasons as $r) {
echo 'Creating activity reason : '.$r['name']['en']."\n";
$activityReason = new ActivityReason()
$activityReason = (new ActivityReason())
->setName($r['name'])
->setActive(true)
->setCategory($this->getReference($r['category'], ActivityReasonCategory::class));

View File

@@ -35,7 +35,7 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu
foreach ($categs as $c) {
echo 'Creating activity reason category : '.$c['name']['en']."\n";
$activityReasonCategory = new ActivityReasonCategory()
$activityReasonCategory = (new ActivityReasonCategory())
->setName($c['name'])
->setActive(true);
$manager->persist($activityReasonCategory);

View File

@@ -56,7 +56,7 @@ class LoadActivityType extends Fixture implements OrderedFixtureInterface
foreach ($types as $t) {
echo 'Creating activity type : '.$t['name']['fr'].' (cat:'.$t['category']." \n";
$activityType = new ActivityType()
$activityType = (new ActivityType())
->setName($t['name'])
->setCategory($this->getReference('activity_type_cat_'.$t['category'], ActivityTypeCategory::class))
->setSocialIssuesVisible(1)

View File

@@ -44,7 +44,7 @@ class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterfac
foreach ($categories as $cat) {
echo 'Creating activity type category : '.$cat['ref']."\n";
$newCat = new ActivityTypeCategory()
$newCat = (new ActivityTypeCategory())
->setName($cat['name']);
$manager->persist($newCat);

View File

@@ -64,25 +64,25 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
$permissionsGroup->getName(),
$scope->getName()['en']
);
$roleScopeUpdate = new RoleScope()
$roleScopeUpdate = (new RoleScope())
->setRole('CHILL_ACTIVITY_UPDATE')
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeUpdate);
$roleScopeCreate = new RoleScope()
$roleScopeCreate = (new RoleScope())
->setRole(ActivityVoter::CREATE_ACCOMPANYING_COURSE)
->setScope($scope);
$roleScopeCreate = new RoleScope()
$roleScopeCreate = (new RoleScope())
->setRole(ActivityVoter::CREATE_PERSON)
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeCreate);
$roleScopeDelete = new RoleScope()
$roleScopeDelete = (new RoleScope())
->setRole('CHILL_ACTIVITY_DELETE')
->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeDelete);
$roleScopeList = new RoleScope()
$roleScopeList = (new RoleScope())
->setRole(ActivityStatsVoter::LISTS);
$permissionsGroup->addRoleScope($roleScopeList);
$roleScopeStat = new RoleScope()
$roleScopeStat = (new RoleScope())
->setRole(ActivityStatsVoter::STATS);
$permissionsGroup->addRoleScope($roleScopeStat);

View File

@@ -25,7 +25,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
*/
class ChillActivityExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container): void
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
@@ -44,14 +44,14 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$loader->load('services/doctrine.entitylistener.yaml');
}
public function prepend(ContainerBuilder $container): void
public function prepend(ContainerBuilder $container)
{
$this->prependRoutes($container);
$this->prependAuthorization($container);
$this->prependCruds($container);
}
public function prependAuthorization(ContainerBuilder $container): void
public function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', [
'role_hierarchy' => [
@@ -71,7 +71,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
/** (non-PHPdoc).
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
*/
public function prependRoutes(ContainerBuilder $container): void
public function prependRoutes(ContainerBuilder $container)
{
// add routes for custom bundle
$container->prependExtensionConfig('chill_main', [

View File

@@ -22,7 +22,7 @@ use function is_int;
*/
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_activity');
$rootNode = $treeBuilder->getRootNode();

View File

@@ -34,9 +34,9 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\DiscriminatorMap;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Attribute\SerializedName;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Symfony\Component\Validator\Constraints as Assert;
/**
@@ -53,9 +53,9 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
use TrackUpdateTrait;
final public const string SENTRECEIVED_RECEIVED = 'received';
final public const SENTRECEIVED_RECEIVED = 'received';
final public const string SENTRECEIVED_SENT = 'sent';
final public const SENTRECEIVED_SENT = 'sent';
#[Groups(['read'])]
#[ORM\ManyToOne(targetEntity: AccompanyingPeriod::class)]
@@ -447,7 +447,9 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return (int) round(($this->travelTime->getTimestamp() + $this->travelTime->getOffset()) / 60.0, 0);
}
#[\Deprecated]
/**
* @deprecated
*/
public function getType(): ActivityType
{
return $this->activityType;
@@ -630,7 +632,9 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
return $this;
}
#[\Deprecated]
/**
* @deprecated
*/
public function setType(ActivityType $activityType): self
{
$this->activityType = $activityType;

View File

@@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute as Serializer;
use Symfony\Component\Serializer\Annotation as Serializer;
/**
* Class ActivityPresence.

View File

@@ -37,8 +37,10 @@ class ActivityReason
/**
* Get active.
*
* @return bool
*/
public function getActive(): bool
public function getActive()
{
return $this->active;
}
@@ -53,8 +55,10 @@ class ActivityReason
/**
* Get id.
*
* @return int
*/
public function getId(): ?int
public function getId()
{
return $this->id;
}

View File

@@ -58,16 +58,20 @@ class ActivityReasonCategory implements \Stringable
/**
* Get active.
*
* @return bool
*/
public function getActive(): bool
public function getActive()
{
return $this->active;
}
/**
* Get id.
*
* @return int
*/
public function getId(): ?int
public function getId()
{
return $this->id;
}

View File

@@ -12,8 +12,8 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute as Serializer;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -25,11 +25,11 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
#[ORM\Table(name: 'activitytype')]
class ActivityType
{
final public const int FIELD_INVISIBLE = 0;
final public const FIELD_INVISIBLE = 0;
final public const int FIELD_OPTIONAL = 1;
final public const FIELD_OPTIONAL = 1;
final public const int FIELD_REQUIRED = 2;
final public const FIELD_REQUIRED = 2;
/**
* @deprecated not in use
@@ -188,7 +188,7 @@ class ActivityType
private int $userVisible = self::FIELD_REQUIRED;
#[Assert\Callback]
public function checkSocialActionsVisibility(ExecutionContextInterface $context, mixed $payload): void
public function checkSocialActionsVisibility(ExecutionContextInterface $context, mixed $payload)
{
if ($this->socialIssuesVisible !== $this->socialActionsVisible) {
// if social issues are invisible then social actions cannot be optional or required + if social issues are optional then social actions shouldn't be required
@@ -461,17 +461,11 @@ class ActivityType
{
$property = $field.'Visible';
// Get the real class name (not the proxy)
$class = static::class;
if (str_contains($class, '__CG__')) {
$class = get_parent_class($this);
}
$realClass = $class;
if (!property_exists($realClass, $property)) {
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
/* @phpstan-ignore-next-line */
return self::FIELD_INVISIBLE !== $this->{$property};
}

View File

@@ -21,7 +21,7 @@ class ActivityEntityListener
{
public function __construct(private readonly EntityManagerInterface $em, private readonly AccompanyingPeriodWorkRepository $workRepository) {}
public function persistActionToCourse(Activity $activity): void
public function persistActionToCourse(Activity $activity)
{
if ($activity->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
$period = $activity->getAccompanyingPeriod();

View File

@@ -25,7 +25,7 @@ use Symfony\Component\Form\FormBuilderInterface;
final readonly class ByActivityTypeAggregator implements AggregatorInterface
{
private const string PREFIX = 'acp_by_activity_type_agg';
private const PREFIX = 'acp_by_activity_type_agg';
public function __construct(
private RollingDateConverterInterface $rollingDateConverter,
@@ -53,7 +53,7 @@ final readonly class ByActivityTypeAggregator implements AggregatorInterface
public function normalizeFormData(array $formData): array
{
return ['after_date' => $formData['after_date']?->normalize(), 'before_date' => $formData['before_date']?->normalize()];
return ['after_date' => $formData['after_date']->normalize(), 'before_date' => $formData['before_date']->normalize()];
}
public function denormalizeFormData(array $formData, int $fromVersion): array

View File

@@ -18,7 +18,7 @@ use Symfony\Component\Form\FormBuilderInterface;
final readonly class ActivityLocationAggregator implements AggregatorInterface
{
public const string KEY = 'activity_location_aggregator';
public const KEY = 'activity_location_aggregator';
public function addRole(): ?string
{

View File

@@ -20,7 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityTypeAggregator implements AggregatorInterface
{
final public const string KEY = 'activity_type_aggregator';
final public const KEY = 'activity_type_aggregator';
public function __construct(protected ActivityTypeRepositoryInterface $activityTypeRepository, protected TranslatableStringHelperInterface $translatableStringHelper) {}

View File

@@ -20,7 +20,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityUserAggregator implements AggregatorInterface
{
final public const string KEY = 'activity_user_id';
final public const KEY = 'activity_user_id';
public function __construct(private readonly UserRepository $userRepository, private readonly UserRender $userRender) {}

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityUsersJobAggregator implements AggregatorInterface
{
private const string PREFIX = 'act_agg_user_job';
private const PREFIX = 'act_agg_user_job';
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class ActivityUsersScopeAggregator implements AggregatorInterface
{
private const string PREFIX = 'act_agg_user_scope';
private const PREFIX = 'act_agg_user_scope';
public function __construct(
private readonly ScopeRepositoryInterface $scopeRepository,

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class CreatorJobAggregator implements AggregatorInterface
{
private const string PREFIX = 'acp_agg_creator_job';
private const PREFIX = 'acp_agg_creator_job';
public function __construct(
private readonly UserJobRepositoryInterface $userJobRepository,

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\FormBuilderInterface;
class CreatorScopeAggregator implements AggregatorInterface
{
private const string PREFIX = 'acp_agg_creator_scope';
private const PREFIX = 'acp_agg_creator_scope';
public function __construct(
private readonly ScopeRepository $scopeRepository,

View File

@@ -19,13 +19,13 @@ use Symfony\Component\Form\FormBuilderInterface;
class DateAggregator implements AggregatorInterface
{
private const array CHOICES = [
private const CHOICES = [
'by month' => 'month',
'by week' => 'week',
'by year' => 'year',
];
private const string DEFAULT_CHOICE = 'year';
private const DEFAULT_CHOICE = 'year';
public function addRole(): ?string
{

View File

@@ -23,7 +23,7 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
final readonly class PersonsAggregator implements AggregatorInterface
{
private const string PREFIX = 'act_persons_agg';
private const PREFIX = 'act_persons_agg';
public function __construct(private LabelPersonHelper $labelPersonHelper) {}

View File

@@ -42,7 +42,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
public function buildForm(FormBuilderInterface $builder)
{
// TODO: Implement buildForm() method.
}

View File

@@ -42,7 +42,7 @@ final readonly class CountHouseholdOnActivity implements ExportInterface, Groupe
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void {}
public function buildForm(FormBuilderInterface $builder) {}
public function getNormalizationVersion(): int
{

View File

@@ -34,7 +34,7 @@ final readonly class ListActivity implements ListInterface, GroupedExportInterfa
private FilterListAccompanyingPeriodHelperInterface $filterListAccompanyingPeriodHelper,
) {}
public function buildForm(FormBuilderInterface $builder): void
public function buildForm(FormBuilderInterface $builder)
{
$this->helper->buildForm($builder);
}
@@ -154,7 +154,7 @@ final readonly class ListActivity implements ListInterface, GroupedExportInterfa
return ActivityStatsVoter::LISTS;
}
public function supportsModifiers(): array
public function supportsModifiers()
{
return array_merge(
$this->helper->supportsModifiers(),

View File

@@ -34,7 +34,7 @@ final readonly class CountHouseholdOnActivity implements ExportInterface, Groupe
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void {}
public function buildForm(FormBuilderInterface $builder) {}
public function getNormalizationVersion(): int
{

View File

@@ -11,7 +11,6 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Export\Declarations;
use Chill\ActivityBundle\Repository\ActivityRepository;
@@ -34,9 +33,6 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class ListActivity implements ListInterface, GroupedExportInterface
{
/**
* @var string[]
*/
protected array $fields = [
'id',
'date',
@@ -63,20 +59,22 @@ class ListActivity implements ListInterface, GroupedExportInterface
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function buildForm(FormBuilderInterface $builder): void
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('fields', ChoiceType::class, [
'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): void {
if (0 === \count($selected)) {
$context->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
})],
'constraints' => [new Callback([
'callback' => static function ($selected, ExecutionContextInterface $context) {
if (0 === \count($selected)) {
$context->buildViolation('You must select at least one element')
->atPath('fields')
->addViolation();
}
},
])],
]);
}
@@ -216,7 +214,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
$qb = $this->entityManager->createQueryBuilder();
$qb
->from(Activity::class, 'activity')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join(
HouseholdMember::class,

View File

@@ -30,7 +30,7 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
class StatActivityDuration implements ExportInterface, GroupedExportInterface
{
final public const string SUM = 'sum';
final public const SUM = 'sum';
private readonly bool $filterStatsByCenters;
/**

View File

@@ -28,7 +28,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class ListActivityHelper
{
final public const string MSG_KEY = 'export.list.activity.';
final public const MSG_KEY = 'export.list.activity.';
public function __construct(
private readonly ActivityPresenceRepositoryInterface $activityPresenceRepository,

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