mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'master' into export/allow-check-multiple-geographical-zones
This commit is contained in:
commit
8bbca7e61a
@ -34,6 +34,7 @@
|
|||||||
"sensio/framework-extra-bundle": "^5.5",
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
"spomky-labs/base64url": "^2.0",
|
"spomky-labs/base64url": "^2.0",
|
||||||
"symfony/browser-kit": "^4.4",
|
"symfony/browser-kit": "^4.4",
|
||||||
|
"symfony/clock": "^6.2",
|
||||||
"symfony/css-selector": "^4.4",
|
"symfony/css-selector": "^4.4",
|
||||||
"symfony/expression-language": "^4.4",
|
"symfony/expression-language": "^4.4",
|
||||||
"symfony/form": "^4.4",
|
"symfony/form": "^4.4",
|
||||||
|
@ -90,9 +90,7 @@ class CountPerson implements ExportInterface
|
|||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
// we gather all center the user choose.
|
// we gather all center the user choose.
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
$qb = $this->entityManager->createQueryBuilder();
|
||||||
|
|
||||||
|
203
docs/source/development/entity-info.rst
Normal file
203
docs/source/development/entity-info.rst
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||||
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
|
under the terms of the GNU Free Documentation License, Version 1.3
|
||||||
|
or any later version published by the Free Software Foundation;
|
||||||
|
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||||
|
A copy of the license is included in the section entitled "GNU
|
||||||
|
Free Documentation License".
|
||||||
|
|
||||||
|
.. _entity-info:
|
||||||
|
|
||||||
|
Stats about event on entity in php world
|
||||||
|
########################################
|
||||||
|
|
||||||
|
It is necessary to be able to gather information about events for some entities:
|
||||||
|
|
||||||
|
- when the event has been done;
|
||||||
|
- who did it;
|
||||||
|
- ...
|
||||||
|
|
||||||
|
Those "infos" are not linked with right management, like describe in :ref:`timelines`.
|
||||||
|
|
||||||
|
|
||||||
|
“infos” for some stats and info about an entity
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Building an info means:
|
||||||
|
|
||||||
|
- create an Entity, and map this entity to a SQL view (not a regular table);
|
||||||
|
- use the framework to build this entity dynamically.
|
||||||
|
|
||||||
|
A framework api is built to be able to build multiple “infos” entities
|
||||||
|
through “union” views:
|
||||||
|
|
||||||
|
- use a command ``bin/console chill:db:sync-views`` to synchronize view (create view if it does not exists, or update
|
||||||
|
views when new SQL parts are added in the UNION query. Internally, this command call a new ``ViewEntityInfoManager``,
|
||||||
|
which iterate over available views to build the SQL;
|
||||||
|
- one can create a new “view entity info” by implementing a
|
||||||
|
``ViewEntityInfoProviderInterface``
|
||||||
|
- this implementation of the interface is free to create another
|
||||||
|
interface for building each part of the UNION query. This interface
|
||||||
|
is created for AccompanyingPeriodInfo:
|
||||||
|
``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``
|
||||||
|
|
||||||
|
So, converting new “events” into rows for ``AccompanyingPeriodInfo`` is
|
||||||
|
just implementing this interface!
|
||||||
|
|
||||||
|
Implementation for AccompanyingPeriod (``AccompanyingPeriod/AccompanyingPeriodInfo``)
|
||||||
|
-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
A class is created for computing some statistical info for an
|
||||||
|
AccompanyingPeriod: ``AccompanyingPeriod/AccompanyingPeriodInfo``. This
|
||||||
|
contains information about “something happens”, who did it and when.
|
||||||
|
|
||||||
|
Having those info in table answer some questions like:
|
||||||
|
|
||||||
|
- when is the last and the first action (AccompanyingPeriodWork,
|
||||||
|
Activity, AccompanyingPeriodWorkEvaluation, …) on the period;
|
||||||
|
- who is “acting” on the period, and when is the last “action” for each
|
||||||
|
user.
|
||||||
|
|
||||||
|
The AccompanyingPeriod info is mapped to a SQL view, not a table. The
|
||||||
|
sql view is built dynamically (see below), and gather infos from
|
||||||
|
ActivityBundle, PersonBundle, CalendarBundle, … It is possible to create
|
||||||
|
custom bundle and add info on this view.
|
||||||
|
|
||||||
|
.. code:: php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table(name="view_chill_person_accompanying_period_info") <==== THIS IS A VIEW, NOT A TABLE
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodInfo
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
Why do we need this ?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For multiple jobs in PHP world:
|
||||||
|
|
||||||
|
- moving the accompanying period to another steps when inactive,
|
||||||
|
automatically;
|
||||||
|
- listing all the users which are intervening on the action on a new
|
||||||
|
“Liste des intervenants” page;
|
||||||
|
- filtering on exports
|
||||||
|
|
||||||
|
Later, we will launch automatic anonymise for accompanying period and
|
||||||
|
all related entities through this information.
|
||||||
|
|
||||||
|
How is built the SQL views which is mapped to “info” entities ?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The AccompanyingPeriodInfo entity is mapped by a SQL view (not a regular
|
||||||
|
table).
|
||||||
|
|
||||||
|
The sql view is built dynamically, it is a SQL view like this, for now (April 2023):
|
||||||
|
|
||||||
|
.. code:: sql
|
||||||
|
|
||||||
|
create view view_chill_person_accompanying_period_info
|
||||||
|
(accompanyingperiod_id, relatedentity, relatedentityid, user_id, infodate, discriminator, metadata) as
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.enddate AS infodate,
|
||||||
|
'accompanying_period_work_end'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE w.enddate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
e.updatedby_id AS user_id,
|
||||||
|
e.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE e.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.startdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument'::text AS relatedentity,
|
||||||
|
doc.id AS relatedentityid,
|
||||||
|
doc.updatedby_id AS user_id,
|
||||||
|
doc.updatedat AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_document_updated_at'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation_document doc
|
||||||
|
JOIN chill_person_accompanying_period_work_evaluation e ON doc.accompanyingperiodworkevaluation_id = e.id
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
WHERE doc.updatedat IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT cpapw.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation'::text AS relatedentity,
|
||||||
|
e.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
e.maxdate AS infodate,
|
||||||
|
'accompanying_period_work_evaluation_max'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work_evaluation e
|
||||||
|
JOIN chill_person_accompanying_period_work cpapw ON cpapw.id = e.accompanyingperiodwork_id
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON cpapw.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
WHERE e.maxdate IS NOT NULL
|
||||||
|
UNION
|
||||||
|
SELECT w.accompanyingperiod_id,
|
||||||
|
'Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork'::text AS relatedentity,
|
||||||
|
w.id AS relatedentityid,
|
||||||
|
cpapwr.user_id,
|
||||||
|
w.startdate AS infodate,
|
||||||
|
'accompanying_period_work_start'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM chill_person_accompanying_period_work w
|
||||||
|
LEFT JOIN chill_person_accompanying_period_work_referrer cpapwr ON w.id = cpapwr.accompanyingperiodwork_id
|
||||||
|
UNION
|
||||||
|
SELECT activity.accompanyingperiod_id,
|
||||||
|
'Chill\ActivityBundle\Entity\Activity'::text AS relatedentity,
|
||||||
|
activity.id AS relatedentityid,
|
||||||
|
au.user_id,
|
||||||
|
activity.date AS infodate,
|
||||||
|
'activity_date'::text AS discriminator,
|
||||||
|
'{}'::jsonb AS metadata
|
||||||
|
FROM activity
|
||||||
|
LEFT JOIN activity_user au ON activity.id = au.activity_id
|
||||||
|
WHERE activity.accompanyingperiod_id IS NOT NULL;
|
||||||
|
|
||||||
|
As you can see, the view gather multiple SELECT queries and bind them
|
||||||
|
with UNION.
|
||||||
|
|
||||||
|
Each SELECT query is built dynamically, through a class implementing an
|
||||||
|
interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``, `like
|
||||||
|
here <https://gitlab.com/Chill-Projet/chill-bundles/-/blob/master/src/Bundle/ChillPersonBundle/Service/EntityInfo/AccompanyingPeriodInfoQueryPart/AccompanyingPeriodWorkEndQueryPartForAccompanyingPeriodInfo.php>`__
|
||||||
|
|
||||||
|
To add new `SELECT` query in different `UNION` parts in the sql view, create a
|
||||||
|
service and implements this interface: ``Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface``.
|
@ -35,6 +35,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
|||||||
manual/index.rst
|
manual/index.rst
|
||||||
Assets <assets.rst>
|
Assets <assets.rst>
|
||||||
Cron Jobs <cronjob.rst>
|
Cron Jobs <cronjob.rst>
|
||||||
|
Info about entities <entity-info.rst>
|
||||||
|
|
||||||
Layout and UI
|
Layout and UI
|
||||||
**************
|
**************
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
A copy of the license is included in the section entitled "GNU
|
A copy of the license is included in the section entitled "GNU
|
||||||
Free Documentation License".
|
Free Documentation License".
|
||||||
|
|
||||||
|
.. _timelines:
|
||||||
|
|
||||||
Timelines
|
Timelines
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
@ -151,6 +151,7 @@ This script will :
|
|||||||
|
|
||||||
# mount into to container
|
# mount into to container
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
|
bin/console chill:db:sync-views
|
||||||
# and load fixtures
|
# and load fixtures
|
||||||
bin/console doctrine:migrations:migrate
|
bin/console doctrine:migrations:migrate
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
|
|||||||
|
|
||||||
# mount into to container
|
# mount into to container
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
# and load fixtures
|
# and load fixtures (do not this for production)
|
||||||
bin/console doctrine:fixtures:load --purge-with-truncate
|
bin/console doctrine:fixtures:load --purge-with-truncate
|
||||||
|
|
||||||
There are several users available:
|
There are several users available:
|
||||||
@ -204,8 +205,10 @@ How to create the database schema (= run migrations) ?
|
|||||||
# if a container is running
|
# if a container is running
|
||||||
./docker-php.sh
|
./docker-php.sh
|
||||||
bin/console doctrine:migrations:migrate
|
bin/console doctrine:migrations:migrate
|
||||||
|
bin/console chill:db:sync-views
|
||||||
# if not
|
# if not
|
||||||
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
docker-compose run --user $(id -u) php bin/console doctrine:migrations:migrate
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:db:sync-views
|
||||||
|
|
||||||
|
|
||||||
How to read the email sent by the program ?
|
How to read the email sent by the program ?
|
||||||
@ -236,6 +239,23 @@ How to open a terminal in the project
|
|||||||
# if not
|
# if not
|
||||||
docker-compose run --user $(id -u) php /bin/bash
|
docker-compose run --user $(id -u) php /bin/bash
|
||||||
|
|
||||||
|
How to run cron-jobs ?
|
||||||
|
======================
|
||||||
|
|
||||||
|
Some command must be executed in :ref:`cron jobs <cronjob>`. To execute them:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# if a container is running
|
||||||
|
./docker-php.sh
|
||||||
|
bin/console chill:cron-job:execute
|
||||||
|
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||||
|
bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||||
|
# if not
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute
|
||||||
|
# some of them are executed only during the night. So, we have to force the execution during the day:
|
||||||
|
docker-compose run --user $(id -u) php bin/console chill:cron-job:execute 'name-of-the-cron'
|
||||||
|
|
||||||
How to run composer ?
|
How to run composer ?
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -38,6 +38,14 @@ This should be adapted to your needs:
|
|||||||
|
|
||||||
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
* Think about how you will backup your database. Some adminsys find easier to store database outside of docker, which might be easier to administrate or replicate.
|
||||||
|
|
||||||
|
Run migrations on each update
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Every time you start a new version, you should apply update the sql schema:
|
||||||
|
|
||||||
|
- running ``bin/console doctrine:migration:migrate`` to run sql migration;
|
||||||
|
- synchonizing sql views to the last state: ``bin/console chill:db:sync-views``
|
||||||
|
|
||||||
Cron jobs
|
Cron jobs
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
45
rector.php
45
rector.php
@ -12,14 +12,49 @@ return static function (RectorConfig $rectorConfig): void {
|
|||||||
__DIR__ . '/src',
|
__DIR__ . '/src',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
|
//$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
|
||||||
$rectorConfig->cacheDirectory(__DIR__.'/.cache/rector');
|
//$rectorConfig->cacheDirectory(__DIR__ . '/.cache/rector');
|
||||||
|
|
||||||
// register a single rule
|
// register a single rule
|
||||||
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
|
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
|
||||||
|
$rectorConfig->disableParallel();
|
||||||
|
|
||||||
//define sets of rules
|
//define sets of rules
|
||||||
// $rectorConfig->sets([
|
$rectorConfig->sets([
|
||||||
// LevelSetList::UP_TO_PHP_74
|
LevelSetList::UP_TO_PHP_74
|
||||||
// ]);
|
]);
|
||||||
|
|
||||||
|
// skip some path...
|
||||||
|
$rectorConfig->skip([
|
||||||
|
// make rector stuck for some files
|
||||||
|
\Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector::class,
|
||||||
|
|
||||||
|
// we need to discuss this: are we going to have FALSE in tests instead of an error ?
|
||||||
|
\Rector\Php71\Rector\FuncCall\CountOnNullRector::class,
|
||||||
|
|
||||||
|
// must merge MR500 and review a typing of "ArrayCollection" in entities
|
||||||
|
\Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector::class,
|
||||||
|
|
||||||
|
// remove all PHP80 rules, in order to activate them one by one
|
||||||
|
\Rector\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector::class,
|
||||||
|
\Rector\Php80\Rector\Class_\AnnotationToAttributeRector::class,
|
||||||
|
\Rector\Php80\Rector\Switch_\ChangeSwitchToMatchRector::class,
|
||||||
|
\Rector\Php80\Rector\FuncCall\ClassOnObjectRector::class,
|
||||||
|
\Rector\Php80\Rector\ClassConstFetch\ClassOnThisVariableObjectRector::class,
|
||||||
|
\Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector::class,
|
||||||
|
\Rector\Php80\Rector\Class_\DoctrineAnnotationClassToAttributeRector::class,
|
||||||
|
\Rector\Php80\Rector\ClassMethod\FinalPrivateToPrivateVisibilityRector::class,
|
||||||
|
\Rector\Php80\Rector\Ternary\GetDebugTypeRector::class,
|
||||||
|
\Rector\Php80\Rector\FunctionLike\MixedTypeRector::class,
|
||||||
|
\Rector\Php80\Rector\Property\NestedAnnotationToAttributeRector::class,
|
||||||
|
\Rector\Php80\Rector\FuncCall\Php8ResourceReturnToObjectRector::class,
|
||||||
|
\Rector\Php80\Rector\Catch_\RemoveUnusedVariableInCatchRector::class,
|
||||||
|
\Rector\Php80\Rector\ClassMethod\SetStateToStaticRector::class,
|
||||||
|
\Rector\Php80\Rector\NotIdentical\StrContainsRector::class,
|
||||||
|
\Rector\Php80\Rector\Identical\StrEndsWithRector::class,
|
||||||
|
\Rector\Php80\Rector\Identical\StrStartsWithRector::class,
|
||||||
|
\Rector\Php80\Rector\Class_\StringableForToStringRector::class,
|
||||||
|
\Rector\Php80\Rector\FuncCall\TokenGetAllToObjectRector::class,
|
||||||
|
\Rector\Php80\Rector\FunctionLike\UnionTypesRector::class
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
@ -50,7 +50,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
->findAll();
|
->findAll();
|
||||||
|
|
||||||
foreach ($persons as $person) {
|
foreach ($persons as $person) {
|
||||||
$activityNbr = mt_rand(0, 3);
|
$activityNbr = random_int(0, 3);
|
||||||
|
|
||||||
for ($i = 0; $i < $activityNbr; ++$i) {
|
for ($i = 0; $i < $activityNbr; ++$i) {
|
||||||
$activity = $this->newRandomActivity($person);
|
$activity = $this->newRandomActivity($person);
|
||||||
@ -75,7 +75,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
|
|
||||||
// ->setAttendee($this->faker->boolean())
|
// ->setAttendee($this->faker->boolean())
|
||||||
|
|
||||||
for ($i = 0; mt_rand(0, 4) > $i; ++$i) {
|
for ($i = 0; random_int(0, 4) > $i; ++$i) {
|
||||||
$reason = $this->getRandomActivityReason();
|
$reason = $this->getRandomActivityReason();
|
||||||
|
|
||||||
if (null !== $reason) {
|
if (null !== $reason) {
|
||||||
|
@ -26,7 +26,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_activity');
|
$treeBuilder = new TreeBuilder('chill_activity');
|
||||||
$rootNode = $treeBuilder->getRootNode('chill_activity');
|
$rootNode = $treeBuilder->getRootNode();
|
||||||
|
|
||||||
$rootNode
|
$rootNode
|
||||||
->children()
|
->children()
|
||||||
@ -59,9 +59,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
->info('The number of seconds of this duration. Must be an integer.')
|
->info('The number of seconds of this duration. Must be an integer.')
|
||||||
->cannotBeEmpty()
|
->cannotBeEmpty()
|
||||||
->validate()
|
->validate()
|
||||||
->ifTrue(static function ($data) {
|
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
|
||||||
return !is_int($data);
|
|
||||||
})->thenInvalid('The value %s is not a valid integer')
|
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->scalarNode('label')
|
->scalarNode('label')
|
||||||
|
@ -195,7 +195,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
|||||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||||
* @Groups({"docgen:read"})
|
* @Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private ?User $user;
|
private ?User $user = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
|
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
|
||||||
|
@ -34,7 +34,7 @@ class ActivityPresence
|
|||||||
* @ORM\GeneratedValue(strategy="AUTO")
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
* @Serializer\Groups({"docgen:read"})
|
* @Serializer\Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private ?int $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="json")
|
* @ORM\Column(type="json")
|
||||||
|
@ -122,7 +122,7 @@ class ActivityType
|
|||||||
* @ORM\GeneratedValue(strategy="AUTO")
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
* @Groups({"docgen:read"})
|
* @Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private ?int $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
||||||
|
@ -86,9 +86,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->repository->createQueryBuilder('activity');
|
$qb = $this->repository->createQueryBuilder('activity');
|
||||||
|
|
||||||
|
@ -87,9 +87,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->repository->createQueryBuilder('activity');
|
$qb = $this->repository->createQueryBuilder('activity');
|
||||||
|
|
||||||
|
@ -86,9 +86,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->repository
|
$qb = $this->repository
|
||||||
->createQueryBuilder('activity')
|
->createQueryBuilder('activity')
|
||||||
|
@ -109,9 +109,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
$qb = $this->entityManager->createQueryBuilder();
|
||||||
|
|
||||||
|
@ -87,9 +87,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->repository
|
$qb = $this->repository
|
||||||
->createQueryBuilder('activity')
|
->createQueryBuilder('activity')
|
||||||
|
@ -87,9 +87,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->repository
|
$qb = $this->repository
|
||||||
->createQueryBuilder('activity')
|
->createQueryBuilder('activity')
|
||||||
|
@ -137,13 +137,11 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
$activity = $activityRepository->find($value);
|
$activity = $activityRepository->find($value);
|
||||||
|
|
||||||
return implode(', ', array_map(function (ActivityReason $r) {
|
return implode(', ', array_map(fn (ActivityReason $r) => '"' .
|
||||||
return '"' .
|
|
||||||
$this->translatableStringHelper->localize($r->getCategory()->getName())
|
$this->translatableStringHelper->localize($r->getCategory()->getName())
|
||||||
. ' > ' .
|
. ' > ' .
|
||||||
$this->translatableStringHelper->localize($r->getName())
|
$this->translatableStringHelper->localize($r->getName())
|
||||||
. '"';
|
. '"', $activity->getReasons()->toArray()));
|
||||||
}, $activity->getReasons()->toArray()));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'circle_name':
|
case 'circle_name':
|
||||||
@ -152,7 +150,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
return 'circle';
|
return 'circle';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize(json_decode($value, true));
|
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'type_name':
|
case 'type_name':
|
||||||
@ -161,7 +159,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
return 'activity type';
|
return 'activity type';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->translatableStringHelper->localize(json_decode($value, true));
|
return $this->translatableStringHelper->localize(json_decode($value, true, 512, JSON_THROW_ON_ERROR));
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -197,9 +195,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
|
|||||||
|
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
// throw an error if any fields are present
|
// throw an error if any fields are present
|
||||||
if (!array_key_exists('fields', $data)) {
|
if (!array_key_exists('fields', $data)) {
|
||||||
|
@ -179,7 +179,7 @@ class ListActivityHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$decoded = json_decode($value);
|
$decoded = json_decode($value, null, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
return implode(
|
return implode(
|
||||||
'|',
|
'|',
|
||||||
|
@ -61,12 +61,9 @@ class ActivityTypeFilter implements FilterInterface
|
|||||||
$builder->add('accepted_activitytypes', EntityType::class, [
|
$builder->add('accepted_activitytypes', EntityType::class, [
|
||||||
'class' => ActivityType::class,
|
'class' => ActivityType::class,
|
||||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||||
'choice_label' => function (ActivityType $aty) {
|
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||||
return
|
|
||||||
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
|
||||||
.
|
.
|
||||||
$this->translatableStringHelper->localize($aty->getName());
|
$this->translatableStringHelper->localize($aty->getName()),
|
||||||
},
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -64,11 +64,9 @@ class UserScopeFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
$builder->add('accepted_userscope', EntityType::class, [
|
$builder->add('accepted_userscope', EntityType::class, [
|
||||||
'class' => Scope::class,
|
'class' => Scope::class,
|
||||||
'choice_label' => function (Scope $s) {
|
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
|
||||||
return $this->translatableStringHelper->localize(
|
|
||||||
$s->getName()
|
$s->getName()
|
||||||
);
|
),
|
||||||
},
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -61,12 +61,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
|
|||||||
$builder->add('types', EntityType::class, [
|
$builder->add('types', EntityType::class, [
|
||||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||||
'class' => ActivityType::class,
|
'class' => ActivityType::class,
|
||||||
'choice_label' => function (ActivityType $aty) {
|
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
||||||
return
|
|
||||||
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
|
|
||||||
.
|
.
|
||||||
$this->translatableStringHelper->localize($aty->getName());
|
$this->translatableStringHelper->localize($aty->getName()),
|
||||||
},
|
|
||||||
'group_by' => function (ActivityType $type) {
|
'group_by' => function (ActivityType $type) {
|
||||||
if (!$type->hasCategory()) {
|
if (!$type->hasCategory()) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -32,7 +32,7 @@ class ActivityReasonCategoryType extends AbstractType
|
|||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory',
|
'data_class' => \Chill\ActivityBundle\Entity\ActivityReasonCategory::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,13 +211,9 @@ class ActivityType extends AbstractType
|
|||||||
'required' => $activityType->isRequired('attendee'),
|
'required' => $activityType->isRequired('attendee'),
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
'class' => ActivityPresence::class,
|
'class' => ActivityPresence::class,
|
||||||
'choice_label' => function (ActivityPresence $activityPresence) {
|
'choice_label' => fn (ActivityPresence $activityPresence) => $this->translatableStringHelper->localize($activityPresence->getName()),
|
||||||
return $this->translatableStringHelper->localize($activityPresence->getName());
|
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('a')
|
||||||
},
|
->where('a.active = true'),
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
|
||||||
return $er->createQueryBuilder('a')
|
|
||||||
->where('a.active = true');
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,9 +353,7 @@ class ActivityType extends AbstractType
|
|||||||
|
|
||||||
return (string) $location->getId();
|
return (string) $location->getId();
|
||||||
},
|
},
|
||||||
function (?string $id): ?Location {
|
fn (?string $id): ?Location => $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id])
|
||||||
return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]);
|
|
||||||
}
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,9 +395,7 @@ class ActivityType extends AbstractType
|
|||||||
// the datetimetransformer will then handle timezone as GMT
|
// the datetimetransformer will then handle timezone as GMT
|
||||||
$timezoneUTC = new DateTimeZone('GMT');
|
$timezoneUTC = new DateTimeZone('GMT');
|
||||||
/** @var DateTime $data */
|
/** @var DateTime $data */
|
||||||
$data = $formEvent->getData() === null ?
|
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
|
||||||
DateTime::createFromFormat('U', '300') :
|
|
||||||
$formEvent->getData();
|
|
||||||
$seconds = $data->getTimezone()->getOffset($data);
|
$seconds = $data->getTimezone()->getOffset($data);
|
||||||
$data->setTimeZone($timezoneUTC);
|
$data->setTimeZone($timezoneUTC);
|
||||||
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
||||||
|
@ -45,9 +45,7 @@ class ActivityTypeType extends AbstractType
|
|||||||
])
|
])
|
||||||
->add('category', EntityType::class, [
|
->add('category', EntityType::class, [
|
||||||
'class' => ActivityTypeCategory::class,
|
'class' => ActivityTypeCategory::class,
|
||||||
'choice_label' => function (ActivityTypeCategory $activityTypeCategory) {
|
'choice_label' => fn (ActivityTypeCategory $activityTypeCategory) => $this->translatableStringHelper->localize($activityTypeCategory->getName()),
|
||||||
return $this->translatableStringHelper->localize($activityTypeCategory->getName());
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
->add('ordering', NumberType::class, [
|
->add('ordering', NumberType::class, [
|
||||||
'required' => true,
|
'required' => true,
|
||||||
|
@ -45,9 +45,7 @@ class PickActivityReasonType extends AbstractType
|
|||||||
$resolver->setDefaults(
|
$resolver->setDefaults(
|
||||||
[
|
[
|
||||||
'class' => ActivityReason::class,
|
'class' => ActivityReason::class,
|
||||||
'choice_label' => function (ActivityReason $choice) {
|
'choice_label' => fn (ActivityReason $choice) => $this->reasonRender->renderString($choice, []),
|
||||||
return $this->reasonRender->renderString($choice, []);
|
|
||||||
},
|
|
||||||
'group_by' => function (ActivityReason $choice): ?string {
|
'group_by' => function (ActivityReason $choice): ?string {
|
||||||
if (null !== $category = $choice->getCategory()) {
|
if (null !== $category = $choice->getCategory()) {
|
||||||
return $this->translatableStringHelper->localize($category->getName());
|
return $this->translatableStringHelper->localize($category->getName());
|
||||||
|
@ -38,10 +38,8 @@ class TranslatableActivityReasonCategoryType extends AbstractType
|
|||||||
$resolver->setDefaults(
|
$resolver->setDefaults(
|
||||||
[
|
[
|
||||||
'class' => ActivityReasonCategory::class,
|
'class' => ActivityReasonCategory::class,
|
||||||
'choice_label' => function (ActivityReasonCategory $category) {
|
'choice_label' => fn (ActivityReasonCategory $category) => $this->translatableStringHelper->localize($category->getName())
|
||||||
return $this->translatableStringHelper->localize($category->getName())
|
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : ''),
|
||||||
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : '');
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,7 @@ class TranslatableActivityType extends AbstractType
|
|||||||
'class' => ActivityType::class,
|
'class' => ActivityType::class,
|
||||||
'active_only' => true,
|
'active_only' => true,
|
||||||
'choices' => $this->activityTypeRepository->findAllActive(),
|
'choices' => $this->activityTypeRepository->findAllActive(),
|
||||||
'choice_label' => function (ActivityType $type) {
|
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
|
||||||
return $this->translatableStringHelper->localize($type->getName());
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -254,9 +254,7 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte
|
|||||||
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), ActivityVoter::SEE, $center);
|
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), ActivityVoter::SEE, $center);
|
||||||
// we get the ids for those scopes
|
// we get the ids for those scopes
|
||||||
$reachablesScopesId = array_map(
|
$reachablesScopesId = array_map(
|
||||||
static function (Scope $scope) {
|
static fn (Scope $scope) => $scope->getId(),
|
||||||
return $scope->getId();
|
|
||||||
},
|
|
||||||
$reachableScopes
|
$reachableScopes
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -134,9 +134,7 @@ class ActivityContext implements
|
|||||||
$builder->add($key, EntityType::class, [
|
$builder->add($key, EntityType::class, [
|
||||||
'class' => Person::class,
|
'class' => Person::class,
|
||||||
'choices' => $persons,
|
'choices' => $persons,
|
||||||
'choice_label' => function (Person $p) {
|
'choice_label' => fn (Person $p) => $this->personRender->renderString($p, []),
|
||||||
return $this->personRender->renderString($p, []);
|
|
||||||
},
|
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
|
@ -145,9 +145,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
|
|||||||
return array_filter(
|
return array_filter(
|
||||||
$activities,
|
$activities,
|
||||||
function ($activity) use ($user) {
|
function ($activity) use ($user) {
|
||||||
$activityUsernames = array_map(static function ($user) {
|
$activityUsernames = array_map(static fn ($user) => $user['username'], $activity['users'] ?? []);
|
||||||
return $user['username'];
|
|
||||||
}, $activity['users'] ?? []);
|
|
||||||
return in_array($user->getUsername(), $activityUsernames, true);
|
return in_array($user->getUsername(), $activityUsernames, true);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -158,9 +156,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
|
|||||||
return array_filter(
|
return array_filter(
|
||||||
$works,
|
$works,
|
||||||
function ($work) use ($user) {
|
function ($work) use ($user) {
|
||||||
$workUsernames = array_map(static function ($user) {
|
$workUsernames = array_map(static fn ($user) => $user['username'], $work['referrers'] ?? []);
|
||||||
return $user['username'];
|
|
||||||
}, $work['referrers'] ?? []);
|
|
||||||
|
|
||||||
return in_array($user->getUsername(), $workUsernames, true);
|
return in_array($user->getUsername(), $workUsernames, true);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Service\EntityInfo\AccompanyingPeriodInfoQueryPart;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\PersonBundle\Service\EntityInfo\AccompanyingPeriodInfoUnionQueryPartInterface;
|
||||||
|
|
||||||
|
class ActivityUsersDateQueryPartForAccompanyingPeriodInfo implements AccompanyingPeriodInfoUnionQueryPartInterface
|
||||||
|
{
|
||||||
|
public function getAccompanyingPeriodIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.accompanyingperiod_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityColumn(): string
|
||||||
|
{
|
||||||
|
return Activity::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelatedEntityIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdColumn(): string
|
||||||
|
{
|
||||||
|
return 'au.user_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateTimeColumn(): string
|
||||||
|
{
|
||||||
|
return 'activity.date';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDiscriminator(): string
|
||||||
|
{
|
||||||
|
return 'activity_date';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadataColumn(): string
|
||||||
|
{
|
||||||
|
return '\'{}\'::jsonb';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStatement(): string
|
||||||
|
{
|
||||||
|
return 'activity
|
||||||
|
LEFT JOIN activity_user au on activity.id = au.activity_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWhereClause(): string
|
||||||
|
{
|
||||||
|
return 'activity.accompanyingperiod_id IS NOT NULL';
|
||||||
|
}
|
||||||
|
}
|
@ -369,12 +369,8 @@ final class ActivityControllerTest extends WebTestCase
|
|||||||
$center
|
$center
|
||||||
);
|
);
|
||||||
$reachableScopesId = array_intersect(
|
$reachableScopesId = array_intersect(
|
||||||
array_map(static function ($s) {
|
array_map(static fn ($s) => $s->getId(), $reachableScopesDelete),
|
||||||
return $s->getId();
|
array_map(static fn ($s) => $s->getId(), $reachableScopesUpdate)
|
||||||
}, $reachableScopesDelete),
|
|
||||||
array_map(static function ($s) {
|
|
||||||
return $s->getId();
|
|
||||||
}, $reachableScopesUpdate)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (count($reachableScopesId) === 0) {
|
if (count($reachableScopesId) === 0) {
|
||||||
|
@ -188,9 +188,7 @@ final class ActivityTypeTest extends KernelTestCase
|
|||||||
|
|
||||||
// map all the values in an array
|
// map all the values in an array
|
||||||
$values = array_map(
|
$values = array_map(
|
||||||
static function ($choice) {
|
static fn ($choice) => $choice->value,
|
||||||
return $choice->value;
|
|
||||||
},
|
|
||||||
$view['activity']['durationTime']->vars['choices']
|
$view['activity']['durationTime']->vars['choices']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -79,15 +79,13 @@ final class TranslatableActivityReasonTest extends TypeTestCase
|
|||||||
$request = $prophet->prophesize();
|
$request = $prophet->prophesize();
|
||||||
$translator = $prophet->prophesize();
|
$translator = $prophet->prophesize();
|
||||||
|
|
||||||
$request->willExtend('Symfony\Component\HttpFoundation\Request');
|
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||||
$request->getLocale()->willReturn($fallbackLocale);
|
$request->getLocale()->willReturn($fallbackLocale);
|
||||||
|
|
||||||
$requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack');
|
$requestStack->willExtend(\Symfony\Component\HttpFoundation\RequestStack::class);
|
||||||
$requestStack->getCurrentRequest()->will(static function () use ($request) {
|
$requestStack->getCurrentRequest()->will(static fn () => $request);
|
||||||
return $request;
|
|
||||||
});
|
|
||||||
|
|
||||||
$translator->willExtend('Symfony\Component\Translation\Translator');
|
$translator->willExtend(\Symfony\Component\Translation\Translator::class);
|
||||||
$translator->getFallbackLocales()->willReturn($locale);
|
$translator->getFallbackLocales()->willReturn($locale);
|
||||||
|
|
||||||
return new TranslatableStringHelper(
|
return new TranslatableStringHelper(
|
||||||
|
@ -160,7 +160,7 @@ final class ActivityVoterTest extends KernelTestCase
|
|||||||
{
|
{
|
||||||
$token = $this->prophet->prophesize();
|
$token = $this->prophet->prophesize();
|
||||||
$token
|
$token
|
||||||
->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
->willImplement('\\' . \Symfony\Component\Security\Core\Authentication\Token\TokenInterface::class);
|
||||||
|
|
||||||
if (null === $user) {
|
if (null === $user) {
|
||||||
$token->getUser()->willReturn(null);
|
$token->getUser()->willReturn(null);
|
||||||
|
@ -34,6 +34,7 @@ services:
|
|||||||
resource: '../Validator/Constraints/'
|
resource: '../Validator/Constraints/'
|
||||||
|
|
||||||
Chill\ActivityBundle\Service\DocGenerator\:
|
Chill\ActivityBundle\Service\DocGenerator\:
|
||||||
autowire: true
|
|
||||||
autoconfigure: true
|
|
||||||
resource: '../Service/DocGenerator/'
|
resource: '../Service/DocGenerator/'
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Service\EntityInfo\:
|
||||||
|
resource: '../Service/EntityInfo/'
|
||||||
|
@ -22,7 +22,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_aside_activity');
|
$treeBuilder = new TreeBuilder('chill_aside_activity');
|
||||||
|
|
||||||
$treeBuilder->getRootNode('chill_aside_activity')
|
$treeBuilder->getRootNode()
|
||||||
->children()
|
->children()
|
||||||
->arrayNode('form')
|
->arrayNode('form')
|
||||||
->canBeEnabled()
|
->canBeEnabled()
|
||||||
@ -132,9 +132,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
->info('The number of seconds of this duration. Must be an integer.')
|
->info('The number of seconds of this duration. Must be an integer.')
|
||||||
->cannotBeEmpty()
|
->cannotBeEmpty()
|
||||||
->validate()
|
->validate()
|
||||||
->ifTrue(static function ($data) {
|
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
|
||||||
return !is_int($data);
|
|
||||||
})->thenInvalid('The value %s is not a valid integer')
|
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->scalarNode('label')
|
->scalarNode('label')
|
||||||
|
@ -57,7 +57,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
*/
|
*/
|
||||||
private ?int $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=100, nullable=true)
|
* @ORM\Column(type="string", length=100, nullable=true)
|
||||||
|
@ -59,9 +59,7 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface
|
|||||||
$labels = array_combine($values, $values);
|
$labels = array_combine($values, $values);
|
||||||
$labels['_header'] = $this->getTitle();
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
return static function ($value) use ($labels) {
|
return static fn ($value) => $labels[$value];
|
||||||
return $labels[$value];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryKeys($data): array
|
public function getQueryKeys($data): array
|
||||||
|
@ -95,9 +95,7 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
// the datetimetransformer will then handle timezone as GMT
|
// the datetimetransformer will then handle timezone as GMT
|
||||||
$timezoneUTC = new DateTimeZone('GMT');
|
$timezoneUTC = new DateTimeZone('GMT');
|
||||||
/** @var DateTimeImmutable $data */
|
/** @var DateTimeImmutable $data */
|
||||||
$data = $formEvent->getData() === null ?
|
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
|
||||||
DateTime::createFromFormat('U', '300') :
|
|
||||||
$formEvent->getData();
|
|
||||||
$seconds = $data->getTimezone()->getOffset($data);
|
$seconds = $data->getTimezone()->getOffset($data);
|
||||||
$data->setTimeZone($timezoneUTC);
|
$data->setTimeZone($timezoneUTC);
|
||||||
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
$data->add(new DateInterval('PT' . $seconds . 'S'));
|
||||||
|
@ -116,7 +116,7 @@ abstract class AbstractElementController extends AbstractController
|
|||||||
$indexPage = 'chill_budget_elements_household_index';
|
$indexPage = 'chill_budget_elements_household_index';
|
||||||
}
|
}
|
||||||
|
|
||||||
$entity = null !== $element->getPerson() ? $element->getPerson() : $element->getHousehold();
|
$entity = $element->getPerson() ?? $element->getHousehold();
|
||||||
|
|
||||||
$form = $this->createForm($this->getType(), $element);
|
$form = $this->createForm($this->getType(), $element);
|
||||||
$form->add('submit', SubmitType::class);
|
$form->add('submit', SubmitType::class);
|
||||||
|
@ -19,7 +19,7 @@ class CalculatorCompilerPass implements CompilerPassInterface
|
|||||||
{
|
{
|
||||||
public function process(ContainerBuilder $container)
|
public function process(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$manager = $container->getDefinition('Chill\BudgetBundle\Calculator\CalculatorManager');
|
$manager = $container->getDefinition(\Chill\BudgetBundle\Calculator\CalculatorManager::class);
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) {
|
foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) {
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
|
@ -19,7 +19,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_budget');
|
$treeBuilder = new TreeBuilder('chill_budget');
|
||||||
$rootNode = $treeBuilder->getRootNode('chill_budget');
|
$rootNode = $treeBuilder->getRootNode();
|
||||||
|
|
||||||
$rootNode
|
$rootNode
|
||||||
->children()
|
->children()
|
||||||
|
@ -41,7 +41,7 @@ abstract class AbstractElement
|
|||||||
/**
|
/**
|
||||||
* @ORM\Column(name="comment", type="text", nullable=true)
|
* @ORM\Column(name="comment", type="text", nullable=true)
|
||||||
*/
|
*/
|
||||||
private ?string $comment;
|
private ?string $comment = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="endDate", type="datetime_immutable", nullable=true)
|
* @ORM\Column(name="endDate", type="datetime_immutable", nullable=true)
|
||||||
@ -50,7 +50,7 @@ abstract class AbstractElement
|
|||||||
* message="The budget element's end date must be after the start date"
|
* message="The budget element's end date must be after the start date"
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private ?DateTimeImmutable $endDate;
|
private ?DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(
|
* @ORM\ManyToOne(
|
||||||
|
@ -52,9 +52,7 @@ class ChargeType extends AbstractType
|
|||||||
'label' => 'Charge type',
|
'label' => 'Charge type',
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'placeholder' => $this->translator->trans('admin.form.Choose the type of charge'),
|
'placeholder' => $this->translator->trans('admin.form.Choose the type of charge'),
|
||||||
'choice_label' => function (ChargeKind $resource) {
|
'choice_label' => fn (ChargeKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
|
||||||
return $this->translatableStringHelper->localize($resource->getName());
|
|
||||||
},
|
|
||||||
'attr' => ['class' => 'select2'],
|
'attr' => ['class' => 'select2'],
|
||||||
])
|
])
|
||||||
->add('amount', MoneyType::class)
|
->add('amount', MoneyType::class)
|
||||||
|
@ -51,9 +51,7 @@ class ResourceType extends AbstractType
|
|||||||
'label' => 'Resource type',
|
'label' => 'Resource type',
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'placeholder' => $this->translator->trans('admin.form.Choose the type of resource'),
|
'placeholder' => $this->translator->trans('admin.form.Choose the type of resource'),
|
||||||
'choice_label' => function (ResourceKind $resource) {
|
'choice_label' => fn (ResourceKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
|
||||||
return $this->translatableStringHelper->localize($resource->getName());
|
|
||||||
},
|
|
||||||
'attr' => ['class' => 'select2'],
|
'attr' => ['class' => 'select2'],
|
||||||
])
|
])
|
||||||
->add('amount', MoneyType::class)
|
->add('amount', MoneyType::class)
|
||||||
|
@ -16,8 +16,14 @@
|
|||||||
<td class="el-type">
|
<td class="el-type">
|
||||||
{% if f.isResource %}
|
{% if f.isResource %}
|
||||||
{{ f.resource.name|localize_translatable_string }}
|
{{ f.resource.name|localize_translatable_string }}
|
||||||
|
{% if f.resource.getKind is same as 'other' %}
|
||||||
|
: {{ f.getComment }}
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ f.charge.name|localize_translatable_string }}
|
{{ f.charge.name|localize_translatable_string }}
|
||||||
|
{% if f.charge.getKind is same as 'other' %}
|
||||||
|
: {{ f.getComment }}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ f.amount|format_currency('EUR') }}</td>
|
<td>{{ f.amount|format_currency('EUR') }}</td>
|
||||||
|
@ -66,9 +66,7 @@ final class SummaryBudget implements SummaryBudgetInterface
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$personIds = $household->getCurrentPersons()->map(static function (Person $p) {
|
$personIds = $household->getCurrentPersons()->map(static fn (Person $p) => $p->getId());
|
||||||
return $p->getId();
|
|
||||||
});
|
|
||||||
$ids = implode(', ', array_fill(0, count($personIds), '?'));
|
$ids = implode(', ', array_fill(0, count($personIds), '?'));
|
||||||
|
|
||||||
$parameters = [...$personIds, $household->getId()];
|
$parameters = [...$personIds, $household->getId()];
|
||||||
@ -127,18 +125,14 @@ final class SummaryBudget implements SummaryBudgetInterface
|
|||||||
{
|
{
|
||||||
$keys = array_map(static fn (ChargeKind $kind) => $kind->getKind(), $this->chargeKindRepository->findAll());
|
$keys = array_map(static fn (ChargeKind $kind) => $kind->getKind(), $this->chargeKindRepository->findAll());
|
||||||
|
|
||||||
return array_combine($keys, array_map(function ($kind) {
|
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
||||||
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
|
|
||||||
}, $keys));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getEmptyResourceArray(): array
|
private function getEmptyResourceArray(): array
|
||||||
{
|
{
|
||||||
$keys = array_map(static fn (ResourceKind $kind) => $kind->getKind(), $this->resourceKindRepository->findAll());
|
$keys = array_map(static fn (ResourceKind $kind) => $kind->getKind(), $this->resourceKindRepository->findAll());
|
||||||
|
|
||||||
return array_combine($keys, array_map(function ($kind) {
|
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
|
||||||
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
|
|
||||||
}, $keys));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function rowToArray(array $rows, string $kind): array
|
private function rowToArray(array $rows, string $kind): array
|
||||||
|
@ -50,9 +50,7 @@ final class SummaryBudgetTest extends TestCase
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$queryCharges->setParameters(Argument::type('array'))
|
$queryCharges->setParameters(Argument::type('array'))
|
||||||
->will(static function ($args, $query) {
|
->will(static fn ($args, $query) => $query);
|
||||||
return $query;
|
|
||||||
});
|
|
||||||
|
|
||||||
$queryResources = $this->prophesize(AbstractQuery::class);
|
$queryResources = $this->prophesize(AbstractQuery::class);
|
||||||
$queryResources->getResult()->willReturn([
|
$queryResources->getResult()->willReturn([
|
||||||
@ -63,9 +61,7 @@ final class SummaryBudgetTest extends TestCase
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$queryResources->setParameters(Argument::type('array'))
|
$queryResources->setParameters(Argument::type('array'))
|
||||||
->will(static function ($args, $query) {
|
->will(static fn ($args, $query) => $query);
|
||||||
return $query;
|
|
||||||
});
|
|
||||||
|
|
||||||
$em = $this->prophesize(EntityManagerInterface::class);
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
$em->createNativeQuery(Argument::type('string'), Argument::type(Query\ResultSetMapping::class))
|
$em->createNativeQuery(Argument::type('string'), Argument::type(Query\ResultSetMapping::class))
|
||||||
@ -100,9 +96,7 @@ final class SummaryBudgetTest extends TestCase
|
|||||||
$resourceRepository->findOneByKind('misc')->willReturn($misc);
|
$resourceRepository->findOneByKind('misc')->willReturn($misc);
|
||||||
|
|
||||||
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
||||||
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($arg) {
|
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($arg) => $arg[0]['fr']);
|
||||||
return $arg[0]['fr'];
|
|
||||||
});
|
|
||||||
|
|
||||||
$person = new Person();
|
$person = new Person();
|
||||||
$personReflection = new ReflectionClass($person);
|
$personReflection = new ReflectionClass($person);
|
||||||
|
@ -60,7 +60,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
|
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
public function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$this->logger->info(__CLASS__ . ' execute command');
|
$this->logger->info(self::class . ' execute command');
|
||||||
|
|
||||||
$limit = 50;
|
$limit = 50;
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
@ -71,7 +71,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
$created = 0;
|
$created = 0;
|
||||||
$renewed = 0;
|
$renewed = 0;
|
||||||
|
|
||||||
$this->logger->info(__CLASS__ . ' the number of user to get - renew', [
|
$this->logger->info(self::class . ' the number of user to get - renew', [
|
||||||
'total' => $total,
|
'total' => $total,
|
||||||
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
|
||||||
]);
|
]);
|
||||||
@ -92,7 +92,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
// we first try to renew an existing subscription, if any.
|
// we first try to renew an existing subscription, if any.
|
||||||
// if not, or if it fails, we try to create a new one
|
// if not, or if it fails, we try to create a new one
|
||||||
if ($this->mapCalendarToUser->hasActiveSubscription($user)) {
|
if ($this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||||
$this->logger->debug(__CLASS__ . ' renew a subscription for', [
|
$this->logger->debug(self::class . ' renew a subscription for', [
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'username' => $user->getUsernameCanonical(),
|
'username' => $user->getUsernameCanonical(),
|
||||||
]);
|
]);
|
||||||
@ -104,7 +104,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
if (0 !== $expirationTs) {
|
if (0 !== $expirationTs) {
|
||||||
++$renewed;
|
++$renewed;
|
||||||
} else {
|
} else {
|
||||||
$this->logger->warning(__CLASS__ . ' could not renew subscription for a user', [
|
$this->logger->warning(self::class . ' could not renew subscription for a user', [
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'username' => $user->getUsernameCanonical(),
|
'username' => $user->getUsernameCanonical(),
|
||||||
]);
|
]);
|
||||||
@ -112,7 +112,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
if (!$this->mapCalendarToUser->hasActiveSubscription($user)) {
|
||||||
$this->logger->debug(__CLASS__ . ' create a subscription for', [
|
$this->logger->debug(self::class . ' create a subscription for', [
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'username' => $user->getUsernameCanonical(),
|
'username' => $user->getUsernameCanonical(),
|
||||||
]);
|
]);
|
||||||
@ -124,7 +124,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
if (0 !== $expirationTs) {
|
if (0 !== $expirationTs) {
|
||||||
++$created;
|
++$created;
|
||||||
} else {
|
} else {
|
||||||
$this->logger->warning(__CLASS__ . ' could not create subscription for a user', [
|
$this->logger->warning(self::class . ' could not create subscription for a user', [
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'username' => $user->getUsernameCanonical(),
|
'username' => $user->getUsernameCanonical(),
|
||||||
]);
|
]);
|
||||||
@ -139,7 +139,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
|
|||||||
$this->em->clear();
|
$this->em->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->warning(__CLASS__ . ' process executed', [
|
$this->logger->warning(self::class . ' process executed', [
|
||||||
'created' => $created,
|
'created' => $created,
|
||||||
'renewed' => $renewed,
|
'renewed' => $renewed,
|
||||||
]);
|
]);
|
||||||
|
@ -24,7 +24,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_calendar');
|
$treeBuilder = new TreeBuilder('chill_calendar');
|
||||||
$rootNode = $treeBuilder->getRootNode('chill_calendar');
|
$rootNode = $treeBuilder->getRootNode();
|
||||||
|
|
||||||
$rootNode
|
$rootNode
|
||||||
->children()
|
->children()
|
||||||
|
@ -514,9 +514,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
|||||||
*/
|
*/
|
||||||
public function getUsers(): ReadableCollection
|
public function getUsers(): ReadableCollection
|
||||||
{
|
{
|
||||||
return $this->getInvites()->map(static function (Invite $i) {
|
return $this->getInvites()->map(static fn (Invite $i) => $i->getUser());
|
||||||
return $i->getUser();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasCalendarRange(): bool
|
public function hasCalendarRange(): bool
|
||||||
@ -601,9 +599,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
|||||||
}
|
}
|
||||||
|
|
||||||
$invite = $this->invites
|
$invite = $this->invites
|
||||||
->filter(static function (Invite $invite) use ($user) {
|
->filter(static fn (Invite $invite) => $invite->getUser() === $user)
|
||||||
return $invite->getUser() === $user;
|
|
||||||
})
|
|
||||||
->first();
|
->first();
|
||||||
$this->removeInvite($invite);
|
$this->removeInvite($invite);
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @Groups({"read", "write", "calendar:read"})
|
* @Groups({"read", "write", "calendar:read"})
|
||||||
* @Assert\NotNull
|
* @Assert\NotNull
|
||||||
*/
|
*/
|
||||||
private ?Location $location;
|
private ?Location $location = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime_immutable", nullable=false)
|
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||||
|
@ -61,9 +61,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
|||||||
$labels = array_combine($values, $values);
|
$labels = array_combine($values, $values);
|
||||||
$labels['_header'] = $this->getTitle();
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
return static function ($value) use ($labels) {
|
return static fn ($value) => $labels[$value];
|
||||||
return $labels[$value];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryKeys($data): array
|
public function getQueryKeys($data): array
|
||||||
@ -91,9 +89,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
|||||||
*/
|
*/
|
||||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||||
{
|
{
|
||||||
$centers = array_map(static function ($el) {
|
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||||
return $el['center'];
|
|
||||||
}, $acl);
|
|
||||||
|
|
||||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||||
|
|
||||||
|
@ -61,9 +61,7 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
|
|||||||
$labels = array_combine($values, $values);
|
$labels = array_combine($values, $values);
|
||||||
$labels['_header'] = $this->getTitle();
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
return static function ($value) use ($labels) {
|
return static fn ($value) => $labels[$value];
|
||||||
return $labels[$value];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryKeys($data): array
|
public function getQueryKeys($data): array
|
||||||
|
@ -61,9 +61,7 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
|
|||||||
$labels = array_combine($values, $values);
|
$labels = array_combine($values, $values);
|
||||||
$labels['_header'] = $this->getTitle();
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
return static function ($value) use ($labels) {
|
return static fn ($value) => $labels[$value];
|
||||||
return $labels[$value];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getQueryKeys($data): array
|
public function getQueryKeys($data): array
|
||||||
|
@ -58,9 +58,7 @@ class AgentFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
$builder->add('accepted_agents', EntityType::class, [
|
$builder->add('accepted_agents', EntityType::class, [
|
||||||
'class' => User::class,
|
'class' => User::class,
|
||||||
'choice_label' => function (User $u) {
|
'choice_label' => fn (User $u) => $this->userRender->renderString($u, []),
|
||||||
return $this->userRender->renderString($u, []);
|
|
||||||
},
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -69,11 +69,9 @@ class JobFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
$builder->add('job', EntityType::class, [
|
$builder->add('job', EntityType::class, [
|
||||||
'class' => UserJob::class,
|
'class' => UserJob::class,
|
||||||
'choice_label' => function (UserJob $j) {
|
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize(
|
||||||
return $this->translatableStringHelper->localize(
|
|
||||||
$j->getLabel()
|
$j->getLabel()
|
||||||
);
|
),
|
||||||
},
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -69,11 +69,9 @@ class ScopeFilter implements FilterInterface
|
|||||||
{
|
{
|
||||||
$builder->add('scope', EntityType::class, [
|
$builder->add('scope', EntityType::class, [
|
||||||
'class' => Scope::class,
|
'class' => Scope::class,
|
||||||
'choice_label' => function (Scope $s) {
|
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
|
||||||
return $this->translatableStringHelper->localize(
|
|
||||||
$s->getName()
|
$s->getName()
|
||||||
);
|
),
|
||||||
},
|
|
||||||
'multiple' => true,
|
'multiple' => true,
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]);
|
]);
|
||||||
|
@ -89,14 +89,10 @@ class CalendarToRemoteHandler implements MessageHandlerInterface
|
|||||||
|
|
||||||
$newInvites = array_filter(
|
$newInvites = array_filter(
|
||||||
array_map(
|
array_map(
|
||||||
function ($id) {
|
fn ($id) => $this->inviteRepository->find($id),
|
||||||
return $this->inviteRepository->find($id);
|
|
||||||
},
|
|
||||||
$calendarMessage->getNewInvitesIds(),
|
$calendarMessage->getNewInvitesIds(),
|
||||||
),
|
),
|
||||||
static function (?Invite $invite) {
|
static fn (?Invite $invite) => null !== $invite
|
||||||
return null !== $invite;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->calendarConnector->syncCalendar(
|
$this->calendarConnector->syncCalendar(
|
||||||
|
@ -77,7 +77,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
|||||||
$user = $this->userRepository->find($changeNotificationMessage->getUserId());
|
$user = $this->userRepository->find($changeNotificationMessage->getUserId());
|
||||||
|
|
||||||
if (null === $user) {
|
if (null === $user) {
|
||||||
$this->logger->warning(__CLASS__ . ' notification concern non-existent user, skipping');
|
$this->logger->warning(self::class . ' notification concern non-existent user, skipping');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
|||||||
$secret = $this->mapCalendarToUser->getSubscriptionSecret($user);
|
$secret = $this->mapCalendarToUser->getSubscriptionSecret($user);
|
||||||
|
|
||||||
if ($secret !== ($notification['clientState'] ?? -1)) {
|
if ($secret !== ($notification['clientState'] ?? -1)) {
|
||||||
$this->logger->warning(__CLASS__ . ' could not validate secret, skipping');
|
$this->logger->warning(self::class . ' could not validate secret, skipping');
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
|
|||||||
$this->calendarSyncer->handleCalendarSync($calendar, $notification, $user);
|
$this->calendarSyncer->handleCalendarSync($calendar, $notification, $user);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
} else {
|
} else {
|
||||||
$this->logger->info(__CLASS__ . ' id not found in any calendar nor calendar range');
|
$this->logger->info(self::class . ' id not found in any calendar nor calendar range');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,14 +58,12 @@ class CalendarMessage
|
|||||||
$this->previousMainUserId = null !== $calendar->previousMainUser ?
|
$this->previousMainUserId = null !== $calendar->previousMainUser ?
|
||||||
$calendar->previousMainUser->getId() : null;
|
$calendar->previousMainUser->getId() : null;
|
||||||
$this->newInvitesIds = array_map(static fn (Invite $i) => $i->getId(), $calendar->newInvites);
|
$this->newInvitesIds = array_map(static fn (Invite $i) => $i->getId(), $calendar->newInvites);
|
||||||
$this->oldInvites = array_map(static function (Invite $i) {
|
$this->oldInvites = array_map(static fn (Invite $i) => [
|
||||||
return [
|
|
||||||
'inviteId' => $i->getId(),
|
'inviteId' => $i->getId(),
|
||||||
'userId' => $i->getUser()->getId(),
|
'userId' => $i->getUser()->getId(),
|
||||||
'userEmail' => $i->getUser()->getEmail(),
|
'userEmail' => $i->getUser()->getEmail(),
|
||||||
'userLabel' => $i->getUser()->getLabel(),
|
'userLabel' => $i->getUser()->getLabel(),
|
||||||
];
|
], $calendar->oldInvites);
|
||||||
}, $calendar->oldInvites);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAction(): string
|
public function getAction(): string
|
||||||
|
@ -121,9 +121,7 @@ class RemoteEventConverter
|
|||||||
'subject' => '[Chill] ' .
|
'subject' => '[Chill] ' .
|
||||||
implode(
|
implode(
|
||||||
', ',
|
', ',
|
||||||
$calendar->getPersons()->map(function (Person $p) {
|
$calendar->getPersons()->map(fn (Person $p) => $this->personRender->renderString($p, []))->toArray()
|
||||||
return $this->personRender->renderString($p, []);
|
|
||||||
})->toArray()
|
|
||||||
),
|
),
|
||||||
'start' => [
|
'start' => [
|
||||||
'dateTime' => $calendar->getStartDate()->setTimezone($this->remoteDateTimeZone)
|
'dateTime' => $calendar->getStartDate()->setTimezone($this->remoteDateTimeZone)
|
||||||
@ -161,9 +159,7 @@ class RemoteEventConverter
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'attendees' => $calendar->getInvites()->map(
|
'attendees' => $calendar->getInvites()->map(
|
||||||
function (Invite $i) {
|
fn (Invite $i) => $this->buildInviteToAttendee($i)
|
||||||
return $this->buildInviteToAttendee($i);
|
|
||||||
}
|
|
||||||
)->toArray(),
|
)->toArray(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ class CalendarRangeSyncer
|
|||||||
}
|
}
|
||||||
$calendarRange->preventEnqueueChanges = true;
|
$calendarRange->preventEnqueueChanges = true;
|
||||||
|
|
||||||
$this->logger->info(__CLASS__ . ' remove a calendar range because deleted on remote calendar');
|
$this->logger->info(self::class . ' remove a calendar range because deleted on remote calendar');
|
||||||
$this->em->remove($calendarRange);
|
$this->em->remove($calendarRange);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -71,7 +71,7 @@ class CalendarRangeSyncer
|
|||||||
$notification['resource']
|
$notification['resource']
|
||||||
)->toArray();
|
)->toArray();
|
||||||
} catch (ClientExceptionInterface $clientException) {
|
} catch (ClientExceptionInterface $clientException) {
|
||||||
$this->logger->warning(__CLASS__ . ' could not retrieve event from ms graph. Already deleted ?', [
|
$this->logger->warning(self::class . ' could not retrieve event from ms graph. Already deleted ?', [
|
||||||
'calendarRangeId' => $calendarRange->getId(),
|
'calendarRangeId' => $calendarRange->getId(),
|
||||||
'remoteEventId' => $notification['resource'],
|
'remoteEventId' => $notification['resource'],
|
||||||
]);
|
]);
|
||||||
@ -82,7 +82,7 @@ class CalendarRangeSyncer
|
|||||||
$lastModified = RemoteEventConverter::convertStringDateWithTimezone($new['lastModifiedDateTime']);
|
$lastModified = RemoteEventConverter::convertStringDateWithTimezone($new['lastModifiedDateTime']);
|
||||||
|
|
||||||
if ($calendarRange->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
if ($calendarRange->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
||||||
$this->logger->info(__CLASS__ . ' change key is equals. Source is probably a local update', [
|
$this->logger->info(self::class . ' change key is equals. Source is probably a local update', [
|
||||||
'calendarRangeId' => $calendarRange->getId(),
|
'calendarRangeId' => $calendarRange->getId(),
|
||||||
'remoteEventId' => $notification['resource'],
|
'remoteEventId' => $notification['resource'],
|
||||||
]);
|
]);
|
||||||
|
@ -79,7 +79,7 @@ class CalendarSyncer
|
|||||||
$notification['resource']
|
$notification['resource']
|
||||||
)->toArray();
|
)->toArray();
|
||||||
} catch (ClientExceptionInterface $clientException) {
|
} catch (ClientExceptionInterface $clientException) {
|
||||||
$this->logger->warning(__CLASS__ . ' could not retrieve event from ms graph. Already deleted ?', [
|
$this->logger->warning(self::class . ' could not retrieve event from ms graph. Already deleted ?', [
|
||||||
'calendarId' => $calendar->getId(),
|
'calendarId' => $calendar->getId(),
|
||||||
'remoteEventId' => $notification['resource'],
|
'remoteEventId' => $notification['resource'],
|
||||||
]);
|
]);
|
||||||
@ -96,7 +96,7 @@ class CalendarSyncer
|
|||||||
);
|
);
|
||||||
|
|
||||||
if ($calendar->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
if ($calendar->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
|
||||||
$this->logger->info(__CLASS__ . ' change key is equals. Source is probably a local update', [
|
$this->logger->info(self::class . ' change key is equals. Source is probably a local update', [
|
||||||
'calendarRangeId' => $calendar->getId(),
|
'calendarRangeId' => $calendar->getId(),
|
||||||
'remoteEventId' => $notification['resource'],
|
'remoteEventId' => $notification['resource'],
|
||||||
]);
|
]);
|
||||||
|
@ -190,23 +190,17 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
]
|
]
|
||||||
)->toArray();
|
)->toArray();
|
||||||
|
|
||||||
$ids = array_map(static function ($item) {
|
$ids = array_map(static fn ($item) => $item['id'], $bareEvents['value']);
|
||||||
return $item['id'];
|
|
||||||
}, $bareEvents['value']);
|
|
||||||
$existingIdsInRange = $this->calendarRangeRepository->findRemoteIdsPresent($ids);
|
$existingIdsInRange = $this->calendarRangeRepository->findRemoteIdsPresent($ids);
|
||||||
$existingIdsInCalendar = $this->calendarRepository->findRemoteIdsPresent($ids);
|
$existingIdsInCalendar = $this->calendarRepository->findRemoteIdsPresent($ids);
|
||||||
|
|
||||||
return array_values(
|
return array_values(
|
||||||
array_map(
|
array_map(
|
||||||
function ($item) {
|
fn ($item) => $this->remoteEventConverter->convertToRemote($item),
|
||||||
return $this->remoteEventConverter->convertToRemote($item);
|
|
||||||
},
|
|
||||||
// filter all event to keep only the one not in range
|
// filter all event to keep only the one not in range
|
||||||
array_filter(
|
array_filter(
|
||||||
$bareEvents['value'],
|
$bareEvents['value'],
|
||||||
static function ($item) use ($existingIdsInRange, $existingIdsInCalendar) {
|
static fn ($item) => ((!$existingIdsInRange[$item['id']]) ?? true) && ((!$existingIdsInCalendar[$item['id']]) ?? true)
|
||||||
return ((!$existingIdsInRange[$item['id']]) ?? true) && ((!$existingIdsInCalendar[$item['id']]) ?? true);
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -604,9 +598,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->cacheScheduleTimeForUser[$userId] = array_map(
|
$this->cacheScheduleTimeForUser[$userId] = array_map(
|
||||||
function ($item) {
|
fn ($item) => $this->remoteEventConverter->convertAvailabilityToRemoteEvent($item),
|
||||||
return $this->remoteEventConverter->convertAvailabilityToRemoteEvent($item);
|
|
||||||
},
|
|
||||||
$response['value'][0]['scheduleItems']
|
$response['value'][0]['scheduleItems']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -66,6 +66,6 @@ class BulkCalendarShortMessageSender
|
|||||||
$this->em->refresh($calendar);
|
$this->em->refresh($calendar);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->info(__CLASS__ . 'a bulk of messages was sent', ['count_calendars' => $countCalendars, 'count_sms' => $countSms]);
|
$this->logger->info(self::class . 'a bulk of messages was sent', ['count_calendars' => $countCalendars, 'count_sms' => $countSms]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,12 +114,8 @@ final class CalendarTypeTest extends TypeTestCase
|
|||||||
$this->assertEquals(8, $calendar->getCalendarRange()->getId());
|
$this->assertEquals(8, $calendar->getCalendarRange()->getId());
|
||||||
$this->assertEquals(9, $calendar->getLocation()->getId());
|
$this->assertEquals(9, $calendar->getLocation()->getId());
|
||||||
$this->assertEquals(true, $calendar->getSendSMS());
|
$this->assertEquals(true, $calendar->getSendSMS());
|
||||||
$this->assertContains(2, $calendar->getUsers()->map(static function (User $u) {
|
$this->assertContains(2, $calendar->getUsers()->map(static fn (User $u) => $u->getId()));
|
||||||
return $u->getId();
|
$this->assertContains(3, $calendar->getUsers()->map(static fn (User $u) => $u->getId()));
|
||||||
}));
|
|
||||||
$this->assertContains(3, $calendar->getUsers()->map(static function (User $u) {
|
|
||||||
return $u->getId();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getExtensions()
|
protected function getExtensions()
|
||||||
@ -148,25 +144,17 @@ final class CalendarTypeTest extends TypeTestCase
|
|||||||
) {
|
) {
|
||||||
$transformer = $this->prophesize($classTransformer);
|
$transformer = $this->prophesize($classTransformer);
|
||||||
$transformer->transform(Argument::type('array'))
|
$transformer->transform(Argument::type('array'))
|
||||||
->will(static function ($args) {
|
->will(static fn ($args) => implode(
|
||||||
return implode(
|
|
||||||
',',
|
',',
|
||||||
array_map(static function ($p) {
|
array_map(static fn ($p) => $p->getId(), $args[0])
|
||||||
return $p->getId();
|
));
|
||||||
}, $args[0])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$transformer->transform(Argument::exact(null))
|
$transformer->transform(Argument::exact(null))
|
||||||
->willReturn([]);
|
->willReturn([]);
|
||||||
$transformer->transform(Argument::type(Collection::class))
|
$transformer->transform(Argument::type(Collection::class))
|
||||||
->will(static function ($args) {
|
->will(static fn ($args) => implode(
|
||||||
return implode(
|
|
||||||
',',
|
',',
|
||||||
array_map(static function ($p) {
|
array_map(static fn ($p) => $p->getId(), $args[0]->toArray())
|
||||||
return $p->getId();
|
));
|
||||||
}, $args[0]->toArray())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$transformer->reverseTransform(Argument::type('string'))
|
$transformer->reverseTransform(Argument::type('string'))
|
||||||
->will(static function ($args) use ($objClass) {
|
->will(static function ($args) use ($objClass) {
|
||||||
if (null === $args[0]) {
|
if (null === $args[0]) {
|
||||||
@ -195,9 +183,7 @@ final class CalendarTypeTest extends TypeTestCase
|
|||||||
) {
|
) {
|
||||||
$transformer = $this->prophesize($classTransformer);
|
$transformer = $this->prophesize($classTransformer);
|
||||||
$transformer->transform(Argument::type('object'))
|
$transformer->transform(Argument::type('object'))
|
||||||
->will(static function ($args) {
|
->will(static fn ($args) => (string) $args[0]->getId());
|
||||||
return (string) $args[0]->getId();
|
|
||||||
});
|
|
||||||
$transformer->transform(Argument::exact(null))
|
$transformer->transform(Argument::exact(null))
|
||||||
->willReturn('');
|
->willReturn('');
|
||||||
$transformer->reverseTransform(Argument::type('string'))
|
$transformer->reverseTransform(Argument::type('string'))
|
||||||
|
@ -63,9 +63,7 @@ final class AddressConverterTest extends TestCase
|
|||||||
{
|
{
|
||||||
$engine = $this->prophesize(EngineInterface::class);
|
$engine = $this->prophesize(EngineInterface::class);
|
||||||
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
||||||
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($args): string {
|
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($args): string => ($args[0] ?? ['fr' => 'not provided'])['fr'] ?? 'not provided');
|
||||||
return ($args[0] ?? ['fr' => 'not provided'])['fr'] ?? 'not provided';
|
|
||||||
});
|
|
||||||
|
|
||||||
$addressRender = new AddressRender($engine->reveal(), $translatableStringHelper->reveal());
|
$addressRender = new AddressRender($engine->reveal(), $translatableStringHelper->reveal());
|
||||||
|
|
||||||
|
@ -72,17 +72,13 @@ final class CalendarForShortMessageProviderTest extends TestCase
|
|||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type('int'),
|
Argument::type('int'),
|
||||||
Argument::exact(0)
|
Argument::exact(0)
|
||||||
)->will(static function ($args) {
|
)->will(static fn ($args) => array_fill(0, $args[2], new Calendar()))->shouldBeCalledTimes(1);
|
||||||
return array_fill(0, $args[2], new Calendar());
|
|
||||||
})->shouldBeCalledTimes(1);
|
|
||||||
$calendarRepository->findByNotificationAvailable(
|
$calendarRepository->findByNotificationAvailable(
|
||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type('int'),
|
Argument::type('int'),
|
||||||
Argument::not(0)
|
Argument::not(0)
|
||||||
)->will(static function ($args) {
|
)->will(static fn ($args) => array_fill(0, $args[2] - 1, new Calendar()))->shouldBeCalledTimes(1);
|
||||||
return array_fill(0, $args[2] - 1, new Calendar());
|
|
||||||
})->shouldBeCalledTimes(1);
|
|
||||||
|
|
||||||
$em = $this->prophesize(EntityManagerInterface::class);
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
$em->clear()->shouldBeCalled();
|
$em->clear()->shouldBeCalled();
|
||||||
@ -108,17 +104,13 @@ final class CalendarForShortMessageProviderTest extends TestCase
|
|||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type('int'),
|
Argument::type('int'),
|
||||||
Argument::exact(0)
|
Argument::exact(0)
|
||||||
)->will(static function ($args) {
|
)->will(static fn ($args) => array_fill(0, 1, new Calendar()))->shouldBeCalledTimes(1);
|
||||||
return array_fill(0, 1, new Calendar());
|
|
||||||
})->shouldBeCalledTimes(1);
|
|
||||||
$calendarRepository->findByNotificationAvailable(
|
$calendarRepository->findByNotificationAvailable(
|
||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type(DateTimeImmutable::class),
|
Argument::type(DateTimeImmutable::class),
|
||||||
Argument::type('int'),
|
Argument::type('int'),
|
||||||
Argument::not(0)
|
Argument::not(0)
|
||||||
)->will(static function ($args) {
|
)->will(static fn ($args) => [])->shouldBeCalledTimes(1);
|
||||||
return [];
|
|
||||||
})->shouldBeCalledTimes(1);
|
|
||||||
|
|
||||||
$em = $this->prophesize(EntityManagerInterface::class);
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
$em->clear()->shouldBeCalled();
|
$em->clear()->shouldBeCalled();
|
||||||
|
@ -192,9 +192,7 @@ class CreateFieldsOnGroupCommand extends Command
|
|||||||
|
|
||||||
foreach ($languages as $lang) {
|
foreach ($languages as $lang) {
|
||||||
//todo replace with service to find lang when available
|
//todo replace with service to find lang when available
|
||||||
$names[] = (isset($cf->getName()[$lang])) ?
|
$names[] = $cf->getName()[$lang] ?? 'Not available in this language';
|
||||||
$cf->getName()[$lang] :
|
|
||||||
'Not available in this language';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->validator->validate($cf)) {
|
if ($this->validator->validate($cf)) {
|
||||||
@ -249,9 +247,7 @@ class CreateFieldsOnGroupCommand extends Command
|
|||||||
|
|
||||||
foreach ($languages as $lang) {
|
foreach ($languages as $lang) {
|
||||||
//todo replace with service to find lang when available
|
//todo replace with service to find lang when available
|
||||||
$row[] = (isset($customFieldGroup->getName()[$lang])) ?
|
$row[] = $customFieldGroup->getName()[$lang] ?? 'Not available in this language';
|
||||||
$customFieldGroup->getName()[$lang] :
|
|
||||||
'Not available in this language';
|
|
||||||
}
|
}
|
||||||
$rows[] = $row;
|
$rows[] = $row;
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ class CustomFieldChoice extends AbstractCustomField
|
|||||||
public function render($value, CustomField $customField, $documentType = 'html')
|
public function render($value, CustomField $customField, $documentType = 'html')
|
||||||
{
|
{
|
||||||
//extract the data. They are under a _choice key if they are stored with allow_other
|
//extract the data. They are under a _choice key if they are stored with allow_other
|
||||||
$data = (isset($value['_choices'])) ? $value['_choices'] : $value;
|
$data = $value['_choices'] ?? $value;
|
||||||
$selected = (is_array($data)) ? $data : [$data];
|
$selected = (is_array($data)) ? $data : [$data];
|
||||||
$choices = $customField->getOptions()[self::CHOICES];
|
$choices = $customField->getOptions()[self::CHOICES];
|
||||||
|
|
||||||
|
@ -58,9 +58,7 @@ class CustomFieldLongChoice extends AbstractCustomField
|
|||||||
$translatableStringHelper = $this->translatableStringHelper;
|
$translatableStringHelper = $this->translatableStringHelper;
|
||||||
$builder->add($customField->getSlug(), Select2ChoiceType::class, [
|
$builder->add($customField->getSlug(), Select2ChoiceType::class, [
|
||||||
'choices' => $entries,
|
'choices' => $entries,
|
||||||
'choice_label' => static function (Option $option) use ($translatableStringHelper) {
|
'choice_label' => static fn (Option $option) => $translatableStringHelper->localize($option->getText()),
|
||||||
return $translatableStringHelper->localize($option->getText());
|
|
||||||
},
|
|
||||||
'choice_value' => static fn (Option $key): ?int => null === $key ? null : $key->getId(),
|
'choice_value' => static fn (Option $key): ?int => null === $key ? null : $key->getId(),
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
'expanded' => false,
|
'expanded' => false,
|
||||||
|
@ -104,7 +104,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
$manager->persist($parent);
|
$manager->persist($parent);
|
||||||
|
|
||||||
//Load children
|
//Load children
|
||||||
$expected_nb_children = mt_rand(10, 50);
|
$expected_nb_children = random_int(10, 50);
|
||||||
|
|
||||||
for ($i = 0; $i < $expected_nb_children; ++$i) {
|
for ($i = 0; $i < $expected_nb_children; ++$i) {
|
||||||
$companyName = $this->fakerFr->company;
|
$companyName = $this->fakerFr->company;
|
||||||
@ -144,7 +144,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
$manager->persist($parent);
|
$manager->persist($parent);
|
||||||
|
|
||||||
//Load children
|
//Load children
|
||||||
$expected_nb_children = mt_rand(10, 50);
|
$expected_nb_children = random_int(10, 50);
|
||||||
|
|
||||||
for ($i = 0; $i < $expected_nb_children; ++$i) {
|
for ($i = 0; $i < $expected_nb_children; ++$i) {
|
||||||
$manager->persist($this->createChildOption($parent, [
|
$manager->persist($this->createChildOption($parent, [
|
||||||
|
@ -25,7 +25,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_custom_fields');
|
$treeBuilder = new TreeBuilder('chill_custom_fields');
|
||||||
$rootNode = $treeBuilder->getRootNode('chill_custom_fields');
|
$rootNode = $treeBuilder->getRootNode();
|
||||||
|
|
||||||
$classInfo = 'The class which may receive custom fields';
|
$classInfo = 'The class which may receive custom fields';
|
||||||
$nameInfo = 'The name which will appears in the user interface. May be translatable';
|
$nameInfo = 'The name which will appears in the user interface. May be translatable';
|
||||||
|
@ -57,8 +57,6 @@ class OptionRepository extends EntityRepository
|
|||||||
->getQuery()
|
->getQuery()
|
||||||
->getScalarResult();
|
->getScalarResult();
|
||||||
|
|
||||||
return array_map(static function ($r) {
|
return array_map(static fn ($r) => $r['key'], $keys);
|
||||||
return $r['key'];
|
|
||||||
}, $keys);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,7 @@ class CustomFieldType extends AbstractType
|
|||||||
if ('entity' === $options['group_widget']) {
|
if ('entity' === $options['group_widget']) {
|
||||||
$builder->add('customFieldsGroup', EntityType::class, [
|
$builder->add('customFieldsGroup', EntityType::class, [
|
||||||
'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup',
|
'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup',
|
||||||
'choice_label' => function ($g) {
|
'choice_label' => fn ($g) => $this->translatableStringHelper->localize($g->getName()),
|
||||||
return $this->translatableStringHelper->localize($g->getName());
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
} elseif ('hidden' === $options['group_widget']) {
|
} elseif ('hidden' === $options['group_widget']) {
|
||||||
$builder->add('customFieldsGroup', HiddenType::class);
|
$builder->add('customFieldsGroup', HiddenType::class);
|
||||||
@ -119,7 +117,7 @@ class CustomFieldType extends AbstractType
|
|||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField',
|
'data_class' => \Chill\CustomFieldsBundle\Entity\CustomField::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$resolver->setRequired(['type', 'group_widget'])
|
$resolver->setRequired(['type', 'group_widget'])
|
||||||
|
@ -38,9 +38,7 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface
|
|||||||
|
|
||||||
// @TODO: in the array_map callback, CustomField::getLabel() does not exist. What do we do here?
|
// @TODO: in the array_map callback, CustomField::getLabel() does not exist. What do we do here?
|
||||||
$customFieldsLablels = array_map(
|
$customFieldsLablels = array_map(
|
||||||
static function ($e) {
|
static fn ($e) => $e->getLabel(),
|
||||||
return $e->getLabel();
|
|
||||||
},
|
|
||||||
$customFields
|
$customFields
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -108,7 +106,7 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface
|
|||||||
|
|
||||||
//echo json_encode($customFieldsArrayRet);
|
//echo json_encode($customFieldsArrayRet);
|
||||||
|
|
||||||
return json_encode($customFieldsArrayRet);
|
return json_encode($customFieldsArrayRet, JSON_THROW_ON_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transform($customFieldsJSON)
|
public function transform($customFieldsJSON)
|
||||||
|
@ -38,7 +38,7 @@ class ChoicesListType extends AbstractType
|
|||||||
$formData = $form->getData();
|
$formData = $form->getData();
|
||||||
|
|
||||||
if (null === $formData['slug']) {
|
if (null === $formData['slug']) {
|
||||||
$slug = uniqid(mt_rand(), true);
|
$slug = uniqid(random_int(0, mt_getrandmax()), true);
|
||||||
|
|
||||||
$data['slug'] = $slug;
|
$data['slug'] = $slug;
|
||||||
$event->setData($data);
|
$event->setData($data);
|
||||||
|
@ -49,7 +49,7 @@ class CustomFieldType extends AbstractType
|
|||||||
{
|
{
|
||||||
$resolver
|
$resolver
|
||||||
->setRequired(['group'])
|
->setRequired(['group'])
|
||||||
->addAllowedTypes('group', ['Chill\CustomFieldsBundle\Entity\CustomFieldsGroup']);
|
->addAllowedTypes('group', [\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup::class]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBlockPrefix()
|
public function getBlockPrefix()
|
||||||
|
@ -49,7 +49,7 @@ class CustomFieldsHelper
|
|||||||
public function isEmptyValue(array $fields, CustomField $customField)
|
public function isEmptyValue(array $fields, CustomField $customField)
|
||||||
{
|
{
|
||||||
$slug = $customField->getSlug();
|
$slug = $customField->getSlug();
|
||||||
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
|
$rawValue = $fields[$slug] ?? null;
|
||||||
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
||||||
|
|
||||||
$deserializedValue = $customFieldType->deserialize($rawValue, $customField);
|
$deserializedValue = $customFieldType->deserialize($rawValue, $customField);
|
||||||
@ -71,7 +71,7 @@ class CustomFieldsHelper
|
|||||||
public function renderCustomField(array $fields, CustomField $customField, $documentType = 'html')
|
public function renderCustomField(array $fields, CustomField $customField, $documentType = 'html')
|
||||||
{
|
{
|
||||||
$slug = $customField->getSlug();
|
$slug = $customField->getSlug();
|
||||||
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
|
$rawValue = $fields[$slug] ?? null;
|
||||||
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
|
||||||
|
|
||||||
return $customFieldType->render($rawValue, $customField, $documentType);
|
return $customFieldType->render($rawValue, $customField, $documentType);
|
||||||
|
@ -52,7 +52,7 @@ final class CustomFieldsGroupControllerTest extends WebTestCase
|
|||||||
// Fill in the form and submit it
|
// Fill in the form and submit it
|
||||||
$form = $crawler->selectButton('Créer')->form([
|
$form = $crawler->selectButton('Créer')->form([
|
||||||
'custom_fields_group[name][fr]' => 'Test',
|
'custom_fields_group[name][fr]' => 'Test',
|
||||||
'custom_fields_group[entity]' => 'Chill\PersonBundle\Entity\Person',
|
'custom_fields_group[entity]' => \Chill\PersonBundle\Entity\Person::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$crawler = $client->submit($form);
|
$crawler = $client->submit($form);
|
||||||
|
@ -34,12 +34,12 @@ trait CustomFieldTestHelper
|
|||||||
$kernel = static::$kernel;
|
$kernel = static::$kernel;
|
||||||
|
|
||||||
//check a kernel is accessible
|
//check a kernel is accessible
|
||||||
$customFieldsGroup = $this->createMock('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup');
|
$customFieldsGroup = $this->createMock(\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup::class);
|
||||||
$customFieldsGroup->expects($this->once())
|
$customFieldsGroup->expects($this->once())
|
||||||
->method('getActiveCustomFields')
|
->method('getActiveCustomFields')
|
||||||
->will($this->returnValue([$field]));
|
->will($this->returnValue([$field]));
|
||||||
|
|
||||||
$request = $this->createMock('Symfony\Component\HttpFoundation\Request');
|
$request = $this->createMock(\Symfony\Component\HttpFoundation\Request::class);
|
||||||
$request->expects($this->any())
|
$request->expects($this->any())
|
||||||
->method('getLocale')
|
->method('getLocale')
|
||||||
->will($this->returnValue($locale));
|
->will($this->returnValue($locale));
|
||||||
|
@ -41,11 +41,11 @@ final class CustomFieldsTextTest extends WebTestCase
|
|||||||
$customField = $this->customFieldProvider->getCustomFieldByType('text');
|
$customField = $this->customFieldProvider->getCustomFieldByType('text');
|
||||||
|
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface',
|
\Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface::class,
|
||||||
$customField
|
$customField
|
||||||
);
|
);
|
||||||
$this->assertInstanceOf(
|
$this->assertInstanceOf(
|
||||||
'Chill\CustomFieldsBundle\CustomFields\CustomFieldText',
|
\Chill\CustomFieldsBundle\CustomFields\CustomFieldText::class,
|
||||||
$customField
|
$customField
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ final class CustomFieldRenderingTwigTest extends KernelTestCase
|
|||||||
// set locale to fr
|
// set locale to fr
|
||||||
$prophet = new \Prophecy\Prophet();
|
$prophet = new \Prophecy\Prophet();
|
||||||
$request = $prophet->prophesize();
|
$request = $prophet->prophesize();
|
||||||
$request->willExtend('Symfony\Component\HttpFoundation\Request');
|
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||||
$request->getLocale()->willReturn('fr');
|
$request->getLocale()->willReturn('fr');
|
||||||
self::$kernel->getContainer()->get('request_stack')
|
self::$kernel->getContainer()->get('request_stack')
|
||||||
->push($request->reveal());
|
->push($request->reveal());
|
||||||
|
@ -48,7 +48,7 @@ final class CustomFieldsGroupRenderingTwigTest extends KernelTestCase
|
|||||||
// set locale to fr
|
// set locale to fr
|
||||||
$prophet = new \Prophecy\Prophet();
|
$prophet = new \Prophecy\Prophet();
|
||||||
$request = $prophet->prophesize();
|
$request = $prophet->prophesize();
|
||||||
$request->willExtend('Symfony\Component\HttpFoundation\Request');
|
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
|
||||||
$request->getLocale()->willReturn('fr');
|
$request->getLocale()->willReturn('fr');
|
||||||
self::$kernel->getContainer()->get('request_stack')
|
self::$kernel->getContainer()->get('request_stack')
|
||||||
->push($request->reveal());
|
->push($request->reveal());
|
||||||
|
@ -61,12 +61,8 @@ class DocGeneratorTemplateType extends AbstractType
|
|||||||
$sub = $builder
|
$sub = $builder
|
||||||
->create('options', null, ['compound' => true])
|
->create('options', null, ['compound' => true])
|
||||||
->addModelTransformer(new CallbackTransformer(
|
->addModelTransformer(new CallbackTransformer(
|
||||||
static function (array $data) use ($context) {
|
static fn (array $data) => $context->adminFormTransform($data),
|
||||||
return $context->adminFormTransform($data);
|
static fn (array $data) => $context->adminFormReverseTransform($data)
|
||||||
},
|
|
||||||
static function (array $data) use ($context) {
|
|
||||||
return $context->adminFormReverseTransform($data);
|
|
||||||
}
|
|
||||||
));
|
));
|
||||||
$context->buildAdminForm($sub);
|
$context->buildAdminForm($sub);
|
||||||
$builder->add($sub);
|
$builder->add($sub);
|
||||||
|
@ -44,7 +44,7 @@ final class RelatorioDriver implements DriverInterface
|
|||||||
{
|
{
|
||||||
$form = new FormDataPart(
|
$form = new FormDataPart(
|
||||||
[
|
[
|
||||||
'variables' => json_encode($data),
|
'variables' => json_encode($data, JSON_THROW_ON_ERROR),
|
||||||
'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType),
|
'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -61,7 +61,7 @@ final class RelatorioDriver implements DriverInterface
|
|||||||
$content = $e->getResponse()->getContent(false);
|
$content = $e->getResponse()->getContent(false);
|
||||||
|
|
||||||
if (400 === $e->getResponse()->getStatusCode()) {
|
if (400 === $e->getResponse()->getStatusCode()) {
|
||||||
$content = json_decode($content, true);
|
$content = json_decode($content, true, 512, JSON_THROW_ON_ERROR);
|
||||||
$this->logger->error('relatorio: template error', [
|
$this->logger->error('relatorio: template error', [
|
||||||
'error' => $content['message'] ?? '_not defined',
|
'error' => $content['message'] ?? '_not defined',
|
||||||
]);
|
]);
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
|
|||||||
|
|
||||||
use ArrayObject;
|
use ArrayObject;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\Common\Collections\ReadableCollection;
|
||||||
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||||
@ -51,7 +52,9 @@ class CollectionDocGenNormalizer implements ContextAwareNormalizerInterface, Nor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $data instanceof Collection
|
return $data instanceof ReadableCollection
|
||||||
|| (null === $data && Collection::class === ($context['docgen:expects'] ?? null));
|
|| (null === $data && Collection::class === ($context['docgen:expects'] ?? null))
|
||||||
|
|| (null === $data && ReadableCollection::class === ($context['docgen:expects'] ?? null))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
|
|||||||
|
|
||||||
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
|
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Doctrine\Common\Collections\ReadableCollection;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Symfony\Component\PropertyAccess\PropertyAccess;
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
@ -271,6 +272,14 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
|
|||||||
if ($isTranslatable) {
|
if ($isTranslatable) {
|
||||||
$data[$key] = $this->translatableStringHelper
|
$data[$key] = $this->translatableStringHelper
|
||||||
->localize($value);
|
->localize($value);
|
||||||
|
} elseif ($value instanceof ReadableCollection) {
|
||||||
|
// when normalizing collection, we should not preserve keys (to ensure that the result is a list)
|
||||||
|
// this is why we make call to the normalizer again to use the CollectionDocGenNormalizer
|
||||||
|
$data[$key] =
|
||||||
|
$this->normalizer->normalize($value, $format, array_merge(
|
||||||
|
$objectContext,
|
||||||
|
$attribute->getNormalizationContextForGroups($expectedGroups)
|
||||||
|
));
|
||||||
} elseif (is_iterable($value)) {
|
} elseif (is_iterable($value)) {
|
||||||
$arr = [];
|
$arr = [];
|
||||||
|
|
||||||
|
@ -17,6 +17,6 @@ class ObjectReadyException extends RuntimeException
|
|||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct('object is already ready', 6698856);
|
parent::__construct('object is already ready', 6_698_856);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class RelatedEntityNotFoundException extends RuntimeException
|
|||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
sprintf('Related entity not found: %s, %s', $relatedEntityClass, $relatedEntityId),
|
sprintf('Related entity not found: %s, %s', $relatedEntityClass, $relatedEntityId),
|
||||||
99876652,
|
99_876_652,
|
||||||
$previous
|
$previous
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
<?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\DocGeneratorBundle\tests\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Criteria;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class CollectionDocGenNormalizerTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
private NormalizerInterface $normalizer;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$this->normalizer = self::$container->get(NormalizerInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNormalizeFilteredArray(): void
|
||||||
|
{
|
||||||
|
$coll = new ArrayCollection([
|
||||||
|
(object) ['v' => 'foo'],
|
||||||
|
(object) ['v' => 'bar'],
|
||||||
|
(object) ['v' => 'baz'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
//filter to get non continuous indexes
|
||||||
|
$criteria = new Criteria();
|
||||||
|
$criteria->where(Criteria::expr()->neq('v', 'bar'));
|
||||||
|
|
||||||
|
$filtered = $coll->matching($criteria);
|
||||||
|
$normalized = $this->normalizer->normalize($filtered, 'docgen', []);
|
||||||
|
|
||||||
|
self::assertIsArray($normalized);
|
||||||
|
self::assertArrayHasKey(0, $normalized);
|
||||||
|
self::assertArrayHasKey(1, $normalized);
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ class Configuration implements ConfigurationInterface
|
|||||||
public function getConfigTreeBuilder()
|
public function getConfigTreeBuilder()
|
||||||
{
|
{
|
||||||
$treeBuilder = new TreeBuilder('chill_doc_store');
|
$treeBuilder = new TreeBuilder('chill_doc_store');
|
||||||
$rootNode = $treeBuilder->getRootNode('chill_doc_store');
|
$rootNode = $treeBuilder->getRootNode();
|
||||||
|
|
||||||
// Here you should define the parameters that are allowed to
|
// Here you should define the parameters that are allowed to
|
||||||
// configure your bundle. See the documentation linked above for
|
// configure your bundle. See the documentation linked above for
|
||||||
|
@ -58,7 +58,7 @@ class StoredObject implements AsyncFileInterface, Document, TrackCreationInterfa
|
|||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
* @Serializer\Groups({"read", "write"})
|
* @Serializer\Groups({"read", "write"})
|
||||||
*/
|
*/
|
||||||
private ?int $id;
|
private ?int $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var int[]
|
* @var int[]
|
||||||
@ -94,7 +94,7 @@ class StoredObject implements AsyncFileInterface, Document, TrackCreationInterfa
|
|||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=DocGeneratorTemplate::class)
|
* @ORM\ManyToOne(targetEntity=DocGeneratorTemplate::class)
|
||||||
*/
|
*/
|
||||||
private ?DocGeneratorTemplate $template;
|
private ?DocGeneratorTemplate $template = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="text", options={"default": "ready"})
|
* @ORM\Column(type="text", options={"default": "ready"})
|
||||||
|
@ -72,14 +72,10 @@ class AccompanyingCourseDocumentType extends AbstractType
|
|||||||
->add('category', EntityType::class, [
|
->add('category', EntityType::class, [
|
||||||
'placeholder' => 'Choose a document category',
|
'placeholder' => 'Choose a document category',
|
||||||
'class' => DocumentCategory::class,
|
'class' => DocumentCategory::class,
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('c')
|
||||||
return $er->createQueryBuilder('c')
|
|
||||||
->where('c.documentClass = :docClass')
|
->where('c.documentClass = :docClass')
|
||||||
->setParameter('docClass', AccompanyingCourseDocument::class);
|
->setParameter('docClass', AccompanyingCourseDocument::class),
|
||||||
},
|
'choice_label' => fn ($entity = null) => $entity ? $this->translatableStringHelper->localize($entity->getName()) : '',
|
||||||
'choice_label' => function ($entity = null) {
|
|
||||||
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +67,10 @@ class PersonDocumentType extends AbstractType
|
|||||||
->add('category', EntityType::class, [
|
->add('category', EntityType::class, [
|
||||||
'placeholder' => 'Choose a document category',
|
'placeholder' => 'Choose a document category',
|
||||||
'class' => DocumentCategory::class,
|
'class' => DocumentCategory::class,
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('c')
|
||||||
return $er->createQueryBuilder('c')
|
|
||||||
->where('c.documentClass = :docClass')
|
->where('c.documentClass = :docClass')
|
||||||
->setParameter('docClass', PersonDocument::class);
|
->setParameter('docClass', PersonDocument::class),
|
||||||
},
|
'choice_label' => fn ($entity = null) => $entity ? $this->translatableStringHelper->localize($entity->getName()) : '',
|
||||||
'choice_label' => function ($entity = null) {
|
|
||||||
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
|
if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user