Merge branch 'master' into export/allow-check-multiple-geographical-zones

This commit is contained in:
Julien Fastré 2023-05-19 11:50:12 +02:00
commit 8bbca7e61a
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
388 changed files with 3159 additions and 1567 deletions

View File

@ -34,6 +34,7 @@
"sensio/framework-extra-bundle": "^5.5",
"spomky-labs/base64url": "^2.0",
"symfony/browser-kit": "^4.4",
"symfony/clock": "^6.2",
"symfony/css-selector": "^4.4",
"symfony/expression-language": "^4.4",
"symfony/form": "^4.4",

View File

@ -90,9 +90,7 @@ class CountPerson implements ExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
// we gather all center the user choose.
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn($el) => $el['center'], $acl);
$qb = $this->entityManager->createQueryBuilder();

View 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``.

View File

@ -35,6 +35,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
manual/index.rst
Assets <assets.rst>
Cron Jobs <cronjob.rst>
Info about entities <entity-info.rst>
Layout and UI
**************

View File

@ -6,6 +6,8 @@
A copy of the license is included in the section entitled "GNU
Free Documentation License".
.. _timelines:
Timelines
*********

View File

@ -151,6 +151,7 @@ This script will :
# mount into to container
./docker-php.sh
bin/console chill:db:sync-views
# and load fixtures
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
./docker-php.sh
# and load fixtures
# and load fixtures (do not this for production)
bin/console doctrine:fixtures:load --purge-with-truncate
There are several users available:
@ -204,8 +205,10 @@ How to create the database schema (= run migrations) ?
# if a container is running
./docker-php.sh
bin/console doctrine:migrations:migrate
bin/console chill:db:sync-views
# if not
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 ?
@ -236,6 +239,23 @@ How to open a terminal in the project
# if not
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 ?
=====================

View File

@ -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.
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
=========

View File

@ -12,14 +12,49 @@ return static function (RectorConfig $rectorConfig): void {
__DIR__ . '/src',
]);
$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
$rectorConfig->cacheDirectory(__DIR__.'/.cache/rector');
//$rectorConfig->cacheClass(\Rector\Caching\ValueObject\Storage\FileCacheStorage::class);
//$rectorConfig->cacheDirectory(__DIR__ . '/.cache/rector');
// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
$rectorConfig->disableParallel();
// define sets of rules
// $rectorConfig->sets([
// LevelSetList::UP_TO_PHP_74
// ]);
//define sets of rules
$rectorConfig->sets([
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
]);
};

View File

@ -50,7 +50,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
->findAll();
foreach ($persons as $person) {
$activityNbr = mt_rand(0, 3);
$activityNbr = random_int(0, 3);
for ($i = 0; $i < $activityNbr; ++$i) {
$activity = $this->newRandomActivity($person);
@ -75,7 +75,7 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface
// ->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();
if (null !== $reason) {

View File

@ -26,7 +26,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_activity');
$rootNode = $treeBuilder->getRootNode('chill_activity');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()
@ -59,9 +59,7 @@ class Configuration implements ConfigurationInterface
->info('The number of seconds of this duration. Must be an integer.')
->cannotBeEmpty()
->validate()
->ifTrue(static function ($data) {
return !is_int($data);
})->thenInvalid('The value %s is not a valid integer')
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
->end()
->end()
->scalarNode('label')

View File

@ -195,7 +195,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
* @Groups({"docgen:read"})
*/
private ?User $user;
private ?User $user = null;
/**
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")

View File

@ -34,7 +34,7 @@ class ActivityPresence
* @ORM\GeneratedValue(strategy="AUTO")
* @Serializer\Groups({"docgen:read"})
*/
private ?int $id;
private ?int $id = null;
/**
* @ORM\Column(type="json")

View File

@ -122,7 +122,7 @@ class ActivityType
* @ORM\GeneratedValue(strategy="AUTO")
* @Groups({"docgen:read"})
*/
private ?int $id;
private ?int $id = null;
/**
* @ORM\Column(type="string", nullable=false, options={"default": ""})

View File

@ -86,9 +86,7 @@ class AvgActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository->createQueryBuilder('activity');

View File

@ -87,9 +87,7 @@ class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository->createQueryBuilder('activity');

View File

@ -86,9 +86,7 @@ class CountActivity implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository
->createQueryBuilder('activity')

View File

@ -109,9 +109,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->entityManager->createQueryBuilder();

View File

@ -87,9 +87,7 @@ class SumActivityDuration implements ExportInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository
->createQueryBuilder('activity')

View File

@ -87,9 +87,7 @@ class SumActivityVisitDuration implements ExportInterface, GroupedExportInterfac
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->repository
->createQueryBuilder('activity')

View File

@ -137,13 +137,11 @@ class ListActivity implements ListInterface, GroupedExportInterface
$activity = $activityRepository->find($value);
return implode(', ', array_map(function (ActivityReason $r) {
return '"' .
$this->translatableStringHelper->localize($r->getCategory()->getName())
. ' > ' .
$this->translatableStringHelper->localize($r->getName())
. '"';
}, $activity->getReasons()->toArray()));
return implode(', ', array_map(fn (ActivityReason $r) => '"' .
$this->translatableStringHelper->localize($r->getCategory()->getName())
. ' > ' .
$this->translatableStringHelper->localize($r->getName())
. '"', $activity->getReasons()->toArray()));
};
case 'circle_name':
@ -152,7 +150,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
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':
@ -161,7 +159,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
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:
@ -197,9 +195,7 @@ class ListActivity implements ListInterface, GroupedExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
// throw an error if any fields are present
if (!array_key_exists('fields', $data)) {

View File

@ -179,7 +179,7 @@ class ListActivityHelper
}
}
$decoded = json_decode($value);
$decoded = json_decode($value, null, 512, JSON_THROW_ON_ERROR);
return implode(
'|',

View File

@ -61,12 +61,9 @@ class ActivityTypeFilter implements FilterInterface
$builder->add('accepted_activitytypes', EntityType::class, [
'class' => ActivityType::class,
'choices' => $this->activityTypeRepository->findAllActive(),
'choice_label' => function (ActivityType $aty) {
return
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName());
},
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName()),
'multiple' => true,
'expanded' => true,
]);

View File

@ -64,11 +64,9 @@ class UserScopeFilter implements FilterInterface
{
$builder->add('accepted_userscope', EntityType::class, [
'class' => Scope::class,
'choice_label' => function (Scope $s) {
return $this->translatableStringHelper->localize(
$s->getName()
);
},
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
$s->getName()
),
'multiple' => true,
'expanded' => true,
]);

View File

@ -61,12 +61,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
$builder->add('types', EntityType::class, [
'choices' => $this->activityTypeRepository->findAllActive(),
'class' => ActivityType::class,
'choice_label' => function (ActivityType $aty) {
return
($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName());
},
'choice_label' => fn (ActivityType $aty) => ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '')
.
$this->translatableStringHelper->localize($aty->getName()),
'group_by' => function (ActivityType $type) {
if (!$type->hasCategory()) {
return null;

View File

@ -32,7 +32,7 @@ class ActivityReasonCategoryType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory',
'data_class' => \Chill\ActivityBundle\Entity\ActivityReasonCategory::class,
]);
}

View File

@ -211,13 +211,9 @@ class ActivityType extends AbstractType
'required' => $activityType->isRequired('attendee'),
'expanded' => true,
'class' => ActivityPresence::class,
'choice_label' => function (ActivityPresence $activityPresence) {
return $this->translatableStringHelper->localize($activityPresence->getName());
},
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('a')
->where('a.active = true');
},
'choice_label' => fn (ActivityPresence $activityPresence) => $this->translatableStringHelper->localize($activityPresence->getName()),
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('a')
->where('a.active = true'),
]);
}
@ -357,9 +353,7 @@ class ActivityType extends AbstractType
return (string) $location->getId();
},
function (?string $id): ?Location {
return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]);
}
fn (?string $id): ?Location => $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
$timezoneUTC = new DateTimeZone('GMT');
/** @var DateTime $data */
$data = $formEvent->getData() === null ?
DateTime::createFromFormat('U', '300') :
$formEvent->getData();
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
$seconds = $data->getTimezone()->getOffset($data);
$data->setTimeZone($timezoneUTC);
$data->add(new DateInterval('PT' . $seconds . 'S'));

View File

@ -45,9 +45,7 @@ class ActivityTypeType extends AbstractType
])
->add('category', EntityType::class, [
'class' => ActivityTypeCategory::class,
'choice_label' => function (ActivityTypeCategory $activityTypeCategory) {
return $this->translatableStringHelper->localize($activityTypeCategory->getName());
},
'choice_label' => fn (ActivityTypeCategory $activityTypeCategory) => $this->translatableStringHelper->localize($activityTypeCategory->getName()),
])
->add('ordering', NumberType::class, [
'required' => true,

View File

@ -45,9 +45,7 @@ class PickActivityReasonType extends AbstractType
$resolver->setDefaults(
[
'class' => ActivityReason::class,
'choice_label' => function (ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []);
},
'choice_label' => fn (ActivityReason $choice) => $this->reasonRender->renderString($choice, []),
'group_by' => function (ActivityReason $choice): ?string {
if (null !== $category = $choice->getCategory()) {
return $this->translatableStringHelper->localize($category->getName());

View File

@ -38,10 +38,8 @@ class TranslatableActivityReasonCategoryType extends AbstractType
$resolver->setDefaults(
[
'class' => ActivityReasonCategory::class,
'choice_label' => function (ActivityReasonCategory $category) {
return $this->translatableStringHelper->localize($category->getName())
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : '');
},
'choice_label' => fn (ActivityReasonCategory $category) => $this->translatableStringHelper->localize($category->getName())
. (!$category->getActive() ? ' (' . $this->translator->trans('inactive') . ')' : ''),
]
);
}

View File

@ -39,9 +39,7 @@ class TranslatableActivityType extends AbstractType
'class' => ActivityType::class,
'active_only' => true,
'choices' => $this->activityTypeRepository->findAllActive(),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
},
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
]
);
}

View File

@ -254,9 +254,7 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), ActivityVoter::SEE, $center);
// we get the ids for those scopes
$reachablesScopesId = array_map(
static function (Scope $scope) {
return $scope->getId();
},
static fn (Scope $scope) => $scope->getId(),
$reachableScopes
);

View File

@ -134,9 +134,7 @@ class ActivityContext implements
$builder->add($key, EntityType::class, [
'class' => Person::class,
'choices' => $persons,
'choice_label' => function (Person $p) {
return $this->personRender->renderString($p, []);
},
'choice_label' => fn (Person $p) => $this->personRender->renderString($p, []),
'multiple' => false,
'required' => false,
'expanded' => true,

View File

@ -145,9 +145,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
return array_filter(
$activities,
function ($activity) use ($user) {
$activityUsernames = array_map(static function ($user) {
return $user['username'];
}, $activity['users'] ?? []);
$activityUsernames = array_map(static fn ($user) => $user['username'], $activity['users'] ?? []);
return in_array($user->getUsername(), $activityUsernames, true);
}
);
@ -158,9 +156,7 @@ class ListActivitiesByAccompanyingPeriodContext implements
return array_filter(
$works,
function ($work) use ($user) {
$workUsernames = array_map(static function ($user) {
return $user['username'];
}, $work['referrers'] ?? []);
$workUsernames = array_map(static fn ($user) => $user['username'], $work['referrers'] ?? []);
return in_array($user->getUsername(), $workUsernames, true);
}

View File

@ -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';
}
}

View File

@ -369,12 +369,8 @@ final class ActivityControllerTest extends WebTestCase
$center
);
$reachableScopesId = array_intersect(
array_map(static function ($s) {
return $s->getId();
}, $reachableScopesDelete),
array_map(static function ($s) {
return $s->getId();
}, $reachableScopesUpdate)
array_map(static fn ($s) => $s->getId(), $reachableScopesDelete),
array_map(static fn ($s) => $s->getId(), $reachableScopesUpdate)
);
if (count($reachableScopesId) === 0) {

View File

@ -188,9 +188,7 @@ final class ActivityTypeTest extends KernelTestCase
// map all the values in an array
$values = array_map(
static function ($choice) {
return $choice->value;
},
static fn ($choice) => $choice->value,
$view['activity']['durationTime']->vars['choices']
);

View File

@ -79,15 +79,13 @@ final class TranslatableActivityReasonTest extends TypeTestCase
$request = $prophet->prophesize();
$translator = $prophet->prophesize();
$request->willExtend('Symfony\Component\HttpFoundation\Request');
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn($fallbackLocale);
$requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack');
$requestStack->getCurrentRequest()->will(static function () use ($request) {
return $request;
});
$requestStack->willExtend(\Symfony\Component\HttpFoundation\RequestStack::class);
$requestStack->getCurrentRequest()->will(static fn () => $request);
$translator->willExtend('Symfony\Component\Translation\Translator');
$translator->willExtend(\Symfony\Component\Translation\Translator::class);
$translator->getFallbackLocales()->willReturn($locale);
return new TranslatableStringHelper(

View File

@ -160,7 +160,7 @@ final class ActivityVoterTest extends KernelTestCase
{
$token = $this->prophet->prophesize();
$token
->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
->willImplement('\\' . \Symfony\Component\Security\Core\Authentication\Token\TokenInterface::class);
if (null === $user) {
$token->getUser()->willReturn(null);

View File

@ -34,6 +34,7 @@ services:
resource: '../Validator/Constraints/'
Chill\ActivityBundle\Service\DocGenerator\:
autowire: true
autoconfigure: true
resource: '../Service/DocGenerator/'
Chill\ActivityBundle\Service\EntityInfo\:
resource: '../Service/EntityInfo/'

View File

@ -22,7 +22,7 @@ class Configuration implements ConfigurationInterface
{
$treeBuilder = new TreeBuilder('chill_aside_activity');
$treeBuilder->getRootNode('chill_aside_activity')
$treeBuilder->getRootNode()
->children()
->arrayNode('form')
->canBeEnabled()
@ -132,9 +132,7 @@ class Configuration implements ConfigurationInterface
->info('The number of seconds of this duration. Must be an integer.')
->cannotBeEmpty()
->validate()
->ifTrue(static function ($data) {
return !is_int($data);
})->thenInvalid('The value %s is not a valid integer')
->ifTrue(static fn ($data) => !is_int($data))->thenInvalid('The value %s is not a valid integer')
->end()
->end()
->scalarNode('label')

View File

@ -57,7 +57,7 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
private ?int $id = null;
/**
* @ORM\Column(type="string", length=100, nullable=true)

View File

@ -59,9 +59,7 @@ class CountAsideActivity implements ExportInterface, GroupedExportInterface
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array

View File

@ -95,9 +95,7 @@ final class AsideActivityFormType extends AbstractType
// the datetimetransformer will then handle timezone as GMT
$timezoneUTC = new DateTimeZone('GMT');
/** @var DateTimeImmutable $data */
$data = $formEvent->getData() === null ?
DateTime::createFromFormat('U', '300') :
$formEvent->getData();
$data = $formEvent->getData() ?? DateTime::createFromFormat('U', '300');
$seconds = $data->getTimezone()->getOffset($data);
$data->setTimeZone($timezoneUTC);
$data->add(new DateInterval('PT' . $seconds . 'S'));

View File

@ -116,7 +116,7 @@ abstract class AbstractElementController extends AbstractController
$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->add('submit', SubmitType::class);

View File

@ -19,7 +19,7 @@ class CalculatorCompilerPass implements CompilerPassInterface
{
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 ($tags as $tag) {

View File

@ -19,7 +19,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_budget');
$rootNode = $treeBuilder->getRootNode('chill_budget');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()

View File

@ -41,7 +41,7 @@ abstract class AbstractElement
/**
* @ORM\Column(name="comment", type="text", nullable=true)
*/
private ?string $comment;
private ?string $comment = null;
/**
* @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"
* )
*/
private ?DateTimeImmutable $endDate;
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\ManyToOne(

View File

@ -52,9 +52,7 @@ class ChargeType extends AbstractType
'label' => 'Charge type',
'required' => true,
'placeholder' => $this->translator->trans('admin.form.Choose the type of charge'),
'choice_label' => function (ChargeKind $resource) {
return $this->translatableStringHelper->localize($resource->getName());
},
'choice_label' => fn (ChargeKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
'attr' => ['class' => 'select2'],
])
->add('amount', MoneyType::class)

View File

@ -51,9 +51,7 @@ class ResourceType extends AbstractType
'label' => 'Resource type',
'required' => true,
'placeholder' => $this->translator->trans('admin.form.Choose the type of resource'),
'choice_label' => function (ResourceKind $resource) {
return $this->translatableStringHelper->localize($resource->getName());
},
'choice_label' => fn (ResourceKind $resource) => $this->translatableStringHelper->localize($resource->getName()),
'attr' => ['class' => 'select2'],
])
->add('amount', MoneyType::class)

View File

@ -16,8 +16,14 @@
<td class="el-type">
{% if f.isResource %}
{{ f.resource.name|localize_translatable_string }}
{% if f.resource.getKind is same as 'other' %}
: {{ f.getComment }}
{% endif %}
{% else %}
{{ f.charge.name|localize_translatable_string }}
{% if f.charge.getKind is same as 'other' %}
: {{ f.getComment }}
{% endif %}
{% endif %}
</td>
<td>{{ f.amount|format_currency('EUR') }}</td>

View File

@ -66,9 +66,7 @@ final class SummaryBudget implements SummaryBudgetInterface
];
}
$personIds = $household->getCurrentPersons()->map(static function (Person $p) {
return $p->getId();
});
$personIds = $household->getCurrentPersons()->map(static fn (Person $p) => $p->getId());
$ids = implode(', ', array_fill(0, count($personIds), '?'));
$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());
return array_combine($keys, array_map(function ($kind) {
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
}, $keys));
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->chargeKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
}
private function getEmptyResourceArray(): array
{
$keys = array_map(static fn (ResourceKind $kind) => $kind->getKind(), $this->resourceKindRepository->findAll());
return array_combine($keys, array_map(function ($kind) {
return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''];
}, $keys));
return array_combine($keys, array_map(fn ($kind) => ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($this->resourceKindRepository->findOneByKind($kind)->getName()), 'comment' => ''], $keys));
}
private function rowToArray(array $rows, string $kind): array

View File

@ -50,9 +50,7 @@ final class SummaryBudgetTest extends TestCase
],
]);
$queryCharges->setParameters(Argument::type('array'))
->will(static function ($args, $query) {
return $query;
});
->will(static fn ($args, $query) => $query);
$queryResources = $this->prophesize(AbstractQuery::class);
$queryResources->getResult()->willReturn([
@ -63,9 +61,7 @@ final class SummaryBudgetTest extends TestCase
],
]);
$queryResources->setParameters(Argument::type('array'))
->will(static function ($args, $query) {
return $query;
});
->will(static fn ($args, $query) => $query);
$em = $this->prophesize(EntityManagerInterface::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);
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($arg) {
return $arg[0]['fr'];
});
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($arg) => $arg[0]['fr']);
$person = new Person();
$personReflection = new ReflectionClass($person);

View File

@ -60,7 +60,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
public function execute(InputInterface $input, OutputInterface $output): int
{
$this->logger->info(__CLASS__ . ' execute command');
$this->logger->info(self::class . ' execute command');
$limit = 50;
$offset = 0;
@ -71,7 +71,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
$created = 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,
'expiration' => $expiration->format(DateTimeImmutable::ATOM),
]);
@ -92,7 +92,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
// we first try to renew an existing subscription, if any.
// if not, or if it fails, we try to create a new one
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(),
'username' => $user->getUsernameCanonical(),
]);
@ -104,7 +104,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
if (0 !== $expirationTs) {
++$renewed;
} 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(),
'username' => $user->getUsernameCanonical(),
]);
@ -112,7 +112,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
}
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(),
'username' => $user->getUsernameCanonical(),
]);
@ -124,7 +124,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
if (0 !== $expirationTs) {
++$created;
} 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(),
'username' => $user->getUsernameCanonical(),
]);
@ -139,7 +139,7 @@ class MapAndSubscribeUserCalendarCommand extends Command
$this->em->clear();
}
$this->logger->warning(__CLASS__ . ' process executed', [
$this->logger->warning(self::class . ' process executed', [
'created' => $created,
'renewed' => $renewed,
]);

View File

@ -24,7 +24,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_calendar');
$rootNode = $treeBuilder->getRootNode('chill_calendar');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()

View File

@ -514,9 +514,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
*/
public function getUsers(): ReadableCollection
{
return $this->getInvites()->map(static function (Invite $i) {
return $i->getUser();
});
return $this->getInvites()->map(static fn (Invite $i) => $i->getUser());
}
public function hasCalendarRange(): bool
@ -601,9 +599,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
}
$invite = $this->invites
->filter(static function (Invite $invite) use ($user) {
return $invite->getUser() === $user;
})
->filter(static fn (Invite $invite) => $invite->getUser() === $user)
->first();
$this->removeInvite($invite);

View File

@ -63,7 +63,7 @@ class CalendarRange implements TrackCreationInterface, TrackUpdateInterface
* @Groups({"read", "write", "calendar:read"})
* @Assert\NotNull
*/
private ?Location $location;
private ?Location $location = null;
/**
* @ORM\Column(type="datetime_immutable", nullable=false)

View File

@ -61,9 +61,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array
@ -91,9 +89,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
{
$centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$centers = array_map(static fn ($el) => $el['center'], $acl);
$qb = $this->calendarRepository->createQueryBuilder('cal');

View File

@ -61,9 +61,7 @@ class StatCalendarAvgDuration implements ExportInterface, GroupedExportInterface
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array

View File

@ -61,9 +61,7 @@ class StatCalendarSumDuration implements ExportInterface, GroupedExportInterface
$labels = array_combine($values, $values);
$labels['_header'] = $this->getTitle();
return static function ($value) use ($labels) {
return $labels[$value];
};
return static fn ($value) => $labels[$value];
}
public function getQueryKeys($data): array

View File

@ -58,9 +58,7 @@ class AgentFilter implements FilterInterface
{
$builder->add('accepted_agents', EntityType::class, [
'class' => User::class,
'choice_label' => function (User $u) {
return $this->userRender->renderString($u, []);
},
'choice_label' => fn (User $u) => $this->userRender->renderString($u, []),
'multiple' => true,
'expanded' => true,
]);

View File

@ -69,11 +69,9 @@ class JobFilter implements FilterInterface
{
$builder->add('job', EntityType::class, [
'class' => UserJob::class,
'choice_label' => function (UserJob $j) {
return $this->translatableStringHelper->localize(
$j->getLabel()
);
},
'choice_label' => fn (UserJob $j) => $this->translatableStringHelper->localize(
$j->getLabel()
),
'multiple' => true,
'expanded' => true,
]);

View File

@ -69,11 +69,9 @@ class ScopeFilter implements FilterInterface
{
$builder->add('scope', EntityType::class, [
'class' => Scope::class,
'choice_label' => function (Scope $s) {
return $this->translatableStringHelper->localize(
$s->getName()
);
},
'choice_label' => fn (Scope $s) => $this->translatableStringHelper->localize(
$s->getName()
),
'multiple' => true,
'expanded' => true,
]);

View File

@ -89,14 +89,10 @@ class CalendarToRemoteHandler implements MessageHandlerInterface
$newInvites = array_filter(
array_map(
function ($id) {
return $this->inviteRepository->find($id);
},
fn ($id) => $this->inviteRepository->find($id),
$calendarMessage->getNewInvitesIds(),
),
static function (?Invite $invite) {
return null !== $invite;
}
static fn (?Invite $invite) => null !== $invite
);
$this->calendarConnector->syncCalendar(

View File

@ -77,7 +77,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
$user = $this->userRepository->find($changeNotificationMessage->getUserId());
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;
}
@ -86,7 +86,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
$secret = $this->mapCalendarToUser->getSubscriptionSecret($user);
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;
}
@ -101,7 +101,7 @@ class MSGraphChangeNotificationHandler implements MessageHandlerInterface
$this->calendarSyncer->handleCalendarSync($calendar, $notification, $user);
$this->em->flush();
} 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');
}
}

View File

@ -58,14 +58,12 @@ class CalendarMessage
$this->previousMainUserId = null !== $calendar->previousMainUser ?
$calendar->previousMainUser->getId() : null;
$this->newInvitesIds = array_map(static fn (Invite $i) => $i->getId(), $calendar->newInvites);
$this->oldInvites = array_map(static function (Invite $i) {
return [
'inviteId' => $i->getId(),
'userId' => $i->getUser()->getId(),
'userEmail' => $i->getUser()->getEmail(),
'userLabel' => $i->getUser()->getLabel(),
];
}, $calendar->oldInvites);
$this->oldInvites = array_map(static fn (Invite $i) => [
'inviteId' => $i->getId(),
'userId' => $i->getUser()->getId(),
'userEmail' => $i->getUser()->getEmail(),
'userLabel' => $i->getUser()->getLabel(),
], $calendar->oldInvites);
}
public function getAction(): string

View File

@ -121,9 +121,7 @@ class RemoteEventConverter
'subject' => '[Chill] ' .
implode(
', ',
$calendar->getPersons()->map(function (Person $p) {
return $this->personRender->renderString($p, []);
})->toArray()
$calendar->getPersons()->map(fn (Person $p) => $this->personRender->renderString($p, []))->toArray()
),
'start' => [
'dateTime' => $calendar->getStartDate()->setTimezone($this->remoteDateTimeZone)
@ -161,9 +159,7 @@ class RemoteEventConverter
{
return [
'attendees' => $calendar->getInvites()->map(
function (Invite $i) {
return $this->buildInviteToAttendee($i);
}
fn (Invite $i) => $this->buildInviteToAttendee($i)
)->toArray(),
];
}

View File

@ -59,7 +59,7 @@ class CalendarRangeSyncer
}
$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);
break;
@ -71,7 +71,7 @@ class CalendarRangeSyncer
$notification['resource']
)->toArray();
} 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(),
'remoteEventId' => $notification['resource'],
]);
@ -82,7 +82,7 @@ class CalendarRangeSyncer
$lastModified = RemoteEventConverter::convertStringDateWithTimezone($new['lastModifiedDateTime']);
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(),
'remoteEventId' => $notification['resource'],
]);

View File

@ -79,7 +79,7 @@ class CalendarSyncer
$notification['resource']
)->toArray();
} 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(),
'remoteEventId' => $notification['resource'],
]);
@ -96,7 +96,7 @@ class CalendarSyncer
);
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(),
'remoteEventId' => $notification['resource'],
]);

View File

@ -190,23 +190,17 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
]
)->toArray();
$ids = array_map(static function ($item) {
return $item['id'];
}, $bareEvents['value']);
$ids = array_map(static fn ($item) => $item['id'], $bareEvents['value']);
$existingIdsInRange = $this->calendarRangeRepository->findRemoteIdsPresent($ids);
$existingIdsInCalendar = $this->calendarRepository->findRemoteIdsPresent($ids);
return array_values(
array_map(
function ($item) {
return $this->remoteEventConverter->convertToRemote($item);
},
fn ($item) => $this->remoteEventConverter->convertToRemote($item),
// filter all event to keep only the one not in range
array_filter(
$bareEvents['value'],
static function ($item) use ($existingIdsInRange, $existingIdsInCalendar) {
return ((!$existingIdsInRange[$item['id']]) ?? true) && ((!$existingIdsInCalendar[$item['id']]) ?? true);
}
static fn ($item) => ((!$existingIdsInRange[$item['id']]) ?? true) && ((!$existingIdsInCalendar[$item['id']]) ?? true)
)
)
);
@ -604,9 +598,7 @@ class MSGraphRemoteCalendarConnector implements RemoteCalendarConnectorInterface
}
$this->cacheScheduleTimeForUser[$userId] = array_map(
function ($item) {
return $this->remoteEventConverter->convertAvailabilityToRemoteEvent($item);
},
fn ($item) => $this->remoteEventConverter->convertAvailabilityToRemoteEvent($item),
$response['value'][0]['scheduleItems']
);

View File

@ -66,6 +66,6 @@ class BulkCalendarShortMessageSender
$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]);
}
}

View File

@ -114,12 +114,8 @@ final class CalendarTypeTest extends TypeTestCase
$this->assertEquals(8, $calendar->getCalendarRange()->getId());
$this->assertEquals(9, $calendar->getLocation()->getId());
$this->assertEquals(true, $calendar->getSendSMS());
$this->assertContains(2, $calendar->getUsers()->map(static function (User $u) {
return $u->getId();
}));
$this->assertContains(3, $calendar->getUsers()->map(static function (User $u) {
return $u->getId();
}));
$this->assertContains(2, $calendar->getUsers()->map(static fn (User $u) => $u->getId()));
$this->assertContains(3, $calendar->getUsers()->map(static fn (User $u) => $u->getId()));
}
protected function getExtensions()
@ -148,25 +144,17 @@ final class CalendarTypeTest extends TypeTestCase
) {
$transformer = $this->prophesize($classTransformer);
$transformer->transform(Argument::type('array'))
->will(static function ($args) {
return implode(
',',
array_map(static function ($p) {
return $p->getId();
}, $args[0])
);
});
->will(static fn ($args) => implode(
',',
array_map(static fn ($p) => $p->getId(), $args[0])
));
$transformer->transform(Argument::exact(null))
->willReturn([]);
$transformer->transform(Argument::type(Collection::class))
->will(static function ($args) {
return implode(
',',
array_map(static function ($p) {
return $p->getId();
}, $args[0]->toArray())
);
});
->will(static fn ($args) => implode(
',',
array_map(static fn ($p) => $p->getId(), $args[0]->toArray())
));
$transformer->reverseTransform(Argument::type('string'))
->will(static function ($args) use ($objClass) {
if (null === $args[0]) {
@ -195,9 +183,7 @@ final class CalendarTypeTest extends TypeTestCase
) {
$transformer = $this->prophesize($classTransformer);
$transformer->transform(Argument::type('object'))
->will(static function ($args) {
return (string) $args[0]->getId();
});
->will(static fn ($args) => (string) $args[0]->getId());
$transformer->transform(Argument::exact(null))
->willReturn('');
$transformer->reverseTransform(Argument::type('string'))

View File

@ -63,9 +63,7 @@ final class AddressConverterTest extends TestCase
{
$engine = $this->prophesize(EngineInterface::class);
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($args): string {
return ($args[0] ?? ['fr' => 'not provided'])['fr'] ?? 'not provided';
});
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($args): string => ($args[0] ?? ['fr' => 'not provided'])['fr'] ?? 'not provided');
$addressRender = new AddressRender($engine->reveal(), $translatableStringHelper->reveal());

View File

@ -72,17 +72,13 @@ final class CalendarForShortMessageProviderTest extends TestCase
Argument::type(DateTimeImmutable::class),
Argument::type('int'),
Argument::exact(0)
)->will(static function ($args) {
return array_fill(0, $args[2], new Calendar());
})->shouldBeCalledTimes(1);
)->will(static fn ($args) => array_fill(0, $args[2], new Calendar()))->shouldBeCalledTimes(1);
$calendarRepository->findByNotificationAvailable(
Argument::type(DateTimeImmutable::class),
Argument::type(DateTimeImmutable::class),
Argument::type('int'),
Argument::not(0)
)->will(static function ($args) {
return array_fill(0, $args[2] - 1, new Calendar());
})->shouldBeCalledTimes(1);
)->will(static fn ($args) => array_fill(0, $args[2] - 1, new Calendar()))->shouldBeCalledTimes(1);
$em = $this->prophesize(EntityManagerInterface::class);
$em->clear()->shouldBeCalled();
@ -108,17 +104,13 @@ final class CalendarForShortMessageProviderTest extends TestCase
Argument::type(DateTimeImmutable::class),
Argument::type('int'),
Argument::exact(0)
)->will(static function ($args) {
return array_fill(0, 1, new Calendar());
})->shouldBeCalledTimes(1);
)->will(static fn ($args) => array_fill(0, 1, new Calendar()))->shouldBeCalledTimes(1);
$calendarRepository->findByNotificationAvailable(
Argument::type(DateTimeImmutable::class),
Argument::type(DateTimeImmutable::class),
Argument::type('int'),
Argument::not(0)
)->will(static function ($args) {
return [];
})->shouldBeCalledTimes(1);
)->will(static fn ($args) => [])->shouldBeCalledTimes(1);
$em = $this->prophesize(EntityManagerInterface::class);
$em->clear()->shouldBeCalled();

View File

@ -192,9 +192,7 @@ class CreateFieldsOnGroupCommand extends Command
foreach ($languages as $lang) {
//todo replace with service to find lang when available
$names[] = (isset($cf->getName()[$lang])) ?
$cf->getName()[$lang] :
'Not available in this language';
$names[] = $cf->getName()[$lang] ?? 'Not available in this language';
}
if ($this->validator->validate($cf)) {
@ -249,9 +247,7 @@ class CreateFieldsOnGroupCommand extends Command
foreach ($languages as $lang) {
//todo replace with service to find lang when available
$row[] = (isset($customFieldGroup->getName()[$lang])) ?
$customFieldGroup->getName()[$lang] :
'Not available in this language';
$row[] = $customFieldGroup->getName()[$lang] ?? 'Not available in this language';
}
$rows[] = $row;
}

View File

@ -294,7 +294,7 @@ class CustomFieldChoice extends AbstractCustomField
public function render($value, CustomField $customField, $documentType = 'html')
{
//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];
$choices = $customField->getOptions()[self::CHOICES];

View File

@ -58,9 +58,7 @@ class CustomFieldLongChoice extends AbstractCustomField
$translatableStringHelper = $this->translatableStringHelper;
$builder->add($customField->getSlug(), Select2ChoiceType::class, [
'choices' => $entries,
'choice_label' => static function (Option $option) use ($translatableStringHelper) {
return $translatableStringHelper->localize($option->getText());
},
'choice_label' => static fn (Option $option) => $translatableStringHelper->localize($option->getText()),
'choice_value' => static fn (Option $key): ?int => null === $key ? null : $key->getId(),
'multiple' => false,
'expanded' => false,

View File

@ -104,7 +104,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
$manager->persist($parent);
//Load children
$expected_nb_children = mt_rand(10, 50);
$expected_nb_children = random_int(10, 50);
for ($i = 0; $i < $expected_nb_children; ++$i) {
$companyName = $this->fakerFr->company;
@ -144,7 +144,7 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface
$manager->persist($parent);
//Load children
$expected_nb_children = mt_rand(10, 50);
$expected_nb_children = random_int(10, 50);
for ($i = 0; $i < $expected_nb_children; ++$i) {
$manager->persist($this->createChildOption($parent, [

View File

@ -25,7 +25,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_custom_fields');
$rootNode = $treeBuilder->getRootNode('chill_custom_fields');
$rootNode = $treeBuilder->getRootNode();
$classInfo = 'The class which may receive custom fields';
$nameInfo = 'The name which will appears in the user interface. May be translatable';

View File

@ -57,8 +57,6 @@ class OptionRepository extends EntityRepository
->getQuery()
->getScalarResult();
return array_map(static function ($r) {
return $r['key'];
}, $keys);
return array_map(static fn ($r) => $r['key'], $keys);
}
}

View File

@ -70,9 +70,7 @@ class CustomFieldType extends AbstractType
if ('entity' === $options['group_widget']) {
$builder->add('customFieldsGroup', EntityType::class, [
'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup',
'choice_label' => function ($g) {
return $this->translatableStringHelper->localize($g->getName());
},
'choice_label' => fn ($g) => $this->translatableStringHelper->localize($g->getName()),
]);
} elseif ('hidden' === $options['group_widget']) {
$builder->add('customFieldsGroup', HiddenType::class);
@ -119,7 +117,7 @@ class CustomFieldType extends AbstractType
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField',
'data_class' => \Chill\CustomFieldsBundle\Entity\CustomField::class,
]);
$resolver->setRequired(['type', 'group_widget'])

View File

@ -38,9 +38,7 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface
// @TODO: in the array_map callback, CustomField::getLabel() does not exist. What do we do here?
$customFieldsLablels = array_map(
static function ($e) {
return $e->getLabel();
},
static fn ($e) => $e->getLabel(),
$customFields
);
@ -108,7 +106,7 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface
//echo json_encode($customFieldsArrayRet);
return json_encode($customFieldsArrayRet);
return json_encode($customFieldsArrayRet, JSON_THROW_ON_ERROR);
}
public function transform($customFieldsJSON)

View File

@ -38,7 +38,7 @@ class ChoicesListType extends AbstractType
$formData = $form->getData();
if (null === $formData['slug']) {
$slug = uniqid(mt_rand(), true);
$slug = uniqid(random_int(0, mt_getrandmax()), true);
$data['slug'] = $slug;
$event->setData($data);

View File

@ -49,7 +49,7 @@ class CustomFieldType extends AbstractType
{
$resolver
->setRequired(['group'])
->addAllowedTypes('group', ['Chill\CustomFieldsBundle\Entity\CustomFieldsGroup']);
->addAllowedTypes('group', [\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup::class]);
}
public function getBlockPrefix()

View File

@ -49,7 +49,7 @@ class CustomFieldsHelper
public function isEmptyValue(array $fields, CustomField $customField)
{
$slug = $customField->getSlug();
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
$rawValue = $fields[$slug] ?? null;
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
$deserializedValue = $customFieldType->deserialize($rawValue, $customField);
@ -71,7 +71,7 @@ class CustomFieldsHelper
public function renderCustomField(array $fields, CustomField $customField, $documentType = 'html')
{
$slug = $customField->getSlug();
$rawValue = (isset($fields[$slug])) ? $fields[$slug] : null;
$rawValue = $fields[$slug] ?? null;
$customFieldType = $this->provider->getCustomFieldByType($customField->getType());
return $customFieldType->render($rawValue, $customField, $documentType);

View File

@ -52,7 +52,7 @@ final class CustomFieldsGroupControllerTest extends WebTestCase
// Fill in the form and submit it
$form = $crawler->selectButton('Créer')->form([
'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);

View File

@ -34,12 +34,12 @@ trait CustomFieldTestHelper
$kernel = static::$kernel;
//check a kernel is accessible
$customFieldsGroup = $this->createMock('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup');
$customFieldsGroup = $this->createMock(\Chill\CustomFieldsBundle\Entity\CustomFieldsGroup::class);
$customFieldsGroup->expects($this->once())
->method('getActiveCustomFields')
->will($this->returnValue([$field]));
$request = $this->createMock('Symfony\Component\HttpFoundation\Request');
$request = $this->createMock(\Symfony\Component\HttpFoundation\Request::class);
$request->expects($this->any())
->method('getLocale')
->will($this->returnValue($locale));

View File

@ -41,11 +41,11 @@ final class CustomFieldsTextTest extends WebTestCase
$customField = $this->customFieldProvider->getCustomFieldByType('text');
$this->assertInstanceOf(
'Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface',
\Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface::class,
$customField
);
$this->assertInstanceOf(
'Chill\CustomFieldsBundle\CustomFields\CustomFieldText',
\Chill\CustomFieldsBundle\CustomFields\CustomFieldText::class,
$customField
);
}

View File

@ -46,7 +46,7 @@ final class CustomFieldRenderingTwigTest extends KernelTestCase
// set locale to fr
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend('Symfony\Component\HttpFoundation\Request');
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
self::$kernel->getContainer()->get('request_stack')
->push($request->reveal());

View File

@ -48,7 +48,7 @@ final class CustomFieldsGroupRenderingTwigTest extends KernelTestCase
// set locale to fr
$prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize();
$request->willExtend('Symfony\Component\HttpFoundation\Request');
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr');
self::$kernel->getContainer()->get('request_stack')
->push($request->reveal());

View File

@ -61,12 +61,8 @@ class DocGeneratorTemplateType extends AbstractType
$sub = $builder
->create('options', null, ['compound' => true])
->addModelTransformer(new CallbackTransformer(
static function (array $data) use ($context) {
return $context->adminFormTransform($data);
},
static function (array $data) use ($context) {
return $context->adminFormReverseTransform($data);
}
static fn (array $data) => $context->adminFormTransform($data),
static fn (array $data) => $context->adminFormReverseTransform($data)
));
$context->buildAdminForm($sub);
$builder->add($sub);

View File

@ -44,7 +44,7 @@ final class RelatorioDriver implements DriverInterface
{
$form = new FormDataPart(
[
'variables' => json_encode($data),
'variables' => json_encode($data, JSON_THROW_ON_ERROR),
'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType),
]
);
@ -61,7 +61,7 @@ final class RelatorioDriver implements DriverInterface
$content = $e->getResponse()->getContent(false);
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', [
'error' => $content['message'] ?? '_not defined',
]);

View File

@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
use ArrayObject;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ReadableCollection;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
@ -51,7 +52,9 @@ class CollectionDocGenNormalizer implements ContextAwareNormalizerInterface, Nor
return false;
}
return $data instanceof Collection
|| (null === $data && Collection::class === ($context['docgen:expects'] ?? null));
return $data instanceof ReadableCollection
|| (null === $data && Collection::class === ($context['docgen:expects'] ?? null))
|| (null === $data && ReadableCollection::class === ($context['docgen:expects'] ?? null))
;
}
}

View File

@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\Common\Collections\ReadableCollection;
use ReflectionClass;
use RuntimeException;
use Symfony\Component\PropertyAccess\PropertyAccess;
@ -271,6 +272,14 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte
if ($isTranslatable) {
$data[$key] = $this->translatableStringHelper
->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)) {
$arr = [];

View File

@ -17,6 +17,6 @@ class ObjectReadyException extends RuntimeException
{
public function __construct()
{
parent::__construct('object is already ready', 6698856);
parent::__construct('object is already ready', 6_698_856);
}
}

View File

@ -19,7 +19,7 @@ class RelatedEntityNotFoundException extends RuntimeException
{
parent::__construct(
sprintf('Related entity not found: %s, %s', $relatedEntityClass, $relatedEntityId),
99876652,
99_876_652,
$previous
);
}

View File

@ -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);
}
}

View File

@ -24,7 +24,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$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
// configure your bundle. See the documentation linked above for

View File

@ -58,7 +58,7 @@ class StoredObject implements AsyncFileInterface, Document, TrackCreationInterfa
* @ORM\Column(type="integer")
* @Serializer\Groups({"read", "write"})
*/
private ?int $id;
private ?int $id = null;
/**
* @var int[]
@ -94,7 +94,7 @@ class StoredObject implements AsyncFileInterface, Document, TrackCreationInterfa
/**
* @ORM\ManyToOne(targetEntity=DocGeneratorTemplate::class)
*/
private ?DocGeneratorTemplate $template;
private ?DocGeneratorTemplate $template = null;
/**
* @ORM\Column(type="text", options={"default": "ready"})

View File

@ -72,14 +72,10 @@ class AccompanyingCourseDocumentType extends AbstractType
->add('category', EntityType::class, [
'placeholder' => 'Choose a document category',
'class' => DocumentCategory::class,
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.documentClass = :docClass')
->setParameter('docClass', AccompanyingCourseDocument::class);
},
'choice_label' => function ($entity = null) {
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
},
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('c')
->where('c.documentClass = :docClass')
->setParameter('docClass', AccompanyingCourseDocument::class),
'choice_label' => fn ($entity = null) => $entity ? $this->translatableStringHelper->localize($entity->getName()) : '',
]);
}

View File

@ -67,14 +67,10 @@ class PersonDocumentType extends AbstractType
->add('category', EntityType::class, [
'placeholder' => 'Choose a document category',
'class' => DocumentCategory::class,
'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.documentClass = :docClass')
->setParameter('docClass', PersonDocument::class);
},
'choice_label' => function ($entity = null) {
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
},
'query_builder' => static fn (EntityRepository $er) => $er->createQueryBuilder('c')
->where('c.documentClass = :docClass')
->setParameter('docClass', PersonDocument::class),
'choice_label' => fn ($entity = null) => $entity ? $this->translatableStringHelper->localize($entity->getName()) : '',
]);
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