mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-21 07:03:49 +00:00
Merge branch 'upgrade-sf5' into signature-app-master
This commit is contained in:
@@ -99,10 +99,10 @@ final class ActivityController extends AbstractController
|
||||
|
||||
$form = $this->createDeleteForm($activity->getId(), $person, $accompanyingPeriod);
|
||||
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
if (Request::METHOD_POST === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->logger->notice('An activity has been removed', [
|
||||
'by_user' => $this->getUser()->getUsername(),
|
||||
'activity_id' => $activity->getId(),
|
||||
@@ -640,7 +640,6 @@ final class ActivityController extends AbstractController
|
||||
|
||||
return $this->createFormBuilder()
|
||||
->setAction($this->generateUrl('chill_activity_activity_delete', $params))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private \DateTime $date;
|
||||
|
||||
/**
|
||||
* @var Collection<StoredObject>
|
||||
* @var Collection<int, StoredObject>
|
||||
*/
|
||||
#[Assert\Valid(traverse: true)]
|
||||
#[ORM\ManyToMany(targetEntity: StoredObject::class, cascade: ['persist'])]
|
||||
@@ -107,7 +107,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private ?Person $person = null;
|
||||
|
||||
/**
|
||||
* @var Collection<Person>
|
||||
* @var Collection<int, \Chill\PersonBundle\Entity\Person>
|
||||
*/
|
||||
#[Groups(['read', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: Person::class)]
|
||||
@@ -117,7 +117,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private PrivateCommentEmbeddable $privateComment;
|
||||
|
||||
/**
|
||||
* @var Collection<ActivityReason>
|
||||
* @var Collection<int, ActivityReason>
|
||||
*/
|
||||
#[Groups(['docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: ActivityReason::class)]
|
||||
@@ -132,7 +132,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private string $sentReceived = '';
|
||||
|
||||
/**
|
||||
* @var Collection<SocialAction>
|
||||
* @var Collection<int, \Chill\PersonBundle\Entity\SocialWork\SocialAction>
|
||||
*/
|
||||
#[Groups(['read', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: SocialAction::class)]
|
||||
@@ -140,7 +140,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private Collection $socialActions;
|
||||
|
||||
/**
|
||||
* @var Collection<SocialIssue>
|
||||
* @var Collection<int, SocialIssue>
|
||||
*/
|
||||
#[Groups(['read', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: SocialIssue::class)]
|
||||
@@ -148,7 +148,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private Collection $socialIssues;
|
||||
|
||||
/**
|
||||
* @var Collection<ThirdParty>
|
||||
* @var Collection<int, ThirdParty>
|
||||
*/
|
||||
#[Groups(['read', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: ThirdParty::class)]
|
||||
@@ -162,7 +162,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
private ?User $user = null;
|
||||
|
||||
/**
|
||||
* @var Collection<User>
|
||||
* @var Collection<int, User>
|
||||
*/
|
||||
#[Groups(['read', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: User::class)]
|
||||
|
@@ -79,11 +79,9 @@ class ActivityReason
|
||||
/**
|
||||
* Set active.
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return ActivityReason
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
@@ -110,11 +108,9 @@ class ActivityReason
|
||||
/**
|
||||
* Set name.
|
||||
*
|
||||
* @param array $name
|
||||
*
|
||||
* @return ActivityReason
|
||||
*/
|
||||
public function setName($name)
|
||||
public function setName(array $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
|
@@ -40,9 +40,9 @@ class ActivityReasonCategory implements \Stringable
|
||||
/**
|
||||
* Array of ActivityReason.
|
||||
*
|
||||
* @var Collection<ActivityReason>
|
||||
* @var Collection<int, ActivityReason>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: ActivityReason::class, mappedBy: 'category')]
|
||||
#[ORM\OneToMany(mappedBy: 'category', targetEntity: ActivityReason::class)]
|
||||
private Collection $reasons;
|
||||
|
||||
/**
|
||||
|
@@ -152,7 +152,7 @@ class ListActivityHelper
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translator->trans($value);
|
||||
return $this->translator->trans((string) $value);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ final readonly class PeriodHavingActivityBetweenDatesFilter implements FilterInt
|
||||
|
||||
$qb->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.Activity::class." {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = acp"
|
||||
'SELECT 1 FROM '.Activity::class." {$alias} WHERE {$alias}.date >= :{$from} AND {$alias}.date < :{$to} AND {$alias}.accompanyingPeriod = activity.accompanyingPeriod"
|
||||
)
|
||||
);
|
||||
|
||||
|
@@ -15,9 +15,9 @@ use Chill\ActivityBundle\Entity\ActivityType;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class ActivityTypeRepository implements ActivityTypeRepositoryInterface
|
||||
final readonly class ActivityTypeRepository implements ActivityTypeRepositoryInterface
|
||||
{
|
||||
private readonly EntityRepository $repository;
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
|
@@ -87,7 +87,6 @@
|
||||
<li>
|
||||
{% if bloc.type == 'user' %}
|
||||
<span class="badge-user">
|
||||
hello
|
||||
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false, 'at_date': entity.date }) }}
|
||||
</span>
|
||||
{% else %}
|
||||
|
@@ -22,9 +22,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
class AsideActivityCategory
|
||||
{
|
||||
/**
|
||||
* @var Collection<AsideActivityCategory>
|
||||
* @var Collection<int, AsideActivityCategory>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: AsideActivityCategory::class, mappedBy: 'parent')]
|
||||
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: AsideActivityCategory::class)]
|
||||
private Collection $children;
|
||||
|
||||
#[ORM\Id]
|
||||
|
@@ -54,7 +54,7 @@ abstract class AbstractElementController extends AbstractController
|
||||
$indexPage = 'chill_budget_elements_household_index';
|
||||
}
|
||||
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
if (Request::METHOD_POST === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
@@ -198,10 +198,9 @@ abstract class AbstractElementController extends AbstractController
|
||||
/**
|
||||
* Creates a form to delete a help request entity by id.
|
||||
*/
|
||||
private function createDeleteForm(): Form
|
||||
private function createDeleteForm(): \Symfony\Component\Form\FormInterface
|
||||
{
|
||||
return $this->createFormBuilder()
|
||||
->setMethod(Request::METHOD_DELETE)
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -100,7 +100,7 @@ class Charge extends AbstractElement implements HasCentersInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHelp($help)
|
||||
public function setHelp(?string $help)
|
||||
{
|
||||
$this->help = $help;
|
||||
|
||||
|
@@ -15,9 +15,9 @@ use Chill\BudgetBundle\Entity\ChargeKind;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
final readonly class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
{
|
||||
private readonly EntityRepository $repository;
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
|
@@ -15,9 +15,9 @@ use Chill\BudgetBundle\Entity\ResourceKind;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
final readonly class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
{
|
||||
private readonly EntityRepository $repository;
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
|
@@ -84,7 +84,7 @@ class CalendarController extends AbstractController
|
||||
|
||||
$form = $this->createDeleteForm($entity);
|
||||
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
if (Request::METHOD_POST === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
@@ -512,7 +512,6 @@ class CalendarController extends AbstractController
|
||||
{
|
||||
return $this->createFormBuilder()
|
||||
->setAction($this->generateUrl('chill_calendar_calendar_delete', ['id' => $calendar->getId()]))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -103,7 +103,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
private int $dateTimeVersion = 0;
|
||||
|
||||
/**
|
||||
* @var Collection<CalendarDoc>
|
||||
* @var Collection<int, \Chill\CalendarBundle\Entity\CalendarDoc>
|
||||
*/
|
||||
#[ORM\OneToMany(mappedBy: 'calendar', targetEntity: CalendarDoc::class, orphanRemoval: true)]
|
||||
private Collection $documents;
|
||||
@@ -120,7 +120,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @var Collection&Selectable<int, Invite>
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\CalendarBundle\Entity\Invite>&Selectable
|
||||
*/
|
||||
#[Serializer\Groups(['read', 'docgen:read'])]
|
||||
#[ORM\OneToMany(mappedBy: 'calendar', targetEntity: Invite::class, cascade: ['persist', 'remove', 'merge', 'detach'], orphanRemoval: true)]
|
||||
@@ -143,7 +143,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
private ?Person $person = null;
|
||||
|
||||
/**
|
||||
* @var Collection<Person>
|
||||
* @var Collection<int, Person>
|
||||
*/
|
||||
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
||||
#[Assert\Count(min: 1, minMessage: 'calendar.At least {{ limit }} person is required.')]
|
||||
@@ -157,7 +157,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
private PrivateCommentEmbeddable $privateComment;
|
||||
|
||||
/**
|
||||
* @var Collection<ThirdParty>
|
||||
* @var Collection<int, ThirdParty>
|
||||
*/
|
||||
#[Serializer\Groups(['calendar:read', 'read', 'calendar:light', 'docgen:read'])]
|
||||
#[ORM\ManyToMany(targetEntity: ThirdParty::class)]
|
||||
|
@@ -47,7 +47,7 @@ final class CalendarContextTest extends TestCase
|
||||
{
|
||||
$expected =
|
||||
[
|
||||
'track_datetime' => true,
|
||||
'trackDatetime' => true,
|
||||
'askMainPerson' => true,
|
||||
'mainPersonLabel' => 'docgen.calendar.Destinee',
|
||||
'askThirdParty' => false,
|
||||
@@ -61,7 +61,7 @@ final class CalendarContextTest extends TestCase
|
||||
{
|
||||
$expected =
|
||||
[
|
||||
'track_datetime' => true,
|
||||
'trackDatetime' => true,
|
||||
'askMainPerson' => true,
|
||||
'mainPersonLabel' => 'docgen.calendar.Destinee',
|
||||
'askThirdParty' => false,
|
||||
|
@@ -172,11 +172,9 @@ class CustomField
|
||||
/**
|
||||
* Set active.
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return CustomField
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
@@ -224,18 +222,16 @@ class CustomField
|
||||
/**
|
||||
* Set order.
|
||||
*
|
||||
* @param float $order
|
||||
*
|
||||
* @return CustomField
|
||||
*/
|
||||
public function setOrdering($order)
|
||||
public function setOrdering(?float $order)
|
||||
{
|
||||
$this->ordering = $order;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRequired($required)
|
||||
public function setRequired(bool $required)
|
||||
{
|
||||
$this->required = $required;
|
||||
|
||||
@@ -245,7 +241,7 @@ class CustomField
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setSlug($slug)
|
||||
public function setSlug(?string $slug)
|
||||
{
|
||||
$this->slug = $slug;
|
||||
|
||||
@@ -255,11 +251,9 @@ class CustomField
|
||||
/**
|
||||
* Set type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return CustomField
|
||||
*/
|
||||
public function setType($type)
|
||||
public function setType(?string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
|
@@ -23,9 +23,9 @@ class Option
|
||||
private bool $active = true;
|
||||
|
||||
/**
|
||||
* @var Collection<Option>
|
||||
* @var Collection<int, Option>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Option::class, mappedBy: 'parent')]
|
||||
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: Option::class)]
|
||||
private Collection $children;
|
||||
|
||||
#[ORM\Id]
|
||||
@@ -129,7 +129,7 @@ class Option
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
@@ -139,7 +139,7 @@ class Option
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setInternalKey($internal_key)
|
||||
public function setInternalKey(string $internal_key)
|
||||
{
|
||||
$this->internalKey = $internal_key;
|
||||
|
||||
@@ -149,7 +149,7 @@ class Option
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setKey($key)
|
||||
public function setKey(?string $key)
|
||||
{
|
||||
$this->key = $key;
|
||||
|
||||
|
@@ -69,7 +69,7 @@ class CustomFieldsDefaultGroup
|
||||
*
|
||||
* @return CustomFieldsDefaultGroup
|
||||
*/
|
||||
public function setCustomFieldsGroup($customFieldsGroup)
|
||||
public function setCustomFieldsGroup(?CustomFieldsGroup $customFieldsGroup)
|
||||
{
|
||||
$this->customFieldsGroup = $customFieldsGroup;
|
||||
|
||||
@@ -79,11 +79,9 @@ class CustomFieldsDefaultGroup
|
||||
/**
|
||||
* Set entity.
|
||||
*
|
||||
* @param string $entity
|
||||
*
|
||||
* @return CustomFieldsDefaultGroup
|
||||
*/
|
||||
public function setEntity($entity)
|
||||
public function setEntity(?string $entity)
|
||||
{
|
||||
$this->entity = $entity;
|
||||
|
||||
|
@@ -32,9 +32,9 @@ class CustomFieldsGroup
|
||||
* The custom fields of the group.
|
||||
* The custom fields are asc-ordered regarding to their property "ordering".
|
||||
*
|
||||
* @var Collection<CustomField>
|
||||
* @var Collection<int, CustomField>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: CustomField::class, mappedBy: 'customFieldGroup')]
|
||||
#[ORM\OneToMany(mappedBy: 'customFieldGroup', targetEntity: CustomField::class)]
|
||||
#[ORM\OrderBy(['ordering' => \Doctrine\Common\Collections\Criteria::ASC])]
|
||||
private Collection $customFields;
|
||||
|
||||
@@ -165,11 +165,9 @@ class CustomFieldsGroup
|
||||
/**
|
||||
* Set entity.
|
||||
*
|
||||
* @param string $entity
|
||||
*
|
||||
* @return CustomFieldsGroup
|
||||
*/
|
||||
public function setEntity($entity)
|
||||
public function setEntity(?string $entity)
|
||||
{
|
||||
$this->entity = $entity;
|
||||
|
||||
|
@@ -21,14 +21,14 @@ use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
final class RelatorioDriver implements DriverInterface
|
||||
final readonly class RelatorioDriver implements DriverInterface
|
||||
{
|
||||
private readonly string $url;
|
||||
private string $url;
|
||||
|
||||
public function __construct(
|
||||
private readonly HttpClientInterface $client,
|
||||
private HttpClientInterface $client,
|
||||
ParameterBagInterface $parameterBag,
|
||||
private readonly LoggerInterface $logger
|
||||
private LoggerInterface $logger
|
||||
) {
|
||||
$this->url = $parameterBag->get('chill_doc_generator')['driver']['relatorio']['url'];
|
||||
}
|
||||
|
@@ -16,11 +16,11 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
final class DocGeneratorTemplateRepository implements DocGeneratorTemplateRepositoryInterface
|
||||
final readonly class DocGeneratorTemplateRepository implements DocGeneratorTemplateRepositoryInterface
|
||||
{
|
||||
private readonly EntityRepository $repository;
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, private readonly RequestStack $requestStack)
|
||||
public function __construct(EntityManagerInterface $entityManager, private RequestStack $requestStack)
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(DocGeneratorTemplate::class);
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ class Document implements TrackCreationInterface, TrackUpdateInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser($user): self
|
||||
public function setUser(?\Chill\MainBundle\Entity\User $user): self
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
|
@@ -86,7 +86,7 @@ class DocumentCategory
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDocumentClass($documentClass): self
|
||||
public function setDocumentClass(?string $documentClass): self
|
||||
{
|
||||
$this->documentClass = $documentClass;
|
||||
|
||||
|
@@ -55,14 +55,14 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
public function setPerson($person): self
|
||||
public function setPerson(Person $person): self
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setScope($scope): self
|
||||
public function setScope(?Scope $scope): self
|
||||
{
|
||||
$this->scope = $scope;
|
||||
|
||||
|
@@ -15,7 +15,7 @@ use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Form\EventType;
|
||||
use Chill\EventBundle\Form\Type\PickEventType;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
@@ -61,7 +61,7 @@ final class EventController extends AbstractController
|
||||
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
|
||||
) {}
|
||||
|
||||
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/delete', name: 'chill_event__event_delete', requirements: ['event_id' => '\d+'], methods: ['GET', 'DELETE'])]
|
||||
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/delete', name: 'chill_event__event_delete', requirements: ['event_id' => '\d+'], methods: ['GET', 'POST', 'DELETE'])]
|
||||
public function deleteAction($event_id, Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|Response
|
||||
{
|
||||
$em = $this->managerRegistry->getManager();
|
||||
@@ -78,10 +78,10 @@ final class EventController extends AbstractController
|
||||
|
||||
$form = $this->createDeleteForm($event_id);
|
||||
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
if (Request::METHOD_POST === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
foreach ($participations as $participation) {
|
||||
$em->remove($participation);
|
||||
}
|
||||
@@ -108,28 +108,6 @@ final class EventController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a form to edit an existing Event entity.
|
||||
*/
|
||||
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/edit', name: 'chill_event__event_edit')]
|
||||
public function editAction($event_id): Response
|
||||
{
|
||||
$em = $this->managerRegistry->getManager();
|
||||
|
||||
$entity = $em->getRepository(Event::class)->find($event_id);
|
||||
|
||||
if (!$entity) {
|
||||
throw $this->createNotFoundException('Unable to find Event entity.');
|
||||
}
|
||||
|
||||
$editForm = $this->createEditForm($entity);
|
||||
|
||||
return $this->render('@ChillEvent/Event/edit.html.twig', [
|
||||
'entity' => $entity,
|
||||
'edit_form' => $editForm->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* List events subscriptions for a person.
|
||||
*
|
||||
@@ -313,7 +291,7 @@ final class EventController extends AbstractController
|
||||
/**
|
||||
* Edits an existing Event entity.
|
||||
*/
|
||||
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/update', name: 'chill_event__event_update', methods: ['POST', 'PUT'])]
|
||||
#[\Symfony\Component\Routing\Annotation\Route(path: '/{_locale}/event/event/{event_id}/edit', name: 'chill_event__event_edit', methods: ['GET', 'POST', 'PUT'])]
|
||||
public function updateAction(Request $request, $event_id): \Symfony\Component\HttpFoundation\RedirectResponse|Response
|
||||
{
|
||||
$em = $this->managerRegistry->getManager();
|
||||
@@ -324,14 +302,20 @@ final class EventController extends AbstractController
|
||||
throw $this->createNotFoundException('Unable to find Event entity.');
|
||||
}
|
||||
|
||||
$editForm = $this->createEditForm($entity);
|
||||
$editForm = $this->createForm(EventType::class, $entity, [
|
||||
'center' => $entity->getCenter(),
|
||||
'role' => EventVoter::UPDATE,
|
||||
]);
|
||||
|
||||
$editForm->add('submit', SubmitType::class, ['label' => 'Update']);
|
||||
|
||||
$editForm->handleRequest($request);
|
||||
|
||||
if ($editForm->isValid()) {
|
||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||
$em->persist($entity);
|
||||
$em->flush();
|
||||
|
||||
$this->addFlash('success', $this->translator
|
||||
->trans('The event was updated'));
|
||||
$this->addFlash('success', $this->translator->trans('The event was updated'));
|
||||
|
||||
return $this->redirectToRoute('chill_event__event_show', ['event_id' => $event_id]);
|
||||
}
|
||||
@@ -418,7 +402,6 @@ final class EventController extends AbstractController
|
||||
$builder->add('event_id', HiddenType::class, [
|
||||
'data' => $event->getId(),
|
||||
]);
|
||||
dump($event->getId());
|
||||
|
||||
return $builder->getForm();
|
||||
}
|
||||
@@ -600,29 +583,7 @@ final class EventController extends AbstractController
|
||||
->setAction($this->generateUrl('chill_event__event_delete', [
|
||||
'event_id' => $event_id,
|
||||
]))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form to edit a Event entity.
|
||||
*
|
||||
* @return \Symfony\Component\Form\FormInterface
|
||||
*/
|
||||
private function createEditForm(Event $entity)
|
||||
{
|
||||
$form = $this->createForm(EventType::class, $entity, [
|
||||
'action' => $this->generateUrl('chill_event__event_update', ['event_id' => $entity->getId()]),
|
||||
'method' => 'PUT',
|
||||
'center' => $entity->getCenter(),
|
||||
'role' => 'CHILL_EVENT_CREATE',
|
||||
]);
|
||||
|
||||
$form->remove('center');
|
||||
|
||||
$form->add('submit', SubmitType::class, ['label' => 'Update']);
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
@@ -201,7 +201,7 @@ class EventTypeController extends AbstractController
|
||||
/**
|
||||
* Creates a form to delete a EventType entity by id.
|
||||
*
|
||||
* @return \Symfony\Component\Form\Form The form
|
||||
* @return \Symfony\Component\Form\FormInterface The form
|
||||
*/
|
||||
private function createDeleteForm(mixed $id)
|
||||
{
|
||||
@@ -210,7 +210,6 @@ class EventTypeController extends AbstractController
|
||||
'chill_eventtype_admin_delete',
|
||||
['id' => $id]
|
||||
))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Form\ParticipationType;
|
||||
use Chill\EventBundle\Repository\EventRepository;
|
||||
use Chill\EventBundle\Security\Authorization\ParticipationVoter;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -259,10 +259,10 @@ final class ParticipationController extends AbstractController
|
||||
|
||||
$form = $this->createDeleteForm($participation_id);
|
||||
|
||||
if (Request::METHOD_DELETE === $request->getMethod()) {
|
||||
if (Request::METHOD_POST === $request->getMethod()) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$em->remove($participation);
|
||||
$em->flush();
|
||||
|
||||
@@ -753,7 +753,6 @@ final class ParticipationController extends AbstractController
|
||||
->setAction($this->generateUrl('chill_event_participation_delete', [
|
||||
'participation_id' => $participation_id,
|
||||
]))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -201,7 +201,7 @@ class RoleController extends AbstractController
|
||||
/**
|
||||
* Creates a form to delete a Role entity by id.
|
||||
*
|
||||
* @return \Symfony\Component\Form\Form The form
|
||||
* @return \Symfony\Component\Form\FormInterface The form
|
||||
*/
|
||||
private function createDeleteForm(mixed $id)
|
||||
{
|
||||
|
@@ -201,13 +201,12 @@ class StatusController extends AbstractController
|
||||
/**
|
||||
* Creates a form to delete a Status entity by id.
|
||||
*
|
||||
* @return \Symfony\Component\Form\Form The form
|
||||
* @return \Symfony\Component\Form\FormInterface The form
|
||||
*/
|
||||
private function createDeleteForm(mixed $id)
|
||||
{
|
||||
return $this->createFormBuilder()
|
||||
->setAction($this->generateUrl('chill_event_admin_status_delete', ['id' => $id]))
|
||||
->setMethod('DELETE')
|
||||
->add('submit', SubmitType::class, ['label' => 'Delete'])
|
||||
->getForm();
|
||||
}
|
||||
|
@@ -11,8 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\DependencyInjection;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\Authorization\ParticipationVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
@@ -33,12 +33,13 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||
$loader->load('services.yaml');
|
||||
$loader->load('services/authorization.yaml');
|
||||
$loader->load('services/security.yaml');
|
||||
$loader->load('services/fixtures.yaml');
|
||||
$loader->load('services/forms.yaml');
|
||||
$loader->load('services/repositories.yaml');
|
||||
$loader->load('services/search.yaml');
|
||||
$loader->load('services/timeline.yaml');
|
||||
$loader->load('services/export.yaml');
|
||||
}
|
||||
|
||||
/** (non-PHPdoc).
|
||||
|
@@ -47,7 +47,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
|
||||
private ?Scope $circle = null;
|
||||
|
||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_MUTABLE)]
|
||||
private ?\DateTime $date;
|
||||
private ?\DateTime $date = null;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
@@ -62,9 +62,9 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
|
||||
private ?string $name = null;
|
||||
|
||||
/**
|
||||
* @var Collection<Participation>
|
||||
* @var Collection<int, Participation>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Participation::class, mappedBy: 'event')]
|
||||
#[ORM\OneToMany(mappedBy: 'event', targetEntity: Participation::class)]
|
||||
private Collection $participations;
|
||||
|
||||
#[Assert\NotNull]
|
||||
@@ -79,7 +79,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
|
||||
private ?Location $location = null;
|
||||
|
||||
/**
|
||||
* @var Collection<StoredObject>
|
||||
* @var Collection<int, StoredObject>
|
||||
*/
|
||||
#[ORM\ManyToMany(targetEntity: StoredObject::class, cascade: ['persist', 'refresh'])]
|
||||
#[ORM\JoinTable('chill_event_event_documents')]
|
||||
@@ -192,7 +192,7 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
|
||||
{
|
||||
$iterator = iterator_to_array($this->participations->getIterator());
|
||||
|
||||
uasort($iterator, static fn ($first, $second) => strnatcasecmp((string) $first->getPerson()->getFirstName(), (string) $second->getPerson()->getFirstName()));
|
||||
uasort($iterator, static fn ($first, $second) => strnatcasecmp($first->getPerson()->getFirstName(), $second->getPerson()->getFirstName()));
|
||||
|
||||
return new \ArrayIterator($iterator);
|
||||
}
|
||||
@@ -265,11 +265,9 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter
|
||||
/**
|
||||
* Set label.
|
||||
*
|
||||
* @param string $label
|
||||
*
|
||||
* @return Event
|
||||
*/
|
||||
public function setName($label)
|
||||
public function setName(?string $label)
|
||||
{
|
||||
$this->name = $label;
|
||||
|
||||
|
@@ -38,13 +38,13 @@ class EventType
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var Collection<Role>
|
||||
* @var Collection<int, Role>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Role::class, mappedBy: 'type')]
|
||||
#[ORM\OneToMany(mappedBy: 'type', targetEntity: Role::class)]
|
||||
private Collection $roles;
|
||||
|
||||
/**
|
||||
* @var Collection<Status>
|
||||
* @var Collection<int, Status>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Status::class, mappedBy: 'type')]
|
||||
private Collection $statuses;
|
||||
@@ -146,11 +146,9 @@ class EventType
|
||||
/**
|
||||
* Set active.
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return EventType
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
|
@@ -81,11 +81,9 @@ class Role
|
||||
/**
|
||||
* Set active.
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return Role
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
|
@@ -81,11 +81,9 @@ class Status
|
||||
/**
|
||||
* Set active.
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return Status
|
||||
*/
|
||||
public function setActive($active)
|
||||
public function setActive(bool $active)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
|
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class EventDateAggregator implements AggregatorInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'by month' => 'month',
|
||||
'by week' => 'week',
|
||||
'by year' => 'year',
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = 'year';
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$order = null;
|
||||
|
||||
switch ($data['frequency']) {
|
||||
case 'month':
|
||||
$fmt = 'YYYY-MM';
|
||||
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
$fmt = 'YYYY-IW';
|
||||
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
$fmt = 'YYYY';
|
||||
$order = 'DESC';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf("TO_CHAR(event.date, '%s') AS date_aggregator", $fmt));
|
||||
$qb->addGroupBy('date_aggregator');
|
||||
$qb->addOrderBy('date_aggregator', $order);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('frequency', ChoiceType::class, [
|
||||
'choices' => self::CHOICES,
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['frequency' => self::DEFAULT_CHOICE];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return static function ($value) use ($data): string {
|
||||
if ('_header' === $value) {
|
||||
return 'by '.$data['frequency'];
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return match ($data['frequency']) {
|
||||
default => $value,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['date_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group event by date';
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\EventTypeRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class EventTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
final public const KEY = 'event_type_aggregator';
|
||||
|
||||
public function __construct(protected EventTypeRepository $eventTypeRepository, protected TranslatableStringHelperInterface $translatableStringHelper) {}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!\in_array('eventtype', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('event.type', 'eventtype');
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf('IDENTITY(event.type) AS %s', self::KEY));
|
||||
$qb->addGroupBy(self::KEY);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form required for this aggregator
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function (int|string|null $value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Event type';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $t = $this->eventTypeRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize($t->getName());
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return [self::KEY];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Group by event type';
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\RoleRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class RoleAggregator implements AggregatorInterface
|
||||
{
|
||||
final public const KEY = 'part_role_aggregator';
|
||||
|
||||
public function __construct(protected RoleRepository $roleRepository, protected TranslatableStringHelperInterface $translatableStringHelper) {}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!\in_array('event_part', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('event_part.role', 'role');
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf('IDENTITY(event_part.role) AS %s', self::KEY));
|
||||
$qb->addGroupBy(self::KEY);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form required for this aggregator
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function (int|string|null $value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Participant role';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $r = $this->roleRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize($r->getName());
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return [self::KEY];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Group by participant role';
|
||||
}
|
||||
}
|
22
src/Bundle/ChillEventBundle/Export/Declarations.php
Normal file
22
src/Bundle/ChillEventBundle/Export/Declarations.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export;
|
||||
|
||||
/**
|
||||
* This class declare constants used for the export framework.
|
||||
*/
|
||||
abstract class Declarations
|
||||
{
|
||||
final public const EVENT = 'event';
|
||||
|
||||
final public const EVENT_PARTICIPANTS = 'event_participants';
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\ParticipationRepository;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
|
||||
readonly class CountEventParticipations implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private bool $filterStatsByCenters;
|
||||
|
||||
public function __construct(
|
||||
private ParticipationRepository $participationRepository,
|
||||
ParameterBagInterface $parameterBag,
|
||||
) {
|
||||
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder) {}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Count participants to an event by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of events';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_count_event_participants' !== $key) {
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Count event participants' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return ['export_count_event_participants'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Count event participants';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->participationRepository
|
||||
->createQueryBuilder('event_part')
|
||||
->join('event_part.person', 'person');
|
||||
|
||||
$qb->select('COUNT(event_part.id) as export_count_event_participants');
|
||||
|
||||
if ($this->filterStatsByCenters) {
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person
|
||||
AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ParticipationVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return [
|
||||
Declarations::EVENT_PARTICIPANTS,
|
||||
PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
126
src/Bundle/ChillEventBundle/Export/Export/CountEvents.php
Normal file
126
src/Bundle/ChillEventBundle/Export/Export/CountEvents.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Export;
|
||||
|
||||
use Chill\EventBundle\Repository\EventRepository;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
|
||||
readonly class CountEvents implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private bool $filterStatsByCenters;
|
||||
|
||||
public function __construct(
|
||||
private EventRepository $eventRepository,
|
||||
ParameterBagInterface $parameterBag,
|
||||
) {
|
||||
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder) {}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Count events by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of events';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_count_event' !== $key) {
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Number of events' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return ['export_count_event'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Count events';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->eventRepository
|
||||
->createQueryBuilder('event')
|
||||
->leftJoin('event.participations', 'epart')
|
||||
->leftJoin('epart.person', 'person');
|
||||
|
||||
$qb->select('COUNT(DISTINCT event.id) as export_count_event');
|
||||
|
||||
if ($this->filterStatsByCenters) {
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person
|
||||
AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return EventVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return [
|
||||
Declarations::EVENT,
|
||||
PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class EventDateFilter implements FilterInterface
|
||||
{
|
||||
public function __construct(protected TranslatorInterface $translator, private readonly RollingDateConverterInterface $rollingDateConverter) {}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->between(
|
||||
'event.date',
|
||||
':date_from',
|
||||
':date_to'
|
||||
);
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter(
|
||||
'date_from',
|
||||
$this->rollingDateConverter->convert($data['date_from'])
|
||||
);
|
||||
$qb->setParameter(
|
||||
'date_to',
|
||||
$this->rollingDateConverter->convert($data['date_to'])
|
||||
);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('date_from', PickRollingDateType::class, [
|
||||
'label' => 'Events after this date',
|
||||
])
|
||||
->add('date_to', PickRollingDateType::class, [
|
||||
'label' => 'Events before this date',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
return [
|
||||
'Filtered by date of event: only between %date_from% and %date_to%',
|
||||
[
|
||||
'%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'),
|
||||
'%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filtered by event date';
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Entity\EventType;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\EventTypeRepository;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
class EventTypeFilter implements ExportElementValidatedInterface, FilterInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected TranslatableStringHelperInterface $translatableStringHelper,
|
||||
protected EventTypeRepository $eventTypeRepository
|
||||
) {}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$clause = $qb->expr()->in('event.type', ':selected_event_types');
|
||||
|
||||
$qb->andWhere($clause);
|
||||
$qb->setParameter('selected_event_types', $data['types']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('types', EntityType::class, [
|
||||
'choices' => $this->eventTypeRepository->findAllActive(),
|
||||
'class' => EventType::class,
|
||||
'choice_label' => fn (EventType $ety) => $this->translatableStringHelper->localize($ety->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
'attr' => [
|
||||
'class' => 'select2',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
$typeNames = array_map(
|
||||
fn (EventType $t): string => $this->translatableStringHelper->localize($t->getName()),
|
||||
$this->eventTypeRepository->findBy(['id' => $data['types'] instanceof \Doctrine\Common\Collections\Collection ? $data['types']->toArray() : $data['types']])
|
||||
);
|
||||
|
||||
return ['Filtered by event type: only %list%', [
|
||||
'%list%' => implode(', ', $typeNames),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filtered by event type';
|
||||
}
|
||||
|
||||
public function validateForm($data, ExecutionContextInterface $context)
|
||||
{
|
||||
if (null === $data['types'] || 0 === \count($data['types'])) {
|
||||
$context
|
||||
->buildViolation('At least one type must be chosen')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
94
src/Bundle/ChillEventBundle/Export/Filter/RoleFilter.php
Normal file
94
src/Bundle/ChillEventBundle/Export/Filter/RoleFilter.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\RoleRepository;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
class RoleFilter implements ExportElementValidatedInterface, FilterInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected TranslatableStringHelperInterface $translatableStringHelper,
|
||||
protected RoleRepository $roleRepository
|
||||
) {}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$clause = $qb->expr()->in('event_part.role', ':selected_part_roles');
|
||||
|
||||
$qb->andWhere($clause);
|
||||
$qb->setParameter('selected_part_roles', $data['part_roles']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('part_roles', EntityType::class, [
|
||||
'choices' => $this->roleRepository->findAllActive(),
|
||||
'class' => Role::class,
|
||||
'choice_label' => fn (Role $r) => $this->translatableStringHelper->localize($r->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
'attr' => [
|
||||
'class' => 'select2',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
$roleNames = array_map(
|
||||
fn (Role $r): string => $this->translatableStringHelper->localize($r->getName()),
|
||||
$this->roleRepository->findBy(['id' => $data['part_roles'] instanceof \Doctrine\Common\Collections\Collection ? $data['part_roles']->toArray() : $data['part_roles']])
|
||||
);
|
||||
|
||||
return ['Filtered by participant roles: only %list%', [
|
||||
'%list%' => implode(', ', $roleNames),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filter by participant roles';
|
||||
}
|
||||
|
||||
public function validateForm($data, ExecutionContextInterface $context)
|
||||
{
|
||||
if (null === $data['part_roles'] || 0 === \count($data['part_roles'])) {
|
||||
$context
|
||||
->buildViolation('At least one role must be chosen')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,6 +13,7 @@ namespace Chill\EventBundle\Form;
|
||||
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Form\StoredObjectType;
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Form\Type\PickEventTypeType;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Form\Type\ChillCollectionType;
|
||||
@@ -23,6 +24,7 @@ use Chill\MainBundle\Form\Type\PickUserLocationType;
|
||||
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@@ -31,7 +33,9 @@ class EventType extends AbstractType
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('name')
|
||||
->add('name', TextType::class, [
|
||||
'required' => true,
|
||||
])
|
||||
->add('date', ChillDateTimeType::class, [
|
||||
'required' => true,
|
||||
])
|
||||
@@ -75,7 +79,7 @@ class EventType extends AbstractType
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => \Chill\EventBundle\Entity\Event::class,
|
||||
'data_class' => Event::class,
|
||||
]);
|
||||
$resolver
|
||||
->setRequired(['center', 'role'])
|
||||
|
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\Menu;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
@@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\Menu;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
@@ -13,7 +13,7 @@ namespace Chill\EventBundle\Repository;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
@@ -12,13 +12,57 @@ declare(strict_types=1);
|
||||
namespace Chill\EventBundle\Repository;
|
||||
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
class RoleRepository extends ServiceEntityRepository
|
||||
readonly class RoleRepository implements ObjectRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, private TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
parent::__construct($registry, Role::class);
|
||||
$this->repository = $entityManager->getRepository(Role::class);
|
||||
}
|
||||
|
||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||
{
|
||||
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
{
|
||||
return $this->repository->find($id);
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->repository->findAll();
|
||||
}
|
||||
|
||||
public function findAllActive(): array
|
||||
{
|
||||
$roles = $this->repository->findBy(['active' => true]);
|
||||
|
||||
usort($roles, fn (Role $a, Role $b) => $this->translatableStringHelper->localize($a->getName()) <=> $this->translatableStringHelper->localize($b->getName()));
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
public function findOneBy(array $criteria)
|
||||
{
|
||||
return $this->repository->findOneBy($criteria);
|
||||
}
|
||||
|
||||
public function getClassName(): string
|
||||
{
|
||||
return Role::class;
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{% import '@ChillPerson/Person/macro.html.twig' as person_macro %}
|
||||
|
||||
{% if ignored_participations|length > 0 %}
|
||||
<p>{% transchoice ignored_participations|length %}The following people have been ignored because they are already participating on the event{% endtranschoice %} :</p>
|
||||
<p>{{ 'ignored_participations'|trans({'count': ignored_participations|length}) }}:</p>
|
||||
<ul>
|
||||
{% for p in ignored_participations %}
|
||||
<li>{{ person_macro.render(p.person) }}</li>
|
||||
|
@@ -9,18 +9,19 @@ declare(strict_types=1);
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Security\Authorization;
|
||||
namespace Chill\EventBundle\Security;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
|
||||
/**
|
||||
* Description of EventVoter.
|
||||
@@ -42,61 +43,46 @@ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInter
|
||||
|
||||
final public const UPDATE = 'CHILL_EVENT_UPDATE';
|
||||
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
*/
|
||||
protected $accessDecisionManager;
|
||||
final public const STATS = 'CHILL_EVENT_STATS';
|
||||
|
||||
/**
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
protected $authorizationHelper;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
private readonly VoterHelperInterface $voterHelper;
|
||||
|
||||
public function __construct(
|
||||
AccessDecisionManagerInterface $accessDecisionManager,
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
LoggerInterface $logger
|
||||
private readonly AuthorizationHelper $authorizationHelper,
|
||||
private readonly LoggerInterface $logger,
|
||||
VoterHelperFactoryInterface $voterHelperFactory
|
||||
) {
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->logger = $logger;
|
||||
$this->voterHelper = $voterHelperFactory
|
||||
->generate(self::class)
|
||||
->addCheckFor(null, [self::SEE])
|
||||
->addCheckFor(Event::class, [...self::ROLES])
|
||||
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
||||
->addCheckFor(Center::class, [self::STATS])
|
||||
->build();
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return self::ROLES;
|
||||
return [...self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function getRolesWithHierarchy(): array
|
||||
{
|
||||
return [
|
||||
'Event' => self::ROLES,
|
||||
'Event' => $this->getRoles(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope(): array
|
||||
{
|
||||
return [];
|
||||
return [self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function supports($attribute, $subject)
|
||||
{
|
||||
return ($subject instanceof Event && \in_array($attribute, self::ROLES, true))
|
||||
|| ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE], true))
|
||||
|| (null === $subject && self::SEE === $attribute);
|
||||
return $this->voterHelper->supports($attribute, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param Event $subject
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||
{
|
||||
$this->logger->debug(sprintf('Voting from %s class', self::class));
|
||||
@@ -118,15 +104,5 @@ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInter
|
||||
->getReachableCenters($token->getUser(), $attribute);
|
||||
|
||||
return \count($centers) > 0;
|
||||
|
||||
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->authorizationHelper->userHasAccess(
|
||||
$token->getUser(),
|
||||
$subject,
|
||||
$attribute
|
||||
);
|
||||
}
|
||||
}
|
@@ -9,18 +9,19 @@ declare(strict_types=1);
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Security\Authorization;
|
||||
namespace Chill\EventBundle\Security;
|
||||
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
|
||||
class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||
{
|
||||
@@ -39,58 +40,48 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar
|
||||
|
||||
final public const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE';
|
||||
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
*/
|
||||
protected $accessDecisionManager;
|
||||
final public const STATS = 'CHILL_EVENT_PARTICIPATION_STATS';
|
||||
|
||||
/**
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
protected $authorizationHelper;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
private readonly VoterHelperInterface $voterHelper;
|
||||
|
||||
public function __construct(
|
||||
AccessDecisionManagerInterface $accessDecisionManager,
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
LoggerInterface $logger
|
||||
private readonly AuthorizationHelper $authorizationHelper,
|
||||
private readonly LoggerInterface $logger,
|
||||
VoterHelperFactoryInterface $voterHelperFactory
|
||||
) {
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->logger = $logger;
|
||||
$this->voterHelper = $voterHelperFactory
|
||||
->generate(self::class)
|
||||
->addCheckFor(null, [self::SEE])
|
||||
->addCheckFor(Participation::class, [...self::ROLES])
|
||||
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
||||
->addCheckFor(Center::class, [self::STATS])
|
||||
->build();
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return self::ROLES;
|
||||
return [...self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function getRolesWithHierarchy(): array
|
||||
{
|
||||
return [
|
||||
'Event' => self::ROLES,
|
||||
'Participation' => $this->getRoles(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope(): array
|
||||
{
|
||||
return [];
|
||||
return [self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function supports($attribute, $subject)
|
||||
{
|
||||
return ($subject instanceof Participation && \in_array($attribute, self::ROLES, true))
|
||||
|| ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE], true))
|
||||
|| (null === $subject && self::SEE === $attribute);
|
||||
return $this->voterHelper->supports($attribute, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param Participation $subject
|
||||
* @param string $attribute
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -115,15 +106,5 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar
|
||||
->getReachableCenters($token->getUser(), $attribute);
|
||||
|
||||
return \count($centers) > 0;
|
||||
|
||||
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->authorizationHelper->userHasAccess(
|
||||
$token->getUser(),
|
||||
$subject,
|
||||
$attribute
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Tests\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Export\CountEventParticipations;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class CountEventParticipationsTest extends KernelTestCase
|
||||
{
|
||||
private CountEventParticipations $countEventParticipations;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
$this->countEventParticipations = self::getContainer()->get(CountEventParticipations::class);
|
||||
}
|
||||
|
||||
public function testExecuteQuery(): void
|
||||
{
|
||||
$qb = $this->countEventParticipations->initiateQuery([], [], [])
|
||||
->setMaxResults(1);
|
||||
|
||||
$results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
self::assertIsArray($results, 'smoke test: test that the result is an array');
|
||||
}
|
||||
}
|
43
src/Bundle/ChillEventBundle/Tests/Export/CountEventTest.php
Normal file
43
src/Bundle/ChillEventBundle/Tests/Export/CountEventTest.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Tests\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Export\CountEvents;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class CountEventTest extends KernelTestCase
|
||||
{
|
||||
private CountEvents $countEvents;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
$this->countEvents = self::getContainer()->get(CountEvents::class);
|
||||
}
|
||||
|
||||
public function testExecuteQuery(): void
|
||||
{
|
||||
$qb = $this->countEvents->initiateQuery([], [], [])
|
||||
->setMaxResults(1);
|
||||
|
||||
$results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
self::assertIsArray($results, 'smoke test: test that the result is an array');
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Aggregator\EventDateAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventDateAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::getContainer()->get(EventDateAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array|\Generator
|
||||
{
|
||||
yield ['frequency' => 'YYYY'];
|
||||
yield ['frequency' => 'YYYY-MM'];
|
||||
yield ['frequency' => 'YYYY-IV'];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Aggregator\EventTypeAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventTypeAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::getContainer()->get(EventTypeAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Export\Aggregator\RoleAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RoleAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::getContainer()->get(RoleAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
$em->createQueryBuilder()
|
||||
->select('event_part')
|
||||
->from(Participation::class, 'event_part'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Filter\EventDateFilter;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private RollingDateConverterInterface $rollingDateConverter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
|
||||
$this->rollingDateConverter = self::getContainer()->get(RollingDateConverterInterface::class);
|
||||
}
|
||||
|
||||
public function getFilter()
|
||||
{
|
||||
return new EventDateFilter($this->rollingDateConverter);
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'date_from' => new RollingDate(RollingDate::T_YEAR_CURRENT_START),
|
||||
'date_to' => new RollingDate(RollingDate::T_TODAY),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\EventType;
|
||||
use Chill\EventBundle\Export\Filter\EventTypeFilter;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private EventTypeFilter $filter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->filter = self::getContainer()->get(EventTypeFilter::class);
|
||||
}
|
||||
|
||||
public function getFilter(): EventTypeFilter|\Chill\MainBundle\Export\FilterInterface
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
$array = $em->createQueryBuilder()
|
||||
->from(EventType::class, 'et')
|
||||
->select('et')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($array as $a) {
|
||||
$data[] = [
|
||||
'types' => new ArrayCollection([$a]),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getQueryBuilders()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Chill\EventBundle\Export\Filter\RoleFilter;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RoleFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private RoleFilter $filter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->filter = self::getContainer()->get(RoleFilter::class);
|
||||
}
|
||||
|
||||
public function getFilter()
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
$array = $em->createQueryBuilder()
|
||||
->from(Role::class, 'r')
|
||||
->select('r')
|
||||
->getQuery()
|
||||
->setMaxResults(1)
|
||||
->getResult();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($array as $a) {
|
||||
$data[] = [
|
||||
'roles' => new ArrayCollection([$a]),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getQueryBuilders()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
$em->createQueryBuilder()
|
||||
->select('event_part')
|
||||
->from(Participation::class, 'event_part'),
|
||||
];
|
||||
}
|
||||
}
|
@@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||
namespace Chill\EventBundle\Tests\Repository;
|
||||
|
||||
use Chill\EventBundle\Repository\EventACLAwareRepository;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
|
@@ -1,18 +0,0 @@
|
||||
services:
|
||||
chill_event.event_voter:
|
||||
class: Chill\EventBundle\Security\Authorization\EventVoter
|
||||
arguments:
|
||||
- "@security.access.decision_manager"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@logger"
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
|
||||
chill_event.event_participation:
|
||||
class: Chill\EventBundle\Security\Authorization\ParticipationVoter
|
||||
arguments:
|
||||
- "@security.access.decision_manager"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@logger"
|
||||
tags:
|
||||
- { name: security.voter }
|
41
src/Bundle/ChillEventBundle/config/services/export.yaml
Normal file
41
src/Bundle/ChillEventBundle/config/services/export.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
# indicators
|
||||
|
||||
Chill\EventBundle\Export\Export\CountEvents:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_events' }
|
||||
Chill\EventBundle\Export\Export\CountEventParticipations:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_event_participants' }
|
||||
|
||||
# filters
|
||||
|
||||
Chill\EventBundle\Export\Filter\EventDateFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'event_date_filter' }
|
||||
|
||||
Chill\EventBundle\Export\Filter\EventTypeFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'event_type_filter' }
|
||||
|
||||
Chill\EventBundle\Export\Filter\RoleFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'role_filter' }
|
||||
|
||||
# aggregators
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\EventTypeAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: event_type_aggregator }
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\EventDateAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: event_date_aggregator }
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\RoleAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: role_aggregator }
|
14
src/Bundle/ChillEventBundle/config/services/security.yaml
Normal file
14
src/Bundle/ChillEventBundle/config/services/security.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
Chill\EventBundle\Security\EventVoter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
- { name: chill.role }
|
||||
|
||||
Chill\EventBundle\Security\ParticipationVoter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
- { name: chill.role }
|
@@ -19,3 +19,9 @@ events:
|
||||
one {et un autre participant}
|
||||
other {et # autres participants}
|
||||
}
|
||||
|
||||
ignored_participations: >-
|
||||
{ count, plural,
|
||||
one {La personne suivante a été ignorée parce qu''elle participe déjà à l''événement}
|
||||
other {Les personnes suivantes ont été ignorées parce qu''elles participent déjà à l'événement}
|
||||
}
|
||||
|
@@ -41,7 +41,6 @@ Back to the event: Retour à l'événement
|
||||
The participation was created: La participation a été créée
|
||||
The participation was updated: La participation a été mise à jour
|
||||
'None of the requested people may participate the event: they are maybe already participating.': 'Aucune des personnes indiquées ne peut être ajoutée à l''événement: elles sont peut-être déjà inscrites comme participantes.'
|
||||
'The following people have been ignored because they are already participating on the event': '{1} La personne suivante a été ignorée parce qu''elle participe déjà à l''événement | ]1,Inf] Les personnes suivantes ont été ignorées parce qu''elles participent déjà à l''événement'
|
||||
There are no participation to edit for this event: Il n'y a pas de participation pour cet événement
|
||||
The participations have been successfully updated.: Les participations ont été mises à jour.
|
||||
The participation has been sucessfully removed: La participation a été correctement supprimée.
|
||||
@@ -81,9 +80,31 @@ Pick an event: Choisir un événement
|
||||
Pick a type of event: Choisir un type d'événement
|
||||
Pick a moderator: Choisir un animateur
|
||||
|
||||
# exports
|
||||
Select a format: Choisir un format
|
||||
Export: Exporter
|
||||
|
||||
Count events: Nombre d'événements
|
||||
Count events by various parameters.: Compte le nombre d'événements selon divers critères
|
||||
Exports of events: Exports d'événements
|
||||
|
||||
Filtered by event date: Filtrer par date d'événement
|
||||
'Filtered by date of event: only between %date_from% and %date_to%': "Filtré par date d'événement: uniquement entre le %date_from% et le %date_to%"
|
||||
Events after this date: Événements après cette date
|
||||
Events before this date: Événements avant cette date
|
||||
Filtered by event type: Filtrer par type d'événement
|
||||
'Filtered by event type: only %list%': "Filtré par type: uniquement %list%"
|
||||
Group event by date: Grouper par date d'événement
|
||||
Group by event type: Grouper par type d'événement
|
||||
|
||||
Count event participants: Nombre de participations
|
||||
Count participants to an event by various parameters.: Compte le nombre de participations selon divers critères
|
||||
Exports of event participants: Exports de participations
|
||||
'Filtered by participant roles: only %list%': "Filtré par rôles de participation: uniquement %list%"
|
||||
Filter by participant roles: Filtrer par rôles de participation
|
||||
Part roles: Rôles de participation
|
||||
Group by participant role: Grouper par rôle de participation
|
||||
|
||||
|
||||
Events configuration: Configuration des événements
|
||||
Events configuration menu: Menu des événements
|
||||
|
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\ApiHelper;
|
||||
|
||||
use Chill\MainBundle\Redis\ChillRedis;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
|
||||
/**
|
||||
* Wraps the pole emploi api.
|
||||
*/
|
||||
class ApiWrapper
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* key for the bearer for the api pole emploi.
|
||||
*
|
||||
* This bearer is shared across users
|
||||
*/
|
||||
public const UNPERSONAL_BEARER = 'api_pemploi_bear_';
|
||||
|
||||
public function __construct(private $clientId, private $clientSecret, private readonly ChillRedis $redis)
|
||||
{
|
||||
$this->client = new Client([
|
||||
'base_uri' => 'https://entreprise.francetravail.fr/connexion/oauth2/access_token',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getPublicBearer($scopes): string
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($scopes);
|
||||
|
||||
if ($this->redis->exists($cacheKey) > 0) {
|
||||
$data = \unserialize($this->redis->get($cacheKey));
|
||||
|
||||
return $data->access_token;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->client->post('', [
|
||||
'query' => ['realm' => '/partenaire'],
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
],
|
||||
'form_params' => [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => $this->clientId,
|
||||
'client_secret' => $this->clientSecret,
|
||||
'scope' => \implode(' ', \array_merge($scopes, ['application_'.$this->clientId])),
|
||||
],
|
||||
]);
|
||||
} catch (ClientException $e) {
|
||||
dump($e->getResponse());
|
||||
}
|
||||
$data = \json_decode((string) $response->getBody());
|
||||
|
||||
// set the key with an expiry time
|
||||
$this->redis->setex(
|
||||
$cacheKey,
|
||||
$data->expires_in - 2,
|
||||
\serialize($data)
|
||||
);
|
||||
|
||||
return $data->access_token;
|
||||
}
|
||||
|
||||
protected function getCacheKey($scopes)
|
||||
{
|
||||
return self::UNPERSONAL_BEARER.implode('', $scopes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\ApiHelper;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
|
||||
/**
|
||||
* Queries for ROME partenaires api.
|
||||
*/
|
||||
class PartenaireRomeAppellation
|
||||
{
|
||||
use ProcessRequestTrait;
|
||||
/**
|
||||
* @var ApiWrapper
|
||||
*/
|
||||
protected $wrapper;
|
||||
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
private const BASE = 'https://api.pole-emploi.io/partenaire/rome-metiers/v1/metiers/';
|
||||
|
||||
public function __construct(
|
||||
ApiWrapper $wrapper,
|
||||
LoggerInterface $logger,
|
||||
private \Symfony\Contracts\HttpClient\HttpClientInterface $httpClient,
|
||||
) {
|
||||
$this->wrapper = $wrapper;
|
||||
$this->logger = $logger;
|
||||
$this->client = new Client([
|
||||
'base_uri' => 'https://api.pole-emploi.io/partenaire/rome-metiers/v1/metiers/',
|
||||
]);
|
||||
}
|
||||
|
||||
private function getBearer()
|
||||
{
|
||||
return $this->wrapper->getPublicBearer([
|
||||
'api_rome-metiersv1',
|
||||
'nomenclatureRome',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getListeAppellation(string $search): array
|
||||
{
|
||||
$bearer = $this->getBearer();
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request(
|
||||
'GET',
|
||||
self::BASE.'appellation/requete',
|
||||
[
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$bearer,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'query' => [
|
||||
'q' => $search,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $response->toArray()['resultats'];
|
||||
} catch (HttpExceptionInterface $exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
public function getAppellation(string $code): array
|
||||
{
|
||||
$bearer = $this->getBearer();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
$response = $this->httpClient->request('GET', sprintf(self::BASE.'appellation/%s', $code), [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$bearer,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
'query' => [
|
||||
'champs' => 'code,libelle,metier(code,libelle)',
|
||||
],
|
||||
]);
|
||||
|
||||
return $response->toArray();
|
||||
} catch (HttpExceptionInterface $exception) {
|
||||
if (429 === $exception->getResponse()->getStatusCode()) {
|
||||
$retryAfter = $exception->getResponse()->getHeaders(false)['retry-after'][0] ?? 1;
|
||||
sleep((int) $retryAfter);
|
||||
} else {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\ApiHelper;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Methods to process request against the api, and handle the
|
||||
* Exceptions.
|
||||
*/
|
||||
trait ProcessRequestTrait
|
||||
{
|
||||
/**
|
||||
* Handle a request and 429 errors.
|
||||
*
|
||||
* @param Request $request the request
|
||||
* @param array $parameters the requests parameters
|
||||
*/
|
||||
protected function handleRequest(
|
||||
Request $request,
|
||||
array $parameters,
|
||||
Client $client,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
return $this->handleRequestRecursive(
|
||||
$request,
|
||||
$parameters,
|
||||
$client,
|
||||
$logger
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* internal method to handle recursive requests.
|
||||
*
|
||||
* @throws BadResponseException
|
||||
*/
|
||||
private function handleRequestRecursive(
|
||||
Request $request,
|
||||
array $parameters,
|
||||
Client $client,
|
||||
LoggerInterface $logger,
|
||||
$counter = 0
|
||||
) {
|
||||
try {
|
||||
return $client->send($request, $parameters);
|
||||
} catch (BadResponseException $e) {
|
||||
if (
|
||||
// get 429 exceptions
|
||||
$e instanceof ClientException
|
||||
&& 429 === $e->getResponse()->getStatusCode()
|
||||
&& count($e->getResponse()->getHeader('Retry-After')) > 0) {
|
||||
if ($counter > 5) {
|
||||
$logger->error('too much 429 response', [
|
||||
'request' => Psr7\get($e->getRequest()),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$delays = $e->getResponse()->getHeader('Retry-After');
|
||||
$delay = \end($delays);
|
||||
|
||||
sleep($delay);
|
||||
|
||||
return $this->handleRequestRecursive(
|
||||
$request,
|
||||
$parameters,
|
||||
$client,
|
||||
$logger,
|
||||
$counter + 1
|
||||
);
|
||||
}
|
||||
|
||||
// handling other errors
|
||||
$logger->error('Error while querying ROME api', [
|
||||
'status_code' => $e->getResponse()->getStatusCode(),
|
||||
'part' => 'appellation',
|
||||
'request' => $e->getRequest()->getBody()->getContents(),
|
||||
'response' => $e->getResponse()->getBody()->getContents(),
|
||||
]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class ChillFranceTravailApiBundle extends Bundle {}
|
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class RomeController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var PartenaireRomeAppellation
|
||||
*/
|
||||
protected $apiAppellation;
|
||||
|
||||
public function __construct(PartenaireRomeAppellation $apiAppellation)
|
||||
{
|
||||
$this->apiAppellation = $apiAppellation;
|
||||
}
|
||||
|
||||
#[Route(path: '/{_locale}/france-travail/appellation/search.{_format}', name: 'chill_france_travail_api_appellation_search')]
|
||||
public function appellationSearchAction(Request $request)
|
||||
{
|
||||
if (false === $request->query->has('q')) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
$appellations = $this->apiAppellation
|
||||
->getListeAppellation($request->query->get('q'));
|
||||
$results = [];
|
||||
|
||||
foreach ($appellations as $appellation) {
|
||||
$appellation['id'] = 'original-'.$appellation['code'];
|
||||
$appellation['text'] = $appellation['libelle'];
|
||||
$results[] = $appellation;
|
||||
}
|
||||
|
||||
$computed = new \stdClass();
|
||||
$computed->pagination = (new \stdClass());
|
||||
$computed->pagination->more = false;
|
||||
$computed->results = $results;
|
||||
|
||||
return new JsonResponse($computed);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
/**
|
||||
* This is the class that loads and manages your bundle configuration.
|
||||
*
|
||||
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
|
||||
*/
|
||||
class ChillFranceTravailApiExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
public function load(array $configs, ContainerBuilder $container)
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
}
|
||||
|
||||
public function prepend(ContainerBuilder $container): void
|
||||
{
|
||||
$this->prependRoute($container);
|
||||
}
|
||||
|
||||
protected function prependRoute(ContainerBuilder $container): void
|
||||
{
|
||||
// declare routes for france travail api bundle
|
||||
$container->prependExtensionConfig('chill_main', [
|
||||
'routing' => [
|
||||
'resources' => [
|
||||
'@ChillFranceTravailApiBundle/Resources/config/routing.yml',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* This is the class that validates and merges configuration from your app/config files.
|
||||
*
|
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_france_travail_api');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
// Here you should define the parameters that are allowed to
|
||||
// configure your bundle. See the documentation linked above for
|
||||
// more information on that topic.
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
chill_france_travail_api_controllers:
|
||||
resource: "@ChillFranceTravailApiBundle/Controller"
|
||||
type: annotation
|
@@ -0,0 +1,16 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\FranceTravailApiBundle\ApiHelper\ApiWrapper:
|
||||
$clientId: '%env(FRANCE_TRAVAIL_CLIENT_ID)%'
|
||||
$clientSecret: '%env(FRANCE_TRAVAIL_CLIENT_SECRET)%'
|
||||
$redis: '@Chill\MainBundle\Redis\ChillRedis'
|
||||
|
||||
Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation: ~
|
||||
|
||||
Chill\FranceTravailApiBundle\Controller\RomeController:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags: ['controller.service_arguments']
|
@@ -0,0 +1 @@
|
||||
|
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\Tests\ApiHelper;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Chill\FranceTravailApiBundle\ApiHelper\PartenaireRomeAppellation;
|
||||
|
||||
/**
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class PartenaireRomeAppellationTest extends KernelTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
self::bootKernel();
|
||||
}
|
||||
|
||||
public function testGetListeMetiersSimple()
|
||||
{
|
||||
/** @var PartenaireRomeAppellation $appellations */
|
||||
$appellations = self::$kernel
|
||||
->getContainer()
|
||||
->get(PartenaireRomeAppellation::class)
|
||||
;
|
||||
|
||||
$data = $appellations->getListeAppellation('arb');
|
||||
|
||||
$this->assertTrue(\is_array($data));
|
||||
$this->assertNotNull($data[0]->libelle);
|
||||
$this->assertNotNull($data[0]->code);
|
||||
}
|
||||
|
||||
public function testGetListeMetiersTooMuchRequests()
|
||||
{
|
||||
/** @var PartenaireRomeMetier $appellations */
|
||||
$appellations = self::$kernel
|
||||
->getContainer()
|
||||
->get(PartenaireRomeAppellation::class)
|
||||
;
|
||||
|
||||
$appellations->getListeAppellation('arb');
|
||||
$appellations->getListeAppellation('ing');
|
||||
$appellations->getListeAppellation('rob');
|
||||
$appellations->getListeAppellation('chori');
|
||||
$data = $appellations->getListeAppellation('camion');
|
||||
|
||||
$this->assertTrue(
|
||||
$data[0] instanceof \stdClass,
|
||||
'assert that first index of data is an instance of stdClass'
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetAppellation()
|
||||
{
|
||||
/** @var PartenaireRomeMetier $appellations */
|
||||
$appellations = self::$kernel
|
||||
->getContainer()
|
||||
->get(PartenaireRomeAppellation::class)
|
||||
;
|
||||
|
||||
$a = $appellations->getListeAppellation('arb');
|
||||
|
||||
$full = $appellations->getAppellation($a[0]->code);
|
||||
|
||||
$this->assertNotNull(
|
||||
$full->libelle,
|
||||
'assert that libelle is not null'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$full->metier instanceof \stdClass,
|
||||
'assert that metier is returned'
|
||||
);
|
||||
$this->assertNotNull(
|
||||
$full->metier->libelle,
|
||||
'assert that metier->libelle is not null'
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\FranceTravailApiBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RomeControllerTest extends WebTestCase
|
||||
{
|
||||
public function testAppellationsearch()
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$crawler = $client->request('GET', '/{_locale}/pole-emploi/appellation/search');
|
||||
}
|
||||
}
|
16
src/Bundle/ChillJobBundle/src/ChillJobBundle.php
Normal file
16
src/Bundle/ChillJobBundle/src/ChillJobBundle.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class ChillJobBundle extends Bundle {}
|
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Chill\JobBundle\Entity\Immersion;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* CRUD Controller for reports (Frein, ...).
|
||||
*/
|
||||
class CSCrudReportController extends EntityPersonCRUDController
|
||||
{
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
$next = $request->request->get('submit', 'save-and-close');
|
||||
|
||||
return match ($next) {
|
||||
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
|
||||
'person' => $entity->getPerson()->getId(),
|
||||
]),
|
||||
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
|
||||
};
|
||||
}
|
||||
|
||||
protected function duplicateEntity(string $action, Request $request)
|
||||
{
|
||||
if ('cscv' === $this->getCrudName()) {
|
||||
$id = $request->query->get('duplicate_id', 0);
|
||||
/** @var \Chill\JobBundle\Entity\CV $cv */
|
||||
$cv = $this->getEntity($action, $id, $request);
|
||||
$em = $this->managerRegistry->getManager();
|
||||
|
||||
$em->detach($cv);
|
||||
|
||||
foreach ($cv->getExperiences() as $experience) {
|
||||
$cv->removeExperience($experience);
|
||||
$em->detach($experience);
|
||||
$cv->addExperience($experience);
|
||||
}
|
||||
foreach ($cv->getFormations() as $formation) {
|
||||
$cv->removeFormation($formation);
|
||||
$em->detach($formation);
|
||||
$cv->addFormation($formation);
|
||||
}
|
||||
|
||||
return $cv;
|
||||
}
|
||||
if ('projet_prof' === $this->getCrudName()) {
|
||||
$id = $request->query->get('duplicate_id', 0);
|
||||
/** @var \Chill\JobBundle\Entity\ProjetProfessionnel $original */
|
||||
$original = $this->getEntity($action, $id, $request);
|
||||
|
||||
$new = parent::duplicateEntity($action, $request);
|
||||
|
||||
foreach ($original->getSouhait() as $s) {
|
||||
$new->addSouhait($s);
|
||||
}
|
||||
foreach ($original->getValide() as $s) {
|
||||
$new->addValide($s);
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
return parent::duplicateEntity($action, $request);
|
||||
}
|
||||
|
||||
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
|
||||
{
|
||||
if ($entity instanceof Immersion) {
|
||||
if ('edit' === $action || 'new' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, [
|
||||
'center' => $entity->getPerson()->getCenter(),
|
||||
]);
|
||||
}
|
||||
if ('bilan' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, [
|
||||
'center' => $entity->getPerson()->getCenter(),
|
||||
'step' => 'bilan',
|
||||
]);
|
||||
}
|
||||
if ('delete' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||
}
|
||||
throw new \LogicException("this step {$action} is not supported");
|
||||
}
|
||||
|
||||
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||
}
|
||||
|
||||
protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request)
|
||||
{
|
||||
// for immersion / edit-bilan action
|
||||
if ('bilan' === $action) {
|
||||
/* @var $entity Immersion */
|
||||
$entity->setIsBilanFullfilled(true);
|
||||
}
|
||||
|
||||
parent::onPreFlush($action, $entity, $form, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit immersion bilan.
|
||||
*
|
||||
* @param int $id
|
||||
*/
|
||||
public function editBilan(Request $request, $id): Response
|
||||
{
|
||||
return $this->formEditAction('bilan', $request, $id);
|
||||
}
|
||||
}
|
150
src/Bundle/ChillJobBundle/src/Controller/CSPersonController.php
Normal file
150
src/Bundle/ChillJobBundle/src/Controller/CSPersonController.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\OneToOneEntityPersonCRUDController;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Chill\JobBundle\Form\CSPersonPersonalSituationType;
|
||||
use Chill\JobBundle\Form\CSPersonDispositifsType;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class CSPersonController extends OneToOneEntityPersonCRUDController
|
||||
{
|
||||
#[Route(path: '{_locale}/person/job/personal_situation/{id}/edit', name: 'chill_crud_job_personal_situation_edit')]
|
||||
public function personalSituationEdit(Request $request, $id): Response
|
||||
{
|
||||
return $this->formEditAction(
|
||||
'ps_situation_edit',
|
||||
$request,
|
||||
$id,
|
||||
CSPersonPersonalSituationType::class
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '{_locale}/person/job/dispositifs/{id}/edit', name: 'chill_crud_job_dispositifs_edit')]
|
||||
public function dispositifsEdit(Request $request, $id)
|
||||
{
|
||||
return $this->formEditAction(
|
||||
'dispositifs_edit',
|
||||
$request,
|
||||
$id,
|
||||
CSPersonDispositifsType::class
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(path: '{_locale}/person/job/{person}/personal_situation', name: 'chill_crud_job_personal_situation_view')]
|
||||
public function personalSituationView(Request $request, $person): Response
|
||||
{
|
||||
return $this->viewAction('ps_situation_view', $request, $person);
|
||||
}
|
||||
|
||||
#[Route(path: '{_locale}/person/job/{person}/dispositifs', name: 'chill_crud_job_dispositifs_view')]
|
||||
public function dispositifsView(Request $request, $person): Response
|
||||
{
|
||||
return $this->viewAction('dispositifs_view', $request, $person);
|
||||
}
|
||||
|
||||
protected function generateRedirectOnCreateRoute($action, Request $request, $entity): string
|
||||
{
|
||||
$route = '';
|
||||
|
||||
switch ($action) {
|
||||
case 'ps_situation_view':
|
||||
$route = 'chill_crud_job_personal_situation_edit';
|
||||
break;
|
||||
case 'dispositifs_view':
|
||||
$route = 'chill_crud_job_dispositifs_edit';
|
||||
break;
|
||||
default:
|
||||
parent::generateRedirectOnCreateRoute($action, $request, $entity);
|
||||
}
|
||||
|
||||
return $this->generateUrl($route, ['id' => $entity->getPerson()->getId()]);
|
||||
}
|
||||
|
||||
protected function checkACL($action, $entity): void
|
||||
{
|
||||
match ($action) {
|
||||
'ps_situation_edit', 'dispositifs_edit' => $this->denyAccessUnlessGranted(
|
||||
PersonVoter::UPDATE,
|
||||
$entity->getPerson()
|
||||
),
|
||||
'ps_situation_view', 'dispositifs_view' => $this->denyAccessUnlessGranted(
|
||||
PersonVoter::SEE,
|
||||
$entity->getPerson()
|
||||
),
|
||||
default => parent::checkACL($action, $entity),
|
||||
};
|
||||
}
|
||||
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
return match ($action) {
|
||||
'ps_situation_edit' => $this->redirectToRoute(
|
||||
'chill_crud_'.$this->getCrudName().'_personal_situation_view',
|
||||
['person' => $entity->getId()]
|
||||
),
|
||||
'dispositifs_edit' => $this->redirectToRoute(
|
||||
'chill_crud_'.$this->getCrudName().'_dispositifs_view',
|
||||
['person' => $entity->getId()]
|
||||
),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
protected function getTemplateFor($action, $entity, Request $request): string
|
||||
{
|
||||
return match ($action) {
|
||||
'ps_situation_edit' => '@ChillJob/CSPerson/personal_situation_edit.html.twig',
|
||||
'dispositifs_edit' => '@ChillJob/CSPerson/dispositifs_edit.html.twig',
|
||||
'ps_situation_view' => '@ChillJob/CSPerson/personal_situation_view.html.twig',
|
||||
'dispositifs_view' => '@ChillJob/CSPerson/dispositifs_view.html.twig',
|
||||
default => parent::getTemplateFor($action, $entity, $request),
|
||||
};
|
||||
}
|
||||
|
||||
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
|
||||
{
|
||||
switch ($action) {
|
||||
case 'ps_situation_edit':
|
||||
case 'dispositifs_edit':
|
||||
$form = $this->createForm($formClass, $entity, \array_merge(
|
||||
$formOptions,
|
||||
['center' => $entity->getPerson()->getCenter()]
|
||||
));
|
||||
$this->customizeForm($action, $form);
|
||||
|
||||
return $form;
|
||||
|
||||
default:
|
||||
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateLabelForButton($action, $formName, $form): string
|
||||
{
|
||||
switch ($action) {
|
||||
case 'ps_situation_edit':
|
||||
case 'dispositifs_edit':
|
||||
if ('submit' === $formName) {
|
||||
return 'Enregistrer';
|
||||
}
|
||||
throw new \LogicException("this formName is not supported: {$formName}");
|
||||
break;
|
||||
default:
|
||||
return 'Enregistrer';
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Chill\JobBundle\Entity\Frein;
|
||||
use Chill\JobBundle\Entity\CV;
|
||||
use Chill\JobBundle\Entity\Immersion;
|
||||
use Chill\JobBundle\Entity\ProjetProfessionnel;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\JobBundle\Security\Authorization\JobVoter;
|
||||
|
||||
class CSReportController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry) {}
|
||||
|
||||
#[Route(path: '{_locale}/person/job/{person}/report', name: 'chill_job_report_index')]
|
||||
public function index(Person $person): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person, 'The access to '
|
||||
.'person is denied');
|
||||
|
||||
$reports = $this->getReports($person);
|
||||
|
||||
return $this->render('@ChillJob/Report/index.html.twig', \array_merge([
|
||||
'person' => $person,
|
||||
], $reports));
|
||||
}
|
||||
|
||||
protected function getReports(Person $person): array
|
||||
{
|
||||
$results = [];
|
||||
|
||||
$kinds = [];
|
||||
|
||||
if ($this->isGranted(JobVoter::REPORT_CV, $person)) {
|
||||
$kinds['cvs'] = CV::class;
|
||||
}
|
||||
|
||||
if ($this->isGranted(JobVoter::REPORT_NEW, $person)) {
|
||||
$kinds = \array_merge($kinds, [
|
||||
'cvs' => CV::class,
|
||||
'freins' => Frein::class,
|
||||
'immersions' => Immersion::class,
|
||||
'projet_professionnels' => ProjetProfessionnel::class,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($kinds as $key => $className) {
|
||||
$ordering = match ($key) {
|
||||
'immersions' => ['debutDate' => 'DESC'],
|
||||
default => ['reportDate' => 'DESC'],
|
||||
};
|
||||
$results[$key] = $this->managerRegistry->getManager()
|
||||
->getRepository($className)
|
||||
->findBy(['person' => $person], $ordering);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* CRUD Controller for reports (Frein, ...).
|
||||
*/
|
||||
class CVCrudController extends EntityPersonCRUDController
|
||||
{
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
$next = $request->request->get('submit', 'save-and-close');
|
||||
|
||||
return match ($next) {
|
||||
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
|
||||
'person' => $entity->getPerson()->getId(),
|
||||
]),
|
||||
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
|
||||
};
|
||||
}
|
||||
|
||||
protected function duplicateEntity(string $action, Request $request)
|
||||
{
|
||||
if ('cv' === $this->getCrudName()) {
|
||||
$id = $request->query->get('duplicate_id', 0);
|
||||
/** @var \Chill\JobBundle\Entity\CV $cv */
|
||||
$cv = $this->getEntity($action, $id, $request);
|
||||
$em = $this->managerRegistry->getManager();
|
||||
|
||||
$em->detach($cv);
|
||||
|
||||
foreach ($cv->getExperiences() as $experience) {
|
||||
$cv->removeExperience($experience);
|
||||
$em->detach($experience);
|
||||
$cv->addExperience($experience);
|
||||
}
|
||||
foreach ($cv->getFormations() as $formation) {
|
||||
$cv->removeFormation($formation);
|
||||
$em->detach($formation);
|
||||
$cv->addFormation($formation);
|
||||
}
|
||||
|
||||
return $cv;
|
||||
}
|
||||
|
||||
return parent::duplicateEntity($action, $request);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* CRUD Controller for reports (Frein, ...).
|
||||
*/
|
||||
class FreinCrudController extends EntityPersonCRUDController
|
||||
{
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
$next = $request->request->get('submit', 'save-and-close');
|
||||
|
||||
return match ($next) {
|
||||
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
|
||||
'person' => $entity->getPerson()->getId(),
|
||||
]),
|
||||
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Chill\JobBundle\Entity\Immersion;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* CRUD Controller for reports (Frein, ...).
|
||||
*/
|
||||
class ImmersionCrudController extends EntityPersonCRUDController
|
||||
{
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
$next = $request->request->get('submit', 'save-and-close');
|
||||
|
||||
return match ($next) {
|
||||
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
|
||||
'person' => $entity->getPerson()->getId(),
|
||||
]),
|
||||
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
|
||||
};
|
||||
}
|
||||
|
||||
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
|
||||
{
|
||||
if ($entity instanceof Immersion) {
|
||||
if ('edit' === $action || 'new' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, [
|
||||
'center' => $entity->getPerson()->getCenter(),
|
||||
]);
|
||||
}
|
||||
if ('bilan' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, [
|
||||
'center' => $entity->getPerson()->getCenter(),
|
||||
'step' => 'bilan',
|
||||
]);
|
||||
}
|
||||
if ('delete' === $action) {
|
||||
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||
}
|
||||
throw new \LogicException("this step {$action} is not supported");
|
||||
}
|
||||
|
||||
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||
}
|
||||
|
||||
protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request)
|
||||
{
|
||||
// for immersion / edit-bilan action
|
||||
if ('bilan' === $action) {
|
||||
/* @var $entity Immersion */
|
||||
$entity->setIsBilanFullfilled(true);
|
||||
}
|
||||
|
||||
parent::onPreFlush($action, $entity, $form, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit immersion bilan.
|
||||
*
|
||||
* @param int $id
|
||||
*/
|
||||
public function bilan(Request $request, $id): Response
|
||||
{
|
||||
return $this->formEditAction('bilan', $request, $id);
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\CRUD\Controller\EntityPersonCRUDController;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* CRUD Controller for reports (Frein, ...).
|
||||
*/
|
||||
class ProjetProfessionnelCrudController extends EntityPersonCRUDController
|
||||
{
|
||||
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request): ?Response
|
||||
{
|
||||
$next = $request->request->get('submit', 'save-and-close');
|
||||
|
||||
return match ($next) {
|
||||
'save-and-close', 'delete-and-close' => $this->redirectToRoute('chill_job_report_index', [
|
||||
'person' => $entity->getPerson()->getId(),
|
||||
]),
|
||||
default => parent::onBeforeRedirectAfterSubmission($action, $entity, $form, $request),
|
||||
};
|
||||
}
|
||||
|
||||
protected function duplicateEntity(string $action, Request $request)
|
||||
{
|
||||
if ('projet_prof' === $this->getCrudName()) {
|
||||
$id = $request->query->get('duplicate_id', 0);
|
||||
/** @var \Chill\JobBundle\Entity\ProjetProfessionnel $original */
|
||||
$original = $this->getEntity($action, $id, $request);
|
||||
|
||||
$new = parent::duplicateEntity($action, $request);
|
||||
|
||||
foreach ($original->getSouhait() as $s) {
|
||||
$new->addSouhait($s);
|
||||
}
|
||||
foreach ($original->getValide() as $s) {
|
||||
$new->addValide($s);
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
return parent::duplicateEntity($action, $request);
|
||||
}
|
||||
}
|
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\DependencyInjection;
|
||||
|
||||
use Chill\JobBundle\Controller\CSPersonController;
|
||||
use Chill\JobBundle\Controller\CVCrudController;
|
||||
use Chill\JobBundle\Controller\FreinCrudController;
|
||||
use Chill\JobBundle\Controller\ImmersionCrudController;
|
||||
use Chill\JobBundle\Controller\ProjetProfessionnelCrudController;
|
||||
use Chill\JobBundle\Entity\CSPerson;
|
||||
use Chill\JobBundle\Entity\CV;
|
||||
use Chill\JobBundle\Entity\Frein;
|
||||
use Chill\JobBundle\Entity\Immersion;
|
||||
use Chill\JobBundle\Entity\ProjetProfessionnel;
|
||||
use Chill\JobBundle\Form\CVType;
|
||||
use Chill\JobBundle\Form\FreinType;
|
||||
use Chill\JobBundle\Form\ImmersionType;
|
||||
use Chill\JobBundle\Form\ProjetProfessionnelType;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
/**
|
||||
* This is the class that loads and manages your bundle configuration.
|
||||
*
|
||||
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
|
||||
*/
|
||||
class ChillJobExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
$loader->load('services/3party_type.yml');
|
||||
$loader->load('services/controller.yml');
|
||||
$loader->load('services/form.yml');
|
||||
$loader->load('services/export.yml');
|
||||
$loader->load('services/menu.yml');
|
||||
$loader->load('services/security.yml');
|
||||
}
|
||||
|
||||
public function prepend(ContainerBuilder $container): void
|
||||
{
|
||||
$this->prependRoute($container);
|
||||
$this->prependCruds($container);
|
||||
}
|
||||
|
||||
protected function prependCruds(ContainerBuilder $container)
|
||||
{
|
||||
$container->prependExtensionConfig('chill_main', [
|
||||
'cruds' => [
|
||||
[
|
||||
'class' => CSPerson::class,
|
||||
'controller' => CSPersonController::class,
|
||||
'name' => 'job',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'base_path' => '/person/job/',
|
||||
],
|
||||
[
|
||||
'class' => CV::class,
|
||||
'controller' => CVCrudController::class,
|
||||
'name' => 'cscv',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'base_path' => '/person/report/cv',
|
||||
'form_class' => CVType::class,
|
||||
'actions' => [
|
||||
'view' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/CV/view.html.twig',
|
||||
],
|
||||
'new' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/CV/new.html.twig',
|
||||
],
|
||||
'edit' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/CV/edit.html.twig',
|
||||
],
|
||||
'delete' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Report/delete.html.twig',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'class' => ProjetProfessionnel::class,
|
||||
'controller' => ProjetProfessionnelCrudController::class,
|
||||
'name' => 'projet_prof',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'base_path' => '/person/report/projet-professionnel',
|
||||
'form_class' => ProjetProfessionnelType::class,
|
||||
'actions' => [
|
||||
'view' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/ProjetProfessionnel/view.html.twig',
|
||||
],
|
||||
'new' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/ProjetProfessionnel/new.html.twig',
|
||||
],
|
||||
'edit' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/ProjetProfessionnel/edit.html.twig',
|
||||
],
|
||||
'delete' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Report/delete.html.twig',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'class' => Frein::class,
|
||||
'controller' => FreinCrudController::class,
|
||||
'name' => 'csfrein',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'base_path' => '/person/report/frein',
|
||||
'form_class' => FreinType::class,
|
||||
'actions' => [
|
||||
'view' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Frein/view.html.twig',
|
||||
],
|
||||
'new' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Frein/new.html.twig',
|
||||
],
|
||||
'edit' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Frein/edit.html.twig',
|
||||
],
|
||||
'delete' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Report/delete.html.twig',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'class' => Immersion::class,
|
||||
'controller' => ImmersionCrudController::class,
|
||||
'name' => 'immersion',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'base_path' => '/person/report/immersion',
|
||||
'form_class' => ImmersionType::class,
|
||||
'actions' => [
|
||||
'view' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Immersion/view.html.twig',
|
||||
],
|
||||
'new' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Immersion/new.html.twig',
|
||||
],
|
||||
'bilan' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Immersion/edit-bilan.html.twig',
|
||||
],
|
||||
'edit' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Immersion/edit.html.twig',
|
||||
],
|
||||
'delete' => [
|
||||
'role' => 'ROLE_USER',
|
||||
'template' => '@ChillJob/Report/delete.html.twig',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function prependRoute(ContainerBuilder $container): void
|
||||
{
|
||||
// declare routes for job bundle
|
||||
$container->prependExtensionConfig('chill_main', [
|
||||
'routing' => [
|
||||
'resources' => [
|
||||
'@ChillJobBundle/Resources/config/routing.yml',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* This is the class that validates and merges configuration from your app/config files.
|
||||
*
|
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_job');
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
|
||||
// Here you should define the parameters that are allowed to
|
||||
// configure your bundle. See the documentation linked above for
|
||||
// more information on that topic.
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
1224
src/Bundle/ChillJobBundle/src/Entity/CSPerson.php
Normal file
1224
src/Bundle/ChillJobBundle/src/Entity/CSPerson.php
Normal file
File diff suppressed because it is too large
Load Diff
303
src/Bundle/ChillJobBundle/src/Entity/CV.php
Normal file
303
src/Bundle/ChillJobBundle/src/Entity/CV.php
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity;
|
||||
|
||||
use Doctrine\Common\Collections\Order;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* CV.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.cv')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CVRepository::class)]
|
||||
class CV implements \Stringable
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
#[ORM\Column(name: 'reportDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $reportDate = null;
|
||||
|
||||
public const FORMATION_LEVEL = [
|
||||
'sans_diplome',
|
||||
'BEP_CAP',
|
||||
'BAC',
|
||||
'BAC+2',
|
||||
'BAC+3',
|
||||
'BAC+4',
|
||||
'BAC+5',
|
||||
'BAC+8',
|
||||
];
|
||||
|
||||
/**
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
#[ORM\Column(name: 'formationLevel', type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: true)]
|
||||
private ?string $formationLevel = null;
|
||||
|
||||
public const FORMATION_TYPE = [
|
||||
'formation_initiale',
|
||||
'formation_continue',
|
||||
];
|
||||
|
||||
#[ORM\Column(name: 'formationType', type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: true)]
|
||||
private ?string $formationType = null;
|
||||
|
||||
/**
|
||||
* @var string[]|null
|
||||
*/
|
||||
#[ORM\Column(name: 'spokenLanguages', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)]
|
||||
private $spokenLanguages;
|
||||
|
||||
#[ORM\Column(name: 'notes', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
||||
private ?string $notes = null;
|
||||
|
||||
/**
|
||||
* @Assert\Valid(traverse=true)
|
||||
*
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\CV\Formation>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: CV\Formation::class, mappedBy: 'CV', cascade: ['persist', 'remove', 'detach'], orphanRemoval: true)]
|
||||
// #[ORM\OrderBy(['startDate' => Order::Descending, 'endDate' => 'DESC'])]
|
||||
private Collection $formations;
|
||||
|
||||
/**
|
||||
* @Assert\Valid(traverse=true)
|
||||
*
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\CV\Experience>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: CV\Experience::class, mappedBy: 'CV', cascade: ['persist', 'remove', 'detach'], orphanRemoval: true)]
|
||||
// #[ORM\OrderBy(['startDate' => Order::Descending, 'endDate' => 'DESC'])]
|
||||
private Collection $experiences;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Person::class)]
|
||||
private ?Person $person = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->formations = new ArrayCollection();
|
||||
$this->experiences = new ArrayCollection();
|
||||
$this->reportDate = new \DateTime('now');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set reportDate.
|
||||
*/
|
||||
public function setReportDate(\DateTime $reportDate): self
|
||||
{
|
||||
$this->reportDate = $reportDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reportDate.
|
||||
*/
|
||||
public function getReportDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->reportDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set formationLevel.
|
||||
*/
|
||||
public function setFormationLevel(?string $formationLevel = null): self
|
||||
{
|
||||
$this->formationLevel = $formationLevel;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formationLevel.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFormationLevel()
|
||||
{
|
||||
return $this->formationLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set formationType.
|
||||
*/
|
||||
public function setFormationType(string $formationType): self
|
||||
{
|
||||
$this->formationType = $formationType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formationType.
|
||||
*/
|
||||
public function getFormationType(): ?string
|
||||
{
|
||||
return $this->formationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set spokenLanguages.
|
||||
*
|
||||
* @param mixed|null $spokenLanguages
|
||||
*/
|
||||
public function setSpokenLanguages($spokenLanguages = null): self
|
||||
{
|
||||
$this->spokenLanguages = $spokenLanguages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get spokenLanguages.
|
||||
*/
|
||||
public function getSpokenLanguages(): array
|
||||
{
|
||||
return $this->spokenLanguages ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set notes.
|
||||
*/
|
||||
public function setNotes(?string $notes = null): self
|
||||
{
|
||||
$this->notes = $notes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notes.
|
||||
*/
|
||||
public function getNotes(): ?string
|
||||
{
|
||||
return $this->notes;
|
||||
}
|
||||
|
||||
public function getFormations(): Collection
|
||||
{
|
||||
return $this->formations;
|
||||
}
|
||||
|
||||
public function getExperiences(): Collection
|
||||
{
|
||||
return $this->experiences;
|
||||
}
|
||||
|
||||
public function setFormations(Collection $formations): self
|
||||
{
|
||||
foreach ($formations as $formation) {
|
||||
/* @var CV\Formation $formation */
|
||||
$formation->setCV($this);
|
||||
}
|
||||
$this->formations = $formations;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addFormation(CV\Formation $formation): self
|
||||
{
|
||||
if ($this->formations->contains($formation)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->formations->add($formation);
|
||||
$formation->setCV($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeFormation(CV\Formation $formation): self
|
||||
{
|
||||
if (false === $this->formations->contains($formation)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$formation->setCV(null);
|
||||
$this->formations->removeElement($formation);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setExperiences(Collection $experiences): self
|
||||
{
|
||||
foreach ($experiences as $experience) {
|
||||
/* @var CV\Experience $experience */
|
||||
$experience->setCV($this);
|
||||
}
|
||||
|
||||
$this->experiences = $experiences;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addExperience(CV\Experience $experience): self
|
||||
{
|
||||
if ($this->experiences->contains($experience)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$experience->setCV($this);
|
||||
$this->experiences->add($experience);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeExperience(CV\Experience $experience): self
|
||||
{
|
||||
if (false === $this->experiences->contains($experience)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->experiences->removeElement($experience);
|
||||
$experience->setCV(null);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPerson(): Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function setPerson(Person $person)
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'CV de '.$this->getPerson().' daté du '.
|
||||
$this->getReportDate()->format('d-m-Y');
|
||||
}
|
||||
}
|
205
src/Bundle/ChillJobBundle/src/Entity/CV/Experience.php
Normal file
205
src/Bundle/ChillJobBundle/src/Entity/CV/Experience.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity\CV;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\JobBundle\Entity\CV;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Experience.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.cv_experience')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CV\ExperienceRepository::class)]
|
||||
class Experience
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(name: 'poste', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
||||
private ?string $poste = null;
|
||||
|
||||
#[ORM\Column(name: 'structure', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
||||
private ?string $structure = null;
|
||||
|
||||
#[ORM\Column(name: 'startDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $startDate = null;
|
||||
|
||||
/**
|
||||
* @Assert\GreaterThan(propertyPath="startDate", message="La date de fin doit être postérieure à la date de début")
|
||||
*/
|
||||
#[ORM\Column(name: 'endDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $endDate = null;
|
||||
|
||||
public const CONTRAT_TYPE = [
|
||||
'cddi',
|
||||
'cdd-6mois',
|
||||
'cdd+6mois',
|
||||
'interim',
|
||||
'apprentissage',
|
||||
'contrat_prof',
|
||||
'cui',
|
||||
'cae',
|
||||
'cdi',
|
||||
'stage',
|
||||
'volontariat',
|
||||
'benevolat',
|
||||
'autres',
|
||||
];
|
||||
|
||||
#[ORM\Column(name: 'contratType', type: \Doctrine\DBAL\Types\Types::STRING, length: 100)]
|
||||
private ?string $contratType = null;
|
||||
|
||||
#[ORM\Column(name: 'notes', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
||||
private ?string $notes = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: CV::class, inversedBy: 'experiences')]
|
||||
private ?CV $CV = null;
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*/
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set poste.
|
||||
*/
|
||||
public function setPoste(?string $poste = null): self
|
||||
{
|
||||
$this->poste = $poste;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get poste.
|
||||
*/
|
||||
public function getPoste(): ?string
|
||||
{
|
||||
return $this->poste;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set structure.
|
||||
*/
|
||||
public function setStructure(?string $structure = null): self
|
||||
{
|
||||
$this->structure = $structure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get structure.
|
||||
*/
|
||||
public function getStructure(): ?string
|
||||
{
|
||||
return $this->structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set startDate.
|
||||
*
|
||||
* @param \DateTime|null $startDate
|
||||
*/
|
||||
public function setStartDate(?\DateTimeInterface $startDate = null): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get startDate.
|
||||
*
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
public function getStartDate()
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set endDate.
|
||||
*
|
||||
* @param \DateTime|null $endDate
|
||||
*/
|
||||
public function setEndDate(?\DateTimeInterface $endDate = null): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get endDate.
|
||||
*
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
public function getEndDate()
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set contratType.
|
||||
*/
|
||||
public function setContratType(?string $contratType): self
|
||||
{
|
||||
$this->contratType = $contratType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contratType.
|
||||
*/
|
||||
public function getContratType(): ?string
|
||||
{
|
||||
return $this->contratType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set notes.
|
||||
*/
|
||||
public function setNotes(?string $notes): self
|
||||
{
|
||||
$this->notes = $notes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notes.
|
||||
*/
|
||||
public function getNotes(): ?string
|
||||
{
|
||||
return $this->notes;
|
||||
}
|
||||
|
||||
public function getCV(): CV
|
||||
{
|
||||
return $this->CV;
|
||||
}
|
||||
|
||||
public function setCV(?CV $CV = null): self
|
||||
{
|
||||
$this->CV = $CV;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
214
src/Bundle/ChillJobBundle/src/Entity/CV/Formation.php
Normal file
214
src/Bundle/ChillJobBundle/src/Entity/CV/Formation.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity\CV;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\JobBundle\Entity\CV;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Formation.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.cv_formation')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\CV\FormationRepository::class)]
|
||||
class Formation
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @Assert\Length(min=3)
|
||||
*
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
#[ORM\Column(name: 'title', type: \Doctrine\DBAL\Types\Types::TEXT)]
|
||||
private ?string $title = null;
|
||||
|
||||
#[ORM\Column(name: 'startDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $startDate = null;
|
||||
|
||||
/**
|
||||
* @Assert\GreaterThan(propertyPath="startDate", message="La date de fin doit être postérieure à la date de début")
|
||||
*/
|
||||
#[ORM\Column(name: 'endDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $endDate = null;
|
||||
|
||||
public const DIPLOMA_OBTAINED = [
|
||||
'fr', 'non-fr', 'aucun',
|
||||
];
|
||||
|
||||
#[ORM\Column(name: 'diplomaObtained', type: \Doctrine\DBAL\Types\Types::STRING, nullable: true)]
|
||||
private ?string $diplomaObtained = null;
|
||||
|
||||
public const DIPLOMA_RECONNU = [
|
||||
'oui', 'non', 'nsp',
|
||||
];
|
||||
|
||||
#[ORM\Column(name: 'diplomaReconnue', type: \Doctrine\DBAL\Types\Types::STRING, length: 50, nullable: true)]
|
||||
private ?string $diplomaReconnue = null;
|
||||
|
||||
#[ORM\Column(name: 'organisme', type: \Doctrine\DBAL\Types\Types::TEXT, nullable: true)]
|
||||
private ?string $organisme = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: CV::class, inversedBy: 'formations')]
|
||||
private ?CV $CV = null;
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set title.
|
||||
*
|
||||
* @return Formation
|
||||
*/
|
||||
public function setTitle(?string $title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set startDate.
|
||||
*
|
||||
* @param \DateTime|null $startDate
|
||||
*
|
||||
* @return Formation
|
||||
*/
|
||||
public function setStartDate(?\DateTimeInterface $startDate = null)
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get startDate.
|
||||
*
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
public function getStartDate()
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set endDate.
|
||||
*
|
||||
* @param \DateTime|null $endDate
|
||||
*
|
||||
* @return Formation
|
||||
*/
|
||||
public function setEndDate(?\DateTimeInterface $endDate = null)
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get endDate.
|
||||
*
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
public function getEndDate()
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set diplomaObtained.
|
||||
*
|
||||
* @return Formation
|
||||
*/
|
||||
public function setDiplomaObtained(?string $diplomaObtained = null)
|
||||
{
|
||||
$this->diplomaObtained = $diplomaObtained;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diplomaObtained.
|
||||
*/
|
||||
public function getDiplomaObtained()
|
||||
{
|
||||
return $this->diplomaObtained;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set diplomaReconnue.
|
||||
*/
|
||||
public function setDiplomaReconnue(?string $diplomaReconnue = null): self
|
||||
{
|
||||
$this->diplomaReconnue = $diplomaReconnue;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diplomaReconnue.
|
||||
*/
|
||||
public function getDiplomaReconnue(): ?string
|
||||
{
|
||||
return $this->diplomaReconnue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set organisme.
|
||||
*/
|
||||
public function setOrganisme(?string $organisme): self
|
||||
{
|
||||
$this->organisme = $organisme;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get organisme.
|
||||
*/
|
||||
public function getOrganisme(): ?string
|
||||
{
|
||||
return $this->organisme;
|
||||
}
|
||||
|
||||
public function getCV(): ?CV
|
||||
{
|
||||
return $this->CV;
|
||||
}
|
||||
|
||||
public function setCV(?CV $CV = null): self
|
||||
{
|
||||
$this->CV = $CV;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
192
src/Bundle/ChillJobBundle/src/Entity/Frein.php
Normal file
192
src/Bundle/ChillJobBundle/src/Entity/Frein.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\PersonBundle\Entity\HasPerson;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
/**
|
||||
* Frein.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.frein')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\FreinRepository::class)]
|
||||
class Frein implements HasPerson, \Stringable
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @Assert\NotNull()
|
||||
*
|
||||
* @Assert\GreaterThan("5 years ago",
|
||||
* message="La date du rapport ne peut pas être plus de cinq ans dans le passé"
|
||||
* )
|
||||
*/
|
||||
#[ORM\Column(name: 'reportDate', type: \Doctrine\DBAL\Types\Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $reportDate = null;
|
||||
|
||||
public const FREINS_PERSO = [
|
||||
'situation_administrative',
|
||||
'situation_personnelle_et_familiale',
|
||||
'comportement',
|
||||
'etat_de_sante',
|
||||
'precarite_situation_materielle',
|
||||
'condition_ou_absence_logement',
|
||||
'autres',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
#[ORM\Column(name: 'freinsPerso', type: \Doctrine\DBAL\Types\Types::JSON)]
|
||||
private $freinsPerso = [];
|
||||
|
||||
#[ORM\Column(name: 'notesPerso', type: \Doctrine\DBAL\Types\Types::TEXT)]
|
||||
private ?string $notesPerso = '';
|
||||
|
||||
public const FREINS_EMPLOI = [
|
||||
'garde_d_enfants',
|
||||
'sante',
|
||||
'famille',
|
||||
'finances',
|
||||
'maitrise_de_la_langue',
|
||||
'autres',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
#[ORM\Column(name: 'freinsEmploi', type: \Doctrine\DBAL\Types\Types::JSON)]
|
||||
private $freinsEmploi = [];
|
||||
|
||||
#[ORM\Column(name: 'notesEmploi', type: \Doctrine\DBAL\Types\Types::TEXT)]
|
||||
private ?string $notesEmploi = '';
|
||||
|
||||
/**
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: Person::class)]
|
||||
private Person $person;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reportDate = new \DateTime('today');
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setReportDate(?\DateTimeInterface $reportDate): self
|
||||
{
|
||||
$this->reportDate = $reportDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReportDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->reportDate;
|
||||
}
|
||||
|
||||
public function setFreinsPerso(array $freinsPerso = []): self
|
||||
{
|
||||
$this->freinsPerso = $freinsPerso;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFreinsPerso(): array
|
||||
{
|
||||
return $this->freinsPerso;
|
||||
}
|
||||
|
||||
public function setNotesPerso(?string $notesPerso = null): self
|
||||
{
|
||||
$this->notesPerso = (string) $notesPerso;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNotesPerso(): ?string
|
||||
{
|
||||
return $this->notesPerso;
|
||||
}
|
||||
|
||||
public function setFreinsEmploi(array $freinsEmploi = []): self
|
||||
{
|
||||
$this->freinsEmploi = $freinsEmploi;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFreinsEmploi(): array
|
||||
{
|
||||
return $this->freinsEmploi;
|
||||
}
|
||||
|
||||
public function setNotesEmploi(?string $notesEmploi = null): self
|
||||
{
|
||||
$this->notesEmploi = (string) $notesEmploi;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNotesEmploi(): ?string
|
||||
{
|
||||
return $this->notesEmploi;
|
||||
}
|
||||
|
||||
public function getPerson(): ?Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function setPerson(?Person $person = null): HasPerson
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Assert\Callback()
|
||||
*/
|
||||
public function validateFreinsCount(ExecutionContextInterface $context, $payload): void
|
||||
{
|
||||
$nb = count($this->getFreinsEmploi()) + count($this->getFreinsPerso());
|
||||
|
||||
if (0 === $nb) {
|
||||
$msg = 'Indiquez au moins un frein parmi les freins '
|
||||
."liés à l'emploi et les freins liés à la situation personnelle.";
|
||||
$context->buildViolation($msg)
|
||||
->atPath('freinsEmploi')
|
||||
->addViolation();
|
||||
|
||||
$context->buildViolation($msg)
|
||||
->atPath('freinsPerso')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'Rapport "frein" de '.$this->getPerson().' daté du '.
|
||||
$this->getReportDate()->format('d-m-Y');
|
||||
}
|
||||
}
|
1083
src/Bundle/ChillJobBundle/src/Entity/Immersion.php
Normal file
1083
src/Bundle/ChillJobBundle/src/Entity/Immersion.php
Normal file
File diff suppressed because it is too large
Load Diff
407
src/Bundle/ChillJobBundle/src/Entity/ProjetProfessionnel.php
Normal file
407
src/Bundle/ChillJobBundle/src/Entity/ProjetProfessionnel.php
Normal file
@@ -0,0 +1,407 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity;
|
||||
|
||||
use Chill\JobBundle\Repository\ProjetProfessionnelRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\JobBundle\Entity\Rome\Appellation;
|
||||
|
||||
/**
|
||||
* ProjetProfessionnel.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.projet_professionnel')]
|
||||
#[ORM\Entity(repositoryClass: ProjetProfessionnelRepository::class)]
|
||||
class ProjetProfessionnel implements \Stringable
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
#[ORM\ManyToOne(targetEntity: Person::class)]
|
||||
private ?Person $person = null;
|
||||
|
||||
/**
|
||||
* @Assert\NotNull()
|
||||
*/
|
||||
#[ORM\Column(name: 'reportDate', type: Types::DATE_MUTABLE)]
|
||||
private ?\DateTimeInterface $reportDate = null;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
|
||||
*/
|
||||
#[ORM\JoinTable(name: 'chill_job.projetprofessionnel_souhait')]
|
||||
#[ORM\ManyToMany(targetEntity: Appellation::class, cascade: ['persist'])]
|
||||
private Collection $souhait;
|
||||
|
||||
#[ORM\Column(name: 'domaineActiviteSouhait', type: Types::TEXT, nullable: true)]
|
||||
private ?string $domaineActiviteSouhait = null;
|
||||
|
||||
public const TYPE_CONTRAT = [
|
||||
'cdd', 'cdi', 'contrat_insertion',
|
||||
'interim', 'indifferent', 'apprentissage',
|
||||
'personnalisation', 'creation_entreprise',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*
|
||||
* @Assert\Count(min=1, minMessage="Indiquez au moins un type de contrat")
|
||||
*/
|
||||
#[ORM\Column(name: 'typeContrat', type: Types::JSON, nullable: true)]
|
||||
private $typeContrat;
|
||||
|
||||
#[ORM\Column(name: 'typeContratNotes', type: Types::TEXT, nullable: true)]
|
||||
private ?string $typeContratNotes = null;
|
||||
|
||||
public const VOLUME_HORAIRES = [
|
||||
'temps_plein',
|
||||
'temps_partiel',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*
|
||||
* @Assert\Count(min=1, minMessage="Indiquez un volume horaire souhaité")
|
||||
*/
|
||||
#[ORM\Column(name: 'volumeHoraire', type: Types::JSON, nullable: true)]
|
||||
private $volumeHoraire;
|
||||
|
||||
#[ORM\Column(name: 'volumeHoraireNotes', type: Types::TEXT, nullable: true)]
|
||||
private ?string $volumeHoraireNotes = null;
|
||||
|
||||
#[ORM\Column(name: 'idee', type: Types::TEXT, nullable: true)]
|
||||
private ?string $idee = null;
|
||||
|
||||
#[ORM\Column(name: 'enCoursConstruction', type: Types::TEXT, nullable: true)]
|
||||
private ?string $enCoursConstruction = null;
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
|
||||
*/
|
||||
#[ORM\JoinTable(name: 'chill_job.projetprofessionnel_valide')]
|
||||
#[ORM\ManyToMany(targetEntity: Appellation::class)]
|
||||
private Collection $valide;
|
||||
|
||||
#[ORM\Column(name: 'domaineActiviteValide', type: Types::TEXT, nullable: true)]
|
||||
private ?string $domaineActiviteValide = null;
|
||||
|
||||
#[ORM\Column(name: 'valideNotes', type: Types::TEXT, nullable: true)]
|
||||
private ?string $valideNotes = null;
|
||||
|
||||
#[ORM\Column(name: 'projetProfessionnelNote', type: Types::TEXT, nullable: true)]
|
||||
private ?string $projetProfessionnelNote = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->valide = new ArrayCollection();
|
||||
$this->souhait = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set reportDate.
|
||||
*
|
||||
* @param \DateTime $reportDate
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setReportDate(?\DateTimeInterface $reportDate)
|
||||
{
|
||||
$this->reportDate = $reportDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reportDate.
|
||||
*
|
||||
* @return \DateTimeInterface
|
||||
*/
|
||||
public function getReportDate()
|
||||
{
|
||||
return $this->reportDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set typeContrat.
|
||||
*
|
||||
* @param mixed|null $typeContrat
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setTypeContrat($typeContrat = null)
|
||||
{
|
||||
$this->typeContrat = $typeContrat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get typeContrat.
|
||||
*/
|
||||
public function getTypeContrat()
|
||||
{
|
||||
return $this->typeContrat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set typeContratNotes.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setTypeContratNotes(?string $typeContratNotes = null)
|
||||
{
|
||||
$this->typeContratNotes = $typeContratNotes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get typeContratNotes.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTypeContratNotes()
|
||||
{
|
||||
return $this->typeContratNotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set volumeHoraire.
|
||||
*
|
||||
* @param mixed|null $volumeHoraire
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setVolumeHoraire($volumeHoraire = null)
|
||||
{
|
||||
$this->volumeHoraire = $volumeHoraire;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get volumeHoraire.
|
||||
*/
|
||||
public function getVolumeHoraire()
|
||||
{
|
||||
return $this->volumeHoraire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set volumeHoraireNotes.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setVolumeHoraireNotes(?string $volumeHoraireNotes = null)
|
||||
{
|
||||
$this->volumeHoraireNotes = $volumeHoraireNotes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get volumeHoraireNotes.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getVolumeHoraireNotes()
|
||||
{
|
||||
return $this->volumeHoraireNotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set idee.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setIdee(?string $idee = null)
|
||||
{
|
||||
$this->idee = $idee;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get idee.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getIdee()
|
||||
{
|
||||
return $this->idee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set enCoursConstruction.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setEnCoursConstruction(?string $enCoursConstruction = null)
|
||||
{
|
||||
$this->enCoursConstruction = $enCoursConstruction;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enCoursConstruction.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getEnCoursConstruction()
|
||||
{
|
||||
return $this->enCoursConstruction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set valideNotes.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setValideNotes(?string $valideNotes = null)
|
||||
{
|
||||
$this->valideNotes = $valideNotes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get valideNotes.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getValideNotes()
|
||||
{
|
||||
return $this->valideNotes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set projetProfessionnelNote.
|
||||
*
|
||||
* @return ProjetProfessionnel
|
||||
*/
|
||||
public function setProjetProfessionnelNote(?string $projetProfessionnelNote = null)
|
||||
{
|
||||
$this->projetProfessionnelNote = $projetProfessionnelNote;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get projetProfessionnelNote.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getProjetProfessionnelNote()
|
||||
{
|
||||
return $this->projetProfessionnelNote;
|
||||
}
|
||||
|
||||
public function getPerson(): Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function getSouhait(): Collection
|
||||
{
|
||||
return $this->souhait;
|
||||
}
|
||||
|
||||
public function getValide(): Collection
|
||||
{
|
||||
return $this->valide;
|
||||
}
|
||||
|
||||
public function setPerson(Person $person)
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSouhait(Collection $souhait)
|
||||
{
|
||||
$this->souhait = $souhait;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addSouhait(Appellation $souhait)
|
||||
{
|
||||
$this->souhait->add($souhait);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setValide(Collection $valide)
|
||||
{
|
||||
$this->valide = $valide;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addValide(Appellation $valide)
|
||||
{
|
||||
$this->valide->add($valide);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDomaineActiviteSouhait(): ?string
|
||||
{
|
||||
return $this->domaineActiviteSouhait;
|
||||
}
|
||||
|
||||
public function getDomaineActiviteValide(): ?string
|
||||
{
|
||||
return $this->domaineActiviteValide;
|
||||
}
|
||||
|
||||
public function setDomaineActiviteSouhait(?string $domaineActiviteSouhait = null)
|
||||
{
|
||||
$this->domaineActiviteSouhait = $domaineActiviteSouhait;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDomaineActiviteValide(?string $domaineActiviteValide = null)
|
||||
{
|
||||
$this->domaineActiviteValide = $domaineActiviteValide;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'Rapport "projet professionnel" de '.$this->getPerson().' daté du '.
|
||||
$this->getReportDate()->format('d-m-Y');
|
||||
}
|
||||
}
|
107
src/Bundle/ChillJobBundle/src/Entity/Rome/Appellation.php
Normal file
107
src/Bundle/ChillJobBundle/src/Entity/Rome/Appellation.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity\Rome;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Appellation.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.rome_appellation')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\Rome\AppellationRepository::class)]
|
||||
class Appellation implements \Stringable
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(name: 'code', type: \Doctrine\DBAL\Types\Types::STRING, length: 40, unique: true)]
|
||||
private ?string $code = '';
|
||||
|
||||
#[ORM\Column(name: 'libelle', type: \Doctrine\DBAL\Types\Types::TEXT)]
|
||||
private ?string $libelle = '';
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Metier::class, inversedBy: 'appellations', cascade: ['persist'])]
|
||||
private ?Metier $metier = null;
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set code.
|
||||
*
|
||||
* @return Appellation
|
||||
*/
|
||||
public function setCode(?string $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set libelle.
|
||||
*
|
||||
* @return Appellation
|
||||
*/
|
||||
public function setLibelle(?string $libelle)
|
||||
{
|
||||
$this->libelle = $libelle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get libelle.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLibelle()
|
||||
{
|
||||
return $this->libelle;
|
||||
}
|
||||
|
||||
public function getMetier(): Metier
|
||||
{
|
||||
return $this->metier;
|
||||
}
|
||||
|
||||
public function setMetier(Metier $metier)
|
||||
{
|
||||
$this->metier = $metier;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->libelle;
|
||||
}
|
||||
}
|
100
src/Bundle/ChillJobBundle/src/Entity/Rome/Metier.php
Normal file
100
src/Bundle/ChillJobBundle/src/Entity/Rome/Metier.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Entity\Rome;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* Metier.
|
||||
*/
|
||||
#[ORM\Table(name: 'chill_job.rome_metier')]
|
||||
#[ORM\Entity(repositoryClass: \Chill\JobBundle\Repository\Rome\MetierRepository::class)]
|
||||
class Metier
|
||||
{
|
||||
#[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue(strategy: 'AUTO')]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(name: 'libelle', type: \Doctrine\DBAL\Types\Types::TEXT)]
|
||||
private ?string $libelle = '';
|
||||
|
||||
#[ORM\Column(name: 'code', type: \Doctrine\DBAL\Types\Types::STRING, length: 20, unique: true)]
|
||||
private ?string $code = '';
|
||||
|
||||
/**
|
||||
* @var \Doctrine\Common\Collections\Collection<int, \Chill\JobBundle\Entity\Rome\Appellation>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: Appellation::class, mappedBy: 'metier')]
|
||||
private \Doctrine\Common\Collections\Collection $appellations;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->appellations = new ArrayCollection();
|
||||
// $this->appellation = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set libelle.
|
||||
*
|
||||
* @return Metier
|
||||
*/
|
||||
public function setLibelle(?string $libelle)
|
||||
{
|
||||
$this->libelle = $libelle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get libelle.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLibelle()
|
||||
{
|
||||
return $this->libelle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set code.
|
||||
*
|
||||
* @return Metier
|
||||
*/
|
||||
public function setCode(?string $code)
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Export;
|
||||
|
||||
use Chill\JobBundle\Entity\CSPerson;
|
||||
use Chill\PersonBundle\Export\Helper\CustomizeListPersonHelperInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Class ListCSPerson.
|
||||
*
|
||||
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
|
||||
*/
|
||||
class AddCSPersonToPersonListHelper implements CustomizeListPersonHelperInterface
|
||||
{
|
||||
public function __construct(private readonly TranslatorInterface $translator) {}
|
||||
|
||||
private const CSPERSON_FIELDS = [
|
||||
'dateFinDernierEmploi',
|
||||
/* 'prescripteur__name',
|
||||
'prescripteur__email',
|
||||
'prescripteur__phone',*/
|
||||
'poleEmploiId',
|
||||
'cafId',
|
||||
'cafInscriptionDate',
|
||||
'dateContratIEJ',
|
||||
'cERInscriptionDate',
|
||||
'pPAEInscriptionDate',
|
||||
'pPAESignataire',
|
||||
'cERSignataire',
|
||||
'nEETCommissionDate',
|
||||
'fSEMaDemarcheCode',
|
||||
'enfantACharge',
|
||||
'nEETEligibilite',
|
||||
'situationProfessionnelle',
|
||||
];
|
||||
|
||||
public function alterKeys(array $existing): array
|
||||
{
|
||||
$ressources = array_map(static fn ($key) => 'ressources__'.$key, CSPerson::RESSOURCES);
|
||||
$moyenTransport = array_map(static fn ($key) => 'moyen_transport__'.$key, CSPerson::MOBILITE_MOYEN_TRANSPORT);
|
||||
$accompagnements = array_map(static fn ($key) => 'accompagnements__'.$key, CSPerson::ACCOMPAGNEMENTS);
|
||||
$permisConduire = array_map(static fn ($key) => 'permis_conduire__'.$key, CSPerson::PERMIS_CONDUIRE);
|
||||
$typeContrat = array_map(static fn ($key) => 'type_contrat__'.$key, CSPerson::TYPE_CONTRAT);
|
||||
|
||||
return [
|
||||
...$existing,
|
||||
...self::CSPERSON_FIELDS,
|
||||
...$ressources,
|
||||
...$moyenTransport,
|
||||
...$accompagnements,
|
||||
...$permisConduire,
|
||||
...$typeContrat,
|
||||
];
|
||||
}
|
||||
|
||||
public function alterSelect(QueryBuilder $qb, \DateTimeImmutable $computedDate): void
|
||||
{
|
||||
$qb
|
||||
->leftJoin(CSPerson::class, 'cs_person', Query\Expr\Join::WITH, 'cs_person.person = person');
|
||||
|
||||
foreach (self::CSPERSON_FIELDS as $f) {
|
||||
$qb->addSelect(sprintf('cs_person.%s as %s', $f, $f));
|
||||
}
|
||||
|
||||
/* $qb->addSelect('cs_person.situationProfessionnelle as situation_prof');
|
||||
|
||||
$qb->addSelect('cs_person.nEETEligibilite as nEETEligibilite');*/
|
||||
|
||||
$i = 0;
|
||||
|
||||
foreach (CSPerson::RESSOURCES as $key) {
|
||||
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.ressources, :param_{$i}) AS ressources__".$key)
|
||||
->setParameter('param_'.$i, $key);
|
||||
++$i;
|
||||
}
|
||||
|
||||
foreach (CSPerson::MOBILITE_MOYEN_TRANSPORT as $key) {
|
||||
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.mobiliteMoyenDeTransport, :param_{$i}) AS moyen_transport__".$key)
|
||||
->setParameter('param_'.$i, $key);
|
||||
++$i;
|
||||
}
|
||||
|
||||
foreach (CSPerson::TYPE_CONTRAT as $key) {
|
||||
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.typeContrat, :param_{$i}) AS type_contrat__".$key)
|
||||
->setParameter('param_'.$i, $key);
|
||||
++$i;
|
||||
}
|
||||
|
||||
foreach (CSPerson::ACCOMPAGNEMENTS as $key) {
|
||||
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.accompagnement, :param_{$i}) AS accompagnements__".$key)
|
||||
->setParameter('param_'.$i, $key);
|
||||
++$i;
|
||||
}
|
||||
|
||||
foreach (CSPerson::PERMIS_CONDUIRE as $key) {
|
||||
$qb->addSelect("JSONB_EXISTS_IN_ARRAY(cs_person.permisConduire, :param_{$i}) AS permis_conduire__".$key)
|
||||
->setParameter('param_'.$i, $key);
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
public function getLabels(string $key, array $values, array $data): ?callable
|
||||
{
|
||||
if (str_contains($key, '__')) {
|
||||
return function (string|bool|null $value) use ($key): string {
|
||||
if ('_header' === $value) {
|
||||
[$domain, $v] = explode('__', $key);
|
||||
|
||||
return 'export.list.cs_person.'.$domain.'.'.$v;
|
||||
}
|
||||
|
||||
if ('1' === $value || true === $value || 't' === $value) {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
}
|
||||
|
||||
return match ($key) {
|
||||
'nEETEligibilite' => function (string|bool|null $value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'export.list.cs_person.neet_eligibility';
|
||||
}
|
||||
|
||||
if ('1' === $value || true === $value || 't' === $value) {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
'situationProfessionnelle' => function ($value) {
|
||||
if ('_header' === $value) {
|
||||
return 'export.list.cs_person.situation_professionelle';
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
'cerinscriptiondate', 'ppaeinscriptiondate', 'neetcommissiondate', 'findernieremploidate', 'cafinscriptiondate', 'contratiejdate' => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $this->translator->trans($key);
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return '';
|
||||
}
|
||||
// warning: won't work with DateTimeImmutable as we reset time a few lines later
|
||||
$date = \DateTime::createFromFormat('Y-m-d', $value);
|
||||
$hasTime = false;
|
||||
|
||||
if (false === $date) {
|
||||
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value);
|
||||
$hasTime = true;
|
||||
}
|
||||
|
||||
// check that the creation could occur.
|
||||
if (false === $date) {
|
||||
throw new \Exception(sprintf('The value %s could not be converted to %s', $value, \DateTime::class));
|
||||
}
|
||||
|
||||
if (!$hasTime) {
|
||||
$date->setTime(0, 0, 0);
|
||||
}
|
||||
|
||||
return $date;
|
||||
},
|
||||
default => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $this->translator->trans($key);
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
395
src/Bundle/ChillJobBundle/src/Export/ListCV.php
Normal file
395
src/Bundle/ChillJobBundle/src/Export/ListCV.php
Normal file
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Export;
|
||||
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\ListInterface;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\JobBundle\Security\Authorization\ExportsJobVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class ListCV.
|
||||
*
|
||||
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
|
||||
*/
|
||||
class ListCV implements ListInterface, ExportElementValidatedInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public const FIELDS = [
|
||||
'id' => 'integer',
|
||||
'firstname' => 'string',
|
||||
'lastname' => 'string',
|
||||
'gender' => 'string',
|
||||
'birthdate' => 'date',
|
||||
'placeofbirth' => 'string',
|
||||
'countryofbirth' => 'json',
|
||||
'formationlevel' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $personIds = [];
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* ListAcquisition constructor.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->entityManager = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate the form's data and, if required, build a contraint
|
||||
* violation on the data.
|
||||
*
|
||||
* @param mixed $data the data, as returned by the user
|
||||
*/
|
||||
public function validateForm($data, ExecutionContextInterface $context) {}
|
||||
|
||||
/**
|
||||
* get a title, which will be used in UI (and translated).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Liste des CVs par personne';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to collect data from the user.
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('fields', ChoiceType::class, [
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
// 'choices_as_values' => true,
|
||||
'label' => 'Fields to include in export',
|
||||
'choices' => array_combine($this->getFields(), $this->getFields()),
|
||||
'data' => array_combine($this->getFields(), $this->getFields()),
|
||||
'choice_attr' => [],
|
||||
'attr' => ['class' => ''],
|
||||
'constraints' => [new Callback([
|
||||
'callback' => function ($selected, ExecutionContextInterface $context) {
|
||||
if (0 === count($selected)) {
|
||||
$context
|
||||
->buildViolation('You must select at least one element')
|
||||
->atPath('fields')
|
||||
->addViolation();
|
||||
}
|
||||
},
|
||||
])],
|
||||
])
|
||||
->add('reportdate_min', ChillDateType::class, [
|
||||
'label' => 'Date du rapport après le',
|
||||
'required' => false,
|
||||
'label_attr' => [
|
||||
'class' => 'reportdate_range',
|
||||
],
|
||||
'attr' => [
|
||||
'class' => 'reportdate_range',
|
||||
],
|
||||
])
|
||||
->add('reportdate_max', ChillDateType::class, [
|
||||
'label' => 'Date du rapport avant le',
|
||||
'required' => false,
|
||||
'label_attr' => [
|
||||
'class' => 'report_date_range',
|
||||
],
|
||||
'attr' => [
|
||||
'class' => 'report_date_range',
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Export's type. This will inform _on what_ export will apply.
|
||||
* Most of the type, it will be a string which references an entity.
|
||||
*
|
||||
* Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return Person::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description, which will be used in the UI to explain what the export does.
|
||||
* This description will be translated.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Crée une liste des CVs en fonction de différents paramètres.';
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial query, which will be modified by ModifiersInterface
|
||||
* (i.e. AggregatorInterface, FilterInterface).
|
||||
*
|
||||
* This query should take into account the `$acl` and restrict result only to
|
||||
* what the user is allowed to see. (Do not show personal data the user
|
||||
* is not allowed to see).
|
||||
*
|
||||
* The returned object should be an instance of QueryBuilder or NativeQuery.
|
||||
*
|
||||
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
|
||||
* @param array $data the data from the form, if any
|
||||
*
|
||||
* @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute
|
||||
*/
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
return $this->entityManager->createQueryBuilder()
|
||||
->from('ChillPersonBundle:Person', 'person');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
|
||||
* are allowed. The modifiers should be an array of types the _modifier_ apply on
|
||||
* (@see ModifiersInterface::applyOn()).
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return ['cv', 'person'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required Role to execute the Export.
|
||||
*/
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ExportsJobVoter::EXPORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return which formatter type is allowed for this report.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_LIST];
|
||||
}
|
||||
|
||||
/**
|
||||
* give the list of keys the current export added to the queryBuilder in
|
||||
* self::initiateQuery.
|
||||
*
|
||||
* Example: if your query builder will contains `SELECT count(id) AS count_id ...`,
|
||||
* this function will return `array('count_id')`.
|
||||
*
|
||||
* @param mixed[] $data the data from the export's form (added by self::buildForm)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return array_keys($data['fields']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array FIELDS keys only.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getFields()
|
||||
{
|
||||
return array_keys(self::FIELDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the results of the query builder.
|
||||
*
|
||||
* @param QueryBuilder|\Doctrine\ORM\NativeQuery $qb
|
||||
* @param mixed[] $data the data from the export's form (added by self::buildForm)
|
||||
*/
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
$qb->select('person.id');
|
||||
|
||||
$ids = $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
$this->personIds = array_map(fn ($e) => $e['id'], $ids);
|
||||
$personIdsParameters = '?'.\str_repeat(', ?', count($this->personIds) - 1);
|
||||
$query = \str_replace('%person_ids%', $personIdsParameters, self::QUERY);
|
||||
|
||||
$rsm = new Query\ResultSetMapping();
|
||||
|
||||
foreach (self::FIELDS as $name => $type) {
|
||||
if (null !== $data['fields'][$name]) {
|
||||
$rsm->addScalarResult($name, $name, $type);
|
||||
}
|
||||
}
|
||||
|
||||
$nq = $this->entityManager->createNativeQuery($query, $rsm);
|
||||
|
||||
$idx = 1;
|
||||
for ($i = 1; $i <= count($this->personIds); ++$i) {
|
||||
++$idx;
|
||||
$nq->setParameter($i, $this->personIds[$i - 1]);
|
||||
}
|
||||
$nq->setParameter($idx++, $data['reportdate_min'], 'date');
|
||||
$nq->setParameter($idx, $data['reportdate_max'], 'date');
|
||||
|
||||
return $nq->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* transform the results to viewable and understable string.
|
||||
*
|
||||
* The callable will have only one argument: the `value` to translate.
|
||||
*
|
||||
* The callable should also be able to return a key `_header`, which
|
||||
* will contains the header of the column.
|
||||
*
|
||||
* The string returned **must** be already translated if necessary,
|
||||
* **with an exception** for the string returned for `_header`.
|
||||
*
|
||||
* Example :
|
||||
*
|
||||
* ```
|
||||
* protected $translator;
|
||||
*
|
||||
* public function getLabels($key, array $values, $data)
|
||||
* {
|
||||
* return function($value) {
|
||||
* case $value
|
||||
* {
|
||||
* case '_header' :
|
||||
* return 'my header not translated';
|
||||
* case true:
|
||||
* return $this->translator->trans('true');
|
||||
* case false:
|
||||
* return $this->translator->trans('false');
|
||||
* default:
|
||||
* // this should not happens !
|
||||
* throw new \LogicException();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Note:** Why each string must be translated with an exception for
|
||||
* the `_header` ? For performance reasons: most of the value will be number
|
||||
* which do not need to be translated, or value already translated in
|
||||
* database. But the header must be, in every case, translated.
|
||||
*
|
||||
* @param string $key The column key, as added in the query
|
||||
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
|
||||
* @param mixed $data The data from the export's form (as defined in `buildForm`
|
||||
*/
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return match ($key) {
|
||||
'birthdate' => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value->format('d-m-Y');
|
||||
},
|
||||
'countryofbirth' => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
return $value['fr'];
|
||||
},
|
||||
'gender' => function ($value) use ($key) {
|
||||
$gend_array = ['man' => 'Homme', 'woman' => 'Femme', 'both' => 'Indéterminé'];
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $gend_array[$value];
|
||||
},
|
||||
default => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Native Query SQL.
|
||||
*/
|
||||
public const QUERY = <<<'SQL'
|
||||
|
||||
SELECT
|
||||
p.id as id,
|
||||
p.firstname as firstname,
|
||||
p.lastname as lastname,
|
||||
p.gender as gender,
|
||||
p.birthdate as birthdate,
|
||||
p.place_of_birth as placeofbirth,
|
||||
cn.name as countryofbirth,
|
||||
cv.formationlevel as formationlevel
|
||||
FROM
|
||||
public.chill_person_person AS p
|
||||
LEFT JOIN chill_job.cv AS cv
|
||||
ON p.id = cv.person_id
|
||||
LEFT JOIN public.country AS cn
|
||||
ON p.countryofbirth_id = cn.id
|
||||
|
||||
-- condition 1
|
||||
WHERE p.id IN (%person_ids%)
|
||||
|
||||
-- condition 2
|
||||
AND (
|
||||
cv.reportdate
|
||||
BETWEEN COALESCE(?::date, '1900-01-01')
|
||||
AND COALESCE(?::date, '2100-01-01')
|
||||
)
|
||||
|
||||
ORDER BY cv.reportdate DESC
|
||||
|
||||
SQL;
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
497
src/Bundle/ChillJobBundle/src/Export/ListFrein.php
Normal file
497
src/Bundle/ChillJobBundle/src/Export/ListFrein.php
Normal file
@@ -0,0 +1,497 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\JobBundle\Export;
|
||||
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\ListInterface;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\JobBundle\Entity\Frein;
|
||||
use Chill\JobBundle\Security\Authorization\ExportsJobVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Class ListFrein.
|
||||
*
|
||||
* @author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
|
||||
*/
|
||||
class ListFrein implements ListInterface, ExportElementValidatedInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public const FREINS = [
|
||||
'freinsperso' => Frein::FREINS_PERSO,
|
||||
'freinsemploi' => Frein::FREINS_EMPLOI,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public const FIELDS = [
|
||||
'id' => 'integer',
|
||||
'firstname' => 'string',
|
||||
'lastname' => 'string',
|
||||
'gender' => 'string',
|
||||
'birthdate' => 'date',
|
||||
'placeofbirth' => 'string',
|
||||
'countryofbirth' => 'json',
|
||||
'reportdate' => 'date',
|
||||
'freinsperso' => 'json',
|
||||
'notesperso' => 'string',
|
||||
'freinsemploi' => 'json',
|
||||
'notesemploi' => 'string',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $personIds = [];
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* ListAcquisition constructor.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->entityManager = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate the form's data and, if required, build a contraint
|
||||
* violation on the data.
|
||||
*
|
||||
* @param mixed $data the data, as returned by the user
|
||||
*/
|
||||
public function validateForm($data, ExecutionContextInterface $context) {}
|
||||
|
||||
/**
|
||||
* get a title, which will be used in UI (and translated).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Liste des freins identifiés par personne';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form to collect data from the user.
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('fields', ChoiceType::class, [
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
// 'choices_as_values' => true,
|
||||
'label' => 'Fields to include in export',
|
||||
'choices' => array_combine($this->getFields(), $this->getFields()),
|
||||
'data' => array_combine($this->getFields(), $this->getFields()),
|
||||
'choice_attr' => [],
|
||||
'attr' => ['class' => ''],
|
||||
'constraints' => [new Callback([
|
||||
'callback' => function ($selected, ExecutionContextInterface $context) {
|
||||
if (0 === count($selected)) {
|
||||
$context
|
||||
->buildViolation('You must select at least one element')
|
||||
->atPath('fields')
|
||||
->addViolation();
|
||||
}
|
||||
},
|
||||
])],
|
||||
])
|
||||
->add('reportdate_min', ChillDateType::class, [
|
||||
'label' => 'Date du rapport après le',
|
||||
'required' => false,
|
||||
'label_attr' => [
|
||||
'class' => 'reportdate_range',
|
||||
],
|
||||
'attr' => [
|
||||
'class' => 'reportdate_range',
|
||||
],
|
||||
])
|
||||
->add('reportdate_max', ChillDateType::class, [
|
||||
'label' => 'Date du rapport avant le',
|
||||
'required' => false,
|
||||
'label_attr' => [
|
||||
'class' => 'report_date_range',
|
||||
],
|
||||
'attr' => [
|
||||
'class' => 'report_date_range',
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Export's type. This will inform _on what_ export will apply.
|
||||
* Most of the type, it will be a string which references an entity.
|
||||
*
|
||||
* Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return Person::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* A description, which will be used in the UI to explain what the export does.
|
||||
* This description will be translated.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Crée une liste des personnes et de leurs freins identifiés en fonction de différents paramètres.';
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial query, which will be modified by ModifiersInterface
|
||||
* (i.e. AggregatorInterface, FilterInterface).
|
||||
*
|
||||
* This query should take into account the `$acl` and restrict result only to
|
||||
* what the user is allowed to see. (Do not show personal data the user
|
||||
* is not allowed to see).
|
||||
*
|
||||
* The returned object should be an instance of QueryBuilder or NativeQuery.
|
||||
*
|
||||
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
|
||||
* @param array $data the data from the form, if any
|
||||
*
|
||||
* @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute
|
||||
*/
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
return $this->entityManager->createQueryBuilder()
|
||||
->from(Person::class, 'person');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface)
|
||||
* are allowed. The modifiers should be an array of types the _modifier_ apply on
|
||||
* (@see ModifiersInterface::applyOn()).
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return ['frein', 'person'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required Role to execute the Export.
|
||||
*/
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ExportsJobVoter::EXPORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return which formatter type is allowed for this report.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_LIST];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array FIELDS keys only.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getFields()
|
||||
{
|
||||
return array_keys(self::FIELDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* give the list of keys the current export added to the queryBuilder in
|
||||
* self::initiateQuery.
|
||||
*
|
||||
* Example: if your query builder will contains `SELECT count(id) AS count_id ...`,
|
||||
* this function will return `array('count_id')`.
|
||||
*
|
||||
* @param mixed[] $data the data from the export's form (added by self::buildForm)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
$freins = self::FREINS;
|
||||
$fields = [];
|
||||
foreach ($data['fields'] as $key) {
|
||||
switch ($key) {
|
||||
case 'freinsperso':
|
||||
case 'freinsemploi':
|
||||
foreach ($freins[$key] as $item) {
|
||||
$this->translationCompatKey($item, $key);
|
||||
$fields[] = $item;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$fields[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make key compatible with YAML messages ids
|
||||
* for fields that are splitted in columns.
|
||||
*
|
||||
* @param string $item (&) passed by reference
|
||||
* @param string $key
|
||||
*/
|
||||
private function translationCompatKey(&$item, $key)
|
||||
{
|
||||
$prefix = substr_replace($key, 'freins_', 0, 6);
|
||||
$item = $prefix.'.'.$item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some fields values are arrays that have to be splitted in columns.
|
||||
* This function split theses fields.
|
||||
*
|
||||
* @param array $rows
|
||||
*
|
||||
* @return array|\Closure
|
||||
*/
|
||||
private function splitArrayToColumns($rows)
|
||||
{
|
||||
$freins = self::FREINS;
|
||||
|
||||
$results = [];
|
||||
foreach ($rows as $row) {
|
||||
/**
|
||||
* @var string $key
|
||||
*/
|
||||
$res = [];
|
||||
foreach ($row as $key => $value) {
|
||||
switch ($key) {
|
||||
case 'freinsperso':
|
||||
case 'freinsemploi':
|
||||
foreach ($freins[$key] as $item) {
|
||||
$this->translationCompatKey($item, $key);
|
||||
|
||||
if (0 === count($value)) {
|
||||
$res[$item] = '';
|
||||
} else {
|
||||
foreach ($value as $v) {
|
||||
$this->translationCompatKey($v, $key);
|
||||
if ($item === $v) {
|
||||
$res[$item] = 'x';
|
||||
break;
|
||||
}
|
||||
$res[$item] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$res[$key] = $value;
|
||||
}
|
||||
}
|
||||
$results[] = $res;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the results of the query builder.
|
||||
*
|
||||
* @param QueryBuilder|\Doctrine\ORM\NativeQuery $qb
|
||||
* @param mixed[] $data the data from the export's form (added by self::buildForm)
|
||||
*/
|
||||
public function getResult($qb, $data)
|
||||
{
|
||||
$qb->select('person.id');
|
||||
|
||||
$ids = $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
$this->personIds = array_map(fn ($e) => $e['id'], $ids);
|
||||
$personIdsParameters = '?'.\str_repeat(', ?', count($this->personIds) - 1);
|
||||
$query = \str_replace('%person_ids%', $personIdsParameters, self::QUERY);
|
||||
|
||||
$rsm = new Query\ResultSetMapping();
|
||||
|
||||
foreach (self::FIELDS as $name => $type) {
|
||||
if (null !== $data['fields'][$name]) {
|
||||
$rsm->addScalarResult($name, $name, $type);
|
||||
}
|
||||
}
|
||||
|
||||
$nq = $this->entityManager->createNativeQuery($query, $rsm);
|
||||
|
||||
$idx = 1;
|
||||
for ($i = 1; $i <= count($this->personIds); ++$i) {
|
||||
++$idx;
|
||||
$nq->setParameter($i, $this->personIds[$i - 1]);
|
||||
}
|
||||
$nq->setParameter($idx++, $data['reportdate_min'], 'date');
|
||||
$nq->setParameter($idx, $data['reportdate_max'], 'date');
|
||||
|
||||
return $this->splitArrayToColumns(
|
||||
$nq->getResult()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* transform the results to viewable and understable string.
|
||||
*
|
||||
* The callable will have only one argument: the `value` to translate.
|
||||
*
|
||||
* The callable should also be able to return a key `_header`, which
|
||||
* will contains the header of the column.
|
||||
*
|
||||
* The string returned **must** be already translated if necessary,
|
||||
* **with an exception** for the string returned for `_header`.
|
||||
*
|
||||
* Example :
|
||||
*
|
||||
* ```
|
||||
* protected $translator;
|
||||
*
|
||||
* public function getLabels($key, array $values, $data)
|
||||
* {
|
||||
* return function($value) {
|
||||
* case $value
|
||||
* {
|
||||
* case '_header' :
|
||||
* return 'my header not translated';
|
||||
* case true:
|
||||
* return $this->translator->trans('true');
|
||||
* case false:
|
||||
* return $this->translator->trans('false');
|
||||
* default:
|
||||
* // this should not happens !
|
||||
* throw new \LogicException();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Note:** Why each string must be translated with an exception for
|
||||
* the `_header` ? For performance reasons: most of the value will be number
|
||||
* which do not need to be translated, or value already translated in
|
||||
* database. But the header must be, in every case, translated.
|
||||
*
|
||||
* @param string $key The column key, as added in the query
|
||||
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
|
||||
* @param mixed $data The data from the export's form (as defined in `buildForm`
|
||||
*/
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return match ($key) {
|
||||
'reportdate', 'birthdate' => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value->format('d-m-Y');
|
||||
},
|
||||
'countryofbirth' => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
return $value['fr'];
|
||||
},
|
||||
'gender' => function ($value) use ($key) {
|
||||
$gend_array = ['man' => 'Homme', 'woman' => 'Femme', 'both' => 'Indéterminé'];
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $gend_array[$value];
|
||||
},
|
||||
default => function ($value) use ($key) {
|
||||
if ('_header' === $value) {
|
||||
return $key;
|
||||
}
|
||||
if (null === $value || '' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Native Query SQL.
|
||||
*/
|
||||
public const QUERY = <<<'SQL'
|
||||
|
||||
SELECT
|
||||
p.id as id,
|
||||
p.firstname as firstname,
|
||||
p.lastname as lastname,
|
||||
p.gender as gender,
|
||||
p.birthdate as birthdate,
|
||||
p.place_of_birth as placeofbirth,
|
||||
cn.name as countryofbirth,
|
||||
fr.reportdate as reportdate,
|
||||
fr.freinsperso as freinsperso,
|
||||
fr.notesperso as notesperso,
|
||||
fr.freinsemploi as freinsemploi,
|
||||
fr.notesemploi as notesemploi
|
||||
FROM
|
||||
public.chill_person_person AS p
|
||||
LEFT JOIN chill_job.frein AS fr
|
||||
ON p.id = fr.person_id
|
||||
LEFT JOIN public.country AS cn
|
||||
ON p.countryofbirth_id = cn.id
|
||||
|
||||
-- condition 1
|
||||
WHERE p.id IN (%person_ids%)
|
||||
|
||||
-- condition 2
|
||||
AND (
|
||||
fr.reportdate
|
||||
BETWEEN COALESCE(?::date, '1900-01-01')
|
||||
AND COALESCE(?::date, '2100-01-01')
|
||||
)
|
||||
|
||||
ORDER BY fr.reportdate DESC
|
||||
|
||||
SQL;
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user