mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-07-03 07:26:12 +00:00
merge exports branch into calendar branch
This commit is contained in:
commit
8efb874742
@ -16,6 +16,8 @@ and this project adheres to
|
||||
* [person-thirdparty]: fix quick-add of names that consist of multiple parts (eg. De Vlieger) within onthefly modal person/thirdparty
|
||||
* [search]: Order of birthdate fields changed in advanced search to avoid confusion.
|
||||
* [workflow]: Constraint added to workflow (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/675)
|
||||
* [household]: Reposition and cut button for enfant hors menage have been deleted (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/620)
|
||||
* [admin]: Add crud for composition type in admin (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/611)
|
||||
|
||||
## Test releases
|
||||
|
||||
|
@ -10,10 +10,10 @@
|
||||
Exports
|
||||
*******
|
||||
|
||||
Export is an important issue for the Chill software : users should be able to :
|
||||
Export is an important issue within the Chill software : users should be able to :
|
||||
|
||||
- compute statistics about their activity ;
|
||||
- list "things" which make part of their activities.
|
||||
- list "things" which are a part of their activities.
|
||||
|
||||
The `main bundle`_ provides a powerful framework to build custom queries with re-usable parts across differents bundles.
|
||||
|
||||
@ -34,31 +34,31 @@ Some vocabulary: 3 "Export elements"
|
||||
|
||||
Four terms are used for this framework :
|
||||
|
||||
exports
|
||||
provides some basic operation on the date. Two kind of exports are available :
|
||||
Exports
|
||||
provide some basic operation on the data. Two kinds of exports are available :
|
||||
|
||||
- computed data : it may be "the number of people", "the number of activities", "the duration of activities", ...
|
||||
- list data : it may be "the list of people", "the list of activity", ...
|
||||
- list data : it may be "the list of people", "the list of activities", ...
|
||||
|
||||
filters
|
||||
The filters make a filter on the date: it removes some information the user doesn't want to introduce in the computation done by export. In other word, filters make a filter...
|
||||
Filters
|
||||
The filters create a filter on the data: it removes some information the user doesn't want to introduce in the computation done by the export.
|
||||
|
||||
Example of filter: "people under 18 years olds", "activities between the 1st of June and the 31st December", ...
|
||||
Example of a filter: "people under 18 years olds", "activities between the 1st of June and the 31st December", ...
|
||||
|
||||
aggregators
|
||||
Aggregators
|
||||
The aggregator aggregates the data into some group (some software use the term 'bucket').
|
||||
|
||||
Example of aggregator : "group people by gender", "group people by nationality", "group activity by type", ...
|
||||
Example of an aggregator : "group people by gender", "group people by nationality", "group activity by type", ...
|
||||
|
||||
formatters
|
||||
Formatters
|
||||
The formatters format the data into a :class:`Symfony\Component\HttpFoundation\Response`, which will be returned "as is" by the controller to the web client.
|
||||
|
||||
Example of formatter: "format data as CSV", "format data as ods spreadsheet", ...
|
||||
Example of a formatter: "format data as CSV", "format data as an ods spreadsheet", ...
|
||||
|
||||
Anatomy of an export
|
||||
---------------------
|
||||
|
||||
An export may be explained as a sentence, where each part of this sentence refers to one or multiple exports element. Examples :
|
||||
An export can be thought of as a sentence where each part of this sentence refers to one or multiple export elements. Examples :
|
||||
|
||||
**Example 1**: Count the number of people having at least one activity in the last 12 month, and group them by nationality and gender, and format them in a CSV spreadsheet.
|
||||
|
||||
@ -72,8 +72,8 @@ Here :
|
||||
|
||||
Note that :
|
||||
|
||||
- aggregators, filters, exports and aggregators are cross-bundle. Here the bundle *activity* provides a filter which apply on an export provided by the person bundle ;
|
||||
- there may exists multiple aggregator or filter for one export. Currently, only one export is allowed.
|
||||
- Aggregators, filters, exports and formatters are cross-bundle. Here the bundle *activity* provides a filter which is applied on an export provided by the person bundle ;
|
||||
- Multiple aggregator or filter for one export may exist. Currently, only one export is allowed.
|
||||
|
||||
The result might be :
|
||||
|
||||
@ -89,7 +89,7 @@ The result might be :
|
||||
| France | Female | 150 |
|
||||
+-----------------------+----------------+---------------------------+
|
||||
|
||||
**Example 2**: Count the average duration of an activity with type "meeting", which occurs between the 1st of June and the 31st of December, group them by week, and format the data in a OpenDocument spreadsheet.
|
||||
**Example 2**: Count the average duration of an activity with type "meeting", which occurs between the 1st of June and the 31st of December, group them by week, and format the data in an OpenDocument spreadsheet.
|
||||
|
||||
Here :
|
||||
|
||||
@ -116,13 +116,13 @@ The result might be :
|
||||
Authorization and exports
|
||||
-------------------------
|
||||
|
||||
Exports, filters and aggregators should not make see data the user is not allowed to see.
|
||||
Exports, filters and aggregators should not show data the user is not allowed to see within the application.
|
||||
|
||||
In other words, developers are required to take care of user authorization for each export.
|
||||
|
||||
It should exists a special role that should be granted to users which are allowed to build exports. For more simplicity, this role should apply on center, and should not requires special circles.
|
||||
There should be a specific role that grants permission to users who are allowed to build exports. For more simplicity, this role should apply on a center, and should not require special circles.
|
||||
|
||||
How does the magic works ?
|
||||
How does the magic work ?
|
||||
===========================
|
||||
|
||||
To build an export, we rely on the capacity of the database to execute queries with aggregate (i.e. GROUP BY) and filter (i.e. WHERE) instructions.
|
||||
@ -133,13 +133,13 @@ An export is an SQL query which is initiated by an export, and modified by aggre
|
||||
|
||||
**Example**: Count the number of people having at least one activity in the last 12 month, and group them by nationality and gender
|
||||
|
||||
1. The report initiate the query
|
||||
1. The report initiates the query
|
||||
|
||||
.. code-block:: SQL
|
||||
|
||||
SELECT count(people.*) FROM people
|
||||
|
||||
2. The filter add a where and join clause :
|
||||
2. The filter adds a where and join clause :
|
||||
|
||||
.. code-block:: SQL
|
||||
|
||||
@ -147,7 +147,7 @@ An export is an SQL query which is initiated by an export, and modified by aggre
|
||||
RIGHT JOIN activity
|
||||
WHERE activity.date IS BETWEEN now AND 6 month ago
|
||||
|
||||
3. The aggregator "nationality" add a GROUP BY clause and a column in the SELECT statement:
|
||||
3. The aggregator "nationality" adds a GROUP BY clause and a column in the SELECT statement:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
@ -156,7 +156,7 @@ An export is an SQL query which is initiated by an export, and modified by aggre
|
||||
WHERE activity.date IS BETWEEN now AND 6 month ago
|
||||
GROUP BY nationality
|
||||
|
||||
4. The aggregator "gender" do the same job as the nationality aggregator : it adds a GROUP BY clause and a column in the SELECT statement :
|
||||
4. The aggregator "gender" does the same job as the nationality aggregator : it adds a GROUP BY clause and a column in the SELECT statement :
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
@ -165,28 +165,28 @@ An export is an SQL query which is initiated by an export, and modified by aggre
|
||||
WHERE activity.date IS BETWEEN now AND 6 month ago
|
||||
GROUP BY nationality, gender
|
||||
|
||||
Each filter, aggregator and filter may collect parameters from the user by providing a form. This form is appended to the export form. Here is an example.
|
||||
Each filter, aggregator and filter may collect parameters from the user through a form. This form is appended to the export form. Here is an example.
|
||||
|
||||
.. figure:: /_static/screenshots/development/export_form-fullpage.png
|
||||
|
||||
The screenshot show the export form for ``CountPeople`` (Nombre de personnes). The filter by date of birth is checked (*Filtrer par date de naissance de la personne*), which allow to show a subform, which is provided by the :class:`Chill\PersonBundle\Export\Filter\BirthdateFilter`. The other filter, which are unchecked, does not show the subform.
|
||||
The screenshot shows the export form for ``CountPeople`` (Nombre de personnes). The filter by date of birth is checked (*Filtrer par date de naissance de la personne*), which triggers a subform, which is provided by the :class:`Chill\PersonBundle\Export\Filter\BirthdateFilter`. The other unchecked filter does not show the subform.
|
||||
|
||||
Two aggregators are also checked : by Country of birth (*Aggréger les personnes par pays de naissance*, corresponding class is :class:`Chill\PersonBundle\Export\Aggregator\CountryOfBirthAggregator`, which also open a subform. The aggregator by gender (*Aggréger les personnes par genre*) is also checked, but there is no corresponding subform.
|
||||
Two aggregators are also checked : by Country of birth (*Aggréger les personnes par pays de naissance*, the corresponding class is :class:`Chill\PersonBundle\Export\Aggregator\CountryOfBirthAggregator`, which also triggers a subform. The aggregator by gender (*Aggréger les personnes par genre*) is also checked, but there is no corresponding subform.
|
||||
|
||||
The Export Manager
|
||||
------------------
|
||||
|
||||
The Export manager (:class:`Chill\MainBundle\Export\ExportManager` is the central class which register all exports, aggregators, filters and formatters.
|
||||
The Export manager (:class:`Chill\MainBundle\Export\ExportManager` is the central class which registers all exports, aggregators, filters and formatters.
|
||||
|
||||
The export manager is also responsible for orchestrating the whole export process, producing a :class:`Symfony\FrameworkBundle\HttpFoundation\Request` to each export request.
|
||||
The export manager is also responsible for orchestrating the whole export process, producing a :class:`Symfony\FrameworkBundle\HttpFoundation\Request` for each export request.
|
||||
|
||||
|
||||
The export form step
|
||||
--------------------
|
||||
|
||||
The form step allow to build a form, aggregating different parts of the module.
|
||||
The form step allows you to build a form, combining different parts of the module.
|
||||
|
||||
The building of forms is separated between different subform, which are responsible for rendering their part of the form (aggregators, filters, and export).
|
||||
The building of forms is split into different subforms, where each one is responsible for rendering their part of the form (aggregators, filters, and export).
|
||||
|
||||
.. figure:: /_static/puml/exports/form_steps.png
|
||||
:scale: 40%
|
||||
@ -194,12 +194,12 @@ The building of forms is separated between different subform, which are responsi
|
||||
The formatter form step
|
||||
-----------------------
|
||||
|
||||
The formatter form is processed *after* the user filled the export form. It is built the same way, but receive in parameters the data entered by the user on the previous step (i.e. export form). It may then adapt it accordingly (example: show a list of columns selected in aggregators).
|
||||
The formatter form is processed *after* the user filled the export form. It is built the same way, but receives the data entered by the user on the previous step as parameters (i.e. export form). It may then adapt it accordingly (example: show a list of columns selected in aggregators).
|
||||
|
||||
Processing the export
|
||||
---------------------
|
||||
|
||||
The export process may be explained by this schema :
|
||||
The export process can be explained by this schema :
|
||||
|
||||
.. figure:: /_static/puml/exports/processing_export.png
|
||||
:scale: 40%
|
||||
@ -219,20 +219,20 @@ This is an example of the ``CountPerson`` export :
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
* **Line 36**: the ``getType`` function return a string. This string will be used to find the aggregtors and filters which will apply to this export.
|
||||
* **Line 41**: a simple description to help user to understand what your export does.
|
||||
* **Line 36**: the ``getType`` function returns a string. This string will be used to find the aggregtors and filters which will apply to this export.
|
||||
* **Line 41**: a simple description to help users understand what your export does.
|
||||
* **Line 46**: The title of the export. A summary of what your export does.
|
||||
* **Line 51**: The list of roles requires to execute this export.
|
||||
* **Line 51**: The list of roles required to execute this export.
|
||||
* **Line 56**: We initiate the query here...
|
||||
* **Line 59**: We have to filter the query with centers the users checked in the form. We process the $acl variable to get all ``Center`` object in one array
|
||||
* **Line 63**: We create the query, with a query builder.
|
||||
* **Line 74**: We simply returns the result, but take care of hydrating the results as an array.
|
||||
* **Line 103**: return the list of formatters types which are allowed to apply on this filter
|
||||
* **Line 59**: We have to filter the query with centers the users checked in the form. We process the $acl variable to get all ``Center`` objects in one array
|
||||
* **Line 63**: We create the query with a query builder.
|
||||
* **Line 74**: We return the result, but make sure to hydrate the results as an array.
|
||||
* **Line 103**: return the list of formatter types which are allowed to be applied on this filter
|
||||
|
||||
Filters
|
||||
-------
|
||||
|
||||
This is an example of the *filter by birthdate*. This filter ask some information in a form (`buildForm` is not empty), and this form must be validated. To performs this validations, we implement a new Interface: :class:`Chill\MainBundle\Export\ExportElementValidatedInterface`:
|
||||
This is an example of the *filter by birthdate*. This filter asks some information through a form (`buildForm` is not empty), and this form must be validated. To perform this validation, we implement a new Interface: :class:`Chill\MainBundle\Export\ExportElementValidatedInterface`:
|
||||
|
||||
.. literalinclude:: /_static/code/exports/BirthdateFilter.php
|
||||
:language: php
|
||||
|
@ -24,6 +24,7 @@ parameters:
|
||||
- "/spec/"
|
||||
- "/var/"
|
||||
- "/vendor/"
|
||||
- "/tests/app"
|
||||
|
||||
# Psalm
|
||||
tasks.psalm.blocking: true
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,16 +25,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#"
|
||||
count: 3
|
||||
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
|
||||
count: 2
|
||||
path: src/Bundle/ChillActivityBundle/Form/ActivityType.php
|
||||
|
||||
-
|
||||
message: "#^Only booleans are allowed in an if condition, mixed given\\.$#"
|
||||
count: 3
|
||||
|
@ -22,6 +22,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
||||
use Chill\MainBundle\Repository\LocationRepository;
|
||||
use Chill\MainBundle\Repository\UserRepositoryInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Privacy\PrivacyEvent;
|
||||
@ -41,7 +42,6 @@ use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use function array_key_exists;
|
||||
|
||||
@ -57,6 +57,8 @@ final class ActivityController extends AbstractController
|
||||
|
||||
private ActivityTypeRepository $activityTypeRepository;
|
||||
|
||||
private CenterResolverManagerInterface $centerResolver;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private EventDispatcherInterface $eventDispatcher;
|
||||
@ -86,7 +88,9 @@ final class ActivityController extends AbstractController
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
LoggerInterface $logger,
|
||||
SerializerInterface $serializer,
|
||||
UserRepositoryInterface $userRepository
|
||||
UserRepositoryInterface $userRepository,
|
||||
CenterResolverManagerInterface $centerResolver
|
||||
|
||||
) {
|
||||
$this->activityACLAwareRepository = $activityACLAwareRepository;
|
||||
$this->activityTypeRepository = $activityTypeRepository;
|
||||
@ -101,6 +105,8 @@ final class ActivityController extends AbstractController
|
||||
$this->logger = $logger;
|
||||
$this->serializer = $serializer;
|
||||
$this->userRepository = $userRepository;
|
||||
$this->centerResolver = $centerResolver;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,7 +209,7 @@ final class ActivityController extends AbstractController
|
||||
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
|
||||
|
||||
$form = $this->createForm(ActivityType::class, $entity, [
|
||||
'center' => $entity->getCenter(),
|
||||
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
|
||||
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
|
||||
'activityType' => $entity->getActivityType(),
|
||||
'accompanyingPeriod' => $accompanyingPeriod,
|
||||
@ -431,7 +437,7 @@ final class ActivityController extends AbstractController
|
||||
$this->denyAccessUnlessGranted(ActivityVoter::CREATE, $entity);
|
||||
|
||||
$form = $this->createForm(ActivityType::class, $entity, [
|
||||
'center' => $entity->getCenter(),
|
||||
'center' => $this->centerResolver->resolveCenters($entity)[0] ?? null,
|
||||
'role' => new Role('CHILL_ACTIVITY_CREATE'),
|
||||
'activityType' => $entity->getActivityType(),
|
||||
'accompanyingPeriod' => $accompanyingPeriod,
|
||||
|
@ -61,8 +61,6 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
|
||||
ActivityVoter::DELETE => [ActivityVoter::SEE_DETAILS],
|
||||
ActivityVoter::SEE_DETAILS => [ActivityVoter::SEE],
|
||||
ActivityVoter::FULL => [
|
||||
ActivityVoter::CREATE_PERSON,
|
||||
ActivityVoter::CREATE_ACCOMPANYING_COURSE,
|
||||
ActivityVoter::DELETE,
|
||||
ActivityVoter::UPDATE,
|
||||
],
|
||||
|
@ -16,8 +16,8 @@ use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
||||
use Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable;
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
use Chill\MainBundle\Entity\HasScopeInterface;
|
||||
use Chill\MainBundle\Entity\HasCentersInterface;
|
||||
use Chill\MainBundle\Entity\HasScopesInterface;
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
@ -55,7 +55,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
* getUserFunction="getUser",
|
||||
* path="scope")
|
||||
*/
|
||||
class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface, HasCenterInterface, HasScopeInterface
|
||||
class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface, HasCentersInterface, HasScopesInterface
|
||||
{
|
||||
public const SENTRECEIVED_RECEIVED = 'received';
|
||||
|
||||
@ -306,13 +306,17 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
* get the center
|
||||
* center is extracted from person.
|
||||
*/
|
||||
public function getCenter(): ?Center
|
||||
public function getCenters(): iterable
|
||||
{
|
||||
if ($this->person instanceof Person) {
|
||||
return $this->person->getCenter();
|
||||
return [$this->person->getCenter()];
|
||||
}
|
||||
|
||||
return null;
|
||||
if ($this->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
||||
return $this->getAccompanyingPeriod()->getCenters() ?? [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getComment(): CommentEmbeddable
|
||||
@ -422,6 +426,19 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function getScopes(): iterable
|
||||
{
|
||||
if (null !== $this->getAccompanyingPeriod()) {
|
||||
return $this->getAccompanyingPeriod()->getScopes();
|
||||
}
|
||||
|
||||
if (null !== $this->getPerson()) {
|
||||
return [$this->scope];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getSentReceived(): string
|
||||
{
|
||||
return $this->sentReceived;
|
||||
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
|
||||
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class BySocialActionAggregator implements AggregatorInterface
|
||||
{
|
||||
private SocialActionRender $actionRender;
|
||||
|
||||
private SocialActionRepository $actionRepository;
|
||||
|
||||
public function __construct(
|
||||
SocialActionRender $actionRender,
|
||||
SocialActionRepository $actionRepository
|
||||
) {
|
||||
$this->actionRender = $actionRender;
|
||||
$this->actionRepository = $actionRepository;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('socialaction', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.socialActions', 'socialaction');
|
||||
}
|
||||
|
||||
$qb->addSelect('socialaction.id AS socialaction_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('socialaction_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('socialaction_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'Social action';
|
||||
}
|
||||
|
||||
$sa = $this->actionRepository->find($value);
|
||||
|
||||
return $this->actionRender->renderString($sa, []);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['socialaction_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by linked socialaction';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
|
||||
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class BySocialIssueAggregator implements AggregatorInterface
|
||||
{
|
||||
private SocialIssueRender $issueRender;
|
||||
|
||||
private SocialIssueRepository $issueRepository;
|
||||
|
||||
public function __construct(
|
||||
SocialIssueRepository $issueRepository,
|
||||
SocialIssueRender $issueRender
|
||||
) {
|
||||
$this->issueRepository = $issueRepository;
|
||||
$this->issueRender = $issueRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('socialissue', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.socialIssues', 'socialissue');
|
||||
}
|
||||
|
||||
$qb->addSelect('socialissue.id AS socialissue_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('socialissue_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('socialissue_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Social issues';
|
||||
}
|
||||
|
||||
$i = $this->issueRepository->find($value);
|
||||
|
||||
return $this->issueRender->renderString($i, []);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['socialissue_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by linked socialissue';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
|
||||
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class ByThirdpartyAggregator implements AggregatorInterface
|
||||
{
|
||||
private ThirdPartyRender $thirdPartyRender;
|
||||
|
||||
private ThirdPartyRepository $thirdPartyRepository;
|
||||
|
||||
public function __construct(
|
||||
ThirdPartyRepository $thirdPartyRepository,
|
||||
ThirdPartyRender $thirdPartyRender
|
||||
) {
|
||||
$this->thirdPartyRepository = $thirdPartyRepository;
|
||||
$this->thirdPartyRender = $thirdPartyRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('thirdparty', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.thirdParties', 'thirdparty');
|
||||
}
|
||||
|
||||
$qb->addSelect('thirdparty.id AS thirdparty_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('thirdparty_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('thirdparty_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Accepted thirdparty';
|
||||
}
|
||||
|
||||
$tp = $this->thirdPartyRepository->find($value);
|
||||
|
||||
return $this->thirdPartyRender->renderString($tp, []);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['thirdparty_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by linked thirdparties';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class ByUserAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
UserRepository $userRepository,
|
||||
UserRender $userRender
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('user', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.users', 'user');
|
||||
}
|
||||
|
||||
$qb->addSelect('user.id AS users_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('users_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('users_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Accepted users';
|
||||
}
|
||||
|
||||
$u = $this->userRepository->find($value);
|
||||
|
||||
return $this->userRender->renderString($u, []);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['users_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by linked users';
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class DateAggregator implements AggregatorInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'by month' => 'month',
|
||||
'by week' => 'week',
|
||||
'by year' => 'year',
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = 'year';
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$order = null;
|
||||
|
||||
switch ($data['frequency']) {
|
||||
case 'month':
|
||||
$fmt = 'MM';
|
||||
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
$fmt = 'IW';
|
||||
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
$fmt = 'YYYY'; $order = 'DESC';
|
||||
|
||||
break; // order DESC does not works !
|
||||
|
||||
default:
|
||||
throw new RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf("TO_CHAR(activity.date, '%s') AS date_aggregator", $fmt));
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('date_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('date_aggregator');
|
||||
}
|
||||
|
||||
$orderBy = $qb->getDQLPart('orderBy');
|
||||
|
||||
if (!empty($orderBy)) {
|
||||
$qb->addOrderBy('date_aggregator', $order);
|
||||
} else {
|
||||
$qb->orderBy('date_aggregator', $order);
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('frequency', ChoiceType::class, [
|
||||
'choices' => self::CHOICES,
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
'empty_data' => self::DEFAULT_CHOICE,
|
||||
'data' => self::DEFAULT_CHOICE,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return static function ($value) use ($data): string {
|
||||
if ('_header' === $value) {
|
||||
return 'by ' . $data['frequency'];
|
||||
}
|
||||
|
||||
switch ($data['frequency']) {
|
||||
case 'month':
|
||||
$month = DateTime::createFromFormat('!m', $value);
|
||||
|
||||
return sprintf(
|
||||
'%02d (%s)',
|
||||
$value,
|
||||
$month->format('M')
|
||||
);
|
||||
|
||||
case 'week':
|
||||
//return $this->translator->trans('for week') .' '. $value ;
|
||||
|
||||
case 'year':
|
||||
//return $this->translator->trans('in year') .' '. $value ;
|
||||
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['date_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by date';
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\LocationTypeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class LocationTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
private LocationTypeRepository $locationTypeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
LocationTypeRepository $locationTypeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->locationTypeRepository = $locationTypeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('location', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.location', 'location');
|
||||
}
|
||||
|
||||
$qb->addSelect('IDENTITY(location.locationType) AS locationtype_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('locationtype_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('locationtype_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Accepted locationtype';
|
||||
}
|
||||
|
||||
$lt = $this->locationTypeRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$lt->getTitle()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['locationtype_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by locationtype';
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\ACPAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class UserScopeAggregator implements AggregatorInterface
|
||||
{
|
||||
private ScopeRepository $scopeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ScopeRepository $scopeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('user', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.user', 'user');
|
||||
}
|
||||
|
||||
$qb->addSelect('IDENTITY(user.mainScope) AS userscope_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('userscope_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('userscope_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Scope';
|
||||
}
|
||||
|
||||
$s = $this->scopeRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['userscope_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group activity by userscope';
|
||||
}
|
||||
}
|
@ -11,15 +11,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Closure;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use function in_array;
|
||||
|
||||
class ActivityTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
@ -37,23 +37,31 @@ class ActivityTypeAggregator implements AggregatorInterface
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
// add select element
|
||||
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
|
||||
if (!in_array('type', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.activityType', 'type');
|
||||
}
|
||||
|
||||
// add the "group by" part
|
||||
$qb->addGroupBy(self::KEY);
|
||||
$qb->addSelect(sprintf('IDENTITY(activity.activityType) AS %s', self::KEY));
|
||||
|
||||
$groupby = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy(self::KEY);
|
||||
} else {
|
||||
$qb->groupBy(self::KEY);
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
|
@ -11,29 +11,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator;
|
||||
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
class ActivityUserAggregator implements AggregatorInterface
|
||||
{
|
||||
public const KEY = 'activity_user_id';
|
||||
|
||||
private UserRender $userRender;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
UserRepository $userRepository
|
||||
UserRepository $userRepository,
|
||||
UserRender $userRender
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
@ -47,7 +51,7 @@ class ActivityUserAggregator implements AggregatorInterface
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
@ -62,10 +66,12 @@ class ActivityUserAggregator implements AggregatorInterface
|
||||
|
||||
return function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'activity user';
|
||||
return 'Activity user';
|
||||
}
|
||||
|
||||
return $this->userRepository->find($value)->getUsername();
|
||||
$u = $this->userRepository->find($value);
|
||||
|
||||
return $this->userRender->renderString($u, []);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Aggregator;
|
||||
namespace Chill\ActivityBundle\Export\Aggregator\PersonAggregators;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository;
|
||||
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
@ -23,7 +23,6 @@ use Doctrine\ORM\QueryBuilder;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
use function array_key_exists;
|
||||
@ -47,9 +46,9 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
@ -104,9 +103,9 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY_PERSON;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
24
src/Bundle/ChillActivityBundle/Export/Declarations.php
Normal file
24
src/Bundle/ChillActivityBundle/Export/Declarations.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export;
|
||||
|
||||
/**
|
||||
* This class declare constants used for the export framework.
|
||||
*/
|
||||
abstract class Declarations
|
||||
{
|
||||
public const ACTIVITY = 'activity';
|
||||
|
||||
public const ACTIVITY_ACP = 'activity_linked_to_acp';
|
||||
|
||||
public const ACTIVITY_PERSON = 'activity_linked_to_person';
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AvgActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->repository = $em->getRepository(Activity::class);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// TODO: Implement buildForm() method.
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Average activities linked to an accompanying period duration by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_avg_activity_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period duration' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_avg_activity_duration'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Average activity linked to an accompanying period duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('AVG(activity.durationTime) as export_avg_activity_duration');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_ACP,
|
||||
//PersonDeclarations::ACP_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AvgActivityVisitDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->repository = $em->getRepository(Activity::class);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// TODO: Implement buildForm() method.
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Average activities linked to an accompanying period visit duration by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_avg_activity_visit_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Average activities linked to an accompanying period visit duration' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_avg_activity_visit_duration'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Average activity linked to an accompanying period visit duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('AVG(activity.travelTime) as export_avg_activity_visit_duration');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_ACP,
|
||||
//PersonDeclarations::ACP_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class CountActivity implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->repository = $em->getRepository(Activity::class);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Count activities linked to an accompanying period by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_count_activity' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Number of activities linked to an accompanying period' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_count_activity'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Count activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('COUNT(activity.id) as export_count_activity');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_ACP,
|
||||
//PersonDeclarations::ACP_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class SumActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->repository = $em->getRepository(Activity::class);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// TODO: Implement buildForm() method.
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Sum activities linked to an accompanying period duration by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_sum_activity_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period duration' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_sum_activity_duration'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Sum activity linked to an accompanying period duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('SUM(activity.durationTime) as export_sum_activity_duration');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_ACP,
|
||||
//PersonDeclarations::ACP_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToACP;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class SumActivityVisitDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityRepository $repository;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->repository = $em->getRepository(Activity::class);
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// TODO: Implement buildForm() method.
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Sum activities linked to an accompanying period visit duration by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to an accompanying period';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_sum_activity_visit_duration' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Sum activities linked to an accompanying period visit duration' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_sum_activity_visit_duration'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Sum activity linked to an accompanying period visit duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('activity')
|
||||
->join('activity.accompanyingPeriod', 'acp');
|
||||
|
||||
$qb->select('SUM(activity.travelTime) as export_sum_activity_visit_duration');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_ACP,
|
||||
//PersonDeclarations::ACP_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -9,18 +9,20 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export;
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\Query;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
class CountActivity implements ExportInterface
|
||||
class CountActivity implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
protected ActivityRepository $activityRepository;
|
||||
|
||||
@ -41,7 +43,12 @@ class CountActivity implements ExportInterface
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Count activities by various parameters.';
|
||||
return 'Count activities linked to a person by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to a person';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
@ -50,7 +57,7 @@ class CountActivity implements ExportInterface
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Number of activities' : $value;
|
||||
return static fn ($value) => '_header' === $value ? 'Number of activities linked to a person' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
@ -65,24 +72,23 @@ class CountActivity implements ExportInterface
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Count activities';
|
||||
return 'Count activities linked to a person';
|
||||
}
|
||||
|
||||
public function getType()
|
||||
public function getType(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this
|
||||
->activityRepository
|
||||
->createQueryBuilder('activity')
|
||||
->select('COUNT(activity.id) as export_count_activity')
|
||||
$qb = $this->activityRepository->createQueryBuilder('activity')
|
||||
->join('activity.person', 'person');
|
||||
|
||||
$qb->select('COUNT(activity.id) as export_count_activity');
|
||||
|
||||
$qb
|
||||
->where($qb->expr()->in('person.center', ':centers'))
|
||||
->setParameter('centers', $centers);
|
||||
@ -90,13 +96,17 @@ class CountActivity implements ExportInterface
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole()
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return ['person', 'activity'];
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_PERSON,
|
||||
//PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -9,21 +9,23 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export;
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
|
||||
|
||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\MainBundle\Export\ListInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use DateTime;
|
||||
use Doctrine\DBAL\Exception\InvalidArgumentException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Validator\Constraints\Callback;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
@ -32,7 +34,7 @@ use function array_key_exists;
|
||||
use function count;
|
||||
use function in_array;
|
||||
|
||||
class ListActivity implements ListInterface
|
||||
class ListActivity implements ListInterface, GroupedExportInterface
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
@ -94,7 +96,12 @@ class ListActivity implements ListInterface
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'List activities';
|
||||
return 'List activities linked to a person description';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to a person';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
@ -180,12 +187,12 @@ class ListActivity implements ListInterface
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'List activities';
|
||||
return 'List activity linked to a person';
|
||||
}
|
||||
|
||||
public function getType()
|
||||
public function getType(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
@ -267,13 +274,17 @@ class ListActivity implements ListInterface
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole()
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::LISTS);
|
||||
return ActivityStatsVoter::LISTS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return ['activity', 'person'];
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_PERSON,
|
||||
//PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -9,23 +9,26 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Export;
|
||||
namespace Chill\ActivityBundle\Export\Export\LinkedToPerson;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
use Doctrine\ORM\Query;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
/**
|
||||
* This export allow to compute stats on activity duration.
|
||||
*
|
||||
* The desired stat must be given in constructor.
|
||||
*/
|
||||
class StatActivityDuration implements ExportInterface
|
||||
class StatActivityDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
public const SUM = 'sum';
|
||||
|
||||
@ -59,17 +62,22 @@ class StatActivityDuration implements ExportInterface
|
||||
public function getDescription()
|
||||
{
|
||||
if (self::SUM === $this->action) {
|
||||
return 'Sum activities duration by various parameters.';
|
||||
return 'Sum activities linked to a person duration by various parameters.';
|
||||
}
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of activities linked to a person';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_stat_activity' !== $key) {
|
||||
throw new LogicException(sprintf('The key %s is not used by this export', $key));
|
||||
}
|
||||
|
||||
$header = self::SUM === $this->action ? 'Sum of activities duration' : false;
|
||||
$header = self::SUM === $this->action ? 'Sum activities linked to a person duration' : false;
|
||||
|
||||
return static fn (string $value) => '_header' === $value ? $header : $value;
|
||||
}
|
||||
@ -87,19 +95,19 @@ class StatActivityDuration implements ExportInterface
|
||||
public function getTitle()
|
||||
{
|
||||
if (self::SUM === $this->action) {
|
||||
return 'Sum activity duration';
|
||||
return 'Sum activity linked to a person duration';
|
||||
}
|
||||
}
|
||||
|
||||
public function getType()
|
||||
public function getType(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(
|
||||
static fn (array $el): string => $el['center'],
|
||||
static fn (array $el): Center => $el['center'],
|
||||
$acl
|
||||
);
|
||||
|
||||
@ -118,13 +126,17 @@ class StatActivityDuration implements ExportInterface
|
||||
->setParameter(':centers', $centers);
|
||||
}
|
||||
|
||||
public function requiredRole()
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return ActivityStatsVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return ['person', 'activity'];
|
||||
return [
|
||||
Declarations::ACTIVITY,
|
||||
Declarations::ACTIVITY_PERSON,
|
||||
//PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class BySocialActionFilter implements FilterInterface
|
||||
{
|
||||
private SocialActionRender $actionRender;
|
||||
|
||||
public function __construct(SocialActionRender $actionRender)
|
||||
{
|
||||
$this->actionRender = $actionRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
if (!in_array('socialaction', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.socialActions', 'socialaction');
|
||||
}
|
||||
|
||||
$clause = $qb->expr()->in('socialaction.id', ':socialactions');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('socialactions', $data['accepted_socialactions']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_socialactions', EntityType::class, [
|
||||
'class' => SocialAction::class,
|
||||
'choice_label' => function (SocialAction $sa) {
|
||||
return $this->actionRender->renderString($sa, []);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
foreach ($data['accepted_socialactions'] as $sa) {
|
||||
$actions[] = $this->actionRender->renderString($sa, []);
|
||||
}
|
||||
|
||||
return ['Filtered activity by linked socialaction: only %actions%', [
|
||||
'%actions%' => implode(', ou ', $actions),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by linked socialaction';
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class BySocialIssueFilter implements FilterInterface
|
||||
{
|
||||
private SocialIssueRender $issueRender;
|
||||
|
||||
public function __construct(SocialIssueRender $issueRender)
|
||||
{
|
||||
$this->issueRender = $issueRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
if (!in_array('socialissue', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.socialIssues', 'socialissue');
|
||||
}
|
||||
|
||||
$clause = $qb->expr()->in('socialissue.id', ':socialissues');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('socialissues', $data['accepted_socialissues']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_socialissues', EntityType::class, [
|
||||
'class' => SocialIssue::class,
|
||||
'choice_label' => function (SocialIssue $si) {
|
||||
return $this->issueRender->renderString($si, []);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$issues = [];
|
||||
|
||||
foreach ($data['accepted_socialissues'] as $si) {
|
||||
$issues[] = $this->issueRender->renderString($si, []);
|
||||
}
|
||||
|
||||
return ['Filtered activity by linked socialissue: only %issues%', [
|
||||
'%issues%' => implode(', ou ', $issues),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by linked socialissue';
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class ByUserFilter implements FilterInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
if (!in_array('user', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.users', 'user');
|
||||
}
|
||||
|
||||
$clause = $qb->expr()->in('user.id', ':users');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('users', $data['accepted_users']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_users', EntityType::class, [
|
||||
'class' => User::class,
|
||||
'choice_label' => function (User $u) {
|
||||
return $this->userRender->renderString($u, []);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$users = [];
|
||||
|
||||
foreach ($data['accepted_users'] as $u) {
|
||||
$users[] = $this->userRender->renderString($u, []);
|
||||
}
|
||||
|
||||
return ['Filtered activity by linked users: only %users%', [
|
||||
'%users%' => implode(', ou ', $users),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by linked users';
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class EmergencyFilter implements FilterInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'activity is emergency' => true,
|
||||
'activity is not emergency' => false,
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = false;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
$clause = $qb->expr()->eq('activity.emergency', ':emergency');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('emergency', $data['accepted_emergency']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_emergency', ChoiceType::class, [
|
||||
'choices' => self::CHOICES,
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
'empty_data' => self::DEFAULT_CHOICE,
|
||||
'data' => self::DEFAULT_CHOICE,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
foreach (self::CHOICES as $k => $v) {
|
||||
if ($v === $data['accepted_emergency']) {
|
||||
$choice = $k;
|
||||
}
|
||||
}
|
||||
|
||||
return ['Filtered activity by emergency: only %emergency%', [
|
||||
'%emergency%' => $this->translator->trans($choice),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by emergency';
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\LocationType;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class LocationTypeFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('location', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.location', 'location');
|
||||
}
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('location.locationType', ':locationtype');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('locationtype', $data['accepted_locationtype']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_locationtype', EntityType::class, [
|
||||
'class' => LocationType::class,
|
||||
'choice_label' => function (LocationType $type) {
|
||||
return $this->translatableStringHelper->localize($type->getTitle());
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
foreach ($data['accepted_locationtype'] as $type) {
|
||||
$types[] = $this->translatableStringHelper->localize(
|
||||
$type->getTitle()
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered activity by locationtype: only %types%', [
|
||||
'%types%' => implode(', ou ', $types),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by locationtype';
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class SentReceivedFilter implements FilterInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'is sent' => Activity::SENTRECEIVED_SENT,
|
||||
'is received' => Activity::SENTRECEIVED_RECEIVED,
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = Activity::SENTRECEIVED_SENT;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
$clause = $qb->expr()->eq('activity.sentReceived', ':sentreceived');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('sentreceived', $data['accepted_sentreceived']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_sentreceived', ChoiceType::class, [
|
||||
'choices' => self::CHOICES,
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
'empty_data' => self::DEFAULT_CHOICE,
|
||||
'data' => self::DEFAULT_CHOICE,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$sentreceived = array_flip(self::CHOICES)[$data['accepted_sentreceived']];
|
||||
|
||||
return ['Filtered activity by sentreceived: only %sentreceived%', [
|
||||
'%sentreceived%' => $this->translator->trans($sentreceived),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by sentreceived';
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class UserFilter implements FilterInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
$clause = $qb->expr()->in('activity.user', ':users');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('users', $data['accepted_users']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_users', EntityType::class, [
|
||||
'class' => User::class,
|
||||
'choice_label' => function (User $u) {
|
||||
return $this->userRender->renderString($u, []);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'label' => 'Creators',
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$users = [];
|
||||
|
||||
foreach ($data['accepted_users'] as $u) {
|
||||
$users[] = $this->userRender->renderString($u, []);
|
||||
}
|
||||
|
||||
return ['Filtered activity by user: only %users%', [
|
||||
'%users%' => implode(', ou ', $users),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by user';
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use function in_array;
|
||||
|
||||
class UserScopeFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!in_array('user', $qb->getAllAliases(), true)) {
|
||||
$qb->join('activity.user', 'user');
|
||||
}
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
$clause = $qb->expr()->in('user.mainScope', ':userscope');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('userscope', $data['accepted_userscope']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::ACTIVITY_ACP;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_userscope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choice_label' => function (Scope $s) {
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$scopes = [];
|
||||
|
||||
foreach ($data['accepted_userscope'] as $s) {
|
||||
$scopes[] = $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered activity by userscope: only %scopes%', [
|
||||
'%scopes%' => implode(', ou ', $scopes),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter activity by userscope';
|
||||
}
|
||||
}
|
@ -11,12 +11,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter;
|
||||
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\Export\FilterType;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
@ -32,7 +33,7 @@ class ActivityDateFilter implements FilterInterface
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@ -57,36 +58,22 @@ class ActivityDateFilter implements FilterInterface
|
||||
$qb->setParameter('date_to', $data['date_to']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add(
|
||||
'date_from',
|
||||
DateType::class,
|
||||
[
|
||||
$builder
|
||||
->add('date_from', ChillDateType::class, [
|
||||
'label' => 'Activities after this date',
|
||||
'data' => new DateTime(),
|
||||
'attr' => ['class' => 'datepicker'],
|
||||
'widget' => 'single_text',
|
||||
'format' => 'dd-MM-yyyy',
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'date_to',
|
||||
DateType::class,
|
||||
[
|
||||
])
|
||||
->add('date_to', ChillDateType::class, [
|
||||
'label' => 'Activities before this date',
|
||||
'data' => new DateTime(),
|
||||
'attr' => ['class' => 'datepicker'],
|
||||
'widget' => 'single_text',
|
||||
'format' => 'dd-MM-yyyy',
|
||||
]
|
||||
);
|
||||
]);
|
||||
|
||||
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
|
||||
/** @var \Symfony\Component\Form\FormInterface $filterForm */
|
||||
|
@ -12,8 +12,8 @@ declare(strict_types=1);
|
||||
namespace Chill\ActivityBundle\Export\Filter;
|
||||
|
||||
use Chill\ActivityBundle\Entity\ActivityType;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
@ -22,7 +22,6 @@ use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
use function count;
|
||||
@ -41,15 +40,15 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
|
||||
$this->activityTypeRepository = $activityTypeRepository;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('activity.type', ':selected_activity_types');
|
||||
$clause = $qb->expr()->in('activity.activityType', ':selected_activity_types');
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
$where->add($clause);
|
||||
@ -61,39 +60,33 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter
|
||||
$qb->setParameter('selected_activity_types', $data['types']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add(
|
||||
'types',
|
||||
EntityType::class,
|
||||
[
|
||||
'class' => ActivityType::class,
|
||||
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
]
|
||||
);
|
||||
$builder->add('types', EntityType::class, [
|
||||
'class' => ActivityType::class,
|
||||
'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
|
||||
'group_by' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getCategory()->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
// collect all the reasons'name used in this filter in one array
|
||||
$reasonsNames = array_map(
|
||||
fn (ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"',
|
||||
fn (ActivityType $t): string => $this->translatableStringHelper->localize($t->getName()),
|
||||
$this->activityTypeRepository->findBy(['id' => $data['types']->toArray()])
|
||||
);
|
||||
|
||||
return [
|
||||
'Filtered by activity type: only %list%',
|
||||
[
|
||||
'%list%' => implode(', ', $reasonsNames),
|
||||
],
|
||||
];
|
||||
return ['Filtered by activity type: only %list%', [
|
||||
'%list%' => implode(', ou ', $reasonsNames),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter;
|
||||
namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
|
||||
|
||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||
use Chill\ActivityBundle\Export\Declarations;
|
||||
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
@ -23,7 +23,6 @@ use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
use function array_key_exists;
|
||||
@ -43,9 +42,9 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
|
||||
$this->activityReasonRepository = $activityReasonRepository;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return new Role(ActivityStatsVoter::STATS);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
@ -79,9 +78,9 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
|
||||
$qb->setParameter('selected_activity_reasons', $data['reasons']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return 'activity';
|
||||
return Declarations::ACTIVITY_PERSON;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
@ -9,7 +9,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\ActivityBundle\Export\Filter;
|
||||
namespace Chill\ActivityBundle\Export\Filter\PersonFilters;
|
||||
|
||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
|
||||
@ -52,7 +52,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function addRole()
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@ -102,7 +102,7 @@ class PersonHavingActivityBetweenDateFilter implements ExportElementValidatedInt
|
||||
$qb->setParameter('person_having_activity_reasons', $data['reasons']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::PERSON_IMPLIED_IN;
|
||||
}
|
@ -14,17 +14,20 @@ namespace Chill\ActivityBundle\Form;
|
||||
use Chill\ActivityBundle\Entity\Activity;
|
||||
use Chill\ActivityBundle\Entity\ActivityPresence;
|
||||
use Chill\ActivityBundle\Entity\ActivityReason;
|
||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||
use Chill\DocStoreBundle\Form\StoredObjectType;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\Type\ChillCollectionType;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\CommentType;
|
||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||
use Chill\MainBundle\Form\Type\PrivateCommentType;
|
||||
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||
use Chill\MainBundle\Form\Type\UserPickerType;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||
@ -50,6 +53,7 @@ use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use function in_array;
|
||||
|
||||
class ActivityType extends AbstractType
|
||||
@ -109,19 +113,18 @@ class ActivityType extends AbstractType
|
||||
$activityType = $options['activityType'];
|
||||
|
||||
// TODO revoir la gestion des center au niveau du form des activité.
|
||||
if ($options['center']) {
|
||||
if ($options['center'] instanceof Center && null !== $options['data']->getPerson()) {
|
||||
$builder->add('scope', ScopePickerType::class, [
|
||||
'center' => $options['center'],
|
||||
'role' => $options['role'],
|
||||
// TODO make required again once scope and rights are fixed
|
||||
'required' => false,
|
||||
'role' => ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'],
|
||||
'required' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingPeriod */
|
||||
$accompanyingPeriod = null;
|
||||
|
||||
if ($options['accompanyingPeriod']) {
|
||||
if ($options['accompanyingPeriod'] instanceof AccompanyingPeriod) {
|
||||
$accompanyingPeriod = $options['accompanyingPeriod'];
|
||||
}
|
||||
|
||||
@ -218,12 +221,10 @@ class ActivityType extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
if ($activityType->isVisible('user') && $options['center']) {
|
||||
$builder->add('user', UserPickerType::class, [
|
||||
if ($activityType->isVisible('user') && $options['center'] instanceof Center) {
|
||||
$builder->add('user', PickUserDynamicType::class, [
|
||||
'label' => $activityType->getLabel('user'),
|
||||
'required' => $activityType->isRequired('user'),
|
||||
'center' => $options['center'],
|
||||
'role' => $options['role'],
|
||||
]);
|
||||
}
|
||||
|
||||
@ -442,8 +443,8 @@ class ActivityType extends AbstractType
|
||||
|
||||
$resolver
|
||||
->setRequired(['center', 'role', 'activityType', 'accompanyingPeriod'])
|
||||
->setAllowedTypes('center', ['null', 'Chill\MainBundle\Entity\Center'])
|
||||
->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role')
|
||||
->setAllowedTypes('center', ['null', Center::class])
|
||||
->setAllowedTypes('role', [Role::class, 'string'])
|
||||
->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class)
|
||||
->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']);
|
||||
}
|
||||
|
@ -120,3 +120,11 @@
|
||||
|
||||
{{ form_end(edit_form) }}
|
||||
{# {{ form(delete_form) }} #}
|
||||
|
||||
{% block js %}
|
||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||
{% endblock %}
|
@ -46,7 +46,7 @@
|
||||
|
||||
{% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'person'} %}
|
||||
|
||||
{% if is_granted('CHILL_ACTIVITY_CREATE_PERSON', person) %}
|
||||
{% if is_granted('CHILL_ACTIVITY_CREATE', person) %}
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}"
|
||||
|
@ -119,3 +119,11 @@
|
||||
</li>
|
||||
</ul>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% block js %}
|
||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||
{% endblock %}
|
@ -133,7 +133,7 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
|
||||
|
||||
// change attribute CREATE
|
||||
if (self::CREATE === $attribute) {
|
||||
$attribute = self::CREATE_PERSON;
|
||||
return $this->voterHelper->voteOnAttribute(self::CREATE_PERSON, $subject->getPerson(), $token);
|
||||
}
|
||||
} elseif ($subject->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
||||
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getAccompanyingPeriod())) {
|
||||
@ -144,7 +144,8 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
|
||||
if (AccompanyingPeriod::STEP_CLOSED === $subject->getAccompanyingPeriod()->getStep()) {
|
||||
return false;
|
||||
}
|
||||
$attribute = self::CREATE_ACCOMPANYING_COURSE;
|
||||
|
||||
return $this->voterHelper->voteOnAttribute(self::CREATE_ACCOMPANYING_COURSE, $subject->getAccompanyingPeriod(), $token);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException('Could not determine context of activity.');
|
||||
@ -158,12 +159,12 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
|
||||
|
||||
// transform the attribute
|
||||
if (self::CREATE === $attribute) {
|
||||
$attribute = self::CREATE_ACCOMPANYING_COURSE;
|
||||
return $this->voterHelper->voteOnAttribute(self::CREATE_ACCOMPANYING_COURSE, $subject, $token);
|
||||
}
|
||||
} elseif ($subject instanceof Person) {
|
||||
// transform the attribute
|
||||
if (self::CREATE === $attribute) {
|
||||
$attribute = self::CREATE_PERSON;
|
||||
return $this->voterHelper->voteOnAttribute(self::CREATE_PERSON, $subject, $token);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,8 +130,10 @@ class ActivityContext implements
|
||||
return $this->personRender->renderString($p, []);
|
||||
},
|
||||
'multiple' => false,
|
||||
'required' => false,
|
||||
'expanded' => true,
|
||||
'label' => $options[$key . 'Label'],
|
||||
'placeholder' => $this->translator->trans('Any person selected'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -3,26 +3,48 @@ services:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
chill.activity.export.count_activity:
|
||||
class: Chill\ActivityBundle\Export\Export\CountActivity
|
||||
## Indicators
|
||||
chill.activity.export.count_activity_linked_to_person:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\CountActivity
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_activity' }
|
||||
- { name: chill.export, alias: 'count_activity_linked_to_person' }
|
||||
|
||||
chill.activity.export.sum_activity_duration:
|
||||
class: Chill\ActivityBundle\Export\Export\StatActivityDuration
|
||||
chill.activity.export.sum_activity_duration_linked_to_person:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\StatActivityDuration
|
||||
tags:
|
||||
- { name: chill.export, alias: 'sum_activity_duration' }
|
||||
- { name: chill.export, alias: 'sum_activity_duration_linked_to_person' }
|
||||
|
||||
chill.activity.export.list_activity:
|
||||
class: Chill\ActivityBundle\Export\Export\ListActivity
|
||||
chill.activity.export.list_activity_linked_to_person:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToPerson\ListActivity
|
||||
tags:
|
||||
- { name: chill.export, alias: 'list_activity' }
|
||||
- { name: chill.export, alias: 'list_activity_linked_to_person' }
|
||||
|
||||
chill.activity.export.reason_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter
|
||||
chill.activity.export.count_activity_linked_to_acp:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\CountActivity
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_reason_filter' }
|
||||
- { name: chill.export, alias: 'count_activity_linked_to_acp' }
|
||||
|
||||
chill.activity.export.sum_activity_duration_linked_to_acp:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityDuration
|
||||
tags:
|
||||
- { name: chill.export, alias: 'sum_activity_duration_linked_to_acp' }
|
||||
|
||||
chill.activity.export.sum_activity_visit_duration_linked_to_acp:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\SumActivityVisitDuration
|
||||
tags:
|
||||
- { name: chill.export, alias: 'sum_activity_visit_duration_linked_to_acp' }
|
||||
|
||||
chill.activity.export.avg_activity_duration_linked_to_acp:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityDuration
|
||||
tags:
|
||||
- { name: chill.export, alias: 'avg_activity_duration_linked_to_acp' }
|
||||
|
||||
chill.activity.export.avg_activity_visit_duration_linked_to_acp:
|
||||
class: Chill\ActivityBundle\Export\Export\LinkedToACP\AvgActivityVisitDuration
|
||||
tags:
|
||||
- { name: chill.export, alias: 'avg_activity_visit_duration_linked_to_acp' }
|
||||
|
||||
## Filters
|
||||
chill.activity.export.type_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
|
||||
tags:
|
||||
@ -33,15 +55,61 @@ services:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_date_filter' }
|
||||
|
||||
chill.activity.export.reason_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\PersonFilters\ActivityReasonFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_reason_filter' }
|
||||
|
||||
chill.activity.export.person_having_an_activity_between_date_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
|
||||
class: Chill\ActivityBundle\Export\Filter\PersonFilters\PersonHavingActivityBetweenDateFilter
|
||||
tags:
|
||||
- #0 register as a filter
|
||||
name: chill.export_filter
|
||||
alias: 'activity_person_having_ac_bw_date_filter'
|
||||
|
||||
chill.activity.export.locationtype_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\LocationTypeFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_locationtype_filter' }
|
||||
|
||||
chill.activity.export.byuser_filter: # TMS (M2M)
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\ByUserFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_byuser_filter' }
|
||||
|
||||
chill.activity.export.emergency_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\EmergencyFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_emergency_filter' }
|
||||
|
||||
chill.activity.export.sentreceived_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\SentReceivedFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_sentreceived_filter' }
|
||||
|
||||
chill.activity.export.bysocialaction_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialActionFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_bysocialaction_filter' }
|
||||
|
||||
chill.activity.export.bysocialissue_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\BySocialIssueFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_bysocialissue_filter' }
|
||||
|
||||
chill.activity.export.user_filter: # Creator (M2O)
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\UserFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_user_filter' }
|
||||
|
||||
chill.activity.export.userscope_filter:
|
||||
class: Chill\ActivityBundle\Export\Filter\ACPFilters\UserScopeFilter
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'activity_userscope_filter' }
|
||||
|
||||
## Aggregators
|
||||
chill.activity.export.reason_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
|
||||
class: Chill\ActivityBundle\Export\Aggregator\PersonAggregators\ActivityReasonAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_reason_aggregator }
|
||||
|
||||
@ -54,3 +122,38 @@ services:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_user_aggregator }
|
||||
|
||||
chill.activity.export.locationtype_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\LocationTypeAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_locationtype_aggregator }
|
||||
|
||||
chill.activity.export.date_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\DateAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_date_aggregator }
|
||||
|
||||
chill.activity.export.byuser_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByUserAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_byuser_aggregator }
|
||||
|
||||
chill.activity.export.bythirdparty_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\ByThirdpartyAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_bythirdparty_aggregator }
|
||||
|
||||
chill.activity.export.bysocialaction_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialActionAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_bysocialaction_aggregator }
|
||||
|
||||
chill.activity.export.bysocialissue_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\BySocialIssueAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_bysocialissue_aggregator }
|
||||
|
||||
chill.activity.export.userscope_aggregator:
|
||||
class: Chill\ActivityBundle\Export\Aggregator\ACPAggregators\UserScopeAggregator
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: activity_userscope_aggregator }
|
||||
|
@ -203,18 +203,39 @@ Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr d
|
||||
The activity has been successfully removed.: L'activité a été supprimée.
|
||||
|
||||
# exports
|
||||
Count activities: Nombre d'activités
|
||||
Count activities by various parameters.: Compte le nombre d'activités enregistrées en fonction de différents paramètres.
|
||||
Sum activity duration: Total de la durée des activités
|
||||
Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
List activities: Liste les activités
|
||||
Number of activities: Nombre d'activités
|
||||
Exports of activities linked to a person: Exports des activités liées à une personne
|
||||
Number of activities linked to a person: Nombre d'activités liées à une personne
|
||||
Count activities linked to a person: Nombre d'activités
|
||||
Count activities linked to a person by various parameters.: Compte le nombre d'activités enregistrées et liées à une personne en fonction de différents paramètres.
|
||||
Sum activity linked to a person duration: Durée des activités
|
||||
Sum activities linked to a person duration: Durée des activités liés à un usager
|
||||
Sum activities linked to a person duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
List activity linked to a person: Liste les activités
|
||||
List activities linked to a person: Liste des activités liés à un usager
|
||||
List activities linked to a person description: Crée la liste des activités en fonction de différents paramètres.
|
||||
|
||||
Exports of activities linked to an accompanying period: Exports des activités liées à un parcours
|
||||
Number of activities linked to an accompanying period: Nombre d'activités liées à un parcours
|
||||
Count activities linked to an accompanying period: Nombre d'activités
|
||||
Count activities linked to an accompanying period by various parameters.: Compte le nombre d'activités enregistrées et liées à un parcours en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period duration: Somme de la durée des activités
|
||||
Sum activities linked to an accompanying period duration: Somme de la durée des activités liées à un parcours
|
||||
Sum activities linked to an accompanying period duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
Sum activity linked to an accompanying period visit duration: Somme de la durée de déplacement des activités
|
||||
Sum activities linked to an accompanying period visit duration: Somme de la durée de déplacement des activités liées à un parcours
|
||||
Sum activities linked to an accompanying period visit duration by various parameters.: Additionne la durée de déplacement des activités en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period duration: Moyenne de la durée des activités
|
||||
Average activities linked to an accompanying period duration: Moyenne de la durée des activités liées à un parcours
|
||||
Average activities linked to an accompanying period duration by various parameters.: Moyenne de la durée des activités en fonction de différents paramètres.
|
||||
Average activity linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités
|
||||
Average activities linked to an accompanying period visit duration: Moyenne de la durée de déplacement des activités liées à un parcours
|
||||
Average activities linked to an accompanying period visit duration by various parameters.: Moyenne de la durée de déplacement des activités en fonction de différents paramètres.
|
||||
|
||||
#filters
|
||||
Filter by reason: Filtrer par sujet d'activité
|
||||
Filter by reason: Filtrer les activités par sujet
|
||||
'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%'
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%"
|
||||
Filtered by date activity: Filtrer par date d'activité
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'activité: uniquement %list%"
|
||||
Filtered by date activity: Filtrer les activités par date
|
||||
Activities after this date: Activités après cette date
|
||||
Activities before this date: Activités avant cette date
|
||||
"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'activité: uniquement entre %date_from% et %date_to%"
|
||||
@ -226,18 +247,59 @@ Implied in an activity before this date: Impliqué dans une activité avant cett
|
||||
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name%
|
||||
Activity reasons for those activities: Sujets de ces activités
|
||||
|
||||
Filter by activity type: Filtrer par type d'activité
|
||||
Filter by activity type: Filtrer les activités par type
|
||||
|
||||
Filter activity by locationtype: Filtrer les activités par type de localisation
|
||||
'Filtered activity by locationtype: only %types%': "Filtré par type de localisation: uniquement %types%"
|
||||
Accepted locationtype: Types de localisation
|
||||
Filter activity by linked users: Filtrer les activités par TMS
|
||||
'Filtered activity by linked users: only %users%': "Filtré par TMS: uniquement %users%"
|
||||
Accepted users: TMS(s)
|
||||
Filter activity by emergency: Filtrer les activités par urgence
|
||||
'Filtered activity by emergency: only %emergency%': "Filtré par urgence: uniquement si %emergency%"
|
||||
activity is emergency: l'activité est urgente
|
||||
activity is not emergency: l'activité n'est pas urgente
|
||||
Filter activity by sentreceived: Filtrer les activités par envoyé/reçu
|
||||
'Filtered activity by sentreceived: only %sentreceived%': "Filtré par envoyé/reçu: uniquement %sentreceived%"
|
||||
Accepted sentreceived: ''
|
||||
is sent: envoyé
|
||||
is received: reçu
|
||||
Filter activity by linked socialaction: Filtrer les activités par action liée
|
||||
'Filtered activity by linked socialaction: only %actions%': "Filtré par action liée: uniquement %actions%"
|
||||
Filter activity by linked socialissue: Filtrer les activités par problématique liée
|
||||
'Filtered activity by linked socialissue: only %issues%': "Filtré par problématique liée: uniquement %issues%"
|
||||
Filter activity by user: Filtrer les activités par créateur
|
||||
'Filtered activity by user: only %users%': "Filtré par créateur: uniquement %users%"
|
||||
Creators: Créateurs
|
||||
Filter activity by userscope: Filtrer les activités par service du créateur
|
||||
'Filtered activity by userscope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
||||
Accepted userscope: Services
|
||||
|
||||
#aggregators
|
||||
Activity type: Type d'activité
|
||||
Activity user: Utilisateur lié à l'activity
|
||||
Activity user: Utilisateur lié à l'activité
|
||||
By reason: Par sujet
|
||||
By category of reason: Par catégorie de sujet
|
||||
Reason's level: Niveau du sujet
|
||||
Group by reasons: Sujet d'activité
|
||||
Aggregate by activity user: Aggréger par utilisateur lié à l'activité
|
||||
Aggregate by activity type: Aggréger par type d'activité
|
||||
Aggregate by activity reason: Aggréger par sujet de l'activité
|
||||
Aggregate by activity user: Grouper les activités par utilisateur
|
||||
Aggregate by activity type: Grouper les activités par type
|
||||
Aggregate by activity reason: Grouper les activités par sujet
|
||||
|
||||
Group activity by locationtype: Grouper les activités par type de localisation
|
||||
Group activity by date: Grouper les activités par date
|
||||
Frequency: Fréquence
|
||||
by month: Par mois
|
||||
by week: Par semaine
|
||||
for week: Semaine
|
||||
by year: Par année
|
||||
in year: En
|
||||
Group activity by linked users: Grouper les activités par TMS impliqué
|
||||
Group activity by linked thirdparties: Grouper les activités par tiers impliqué
|
||||
Accepted thirdparty: Tiers impliqué
|
||||
Group activity by linked socialaction: Grouper les activités par action liée
|
||||
Group activity by linked socialissue: Grouper les activités par problématique liée
|
||||
Group activity by userscope: Grouper les activités par service du créateur
|
||||
|
||||
Last activities: Les dernières activités
|
||||
|
||||
|
@ -195,7 +195,7 @@ Number of activities: Nombre d'activités
|
||||
#filters
|
||||
Filter by reason: Filtrer par sujet d'activité
|
||||
'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%'
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%"
|
||||
'Filtered by activity type: only %list%': "Filtré par type d'activity: uniquement %list%"
|
||||
Filtered by date activity: Filtrer par date d'activité
|
||||
Activities after this date: Activités après cette date
|
||||
Activities before this date: Activités avant cette date
|
||||
@ -217,9 +217,9 @@ By reason: Par sujet
|
||||
By category of reason: Par catégorie de sujet
|
||||
Reason's level: Niveau du sujet
|
||||
Group by reasons: Sujet d'activité
|
||||
Aggregate by activity user: Aggréger par utilisateur lié à l'activité
|
||||
Aggregate by activity type: Aggréger par type d'activité
|
||||
Aggregate by activity reason: Aggréger par sujet de l'activité
|
||||
Aggregate by activity user: Grouper par utilisateur lié à l'activité
|
||||
Aggregate by activity type: Grouper par type d'activité
|
||||
Aggregate by activity reason: Grouper par sujet de l'activité
|
||||
|
||||
Last activities: Les dernières activités
|
||||
|
||||
|
@ -32,6 +32,7 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
$loader->load('services/exports.yaml');
|
||||
$loader->load('services/controller.yml');
|
||||
$loader->load('services/fixtures.yml');
|
||||
$loader->load('services/form.yml');
|
||||
|
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class AgentAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
private UserRepository $userRepository;
|
||||
|
||||
public function __construct(
|
||||
UserRepository $userRepository,
|
||||
UserRender $userRender
|
||||
) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.user', 'u');
|
||||
|
||||
$qb->addSelect('u.id AS agent_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('agent_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('agent_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Agent';
|
||||
}
|
||||
|
||||
$r = $this->userRepository->find($value);
|
||||
|
||||
return $this->userRender->renderString($r, []);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['agent_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by agent';
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CancelReasonRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class CancelReasonAggregator implements AggregatorInterface
|
||||
{
|
||||
private CancelReasonRepository $cancelReasonRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
CancelReasonRepository $cancelReasonRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->cancelReasonRepository = $cancelReasonRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
// TODO: still needs to take into account appointments without a cancel reason somehow
|
||||
$qb->join('cal.cancelReason', 'cr');
|
||||
|
||||
$qb->addSelect('IDENTITY(cal.cancelReason) as cancel_reason_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('cancel_reason_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('cancel_reason_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Cancel reason';
|
||||
}
|
||||
|
||||
$j = $this->cancelReasonRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getName()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['cancel_reason_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by cancel reason';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\UserJobRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class JobAggregator implements AggregatorInterface
|
||||
{
|
||||
private UserJobRepository $jobRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
UserJobRepository $jobRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->jobRepository = $jobRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.user', 'u');
|
||||
|
||||
$qb->addSelect('IDENTITY(u.userJob) as job_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('job_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('job_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Job';
|
||||
}
|
||||
|
||||
$j = $this->jobRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['job_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by agent job';
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\LocationRepository;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
final class LocationAggregator implements AggregatorInterface
|
||||
{
|
||||
private LocationRepository $locationRepository;
|
||||
|
||||
public function __construct(
|
||||
LocationRepository $locationRepository
|
||||
) {
|
||||
$this->locationRepository = $locationRepository;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.location', 'l');
|
||||
$qb->addSelect('IDENTITY(cal.location) as location_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('location_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('location_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Location';
|
||||
}
|
||||
|
||||
$l = $this->locationRepository->find($value);
|
||||
|
||||
return $l->getName();
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['location_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by location';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\LocationTypeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class LocationTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
private LocationTypeRepository $locationTypeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
LocationTypeRepository $locationTypeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->locationTypeRepository = $locationTypeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.location', 'l');
|
||||
|
||||
$qb->addSelect('IDENTITY(l.locationType) as location_type_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('location_type_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('location_type_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Location type';
|
||||
}
|
||||
|
||||
$j = $this->locationTypeRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getTitle()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['location_type_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by location type';
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
class MonthYearAggregator implements AggregatorInterface
|
||||
{
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->addSelect("to_char(cal.startDate, 'MM-YYYY') AS month_year_aggregator");
|
||||
// $qb->addSelect("extract(month from age(cal.startDate, cal.endDate)) AS month_aggregator");
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('month_year_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('month_year_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// No form needed
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return static function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'by month and year';
|
||||
}
|
||||
|
||||
$month = substr($value, 0, 2);
|
||||
$year = substr($value, 3, 4);
|
||||
|
||||
return strftime('%B %G', mktime(0, 0, 0, $month, '1', $year));
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['month_year_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by month and year';
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Aggregator;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Repository\ScopeRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Closure;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class ScopeAggregator implements AggregatorInterface
|
||||
{
|
||||
private ScopeRepository $scopeRepository;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
ScopeRepository $scopeRepository,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.user', 'u');
|
||||
|
||||
$qb->addSelect('IDENTITY(u.mainScope) as scope_aggregator');
|
||||
|
||||
$groupBy = $qb->getDQLPart('groupBy');
|
||||
|
||||
if (!empty($groupBy)) {
|
||||
$qb->addGroupBy('scope_aggregator');
|
||||
} else {
|
||||
$qb->groupBy('scope_aggregator');
|
||||
}
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
return function ($value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Scope';
|
||||
}
|
||||
|
||||
$s = $this->scopeRepository->find($value);
|
||||
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['scope_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group appointments by agent scope';
|
||||
}
|
||||
}
|
20
src/Bundle/ChillCalendarBundle/Export/Declarations.php
Normal file
20
src/Bundle/ChillCalendarBundle/Export/Declarations.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export;
|
||||
|
||||
/**
|
||||
* This class declare constants used for the export framework.
|
||||
*/
|
||||
abstract class Declarations
|
||||
{
|
||||
public const CALENDAR_TYPE = 'calendar';
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Closure;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Process\Exception\LogicException;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
|
||||
class CountAppointments implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(CalendarRepository $calendarRepository)
|
||||
{
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// No form necessary
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Count appointments by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of calendar';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_result'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(AbstractQuery::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Count appointments';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate the query.
|
||||
*/
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$centers = array_map(static function ($el) {
|
||||
return $el['center'];
|
||||
}, $acl);
|
||||
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb->select('COUNT(cal.id) AS export_result');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
// which role should we give here?
|
||||
return PersonVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::CALENDAR_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class StatAppointmentAvgDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRepository $calendarRepository
|
||||
) {
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder): void
|
||||
{
|
||||
// no form needed
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Get the average of appointment duration according to various filters';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of calendar';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_result'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Average appointment duration';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb
|
||||
->select('AVG(cal.endDate - cal.startDate) AS export_result');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return AccompanyingPeriodVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::CALENDAR_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Export;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use LogicException;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class StatAppointmentSumDuration implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private CalendarRepository $calendarRepository;
|
||||
|
||||
public function __construct(
|
||||
CalendarRepository $calendarRepository
|
||||
) {
|
||||
$this->calendarRepository = $calendarRepository;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder): void
|
||||
{
|
||||
// no form needed
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes(): array
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Get the sum of appointment durations according to various filters';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of calendar';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
$labels = array_combine($values, $values);
|
||||
$labels['_header'] = $this->getTitle();
|
||||
|
||||
return static function ($value) use ($labels) {
|
||||
return $labels[$value];
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['export_result'];
|
||||
}
|
||||
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Sum of appointment durations';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []): QueryBuilder
|
||||
{
|
||||
$qb = $this->calendarRepository->createQueryBuilder('cal');
|
||||
|
||||
$qb
|
||||
->select('SUM(cal.endDate - cal.startDate) AS export_result');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return AccompanyingPeriodVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers(): array
|
||||
{
|
||||
return [
|
||||
Declarations::CALENDAR_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
87
src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php
Normal file
87
src/Bundle/ChillCalendarBundle/Export/Filter/AgentFilter.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AgentFilter implements FilterInterface
|
||||
{
|
||||
private UserRender $userRender;
|
||||
|
||||
public function __construct(UserRender $userRender)
|
||||
{
|
||||
$this->userRender = $userRender;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('cal.user', ':agents');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('agents', $data['accepted_agents']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('accepted_agents', EntityType::class, [
|
||||
'class' => User::class,
|
||||
'choice_label' => function (User $u) {
|
||||
return $this->userRender->renderString($u, []);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$users = [];
|
||||
|
||||
foreach ($data['accepted_agents'] as $r) {
|
||||
$users[] = $r;
|
||||
}
|
||||
|
||||
return [
|
||||
'Filtered by agent: only %agents%', [
|
||||
'%agents' => implode(', ou ', $users),
|
||||
], ];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter appointments by agent';
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use DateTime;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class BetweenDatesFilter implements FilterInterface
|
||||
{
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
|
||||
$clause = $qb->expr()->andX(
|
||||
$qb->expr()->gte('cal.startDate', ':dateFrom'),
|
||||
$qb->expr()->lte('cal.endDate', ':dateTo')
|
||||
);
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('dateFrom', $data['date_from'], Types::DATE_MUTABLE);
|
||||
// modify dateTo so that entire day is also taken into account up until the beginning of the next day.
|
||||
$qb->setParameter('dateTo', $data['date_to']->modify('+1 day'), Types::DATE_MUTABLE);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('date_from', ChillDateType::class, [
|
||||
'data' => new DateTime(),
|
||||
])
|
||||
->add('date_to', ChillDateType::class, [
|
||||
'data' => new DateTime(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
return ['Filtered by appointments between %dateFrom% and %dateTo%', [
|
||||
'%dateFrom%' => $data['date_from']->format('d-m-Y'),
|
||||
'%dateTo%' => $data['date_to']->format('d-m-Y'),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter appointments between certain dates';
|
||||
}
|
||||
}
|
98
src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php
Normal file
98
src/Bundle/ChillCalendarBundle/Export/Filter/JobFilter.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\UserJob;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class JobFilter implements FilterInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.user', 'u');
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('u.userJob', ':job');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('job', $data['job']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('job', EntityType::class, [
|
||||
'class' => UserJob::class,
|
||||
'choice_label' => function (UserJob $j) {
|
||||
return $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string'): array
|
||||
{
|
||||
$userJobs = [];
|
||||
|
||||
foreach ($data['job'] as $j) {
|
||||
$userJobs[] = $this->translatableStringHelper->localize(
|
||||
$j->getLabel()
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered by agent job: only %jobs%', [
|
||||
'%jobs%' => implode(', ou ', $userJobs),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Filter appointments by agent job';
|
||||
}
|
||||
}
|
98
src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php
Normal file
98
src/Bundle/ChillCalendarBundle/Export/Filter/ScopeFilter.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\CalendarBundle\Export\Filter;
|
||||
|
||||
use Chill\CalendarBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\Query\Expr\Andx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class ScopeFilter implements FilterInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
) {
|
||||
$this->translator = $translator;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$qb->join('cal.user', 'u');
|
||||
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->in('u.mainScope', ':scope');
|
||||
|
||||
if ($where instanceof Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter('scope', $data['scope']);
|
||||
}
|
||||
|
||||
public function applyOn()
|
||||
{
|
||||
return Declarations::CALENDAR_TYPE;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('scope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'choice_label' => function (Scope $s) {
|
||||
return $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
},
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
$scopes = [];
|
||||
|
||||
foreach ($data['scope'] as $s) {
|
||||
$scopes[] = $this->translatableStringHelper->localize(
|
||||
$s->getName()
|
||||
);
|
||||
}
|
||||
|
||||
return ['Filtered by agent scope: only %scopes%', [
|
||||
'%scopes%' => implode(', ou ', $scopes),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filter appointments by agent scope';
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
services:
|
||||
|
||||
## Indicators
|
||||
chill.calendar.export.count_appointments:
|
||||
class: Chill\CalendarBundle\Export\Export\CountAppointments
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export, alias: count_appointments }
|
||||
|
||||
chill.calendar.export.average_duration_appointments:
|
||||
class: Chill\CalendarBundle\Export\Export\StatAppointmentAvgDuration
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export, alias: average_duration_appointments }
|
||||
|
||||
chill.calendar.export.sum_duration_appointments:
|
||||
class: Chill\CalendarBundle\Export\Export\StatAppointmentSumDuration
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export, alias: sum_duration_appointments }
|
||||
|
||||
## Filters
|
||||
|
||||
chill.calendar.export.agent_filter:
|
||||
class: Chill\CalendarBundle\Export\Filter\AgentFilter
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: agent_filter }
|
||||
|
||||
chill.calendar.export.job_filter:
|
||||
class: Chill\CalendarBundle\Export\Filter\JobFilter
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: job_filter }
|
||||
|
||||
chill.calendar.export.scope_filter:
|
||||
class: Chill\CalendarBundle\Export\Filter\ScopeFilter
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: scope_filter }
|
||||
|
||||
chill.calendar.export.between_dates_filter:
|
||||
class: Chill\CalendarBundle\Export\Filter\BetweenDatesFilter
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: between_dates_filter }
|
||||
|
||||
## Aggregator
|
||||
|
||||
chill.calendar.export.agent_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\AgentAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: agent_aggregator }
|
||||
|
||||
chill.calendar.export.job_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\JobAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: job_aggregator }
|
||||
|
||||
chill.calendar.export.scope_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\ScopeAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: scope_aggregator }
|
||||
|
||||
chill.calendar.export.location_type_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\LocationTypeAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: location_type_aggregator }
|
||||
|
||||
chill.calendar.export.location_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\LocationAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: location_aggregator }
|
||||
|
||||
chill.calendar.export.cancel_reason_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\CancelReasonAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: cancel_reason_aggregator }
|
||||
|
||||
chill.calendar.export.month_aggregator:
|
||||
class: Chill\CalendarBundle\Export\Aggregator\MonthYearAggregator
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: month_aggregator }
|
@ -69,3 +69,36 @@ invite:
|
||||
declined: Refusé
|
||||
pending: En attente
|
||||
tentative: Accepté provisoirement
|
||||
|
||||
# exports
|
||||
Exports of calendar: Exports des rendez-vous
|
||||
Count appointments: Nombre de rendez-vous
|
||||
Count appointments by various parameters.: Compte le nombre de rendez-vous en fonction de différents paramètres.
|
||||
|
||||
Average appointment duration: Moyenne de la durée des rendez-vous
|
||||
Get the average of appointment duration according to various filters: Calcule la moyenne des durées des rendez-vous en fonction de différents paramètres.
|
||||
|
||||
Sum of appointment durations: Somme de la durée des rendez-vous
|
||||
Get the sum of appointment durations according to various filters: Calcule la somme des durées des rendez-vous en fonction de différents paramètres.
|
||||
|
||||
'Filtered by agent: only %agents%': "Filtré par agents: uniquement %agents%"
|
||||
Filter appointments by agent: Filtrer les rendez-vous par agents
|
||||
Filter appointments by agent job: Filtrer les rendez-vous par métiers des agents
|
||||
'Filtered by agent job: only %jobs%': 'Filtré par métiers des agents: uniquement les %jobs%'
|
||||
Filter appointments by agent scope: Filtrer les rendez-vous par services des agents
|
||||
'Filtered by agent scope: only %scopes%': 'Filtré par services des agents: uniquement les services %scopes%'
|
||||
Filter appointments between certain dates: Filtrer les rendez-vous par date du rendez-vous
|
||||
'Filtered by appointments between %dateFrom% and %dateTo%': 'Filtré par rendez-vous entre %dateFrom% et %dateTo%'
|
||||
|
||||
Group appointments by agent: Grouper les rendez-vous par agent
|
||||
Group appointments by agent job: Grouper les rendez-vous par métier de l'agent
|
||||
Group appointments by agent scope: Grouper les rendez-vous par service de l'agent
|
||||
Group appointments by location type: Grouper les rendez-vous par type de localisation
|
||||
Group appointments by location: Grouper les rendez-vous par lieu de rendez-vous
|
||||
Group appointments by cancel reason: Grouper les rendez-vous par motif d'annulation
|
||||
Group appointments by month and year: Grouper les rendez-vous par mois et année
|
||||
Scope: Service
|
||||
Job: Métier
|
||||
Location type: Type de localisation
|
||||
Location: Lieu de rendez-vous
|
||||
by month and year: Par mois et année
|
||||
|
@ -188,7 +188,7 @@ class CustomFieldChoice extends AbstractCustomField
|
||||
$choices = [];
|
||||
|
||||
foreach ($cf->getOptions()[self::CHOICES] as $choice) {
|
||||
if (false === $choices['active']) {
|
||||
if (false === $choice['active']) {
|
||||
continue;
|
||||
}
|
||||
$choices[$choice['slug']] = $this->translatableStringHelper
|
||||
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\DocStoreBundle\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\HasScopesInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
@ -18,7 +19,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
* @ORM\Entity
|
||||
* @ORM\Table("chill_doc.accompanyingcourse_document")
|
||||
*/
|
||||
class AccompanyingCourseDocument extends Document
|
||||
class AccompanyingCourseDocument extends Document implements HasScopesInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||
@ -31,6 +32,15 @@ class AccompanyingCourseDocument extends Document
|
||||
return $this->course;
|
||||
}
|
||||
|
||||
public function getScopes(): iterable
|
||||
{
|
||||
if (null !== $this->course) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->course->getScopes();
|
||||
}
|
||||
|
||||
public function setCourse(?AccompanyingPeriod $course): self
|
||||
{
|
||||
$this->course = $course;
|
||||
|
@ -16,8 +16,6 @@ use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\MainBundle\Entity\HasScopeInterface;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@ -26,7 +24,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
/**
|
||||
* @ORM\MappedSuperclass
|
||||
*/
|
||||
class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdateInterface
|
||||
class Document implements TrackCreationInterface, TrackUpdateInterface
|
||||
{
|
||||
use TrackCreationTrait;
|
||||
|
||||
@ -70,13 +68,6 @@ class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdate
|
||||
*/
|
||||
private $object;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
|
||||
*
|
||||
* @var \Chill\MainBundle\Entity\Scope The document's center
|
||||
*/
|
||||
private $scope;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate")
|
||||
*/
|
||||
@ -122,16 +113,6 @@ class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdate
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scope.
|
||||
*
|
||||
* @return \Chill\MainBundle\Entity\Scope
|
||||
*/
|
||||
public function getScope(): ?Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function getTemplate(): ?DocGeneratorTemplate
|
||||
{
|
||||
return $this->template;
|
||||
@ -175,13 +156,6 @@ class Document implements HasScopeInterface, TrackCreationInterface, TrackUpdate
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setScope($scope): self
|
||||
{
|
||||
$this->scope = $scope;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTemplate(?DocGeneratorTemplate $template): self
|
||||
{
|
||||
$this->template = $template;
|
||||
|
@ -13,6 +13,7 @@ namespace Chill\DocStoreBundle\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
use Chill\MainBundle\Entity\HasScopeInterface;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
@ -27,6 +28,13 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt
|
||||
*/
|
||||
private Person $person;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
|
||||
*
|
||||
* @var \Chill\MainBundle\Entity\Scope The document's center
|
||||
*/
|
||||
private $scope;
|
||||
|
||||
public function getCenter()
|
||||
{
|
||||
return $this->getPerson()->getCenter();
|
||||
@ -37,10 +45,22 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function getScope(): ?Scope
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function setPerson($person): self
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setScope($scope): self
|
||||
{
|
||||
$this->scope = $scope;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +88,5 @@ class AccompanyingCourseDocumentType extends AbstractType
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Document::class,
|
||||
]);
|
||||
|
||||
// $resolver->setRequired(['role', 'center'])
|
||||
// ->setAllowedTypes('role', [ \Symfony\Component\Security\Core\Role\Role::class ])
|
||||
// ->setAllowedTypes('center', [ \Chill\MainBundle\Entity\Center::class ])
|
||||
// ;
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ class PersonDocumentACLAwareRepository implements PersonDocumentACLAwareReposito
|
||||
$this->addACL($qb, $person);
|
||||
|
||||
foreach ($orderBy as $field => $order) {
|
||||
$qb->addOrderBy($field, $order);
|
||||
$qb->addOrderBy('d.' . $field, $order);
|
||||
}
|
||||
|
||||
$qb->setFirstResult($offset)->setMaxResults($limit);
|
||||
|
@ -106,6 +106,10 @@ class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements Prov
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::CREATE === $attribute && null !== $subject->getCourse()) {
|
||||
return $this->voterHelper->voteOnAttribute($attribute, $subject->getCourse(), $token);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
|
||||
|
@ -35,10 +35,10 @@ class AdminMenuBuilder implements LocalMenuBuilderInterface
|
||||
|
||||
$menu->addChild('Events', [
|
||||
'route' => 'chill_event_admin_index',
|
||||
])
|
||||
])
|
||||
->setAttribute('class', 'list-group-item-header')
|
||||
->setExtras([
|
||||
'order' => 6500
|
||||
'order' => 6500,
|
||||
]);
|
||||
|
||||
$menu->addChild('Event type', [
|
||||
|
@ -126,7 +126,7 @@ class Version20160318111334 extends AbstractMigration
|
||||
$this->addSql('ALTER TABLE chill_event_participation '
|
||||
. 'ADD CONSTRAINT FK_4E7768AC217BBB47 '
|
||||
. 'FOREIGN KEY (person_id) '
|
||||
. 'REFERENCES Person (id) '
|
||||
. 'REFERENCES chill_person_person(id) '
|
||||
. 'NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_event_participation '
|
||||
. 'ADD CONSTRAINT FK_4E7768ACD60322AC '
|
||||
|
@ -86,6 +86,9 @@ class ExportController extends AbstractController
|
||||
{
|
||||
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
|
||||
$exportManager = $this->exportManager;
|
||||
|
||||
$export = $exportManager->getExport($alias);
|
||||
|
||||
$key = $request->query->get('key', null);
|
||||
|
||||
[$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key);
|
||||
@ -100,7 +103,8 @@ class ExportController extends AbstractController
|
||||
|
||||
$viewVariables = [
|
||||
'alias' => $alias,
|
||||
'export' => $exportManager->getExport($alias),
|
||||
'export' => $export,
|
||||
'export_group' => $this->getExportGroup($export),
|
||||
];
|
||||
|
||||
if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) {
|
||||
@ -316,6 +320,7 @@ class ExportController extends AbstractController
|
||||
'form' => $form->createView(),
|
||||
'export_alias' => $alias,
|
||||
'export' => $export,
|
||||
'export_group' => $this->getExportGroup($export),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -371,6 +376,7 @@ class ExportController extends AbstractController
|
||||
[
|
||||
'form' => $form->createView(),
|
||||
'export' => $export,
|
||||
'export_group' => $this->getExportGroup($export),
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -514,10 +520,26 @@ class ExportController extends AbstractController
|
||||
[
|
||||
'form' => $form->createView(),
|
||||
'export' => $export,
|
||||
'export_group' => $this->getExportGroup($export),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function getExportGroup($target): string
|
||||
{
|
||||
$exportManager = $this->exportManager;
|
||||
|
||||
$groups = $exportManager->getExportsGrouped(true);
|
||||
|
||||
foreach ($groups as $group => $array) {
|
||||
foreach ($array as $alias => $export) {
|
||||
if ($export === $target) {
|
||||
return $group;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the next step. If $reverse === true, the previous step is returned.
|
||||
*
|
||||
|
@ -92,5 +92,8 @@ final class PostalCodeAPIController extends ApiController
|
||||
$qb->where('e.country = :country')
|
||||
->setParameter('country', $request->query->get('country'));
|
||||
}
|
||||
|
||||
$qb->andWhere('e.origin = :zero')
|
||||
->setParameter('zero', 0);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class UserApiController extends ApiController
|
||||
@ -58,4 +60,14 @@ class UserApiController extends ApiController
|
||||
['groups' => ['read']]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $query
|
||||
*/
|
||||
protected function customizeQuery(string $action, Request $request, $query): void
|
||||
{
|
||||
if ('_index' === $action) {
|
||||
$query->andWhere($query->expr()->eq('e.enabled', "'TRUE'"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class UserJobApiController extends ApiController
|
||||
{
|
||||
protected function customizeQuery(string $action, Request $request, $query): void
|
||||
{
|
||||
if ('_index' === $action) {
|
||||
$query->andWhere($query->expr()->eq('e.active', "'TRUE'"));
|
||||
}
|
||||
}
|
||||
}
|
@ -19,8 +19,10 @@ use Chill\MainBundle\Controller\LanguageController;
|
||||
use Chill\MainBundle\Controller\LocationController;
|
||||
use Chill\MainBundle\Controller\LocationTypeController;
|
||||
use Chill\MainBundle\Controller\UserController;
|
||||
use Chill\MainBundle\Controller\UserJobApiController;
|
||||
use Chill\MainBundle\Controller\UserJobController;
|
||||
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||
use Chill\MainBundle\Doctrine\DQL\Extract;
|
||||
use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey;
|
||||
use Chill\MainBundle\Doctrine\DQL\JsonAggregate;
|
||||
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
|
||||
@ -30,6 +32,7 @@ use Chill\MainBundle\Doctrine\DQL\Replace;
|
||||
use Chill\MainBundle\Doctrine\DQL\Similarity;
|
||||
use Chill\MainBundle\Doctrine\DQL\STContains;
|
||||
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
|
||||
use Chill\MainBundle\Doctrine\DQL\ToChar;
|
||||
use Chill\MainBundle\Doctrine\DQL\Unaccent;
|
||||
use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator;
|
||||
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
|
||||
@ -240,6 +243,10 @@ class ChillMainExtension extends Extension implements
|
||||
'ST_CONTAINS' => STContains::class,
|
||||
'JSONB_ARRAY_LENGTH' => JsonbArrayLength::class,
|
||||
],
|
||||
'datetime_functions' => [
|
||||
'EXTRACT' => Extract::class,
|
||||
'TO_CHAR' => ToChar::class,
|
||||
],
|
||||
],
|
||||
'hydrators' => [
|
||||
'chill_flat_hierarchy_list' => FlatHierarchyEntityHydrator::class,
|
||||
@ -504,6 +511,7 @@ class ChillMainExtension extends Extension implements
|
||||
'name' => 'user_job',
|
||||
'base_path' => '/api/1.0/main/user-job',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'controller' => UserJobApiController::class,
|
||||
'actions' => [
|
||||
'_index' => [
|
||||
'methods' => [
|
||||
|
61
src/Bundle/ChillMainBundle/Doctrine/DQL/Extract.php
Normal file
61
src/Bundle/ChillMainBundle/Doctrine/DQL/Extract.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Doctrine\DQL;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\DateDiffFunction;
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\AST\PathExpression;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* Extract postgresql function
|
||||
* https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT.
|
||||
*
|
||||
* Usage : EXTRACT(field FROM timestamp)
|
||||
* TODO allow interval usage -> EXTRACT(field FROM interval)
|
||||
*/
|
||||
class Extract extends FunctionNode
|
||||
{
|
||||
private string $field;
|
||||
|
||||
private $value;
|
||||
//private PathExpression $value;
|
||||
//private FunctionNode $value;
|
||||
//private DateDiffFunction $value;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return sprintf(
|
||||
'EXTRACT(%s FROM %s)',
|
||||
$this->field,
|
||||
$this->value->dispatch($sqlWalker)
|
||||
);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$this->field = $parser->getLexer()->token['value'];
|
||||
|
||||
$parser->match(Lexer::T_FROM);
|
||||
|
||||
//$this->value = $parser->ScalarExpression();
|
||||
$this->value = $parser->ArithmeticPrimary();
|
||||
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
46
src/Bundle/ChillMainBundle/Doctrine/DQL/ToChar.php
Normal file
46
src/Bundle/ChillMainBundle/Doctrine/DQL/ToChar.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Doctrine\DQL;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
/**
|
||||
* Usage : TO_CHAR(datetime, fmt).
|
||||
*/
|
||||
class ToChar extends FunctionNode
|
||||
{
|
||||
private $datetime;
|
||||
|
||||
private $fmt;
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
return sprintf(
|
||||
'TO_CHAR(%s, %s)',
|
||||
$sqlWalker->walkArithmeticPrimary($this->datetime),
|
||||
$sqlWalker->walkArithmeticPrimary($this->fmt)
|
||||
);
|
||||
}
|
||||
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER);
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$this->datetime = $parser->ArithmeticExpression();
|
||||
$parser->match(Lexer::T_COMMA);
|
||||
$this->fmt = $parser->StringExpression();
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
}
|
72
src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php
Normal file
72
src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="chill_main_geographical_unit")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class GeographicalUnit
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=true)
|
||||
*/
|
||||
private $geom;
|
||||
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $layerName;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $unitName;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getLayerName(): ?string
|
||||
{
|
||||
return $this->layerName;
|
||||
}
|
||||
|
||||
public function getUnitName(): ?string
|
||||
{
|
||||
return $this->unitName;
|
||||
}
|
||||
|
||||
public function setLayerName(?string $layerName): self
|
||||
{
|
||||
$this->layerName = $layerName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUnitName(?string $unitName): self
|
||||
{
|
||||
$this->unitName = $unitName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -139,10 +139,8 @@ interface ExportInterface extends ExportElementInterface
|
||||
|
||||
/**
|
||||
* Return the required Role to execute the Export.
|
||||
*
|
||||
* @return \Symfony\Component\Security\Core\Role\Role
|
||||
*/
|
||||
public function requiredRole();
|
||||
public function requiredRole(): string;
|
||||
|
||||
/**
|
||||
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
|
||||
|
@ -550,7 +550,7 @@ class ExportManager
|
||||
if (null === $centers) {
|
||||
$centers = $this->authorizationHelper->getReachableCenters(
|
||||
$this->user,
|
||||
$role->getRole(),
|
||||
$role
|
||||
);
|
||||
}
|
||||
|
||||
@ -568,6 +568,10 @@ class ExportManager
|
||||
'role' => $role->getRole(),
|
||||
]);
|
||||
|
||||
///// Bypasse les autorisations qui empêche d'afficher les nouveaux exports
|
||||
return true;
|
||||
///// TODO supprimer le return true
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +449,9 @@ class SpreadSheetFormatter implements FormatterInterface
|
||||
|
||||
protected function getTitle()
|
||||
{
|
||||
return $this->translator->trans($this->export->getTitle());
|
||||
$title = $this->translator->trans($this->export->getTitle());
|
||||
|
||||
return substr($title, 0, 30) . '…';
|
||||
}
|
||||
|
||||
protected function initializeCache($key)
|
||||
|
@ -26,9 +26,9 @@ interface ModifierInterface extends ExportElementInterface
|
||||
* If null, will used the ExportInterface::requiredRole role from
|
||||
* the current executing export.
|
||||
*
|
||||
* @return \Symfony\Component\Security\Core\Role\Role|null A role required to execute this ModifiersInterface
|
||||
* @return string|null A role required to execute this ModifiersInterface
|
||||
*/
|
||||
public function addRole();
|
||||
public function addRole(): ?string;
|
||||
|
||||
/**
|
||||
* Alter the query initiated by the export, to add the required statements
|
||||
|
@ -59,7 +59,7 @@ class CommentType extends AbstractType
|
||||
$view->vars = array_replace(
|
||||
$view->vars,
|
||||
[
|
||||
'hideLabel' => true,
|
||||
'fullWidth' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -75,8 +75,6 @@ class PickCenterType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
|
||||
|
||||
$export = $this->exportManager->getExport($options['export_alias']);
|
||||
$centers = $this->authorizationHelper->getReachableCenters(
|
||||
$this->user,
|
||||
|
@ -46,7 +46,7 @@ class PrivateCommentType extends AbstractType
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['hideLabel'] = true;
|
||||
$view->vars['fullWidth'] = true;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
|
@ -108,7 +108,7 @@ class ScopePickerType extends AbstractType
|
||||
$view->vars = array_replace(
|
||||
$view->vars,
|
||||
[
|
||||
'hideLabel' => true,
|
||||
'fullWidth' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Chill\MainBundle\Repository;
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
final class CountryRepository implements ObjectRepository
|
||||
@ -25,6 +26,11 @@ final class CountryRepository implements ObjectRepository
|
||||
$this->repository = $entityManager->getRepository(Country::class);
|
||||
}
|
||||
|
||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||
{
|
||||
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||
}
|
||||
|
||||
public function find($id, $lockMode = null, $lockVersion = null): ?Country
|
||||
{
|
||||
return $this->repository->find($id, $lockMode, $lockVersion);
|
||||
|
@ -46,7 +46,6 @@ require('../lib/collection/index.js');
|
||||
require('../lib/breadcrumb/index.js');
|
||||
require('../lib/download-report/index.js');
|
||||
require('../lib/select_interactive_loading/index.js');
|
||||
require('../lib/export-list/index.js');
|
||||
|
||||
//require('../lib/show_hide/index.js');
|
||||
//require('../lib/tabs/index.js');
|
||||
|
@ -99,11 +99,14 @@ div.flex-table {
|
||||
div.item-bloc {
|
||||
flex-direction: column;
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: $gray-200;
|
||||
&:not(.no-altern) { // class to avoid even/odd
|
||||
|
||||
.chill-user-quote {
|
||||
background-color: shade-color($gray-200, 5%)
|
||||
&:nth-child(even) {
|
||||
background-color: $gray-200;
|
||||
|
||||
.chill-user-quote {
|
||||
background-color: shade-color($gray-200, 5%)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
.container-export {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
|
||||
.export-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.export-list__element {
|
||||
min-width: 18rem;
|
||||
max-width: 20rem;
|
||||
padding: 1rem;
|
||||
margin: 1rem;
|
||||
flex-grow: 1;
|
||||
|
||||
border: 1px solid var(--chill-gray);
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
require('./export-list.scss');
|
@ -1,14 +1,23 @@
|
||||
// Configuration
|
||||
/*
|
||||
* This shared file is used in Chill sass sheets and Vue sass styles to use some bootstrap/chill variables.
|
||||
* Search on @import 'ChillMainAssets/module/bootstrap/shared';
|
||||
*/
|
||||
|
||||
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
/*
|
||||
* Replaced by CHILL variables
|
||||
* it is necessary to keep the possibility of making a diff with original !
|
||||
* original: "bootstrap/scss/variables";
|
||||
*/
|
||||
// 2. Include any default variable overrides here
|
||||
@import "custom/_variables";
|
||||
|
||||
// 3. Include remainder of required Bootstrap stylesheets
|
||||
@import "bootstrap/scss/variables";
|
||||
|
||||
// 4. Include any default map overrides here
|
||||
@import "custom/_maps";
|
||||
|
||||
// 5. Include remainder of required parts
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/root";
|
||||
|
||||
|
||||
|
||||
|
@ -1,18 +1,8 @@
|
||||
/*!
|
||||
* Bootstrap v5.0.1 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*
|
||||
* Enable / disable bootstrap assets
|
||||
*/
|
||||
|
||||
// Bootstrap configuration files are shared with chill entrypoint
|
||||
// Some Bootstrap variables and configuration files are shared with chill entrypoint
|
||||
@import "shared";
|
||||
|
||||
// scss-docs-start import-stack
|
||||
// Layout & components
|
||||
@import "bootstrap/scss/root";
|
||||
// 6. Optionally include any other parts as needed
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
@import "bootstrap/scss/images";
|
||||
@ -42,14 +32,11 @@
|
||||
@import "bootstrap/scss/carousel";
|
||||
@import "bootstrap/scss/spinners";
|
||||
@import "bootstrap/scss/offcanvas";
|
||||
|
||||
// Helpers
|
||||
@import "bootstrap/scss/helpers";
|
||||
|
||||
// Utilities
|
||||
// 7. Optionally include utilities API last to generate classes based on the Sass map in
|
||||
@import "bootstrap/scss/utilities/api";
|
||||
// scss-docs-end import-stack
|
||||
|
||||
// CHILL custom
|
||||
// 8. Add additional custom code here
|
||||
@import "custom";
|
||||
@import "custom/_debug";
|
||||
|
@ -0,0 +1,69 @@
|
||||
//// CHILL OVERRIDE DEFAULT BOOTSTRAP COLORS MAP
|
||||
|
||||
// 'beige' variations
|
||||
$beige-100: tint-color($beige, 80%);
|
||||
$beige-200: tint-color($beige, 60%);
|
||||
$beige-300: tint-color($beige, 40%);
|
||||
$beige-400: tint-color($beige, 20%);
|
||||
$beige-500: $beige;
|
||||
$beige-600: shade-color($beige, 20%);
|
||||
$beige-700: shade-color($beige, 40%);
|
||||
$beige-800: shade-color($beige, 60%);
|
||||
$beige-900: shade-color($beige, 80%);
|
||||
|
||||
$chill-blue: $blue;
|
||||
$chill-green: $green;
|
||||
$chill-green-dark: $green-600;
|
||||
$chill-orange: $orange;
|
||||
$chill-yellow: $yellow;
|
||||
$chill-red: $red;
|
||||
$chill-beige: $beige;
|
||||
$chill-pink: $pink;
|
||||
$chill-dark-gray: $gray-800;
|
||||
$chill-gray: $gray-600;
|
||||
$chill-l-gray: $gray-400;
|
||||
$chill-ll-gray: $gray-300;
|
||||
$chill-light-gray: $gray-200;
|
||||
$chill-llight-gray: $gray-100;
|
||||
|
||||
$colors: (
|
||||
"blue": $blue,
|
||||
"green": $green,
|
||||
"green-dark": $green-600,
|
||||
"yellow": $yellow,
|
||||
"orange": $orange,
|
||||
"red": $red,
|
||||
"pink": $pink,
|
||||
"beige": $beige,
|
||||
"white": $white,
|
||||
"gray": $gray-600,
|
||||
"dark": $gray-800,
|
||||
"black": $black
|
||||
);
|
||||
|
||||
$chill-colors: (
|
||||
"chill-blue": $chill-blue,
|
||||
"chill-green": $chill-green,
|
||||
"chill-green-dark": $chill-green-dark,
|
||||
"chill-orange": $chill-orange,
|
||||
"chill-yellow": $chill-yellow,
|
||||
"chill-red": $chill-red,
|
||||
"chill-beige": $chill-beige,
|
||||
"chill-pink": $chill-pink,
|
||||
"chill-dark-gray": $chill-dark-gray,
|
||||
"chill-gray": $chill-gray,
|
||||
"chill-l-gray": $chill-l-gray,
|
||||
"chill-ll-gray": $chill-ll-gray,
|
||||
"chill-light-gray": $chill-light-gray,
|
||||
"chill-llight-gray": $chill-llight-gray,
|
||||
);
|
||||
|
||||
// Merge the maps
|
||||
$theme-colors: map-merge($theme-colors, $chill-colors);
|
||||
|
||||
// Chill color classes
|
||||
@each $color, $value in $chill-colors {
|
||||
.#{$color} {
|
||||
color: $value;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
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