cs: Fix code style (safe rules only).

This commit is contained in:
Pol Dellaiera
2021-11-23 14:06:38 +01:00
parent 149d7ce991
commit 8f96a1121d
1223 changed files with 65199 additions and 64625 deletions

View File

@@ -1,41 +1,53 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\MainBundle\Entity\Scope;
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
use Symfony\Component\Workflow\Registry;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use function array_values;
final class AccompanyingCourseApiController extends ApiController
{
private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository;
private EventDispatcherInterface $eventDispatcher;
private ValidatorInterface $validator;
private Registry $registry;
private ReferralsSuggestionInterface $referralAvailable;
private Registry $registry;
private ValidatorInterface $validator;
public function __construct(
EventDispatcherInterface $eventDispatcher,
ValidatorInterface $validator,
@@ -50,6 +62,11 @@ final class AccompanyingCourseApiController extends ApiController
$this->referralAvailable = $referralAvailable;
}
public function commentApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('comment', $id, $request, $_format, 'comment', Comment::class);
}
public function confirmApi($id, Request $request, $_format): Response
{
/** @var AccompanyingPeriod $accompanyingPeriod */
@@ -58,10 +75,11 @@ final class AccompanyingCourseApiController extends ApiController
$this->checkACL('confirm', $request, $_format, $accompanyingPeriod);
$workflow = $this->registry->get($accompanyingPeriod);
if (FALSE === $workflow->can($accompanyingPeriod, 'confirm')) {
if (false === $workflow->can($accompanyingPeriod, 'confirm')) {
// throw new BadRequestException('It is not possible to confirm this period');
$errors = $this->validator->validate($accompanyingPeriod, null, [$accompanyingPeriod::STEP_CONFIRMED]);
if( count($errors) > 0 ){
if (count($errors) > 0) {
return $this->json($errors, 422);
}
}
@@ -71,10 +89,26 @@ final class AccompanyingCourseApiController extends ApiController
$this->getDoctrine()->getManager()->flush();
return $this->json($accompanyingPeriod, Response::HTTP_OK, [], [
'groups' => [ 'read' ]
'groups' => ['read'],
]);
}
/**
* @ParamConverter("person", options={"id": "person_id"})
*/
public function getAccompanyingPeriodsByPerson(Person $person)
{
$accompanyingPeriods = $person->getCurrentAccompanyingPeriods();
$accompanyingPeriodsChecked = array_filter(
$accompanyingPeriods,
function (AccompanyingPeriod $period) {
return $this->isGranted(AccompanyingPeriodVoter::SEE, $period);
}
);
return $this->json(array_values($accompanyingPeriodsChecked), Response::HTTP_OK, [], ['groups' => ['read']]);
}
public function participationApi($id, Request $request, $_format)
{
/** @var AccompanyingPeriod $accompanyingPeriod */
@@ -82,7 +116,7 @@ final class AccompanyingCourseApiController extends ApiController
$person = $this->getSerializer()
->deserialize($request->getContent(), Person::class, $_format, []);
if (NULL === $person) {
if (null === $person) {
throw new BadRequestException('person id not found');
}
@@ -93,12 +127,16 @@ final class AccompanyingCourseApiController extends ApiController
switch ($request->getMethod()) {
case Request::METHOD_POST:
$participation = $accompanyingPeriod->createParticipationFor($person);
break;
case Request::METHOD_DELETE:
$participation = $accompanyingPeriod->closeParticipationFor($person);
break;
default:
throw new BadRequestException("This method is not supported");
throw new BadRequestException('This method is not supported');
}
$errors = $this->validator->validate($accompanyingPeriod);
@@ -110,48 +148,7 @@ final class AccompanyingCourseApiController extends ApiController
$this->getDoctrine()->getManager()->flush();
return $this->json($participation, 200, [], ['groups' => [ 'read' ]]);
}
public function resourceApi($id, Request $request, string $_format): Response
{
$accompanyingPeriod = $this->getEntity('resource', $id, $request);
$errors = $this->validator->validate($accompanyingPeriod);
if ($errors->count() > 0) {
return $this->json($errors, 422);
}
return $this->addRemoveSomething('resource', $id, $request, $_format, 'resource', Resource::class);
}
public function scopeApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, [ 'groups' => [ 'read' ] ]);
}
public function commentApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('comment', $id, $request, $_format, 'comment', Comment::class);
}
public function socialIssueApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, [ 'groups' => [ 'read' ] ]);
}
public function workApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething(
'work',
$id,
$request,
$_format,
'work',
AccompanyingPeriodWork::class,
[ 'groups' => [ 'accompanying_period_work:create' ] ],
true // force persist
);
return $this->json($participation, 200, [], ['groups' => ['read']]);
}
public function requestorApi($id, Request $request, string $_format): Response
@@ -165,10 +162,11 @@ final class AccompanyingCourseApiController extends ApiController
$this->onPostCheckACL($action, $request, $_format, $accompanyingPeriod);
if (Request::METHOD_DELETE === $request->getMethod()) {
$accompanyingPeriod->setRequestor(NULL);
$accompanyingPeriod->setRequestor(null);
} elseif (Request::METHOD_POST === $request->getMethod()) {
$requestor = null;
$exceptions = [];
foreach ([Person::class, ThirdParty::class] as $class) {
try {
$requestor = $this->getSerializer()
@@ -177,7 +175,8 @@ final class AccompanyingCourseApiController extends ApiController
$exceptions[] = $e;
}
}
if ($requestor === null) {
if (null === $requestor) {
throw new BadRequestException('Could not find any person or requestor', 0, $exceptions[0]);
}
@@ -195,40 +194,35 @@ final class AccompanyingCourseApiController extends ApiController
$this->getDoctrine()->getManager()->flush();
return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => [ 'read']]);
return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => ['read']]);
}
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
public function resourceApi($id, Request $request, string $_format): Response
{
$this->eventDispatcher->dispatch(
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT,
new AccompanyingPeriodPrivacyEvent($entity, [
'action' => $action,
'request' => $request->getMethod()
])
);
$accompanyingPeriod = $this->getEntity('resource', $id, $request);
$errors = $this->validator->validate($accompanyingPeriod);
return null;
if ($errors->count() > 0) {
return $this->json($errors, 422);
}
return $this->addRemoveSomething('resource', $id, $request, $_format, 'resource', Resource::class);
}
/**
* @ParamConverter("person", options={"id" = "person_id"})
*/
public function getAccompanyingPeriodsByPerson(Person $person){
$accompanyingPeriods = $person->getCurrentAccompanyingPeriods();
$accompanyingPeriodsChecked = array_filter($accompanyingPeriods,
function(AccompanyingPeriod $period){
return $this->isGranted(AccompanyingPeriodVoter::SEE, $period);
});
return $this->json(\array_values($accompanyingPeriodsChecked), Response::HTTP_OK, [], ['groups' => [ 'read']]);
public function scopeApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, ['groups' => ['read']]);
}
public function socialIssueApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, ['groups' => ['read']]);
}
/**
* @Route("/api/1.0/person/accompanying-course/{id}/referrers-suggested.{_format}",
* requirements={ "_format"="json"},
* name="chill_api_person_accompanying_period_referrers_suggested")
* @param AccompanyingPeriod $period
* @return JsonResponse
* requirements={ "_format": "json"},
* name="chill_api_person_accompanying_period_referrers_suggested")
*/
public function suggestReferrals(AccompanyingPeriod $period, string $_format = 'json'): JsonResponse
{
@@ -238,13 +232,47 @@ final class AccompanyingCourseApiController extends ApiController
$paginator = $this->getPaginatorFactory()->create($total);
if (0 < $total) {
$users = $this->referralAvailable->findReferralSuggested($period, $paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber());
$users = $this->referralAvailable->findReferralSuggested(
$period,
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
} else {
$users = [];
}
return $this->json(new Collection($users, $paginator), Response::HTTP_OK,
[], [ AbstractNormalizer::GROUPS => [ 'read' ]]);
return $this->json(
new Collection($users, $paginator),
Response::HTTP_OK,
[],
[AbstractNormalizer::GROUPS => ['read']]
);
}
public function workApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething(
'work',
$id,
$request,
$_format,
'work',
AccompanyingPeriodWork::class,
['groups' => ['accompanying_period_work:create']],
true // force persist
);
}
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
{
$this->eventDispatcher->dispatch(
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT,
new AccompanyingPeriodPrivacyEvent($entity, [
'action' => $action,
'request' => $request->getMethod(),
])
);
return null;
}
}

View File

@@ -1,47 +1,47 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\AccompanyingCourseType;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use function is_array;
/**
* Class AccompanyingCourseController
*
* @package Chill\PersonBundle\Controller
* Class AccompanyingCourseController.
*/
class AccompanyingCourseController extends Controller
{
protected SerializerInterface $serializer;
protected EventDispatcherInterface $dispatcher;
protected SerializerInterface $serializer;
protected ValidatorInterface $validator;
private AccompanyingPeriodWorkRepository $workRepository;
private Registry $registry;
private AccompanyingPeriodWorkRepository $workRepository;
public function __construct(
SerializerInterface $serializer,
EventDispatcherInterface $dispatcher,
@@ -57,41 +57,80 @@ class AccompanyingCourseController extends Controller
}
/**
* @Route("/{_locale}/person/parcours/new", name="chill_person_accompanying_course_new")
* @Route("/{_locale}/parcours/{accompanying_period_id}/close", name="chill_person_accompanying_course_close")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
*/
public function newAction(Request $request): Response
public function closeAction(AccompanyingPeriod $accompanyingCourse, Request $request): Response
{
$period = new AccompanyingPeriod();
$em = $this->getDoctrine()->getManager();
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse);
if ($request->query->has('person_id')) {
$personIds = $request->query->get('person_id');
$form = $this->createForm(AccompanyingCourseType::class, $accompanyingCourse);
if (FALSE === \is_array($personIds)) {
throw new BadRequestException("person_id parameter should be an array");
}
$form->handleRequest($request);
foreach ($personIds as $personId) {
$person = $em->getRepository(Person::class)->find($personId);
if (NULL !== $person) {
$period->addPerson($person);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$workflow = $this->registry->get($accompanyingCourse);
if ($workflow->can($accompanyingCourse, 'close')) {
$errors = $this->validator->validate($accompanyingCourse, null, [$accompanyingCourse::STEP_CLOSED]);
if (count($errors) > 0) {
return $this->json($errors, 422);
}
$workflow->apply($accompanyingCourse, 'close');
$em->flush();
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $accompanyingCourse->getId(),
]);
}
}
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CREATE, $period);
$em->persist($period);
$em->flush();
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId()
return $this->render('@ChillPerson/AccompanyingCourse/close.html.twig', [
'form' => $form->createView(),
'accompanyingCourse' => $accompanyingCourse,
]);
}
/**
* Homepage of Accompanying Course section
* Edit page of Accompanying Course section.
*
* the page edit all blocks managed by vuejs component
*
* @Route("/{_locale}/parcours/{accompanying_period_id}/edit", name="chill_person_accompanying_course_edit")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
*/
public function editAction(AccompanyingPeriod $accompanyingCourse): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [
'accompanyingCourse' => $accompanyingCourse,
]);
}
/**
* History page of Accompanying Course section.
*
* the page show anti chronologic history with all actions, title of page is 'Accompanying Course History'
*
* @Route("/{_locale}/parcours/{accompanying_period_id}/history", name="chill_person_accompanying_course_history")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
*/
public function historyAction(AccompanyingPeriod $accompanyingCourse): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
return $this->render('@ChillPerson/AccompanyingCourse/history.html.twig', [
'accompanyingCourse' => $accompanyingCourse,
]);
}
/**
* Homepage of Accompanying Course section.
*
* @Route("/{_locale}/parcours/{accompanying_period_id}", name="chill_person_accompanying_course_index")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
@@ -99,13 +138,13 @@ class AccompanyingCourseController extends Controller
public function indexAction(AccompanyingPeriod $accompanyingCourse): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
// compute some warnings
// get persons without household
$withoutHousehold = [];
foreach ($accompanyingCourse->getParticipations() as
$p) {
if (FALSE === $p->getPerson()->isSharingHousehold()) {
foreach ($accompanyingCourse->getParticipations() as $p) {
if (false === $p->getPerson()->isSharingHousehold()) {
$withoutHousehold[] = $p->getPerson();
}
}
@@ -126,82 +165,41 @@ class AccompanyingCourseController extends Controller
'withoutHousehold' => $withoutHousehold,
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
'works' => $works,
'activities' => $activities
'activities' => $activities,
]);
}
/**
* Edit page of Accompanying Course section
*
* the page edit all blocks managed by vuejs component
*
* @Route("/{_locale}/parcours/{accompanying_period_id}/edit", name="chill_person_accompanying_course_edit")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
* @Route("/{_locale}/person/parcours/new", name="chill_person_accompanying_course_new")
*/
public function editAction(AccompanyingPeriod $accompanyingCourse): Response
public function newAction(Request $request): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
$period = new AccompanyingPeriod();
$em = $this->getDoctrine()->getManager();
return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [
'accompanyingCourse' => $accompanyingCourse
]);
}
if ($request->query->has('person_id')) {
$personIds = $request->query->get('person_id');
/**
* History page of Accompanying Course section
*
* the page show anti chronologic history with all actions, title of page is 'Accompanying Course History'
*
* @Route("/{_locale}/parcours/{accompanying_period_id}/history", name="chill_person_accompanying_course_history")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
*/
public function historyAction(AccompanyingPeriod $accompanyingCourse): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse);
if (false === is_array($personIds)) {
throw new BadRequestException('person_id parameter should be an array');
}
return $this->render('@ChillPerson/AccompanyingCourse/history.html.twig', [
'accompanyingCourse' => $accompanyingCourse
]);
}
foreach ($personIds as $personId) {
$person = $em->getRepository(Person::class)->find($personId);
/**
* @Route("/{_locale}/parcours/{accompanying_period_id}/close", name="chill_person_accompanying_course_close")
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
*/
public function closeAction(AccompanyingPeriod $accompanyingCourse, Request $request): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse);
$form = $this->createForm(AccompanyingCourseType::class, $accompanyingCourse);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$workflow = $this->registry->get($accompanyingCourse);
if ($workflow->can($accompanyingCourse, 'close')) {
$errors = $this->validator->validate($accompanyingCourse, null, [$accompanyingCourse::STEP_CLOSED]);
if (count($errors) > 0) {
return $this->json($errors, 422);
if (null !== $person) {
$period->addPerson($person);
}
$workflow->apply($accompanyingCourse, 'close');
$em->flush();
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $accompanyingCourse->getId()
]);
}
}
return $this->render('@ChillPerson/AccompanyingCourse/close.html.twig', [
'form' => $form->createView(),
'accompanyingCourse' => $accompanyingCourse
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CREATE, $period);
$em->persist($period);
$em->flush();
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
'accompanying_period_id' => $period->getId(),
]);
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
@@ -9,15 +16,14 @@ class AccompanyingCourseWorkApiController extends ApiController
{
protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
{
switch($action) {
switch ($action) {
case '_entity':
switch ($request->getMethod()) {
case Request::METHOD_PUT:
return [ 'groups' => [ 'accompanying_period_work:edit' ] ];
return ['groups' => ['accompanying_period_work:edit']];
}
}
return parent::getContextForSerialization($action, $request, $_format, $entity);
}
}

View File

@@ -1,29 +1,40 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Form\Form;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class AccompanyingCourseWorkController extends AbstractController
{
private TranslatorInterface $trans;
private SerializerInterface $serializer;
private AccompanyingPeriodWorkRepository $workRepository;
private PaginatorFactory $paginator;
private LoggerInterface $chillLogger;
private PaginatorFactory $paginator;
private SerializerInterface $serializer;
private TranslatorInterface $trans;
private AccompanyingPeriodWorkRepository $workRepository;
public function __construct(
TranslatorInterface $trans,
SerializerInterface $serializer,
@@ -40,58 +51,107 @@ class AccompanyingCourseWorkController extends AbstractController
/**
* @Route(
* "{_locale}/person/accompanying-period/{id}/work/new",
* name="chill_person_accompanying_period_work_new",
* methods={"GET"}
* )
* "{_locale}/person/accompanying-period/{id}/work/new",
* name="chill_person_accompanying_period_work_new",
* methods={"GET"}
* )
*/
public function createWork(AccompanyingPeriod $period): Response
{
// TODO ACL
if ($period->getSocialIssues()->count() === 0) {
$this->addFlash('error', $this->trans->trans(
"accompanying_work.You must add at least ".
"one social issue on accompanying period")
$this->addFlash(
'error',
$this->trans->trans(
'accompanying_work.You must add at least ' .
'one social issue on accompanying period'
)
);
return $this->redirectToRoute('chill_person_accompanying_course_index', [
'accompanying_period_id' => $period->getId()
'accompanying_period_id' => $period->getId(),
]);
}
$json = $this->serializer->normalize($period, 'json', [ "groups" => [ "read" ]]);
$json = $this->serializer->normalize($period, 'json', ['groups' => ['read']]);
return $this->render('@ChillPerson/AccompanyingCourseWork/create.html.twig', [
'accompanyingCourse' => $period,
'json' => $json
'json' => $json,
]);
}
/**
* @Route(
* "{_locale}/person/accompanying-period/work/{id}/edit",
* name="chill_person_accompanying_period_work_edit",
* methods={"GET"}
* )
* "{_locale}/person/accompanying-period/work/{id}/delete",
* name="chill_person_accompanying_period_work_delete",
* methods={"GET", "POST", "DELETE"}
* )
*/
public function deleteWork(AccompanyingPeriodWork $work, Request $request): Response
{
// TODO ACL
$em = $this->getDoctrine()->getManager();
$form = $this->createDeleteForm($work->getId());
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->chillLogger->notice('An accompanying period work has been removed', [
'by_user' => $this->getUser()->getUsername(),
'work_id' => $work->getId(),
'accompanying_period_id' => $work->getAccompanyingPeriod()->getId(),
]);
$em->remove($work);
$em->flush();
$this->addFlash(
'success',
$this->trans->trans('The accompanying period work has been successfully removed.')
);
return $this->redirectToRoute('chill_person_accompanying_period_work_list', [
'id' => $work->getAccompanyingPeriod()->getId(),
]);
}
}
return $this->render('@ChillPerson/AccompanyingCourseWork/delete.html.twig', [
'accompanyingCourse' => $work->getAccompanyingPeriod(),
'work' => $work,
'delete_form' => $form->createView(),
]);
}
/**
* @Route(
* "{_locale}/person/accompanying-period/work/{id}/edit",
* name="chill_person_accompanying_period_work_edit",
* methods={"GET"}
* )
*/
public function editWork(AccompanyingPeriodWork $work): Response
{
// TODO ACL
$json = $this->serializer->normalize($work, 'json', [ "groups" => [ "read" ] ]);
$json = $this->serializer->normalize($work, 'json', ['groups' => ['read']]);
return $this->render('@ChillPerson/AccompanyingCourseWork/edit.html.twig', [
'accompanyingCourse' => $work->getAccompanyingPeriod(),
'work' => $work,
'json' => $json
'json' => $json,
]);
}
/**
* @Route(
* "{_locale}/person/accompanying-period/{id}/work",
* name="chill_person_accompanying_period_work_list",
* methods={"GET"}
* )
* "{_locale}/person/accompanying-period/{id}/work",
* name="chill_person_accompanying_period_work_list",
* methods={"GET"}
* )
*/
public function listWorkByAccompanyingPeriod(AccompanyingPeriod $period): Response
{
@@ -109,54 +169,7 @@ class AccompanyingCourseWorkController extends AbstractController
return $this->render('@ChillPerson/AccompanyingCourseWork/index.html.twig', [
'accompanyingCourse' => $period,
'works' => $works,
'paginator' => $paginator
]);
}
/**
* @Route(
* "{_locale}/person/accompanying-period/work/{id}/delete",
* name="chill_person_accompanying_period_work_delete",
* methods={"GET", "POST", "DELETE"}
* )
*/
public function deleteWork(AccompanyingPeriodWork $work, Request $request): Response
{
// TODO ACL
$em = $this->getDoctrine()->getManager();
$form = $this->createDeleteForm($work->getId());
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->chillLogger->notice("An accompanying period work has been removed", [
'by_user' => $this->getUser()->getUsername(),
'work_id' => $work->getId(),
'accompanying_period_id' => $work->getAccompanyingPeriod()->getId()
]);
$em->remove($work);
$em->flush();
$this->addFlash(
'success',
$this->trans->trans("The accompanying period work has been successfully removed.")
);
return $this->redirectToRoute('chill_person_accompanying_period_work_list', [
'id' => $work->getAccompanyingPeriod()->getId()
]);
}
}
return $this->render('@ChillPerson/AccompanyingCourseWork/delete.html.twig', [
'accompanyingCourse' => $work->getAccompanyingPeriod(),
'work' => $work,
'delete_form' => $form->createView()
'paginator' => $paginator,
]);
}
@@ -169,9 +182,6 @@ class AccompanyingCourseWorkController extends AbstractController
->setAction($this->generateUrl('chill_person_accompanying_period_work_delete', $params))
->setMethod('DELETE')
->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm()
;
->getForm();
}
}

View File

@@ -1,51 +1,39 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\AccompanyingPeriodType;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime;
use Doctrine\DBAL\Exception;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\AccompanyingPeriodType;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\Common\Collections\Criteria;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use function array_filter;
/**
* Class AccompanyingPeriodController
*
* @package Chill\PersonBundle\Controller
* Class AccompanyingPeriodController.
*/
class AccompanyingPeriodController extends AbstractController
{
protected AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
/**
* @var EventDispatcherInterface
*/
@@ -56,8 +44,6 @@ class AccompanyingPeriodController extends AbstractController
*/
protected $validator;
protected AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
public function __construct(
AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository,
EventDispatcherInterface $eventDispatcher,
@@ -68,218 +54,71 @@ class AccompanyingPeriodController extends AbstractController
$this->validator = $validator;
}
/**
* @ParamConverter("person", options={"id"="person_id"})
*/
public function listAction(Person $person): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $person);
$event = new PrivacyEvent($person, [
'element_class' => AccompanyingPeriod::class,
'action' => 'list'
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$accompanyingPeriods = $this->accompanyingPeriodACLAwareRepository
->findByPerson($person, AccompanyingPeriodVoter::SEE);
return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [
'accompanying_periods' => $accompanyingPeriods,
'person' => $person
]);
}
public function createAction(int $person_id, Request $request): Response
{
$person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
'You are not allowed to update this person');
$accompanyingPeriod = new AccompanyingPeriod(new \DateTime('now'));
$accompanyingPeriod->setClosingDate(new \DateTime('now'));
$accompanyingPeriod->addPerson($person);
//or $person->addAccompanyingPeriod($accompanyingPeriod);
$form = $this->createForm(
AccompanyingPeriodType::class,
$accompanyingPeriod, [
'period_action' => 'create',
'center' => $person->getCenter()
]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
$em = $this->getDoctrine()->getManager();
$em->persist($accompanyingPeriod);
$em->flush();
$flashBag->add('success',
$this->get('translator')->trans(
'A period has been created.'));
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
]));
} else {
$flashBag->add('error', $this->get('translator')
->trans('Error! Period not created!'));
foreach($errors as $error) {
$flashBag->add('info', $error->getMessage());
}
}
}
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $accompanyingPeriod
]);
}
/**
* @throws Exception
*/
public function updateAction(int $person_id, int $period_id, Request $request): Response
{
$em = $this->getDoctrine()->getManager();
/** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($period_id);
if ($accompanyingPeriod === null) {
throw $this->createNotFoundException("Period with id " . $period_id . " is not found");
}
/** @var Person $person */
$person = $this->_getPerson($person_id);
// CHECK
if (! $accompanyingPeriod->containsPerson($person)) {
throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id);
}
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
'You are not allowed to update this person');
$form = $this->createForm(AccompanyingPeriodType::class,
$accompanyingPeriod, [
'period_action' => 'update',
'center' => $person->getCenter()
]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
$em->flush();
$flashBag->add('success',
$this->get('translator')->trans('An accompanying period has been updated.'));
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
]));
} else {
$flashBag->add('error', $this->get('translator')
->trans('Error when updating the period'));
foreach($errors as $error) {
$flashBag->add('info', $error->getMessage());
}
}
}
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $accompanyingPeriod
]);
}
/**
* @throws \Exception
*/
public function closeAction(int $person_id, Request $request): Response
{
$person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person');
if ($person->isOpen() === false) {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Beware period is closed', ['%name%' => $person->__toString()]
));
->trans(
'Beware period is closed',
['%name%' => $person->__toString()]
));
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
]));
'person_id' => $person->getId(),
])
);
}
$current = $person->getCurrentAccompanyingPeriod();
$form = $this->createForm(AccompanyingPeriodType::class, $current, [
'period_action' => 'close',
'center' => $person->getCenter()
'center' => $person->getCenter(),
]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
if ($form->isValid()){
if ($form->isValid()) {
$person->close($current);
$errors = $this->_validatePerson($person);
if (count($errors) === 0) {
$this->get('session')->getFlashBag()
->add('success', $this->get('translator')
->trans('An accompanying period has been closed.', [
'%name%' => $person->__toString()
]));
->trans('An accompanying period has been closed.', [
'%name%' => $person->__toString(),
]));
$this->getDoctrine()->getManager()->flush();
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
'person_id' => $person->getId(),
])
);
} else {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Error! Period not closed!'));
foreach ($errors as $error) {
$this->get('session')->getFlashBag()
->add('info', $error->getMessage());
}
}
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Error! Period not closed!'));
foreach ($errors as $error) {
$this->get('session')->getFlashBag()
->add('info', $error->getMessage());
}
} else { //if form is not valid
$this->get('session')->getFlashBag()
->add('error',
->add(
'error',
$this->get('translator')
->trans('Pediod closing form is not valid')
);
@@ -294,57 +133,131 @@ class AccompanyingPeriodController extends AbstractController
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $current
'accompanying_period' => $current,
]);
}
private function _validatePerson(Person $person): ConstraintViolationListInterface
public function createAction(int $person_id, Request $request): Response
{
$errors = $this->validator->validate($person, null,
['Default']);
$person = $this->_getPerson($person_id);
// Can be disabled with config
if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) {
$this->denyAccessUnlessGranted(
PersonVoter::UPDATE,
$person,
'You are not allowed to update this person'
);
$errors_accompanying_period = $this->validator->validate($person, null,
['accompanying_period_consistent']);
$accompanyingPeriod = new AccompanyingPeriod(new DateTime('now'));
$accompanyingPeriod->setClosingDate(new DateTime('now'));
foreach($errors_accompanying_period as $error ) {
$errors->add($error);
$accompanyingPeriod->addPerson($person);
//or $person->addAccompanyingPeriod($accompanyingPeriod);
$form = $this->createForm(
AccompanyingPeriodType::class,
$accompanyingPeriod,
[
'period_action' => 'create',
'center' => $person->getCenter(),
]
);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
$em = $this->getDoctrine()->getManager();
$em->persist($accompanyingPeriod);
$em->flush();
$flashBag->add(
'success',
$this->get('translator')->trans(
'A period has been created.'
)
);
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId(),
])
);
}
$flashBag->add('error', $this->get('translator')
->trans('Error! Period not created!'));
foreach ($errors as $error) {
$flashBag->add('info', $error->getMessage());
}
}
return $errors;
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $accompanyingPeriod,
]);
}
/**
* @ParamConverter("person", options={"id": "person_id"})
*/
public function listAction(Person $person): Response
{
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $person);
$event = new PrivacyEvent($person, [
'element_class' => AccompanyingPeriod::class,
'action' => 'list',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$accompanyingPeriods = $this->accompanyingPeriodACLAwareRepository
->findByPerson($person, AccompanyingPeriodVoter::SEE);
return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [
'accompanying_periods' => $accompanyingPeriods,
'person' => $person,
]);
}
public function openAction(int $person_id, Request $request): Response
{
$person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person,
'You are not allowed to update this person');
$this->denyAccessUnlessGranted(
PersonVoter::UPDATE,
$person,
'You are not allowed to update this person'
);
//in case the person is already open
if ($person->isOpen()) {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Error! Period %name% is not closed ; it can be open',
['%name%' => $person->__toString()]
));
->trans(
'Error! Period %name% is not closed ; it can be open',
['%name%' => $person->__toString()]
));
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
]));
'person_id' => $person->getId(),
])
);
}
$accompanyingPeriod = new AccompanyingPeriod(new \DateTime());
$accompanyingPeriod = new AccompanyingPeriod(new DateTime());
$form = $this->createForm(AccompanyingPeriodType::class,
$accompanyingPeriod, [
$form = $this->createForm(
AccompanyingPeriodType::class,
$accompanyingPeriod,
[
'period_action' => 'open',
'center' => $person->getCenter()
]);
'center' => $person->getCenter(),
]
);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
@@ -357,40 +270,41 @@ class AccompanyingPeriodController extends AbstractController
if (count($errors) <= 0) {
$this->get('session')->getFlashBag()
->add('success', $this->get('translator')
->trans('An accompanying period has been opened.',
->trans(
'An accompanying period has been opened.',
['%name%' => $person->__toString()]
));
));
$this->getDoctrine()->getManager()->flush();
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
]));
} else {
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Period not opened'));
foreach ($errors as $error) {
$this->get('session')->getFlashBag()
->add('info', $error->getMessage());
}
'person_id' => $person->getId(),
])
);
}
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Period not opened'));
foreach ($errors as $error) {
$this->get('session')->getFlashBag()
->add('info', $error->getMessage());
}
} else { // if errors in forms
$this->get('session')->getFlashBag()
->add('error', $this->get('translator')
->trans('Period not opened : form is invalid')
);
->add(
'error',
$this->get('translator')
->trans('Period not opened : form is invalid')
);
}
}
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $accompanyingPeriod
'accompanying_period' => $accompanyingPeriod,
]);
}
@@ -400,20 +314,20 @@ class AccompanyingPeriodController extends AbstractController
$person = $this->_getPerson($person_id);
/* @var $period AccompanyingPeriod */
$period = \array_filter(
$period = array_filter(
$person->getAccompanyingPeriods(),
function (AccompanyingPeriod $p) use ($period_id) {
return $p->getId() === ($period_id);
}
)[0] ?? NULL;
)[0] ?? null;
if ($period === NULL) {
if (null === $period) {
throw $this->createNotFoundException('period not found');
}
$confirm = $request->query->getBoolean('confirm', false);
if ($confirm === true && $period->canBeReOpened($person)) {
if (true === $confirm && $period->canBeReOpened($person)) {
$period->reOpen();
$this->_validatePerson($person);
@@ -421,40 +335,141 @@ class AccompanyingPeriodController extends AbstractController
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans(
'The period has been re-opened'));
'The period has been re-opened'
));
return $this->redirectToRoute('chill_person_accompanying_period_list', [
'person_id' => $person->getId()
'person_id' => $person->getId(),
]);
}
} elseif ($confirm === false && $period->canBeReOpened($person)) {
if (false === $confirm && $period->canBeReOpened($person)) {
return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', [
'period' => $period,
'person' => $person
'person' => $person,
]);
} else {
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent("You cannot re-open this period");
}
return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST)
->setContent('You cannot re-open this period');
}
/**
* @throws Exception
*/
public function updateAction(int $person_id, int $period_id, Request $request): Response
{
$em = $this->getDoctrine()->getManager();
/** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($period_id);
if (null === $accompanyingPeriod) {
throw $this->createNotFoundException('Period with id ' . $period_id . ' is not found');
}
/** @var Person $person */
$person = $this->_getPerson($person_id);
// CHECK
if (!$accompanyingPeriod->containsPerson($person)) {
throw new Exception('Accompanying period ' . $period_id . ' does not contain person ' . $person_id);
}
$this->denyAccessUnlessGranted(
PersonVoter::UPDATE,
$person,
'You are not allowed to update this person'
);
$form = $this->createForm(
AccompanyingPeriodType::class,
$accompanyingPeriod,
[
'period_action' => 'update',
'center' => $person->getCenter(),
]
);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
$errors = $this->_validatePerson($person);
$flashBag = $this->get('session')->getFlashBag();
if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) {
$em->flush();
$flashBag->add(
'success',
$this->get('translator')->trans('An accompanying period has been updated.')
);
return $this->redirect(
$this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId(),
])
);
}
$flashBag->add('error', $this->get('translator')
->trans('Error when updating the period'));
foreach ($errors as $error) {
$flashBag->add('info', $error->getMessage());
}
}
return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [
'form' => $form->createView(),
'person' => $person,
'accompanying_period' => $accompanyingPeriod,
]);
}
/**
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
private function _getPerson(int $id) : Person
private function _getPerson(int $id): Person
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')->find($id);
if ($person === null) {
if (null === $person) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person,
"You are not allowed to see this person");
$this->denyAccessUnlessGranted(
PersonVoter::SEE,
$person,
'You are not allowed to see this person'
);
return $person;
}
private function _validatePerson(Person $person): ConstraintViolationListInterface
{
$errors = $this->validator->validate(
$person,
null,
['Default']
);
// Can be disabled with config
if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) {
$errors_accompanying_period = $this->validator->validate(
$person,
null,
['accompanying_period_consistent']
);
foreach ($errors_accompanying_period as $error) {
$errors->add($error);
}
}
return $errors;
}
}

View File

@@ -1,50 +1,51 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class AdminClosingMotiveController
* Controller for closing motives
*
* @package Chill\PersonBundle\Controller
* Controller for closing motives.
*/
class AdminClosingMotiveController extends CRUDController
{
/**
* @param \Chill\MainBundle\CRUD\Controller\string|string $action
* @param Request $request
* @return object
*/
protected function createEntity($action, Request $request): object
{
$entity = parent::createEntity($action, $request);
if ($request->query->has('parent_id')) {
$parentId = $request->query->getInt('parent_id');
$parent = $this->getDoctrine()->getManager()
->getRepository($this->getEntityClass())
->find($parentId);
if (NULL === $parent) {
if (null === $parent) {
throw $this->createNotFoundException('parent id not found');
}
$entity->setParent($parent);
}
return $entity;
}
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
*
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)

View File

@@ -1,26 +1,31 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class AdminController
*
* @package Chill\PersonBundle\Controller
* Class AdminController.
*/
class AdminController extends AbstractController
{
/**
* @param $_locale
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction($_locale)
{
return $this->render('ChillPersonBundle:Admin:layout.html.twig', []);
}
/**
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/

View File

@@ -1,15 +1,20 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminMaritalStatusController
*
* @package Chill\PersonBundle\Controller
* Class AdminMaritalStatusController.
*/
class AdminMaritalStatusController extends CRUDController
{
// for minimal cases, nothing is required here !
}
}

View File

@@ -1,27 +1,36 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\AddressReference;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\Household\HouseholdACLAwareRepositoryInterface;
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use function array_filter;
use function array_values;
class HouseholdApiController extends ApiController
{
private HouseholdRepository $householdRepository;
private HouseholdACLAwareRepositoryInterface $householdACLAwareRepository;
private HouseholdRepository $householdRepository;
public function __construct(
HouseholdRepository $householdRepository,
HouseholdACLAwareRepositoryInterface $householdACLAwareRepository
@@ -30,53 +39,44 @@ class HouseholdApiController extends ApiController
$this->householdACLAwareRepository = $householdACLAwareRepository;
}
public function householdAddressApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]);
}
/**
* Find Household of people participating to the same AccompanyingPeriod
* @Route("/api/1.0/person/household/by-address-reference/{id}.json",
* name="chill_api_person_household_by_address_reference")
*
* @ParamConverter("person", options={"id" = "person_id"})
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format)
public function getHouseholdByAddressReference(AddressReference $addressReference): Response
{
// TODO add acl
// TODO ACL
$this->denyAccessUnlessGranted('ROLE_USER');
$count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
$paginator = $this->getPaginatorFactory()->create($count);
$households = [];
if ($count !== 0) {
$allHouseholds = $this->householdRepository->findByAccompanyingPeriodParticipation($person,
$paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
$currentHouseholdPerson = $person->getCurrentHousehold();
foreach ($allHouseholds as $h) {
if ($h !== $currentHouseholdPerson) {
array_push($households, $h);
}
}
if (null !== $currentHouseholdPerson) {
$count = $count - 1;
$paginator = $this->getPaginatorFactory()->create($count);
}
}
$total = $this->householdACLAwareRepository->countByAddressReference($addressReference);
$paginator = $this->getPaginatorFactory()->create($total);
$households = $this->householdACLAwareRepository->findByAddressReference(
$addressReference,
$paginator->getCurrentPageFirstItemNumber(),
$paginator->getItemsPerPage()
);
$collection = new Collection($households, $paginator);
return $this->json($collection, Response::HTTP_OK, [],
[ "groups" => ["read"]]);
return $this->json($collection, Response::HTTP_OK, [], [
AbstractNormalizer::GROUPS => ['read'],
]);
}
public function householdAddressApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, ['groups' => ['read']]);
}
/**
* @Route("/api/1.0/person/address/suggest/by-household/{household_id}.{_format}",
* name="chill_person_address_suggest_by_household",
* requirements={
* "_format"="json"
* name="chill_person_address_suggest_by_household",
* requirements={
* "_format": "json"
* }
* )
* @ParamConverter("household", options={"id" = "household_id"})
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function suggestAddressByHousehold(Household $household, string $_format)
{
@@ -90,9 +90,11 @@ class HouseholdApiController extends ApiController
$a = $participation->getAccompanyingPeriod()->getAddressLocation();
$addresses[$a->getId()] = $a;
}
if (null !== $personLocation = $participation
->getAccompanyingPeriod()->getPersonLocation()) {
$a = $personLocation->getCurrentHouseholdAddress();
if (null !== $a) {
$addresses[$a->getId()] = $a;
}
@@ -102,34 +104,59 @@ class HouseholdApiController extends ApiController
// remove the actual address
$actual = $household->getCurrentAddress();
if (null !== $actual) {
$addresses = \array_filter($addresses, fn($a) => $a !== $actual);
$addresses = array_filter($addresses, fn ($a) => $a !== $actual);
}
return $this->json(\array_values($addresses), Response::HTTP_OK, [],
[ 'groups' => [ 'read' ] ]);
return $this->json(
array_values($addresses),
Response::HTTP_OK,
[],
['groups' => ['read']]
);
}
/**
* Find Household of people participating to the same AccompanyingPeriod.
*
* @Route("/api/1.0/person/household/by-address-reference/{id}.json",
* name="chill_api_person_household_by_address_reference")
* @param AddressReference $addressReference
* @return \Symfony\Component\HttpFoundation\JsonResponse
* @ParamConverter("person", options={"id": "person_id"})
*/
public function getHouseholdByAddressReference(AddressReference $addressReference): Response
public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format)
{
// TODO ACL
$this->denyAccessUnlessGranted('ROLE_USER');
// TODO add acl
$total = $this->householdACLAwareRepository->countByAddressReference($addressReference);
$paginator = $this->getPaginatorFactory()->create($total);
$households = $this->householdACLAwareRepository->findByAddressReference($addressReference,
$paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage());
$count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
$paginator = $this->getPaginatorFactory()->create($count);
$households = [];
if (0 !== $count) {
$allHouseholds = $this->householdRepository->findByAccompanyingPeriodParticipation(
$person,
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
$currentHouseholdPerson = $person->getCurrentHousehold();
foreach ($allHouseholds as $h) {
if ($h !== $currentHouseholdPerson) {
array_push($households, $h);
}
}
if (null !== $currentHouseholdPerson) {
$count = $count - 1;
$paginator = $this->getPaginatorFactory()->create($count);
}
}
$collection = new Collection($households, $paginator);
return $this->json($collection, Response::HTTP_OK, [], [
AbstractNormalizer::GROUPS => ['read']
]);
return $this->json(
$collection,
Response::HTTP_OK,
[],
['groups' => ['read']]
);
}
}

View File

@@ -1,36 +1,41 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Entity\Address;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Form\HouseholdType;
use Chill\PersonBundle\Repository\Household\PositionRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\Position;
use Chill\PersonBundle\Repository\Household\PositionRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Symfony\Component\Security\Core\Security;
/**
* @Route("/{_locale}/person/household")
*/
class HouseholdController extends AbstractController
{
private TranslatorInterface $translator;
private PositionRepository $positionRepository;
private Security $security;
private SerializerInterface $serializer;
private Security $security;
private TranslatorInterface $translator;
public function __construct(
TranslatorInterface $translator,
@@ -46,51 +51,14 @@ class HouseholdController extends AbstractController
/**
* @Route(
* "/{household_id}/summary",
* name="chill_person_household_summary",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
*/
public function summary(Request $request, Household $household)
{
// TODO ACL
$positions = $this->positionRepository
->findByActiveOrdered()
;
// little performance improvement:
// initialize members collection, which will avoid
// some queries
$household->getMembers()->initialize();
if ($request->query->has('edit')) {
$form = $this->createMetadataForm($household);
} else {
$form = null;
}
return $this->render('@ChillPerson/Household/summary.html.twig',
[
'household' => $household,
'positions' => $positions,
'form' => NULL !== $form ? $form->createView() : null,
]
);
}
/**
* @Route(
* "/{household_id}/accompanying-period",
* name="chill_person_household_accompanying_period",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
* "/{household_id}/accompanying-period",
* name="chill_person_household_accompanying_period",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function accompanyingPeriod(Request $request, Household $household)
{
$currentMembers = $household->getCurrentPersons();
$accompanyingPeriods = [];
@@ -100,9 +68,8 @@ class HouseholdController extends AbstractController
foreach ($accompanyingPeriodsMember as $accompanyingPeriod) {
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) {
continue;
} else {
$accompanyingPeriods[$accompanyingPeriod->getId()] = $accompanyingPeriod;
}
$accompanyingPeriods[$accompanyingPeriod->getId()] = $accompanyingPeriod;
}
}
@@ -115,93 +82,44 @@ class HouseholdController extends AbstractController
foreach ($accompanyingPeriodsOldMember as $accompanyingPeriod) {
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) {
continue;
} else {
$id = $accompanyingPeriod->getId();
}
$id = $accompanyingPeriod->getId();
if (!array_key_exists($id, $accompanyingPeriodsOld) && !array_key_exists($id, $accompanyingPeriods)) {
$accompanyingPeriodsOld[$id] = $accompanyingPeriod;
}
if (!array_key_exists($id, $accompanyingPeriodsOld) && !array_key_exists($id, $accompanyingPeriods)) {
$accompanyingPeriodsOld[$id] = $accompanyingPeriod;
}
}
}
return $this->render('@ChillPerson/Household/accompanying_period.html.twig',
return $this->render(
'@ChillPerson/Household/accompanying_period.html.twig',
[
'household' => $household,
'accompanying_periods' => $accompanyingPeriods,
'accompanying_periods_old' => $accompanyingPeriodsOld
'accompanying_periods_old' => $accompanyingPeriodsOld,
]
);
}
/**
* @Route(
* "/{household_id}/addresses",
* name="chill_person_household_addresses",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
*/
public function addresses(Request $request, Household $household)
{
// TODO ACL
//TODO put these lines into a validator constraint on household->getAddress
$addresses = $household->getAddresses();
$cond = True;
for ($i=0; $i < count($addresses) - 1; $i++) {
if ($addresses[$i]->getValidFrom() != $addresses[$i + 1]->getValidTo()) {
$cond = False;
}
}
return $this->render('@ChillPerson/Household/addresses.html.twig',
[
'household' => $household
]
);
}
/**
* @Route(
* "/{household_id}/address/move",
* name="chill_person_household_address_move",
* methods={"GET", "HEAD", "POST"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
*/
public function addressMove(Request $request, Household $household)
{
// TODO ACL
return $this->render('@ChillPerson/Household/address_move.html.twig',
[
'household' => $household
]
);
}
/**
* @Route(
* "/{household_id}/address/edit",
* name="chill_person_household_address_edit",
* methods={"GET", "HEAD", "POST"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
* "/{household_id}/address/edit",
* name="chill_person_household_address_edit",
* methods={"GET", "HEAD", "POST"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function addressEdit(Request $request, Household $household)
{
// TODO ACL
$address_id = $request->query->get('address_id');
$address = $this->getDoctrine()->getManager()
->getRepository(Address::class)
->find($address_id)
;
->find($address_id);
return $this->render('@ChillPerson/Household/address_edit.html.twig',
return $this->render(
'@ChillPerson/Household/address_edit.html.twig',
[
'household' => $household,
'address' => $address,
@@ -211,32 +129,61 @@ class HouseholdController extends AbstractController
/**
* @Route(
* "/{household_id}/relationship",
* name="chill_person_household_relationship",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
* "/{household_id}/addresses",
* name="chill_person_household_addresses",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function showRelationship(Request $request, Household $household)
public function addresses(Request $request, Household $household)
{
$jsonString = $this->serializer->serialize($household->getCurrentPersons(),
'json', [ AbstractNormalizer::GROUPS => ['read']]);
// TODO ACL
return $this->render('@ChillPerson/Household/relationship.html.twig',
//TODO put these lines into a validator constraint on household->getAddress
$addresses = $household->getAddresses();
$cond = true;
for ($i = 0; count($addresses) - 1 > $i; ++$i) {
if ($addresses[$i]->getValidFrom() != $addresses[$i + 1]->getValidTo()) {
$cond = false;
}
}
return $this->render(
'@ChillPerson/Household/addresses.html.twig',
[
'household' => $household,
'persons' => $jsonString
]
);
}
/**
* @Route(
* "/{household_id}/members/metadata/edit",
* name="chill_person_household_members_metadata_edit",
* methods={"GET", "POST"}
* )
* @ParamConverter("household", options={"id" = "household_id"})
* "/{household_id}/address/move",
* name="chill_person_household_address_move",
* methods={"GET", "HEAD", "POST"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function addressMove(Request $request, Household $household)
{
// TODO ACL
return $this->render(
'@ChillPerson/Household/address_move.html.twig',
[
'household' => $household,
]
);
}
/**
* @Route(
* "/{household_id}/members/metadata/edit",
* name="chill_person_household_members_metadata_edit",
* methods={"GET", "POST"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function editHouseholdMetadata(Request $request, Household $household)
{
@@ -251,32 +198,90 @@ class HouseholdController extends AbstractController
$this->addFlash('success', $this->translator->trans('household.data_saved'));
return $this->redirectToRoute('chill_person_household_summary', [
'household_id' => $household->getId()
'household_id' => $household->getId(),
]);
}
return $this->render('@ChillPerson/Household/edit_member_metadata.html.twig', [
'household' => $household,
'form' => $form->createView()
'form' => $form->createView(),
]);
}
/**
* @Route(
* "/{household_id}/relationship",
* name="chill_person_household_relationship",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function showRelationship(Request $request, Household $household)
{
$jsonString = $this->serializer->serialize(
$household->getCurrentPersons(),
'json',
[AbstractNormalizer::GROUPS => ['read']]
);
return $this->render(
'@ChillPerson/Household/relationship.html.twig',
[
'household' => $household,
'persons' => $jsonString,
]
);
}
/**
* @Route(
* "/{household_id}/summary",
* name="chill_person_household_summary",
* methods={"GET", "HEAD"}
* )
* @ParamConverter("household", options={"id": "household_id"})
*/
public function summary(Request $request, Household $household)
{
// TODO ACL
$positions = $this->positionRepository
->findByActiveOrdered();
// little performance improvement:
// initialize members collection, which will avoid
// some queries
$household->getMembers()->initialize();
if ($request->query->has('edit')) {
$form = $this->createMetadataForm($household);
} else {
$form = null;
}
return $this->render(
'@ChillPerson/Household/summary.html.twig',
[
'household' => $household,
'positions' => $positions,
'form' => null !== $form ? $form->createView() : null,
]
);
}
private function createMetadataForm(Household $household): FormInterface
{
$form = $this->createForm(
return $this->createForm(
HouseholdType::class,
$household,
[
'action' => $this->generateUrl(
'chill_person_household_members_metadata_edit',
[
'household_id' => $household->getId()
'household_id' => $household->getId(),
]
)
),
]
);
return $form;
}
}

View File

@@ -1,39 +1,44 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Household\Position;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\HouseholdMemberType;
use Chill\PersonBundle\Household\MembersEditor;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Form\HouseholdMemberType;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Serializer\Exception;
use Symfony\Component\Routing\Annotation\Route;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\Translation\TranslatorInterface;
use Chill\PersonBundle\Household\MembersEditor;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
class HouseholdMemberController extends ApiController
{
private UrlGeneratorInterface $generator;
private TranslatorInterface $translator;
private AccompanyingPeriodRepository $periodRepository;
private TranslatorInterface $translator;
public function __construct(
UrlGeneratorInterface $generator,
TranslatorInterface $translator,
AccompanyingPeriodRepository $periodRepository
)
{
) {
$this->generator = $generator;
$this->translator = $translator;
$this->periodRepository = $periodRepository;
@@ -41,16 +46,143 @@ class HouseholdMemberController extends ApiController
/**
* @Route(
* "/api/1.0/person/household/members/move.{_format}",
* name="chill_api_person_household_members_move"
* )
* "/{_locale}/person/household/member/{id}/edit",
* name="chill_person_household_member_edit"
* )
*/
public function editMembership(Request $request, HouseholdMember $member): Response
{
// TODO ACL
$form = $this->createForm(HouseholdMemberType::class, $member, [
'validation_groups' => ['household_memberships'],
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator
->trans('household.successfully saved member'));
return $this->redirect(
$request->get('returnPath', null) ??
$this->generator->generate('chill_person_household_summary', ['household_id' => $member->getHousehold()->getId()])
);
}
return $this->render('@ChillPerson/Household/Member/edit.html.twig', [
'household' => $member->getHousehold(),
'member' => $member,
'form' => $form->createView(),
]);
}
/**
* Route for showing an editor to leave a household.
*
* Possibles arguments are:
*
* * persons[]: an id of the person to add to the form
* * household: the id of the destination household
* * allow_leave_without_household: if present, the editor will allow
* to leave household without joining another
*
* @Route(
* "/{_locale}/person/household/members/editor",
* name="chill_person_household_members_editor"
* )
*/
public function editor(Request $request)
{
$em = $this->getDoctrine()->getManager();
if ($request->query->has('persons')) {
$ids = $request->query->get('persons', []);
if (0 === count($ids)) {
throw new BadRequestException('parameters persons in query ' .
'is not an array or empty');
}
$persons = $em->getRepository(Person::class)
->findById($ids);
foreach ($persons as $person) {
$this->denyAccessUnlessGranted(
PersonVoter::SEE,
$person,
"You are not allowed to see person with id {$person->getId()}"
);
}
}
if ($householdId = $request->query->get('household', false)) {
$household = $em->getRepository(Household::class)
->find($householdId);
$allowHouseholdCreate = false;
$allowHouseholdSearch = false;
$allowLeaveWithoutHousehold = false;
if (null === $household) {
throw $this->createNotFoundException('household not found');
}
// TODO ACL on household
}
$positions = $this->getDoctrine()->getManager()
->getRepository(Position::class)
->findAll();
$data = [
'persons' => $persons ?? false ?
$this->getSerializer()->normalize($persons, 'json', ['groups' => ['read']]) : [],
'household' => $household ?? false ?
$this->getSerializer()->normalize($household, 'json', ['groups' => ['read']]) : null,
'positions' => $this->getSerializer()->normalize($positions, 'json', ['groups' => ['read']]),
'allowHouseholdCreate' => $allowHouseholdCreate ?? true,
'allowHouseholdSearch' => $allowHouseholdSearch ?? true,
'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'),
];
// context
if ($request->query->has('accompanying_period_id')) {
$period = $this->periodRepository->find(
$request->query->getInt('accompanying_period_id')
);
if (null === $period) {
throw $this->createNotFoundException('period not found');
}
// TODO add acl on accompanying Course
}
return $this->render('@ChillPerson/Household/members_editor.html.twig', [
'data' => $data,
'expandSuggestions' => (int) $request->query->getBoolean('expand_suggestions', false),
'accompanyingCourse' => $period ?? null,
]);
}
/**
* @Route(
* "/api/1.0/person/household/members/move.{_format}",
* name="chill_api_person_household_members_move"
* )
*
* @param mixed $_format
*/
public function move(Request $request, $_format): Response
{
try {
$editor = $this->getSerializer()
->deserialize($request->getContent(), MembersEditor::class,
$_format, ['groups' => [ "read" ]]);
->deserialize(
$request->getContent(),
MembersEditor::class,
$_format,
['groups' => ['read']]
);
} catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) {
throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e);
}
@@ -68,143 +200,16 @@ class HouseholdMemberController extends ApiController
// if new household, persist it
if (
$editor->hasHousehold()
&&
FALSE === $em->contains($editor->getHousehold())
&& false === $em->contains($editor->getHousehold())
) {
$em->persist($editor->getHousehold());
}
foreach ($editor->getPersistable() as $el) {
$em->persist($el);
$em->persist($el);
}
$em->flush();
return $this->json($editor->getHousehold(), Response::HTTP_OK, [], ["groups" => ["read"]]);
}
/**
* Route for showing an editor to leave a household.
*
* Possibles arguments are:
*
* * persons[]: an id of the person to add to the form
* * household: the id of the destination household
* * allow_leave_without_household: if present, the editor will allow
* to leave household without joining another
*
* @Route(
* "/{_locale}/person/household/members/editor",
* name="chill_person_household_members_editor"
* )
*/
public function editor(Request $request)
{
$em = $this->getDoctrine()->getManager();
if ($request->query->has('persons')) {
$ids = $request->query->get('persons', []);
if (0 === count($ids)) {
throw new BadRequestException("parameters persons in query ".
"is not an array or empty");
}
$persons = $em->getRepository(Person::class)
->findById($ids)
;
foreach ($persons as $person) {
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person,
"You are not allowed to see person with id {$person->getId()}"
);
}
}
if ($householdId = $request->query->get('household', false)) {
$household = $em->getRepository(Household::class)
->find($householdId)
;
$allowHouseholdCreate = false;
$allowHouseholdSearch = false;
$allowLeaveWithoutHousehold = false;
if (NULL === $household) {
throw $this->createNotFoundException('household not found');
}
// TODO ACL on household
}
$positions = $this->getDoctrine()->getManager()
->getRepository(Position::class)
->findAll()
;
$data = [
'persons' => $persons ?? false ?
$this->getSerializer()->normalize($persons, 'json', [ 'groups' => [ 'read' ]]) : [],
'household' => $household ?? false ?
$this->getSerializer()->normalize($household, 'json', [ 'groups' => [ 'read' ]]) : null,
'positions' =>
$this->getSerializer()->normalize($positions, 'json', [ 'groups' => [ 'read' ]]),
'allowHouseholdCreate' => $allowHouseholdCreate ?? true,
'allowHouseholdSearch' => $allowHouseholdSearch ?? true,
'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'),
];
// context
if ($request->query->has('accompanying_period_id')) {
$period = $this->periodRepository->find(
$request->query->getInt('accompanying_period_id')
);
if ($period === null) {
throw $this->createNotFoundException('period not found');
}
// TODO add acl on accompanying Course
}
return $this->render('@ChillPerson/Household/members_editor.html.twig', [
'data' => $data,
'expandSuggestions' => (int) $request->query->getBoolean('expand_suggestions', false),
'accompanyingCourse' => $period ?? null,
]);
}
/**
* @Route(
* "/{_locale}/person/household/member/{id}/edit",
* name="chill_person_household_member_edit"
* )
*/
public function editMembership(Request $request, HouseholdMember $member): Response
{
// TODO ACL
$form = $this->createForm(HouseholdMemberType::class, $member, [
'validation_groups' => [ 'household_memberships' ]
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator
->trans('household.successfully saved member'))
;
return $this->redirect(
$request->get('returnPath', null) ??
$this->generator->generate('chill_person_household_summary', [ 'household_id' =>
$member->getHousehold()->getId() ])
);
}
return $this->render('@ChillPerson/Household/Member/edit.html.twig', [
'household' => $member->getHousehold(),
'member' => $member,
'form' => $form->createView()
]);
return $this->json($editor->getHousehold(), Response::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,10 +1,17 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use DateTime;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class OpeningApiController extends ApiController
{
@@ -12,6 +19,6 @@ class OpeningApiController extends ApiController
{
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
$qb->setParameter('now', new \DateTime('now'));
}
$qb->setParameter('now', new DateTime('now'));
}
}

View File

@@ -1,43 +1,25 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2016, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Form\Type\AddressType;
use Chill\PersonBundle\Entity\Person;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Form\Type\AddressType;
use Chill\MainBundle\Entity\Address;
use Doctrine\Common\Collections\Criteria;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class PersonAddressController
* Controller for addresses associated with person
*
* @package Chill\PersonBundle\Controller
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
* Controller for addresses associated with person.
*/
class PersonAddressController extends AbstractController
{
@@ -48,78 +30,27 @@ class PersonAddressController extends AbstractController
/**
* PersonAddressController constructor.
*
* @param ValidatorInterface $validator
*/
public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}
public function listAction($person_id)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found ");
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_SEE',
$person,
"You are not allowed to edit this person."
);
return $this->render('ChillPersonBundle:Address:list.html.twig', array(
'person' => $person
));
}
public function newAction($person_id)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found ");
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
"You are not allowed to edit this person."
);
$address = new Address();
$form = $this->createCreateForm($person, $address);
return $this->render('ChillPersonBundle:Address:new.html.twig', array(
'person' => $person,
'form' => $form->createView()
));
}
public function createAction($person_id, Request $request)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found ");
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found ');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
"You are not allowed to edit this person."
'You are not allowed to edit this person.'
);
$address = new Address();
@@ -137,7 +68,6 @@ class PersonAddressController extends AbstractController
$this->addFlash('error', $error->getMessage());
}
} elseif ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
@@ -146,47 +76,96 @@ class PersonAddressController extends AbstractController
$this->get('translator')->trans('The new address was created successfully')
);
return $this->redirectToRoute('chill_person_address_list', array(
'person_id' => $person->getId()
));
return $this->redirectToRoute('chill_person_address_list', [
'person_id' => $person->getId(),
]);
} else {
$this->addFlash('error', $this->get('translator')
->trans('Error! Address not created!'));
->trans('Error! Address not created!'));
}
}
return $this->render('ChillPersonBundle:Address:new.html.twig', array(
return $this->render('ChillPersonBundle:Address:new.html.twig', [
'person' => $person,
'form' => $form->createView()
));
'form' => $form->createView(),
]);
}
public function editAction($person_id, $address_id)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found ");
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found ');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
"You are not allowed to edit this person."
'You are not allowed to edit this person.'
);
$address = $this->findAddressById($person, $address_id);
$form = $this->createEditForm($person, $address);
return $this->render('ChillPersonBundle:Address:edit.html.twig', array(
'person' => $person,
'address' => $address,
'form' => $form->createView()
));
return $this->render('ChillPersonBundle:Address:edit.html.twig', [
'person' => $person,
'address' => $address,
'form' => $form->createView(),
]);
}
public function listAction($person_id)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found ');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_SEE',
$person,
'You are not allowed to edit this person.'
);
return $this->render('ChillPersonBundle:Address:list.html.twig', [
'person' => $person,
]);
}
public function newAction($person_id)
{
$person = $this->getDoctrine()->getManager()
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found ');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
'You are not allowed to edit this person.'
);
$address = new Address();
$form = $this->createCreateForm($person, $address);
return $this->render('ChillPersonBundle:Address:new.html.twig', [
'person' => $person,
'form' => $form->createView(),
]);
}
public function updateAction($person_id, $address_id, Request $request)
@@ -195,15 +174,15 @@ class PersonAddressController extends AbstractController
->getRepository('ChillPersonBundle:Person')
->find($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found ");
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found ');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
"You are not allowed to edit this person."
'You are not allowed to edit this person.'
);
$address = $this->findAddressById($person, $address_id);
@@ -220,90 +199,84 @@ class PersonAddressController extends AbstractController
}
} elseif ($form->isValid()) {
$this->getDoctrine()->getManager()
->flush();
->flush();
$this->addFlash('success', $this->get('translator')->trans(
"The address has been successfully updated"
'The address has been successfully updated'
));
return $this->redirectToRoute('chill_person_address_list', array(
'person_id' => $person->getId()
));
return $this->redirectToRoute('chill_person_address_list', [
'person_id' => $person->getId(),
]);
} else {
$this->addFlash('error', $this->get('translator')
->trans('Error when updating the period'));
}
}
return $this->render('ChillPersonBundle:Address:edit.html.twig', array(
'person' => $person,
'address' => $address,
'form' => $form->createView()
));
return $this->render('ChillPersonBundle:Address:edit.html.twig', [
'person' => $person,
'address' => $address,
'form' => $form->createView(),
]);
}
/**
* @param Person $person
* @param Address $address
* @return \Symfony\Component\Form\Form
*/
protected function createEditForm(Person $person, Address $address)
{
$form = $this->createForm(AddressType::class, $address, array(
'method' => 'POST',
'action' => $this->generateUrl('chill_person_address_update', array(
'person_id' => $person->getId(),
'address_id' => $address->getId()
)),
'has_no_address' => true
));
$form->add('submit', SubmitType::class, array(
'label' => 'Submit'
));
return $form;
}
/**
*
* @param Person $person
* @param Address $address
* @return \Symfony\Component\Form\Form
*/
protected function createCreateForm(Person $person, Address $address)
{
$form = $this->createForm(AddressType::class, $address, array(
'method' => 'POST',
'action' => $this->generateUrl('chill_person_address_create', array(
'person_id' => $person->getId()
)),
'has_no_address' => true
));
$form = $this->createForm(AddressType::class, $address, [
'method' => 'POST',
'action' => $this->generateUrl('chill_person_address_create', [
'person_id' => $person->getId(),
]),
'has_no_address' => true,
]);
$form->add('submit', SubmitType::class, array(
'label' => 'Submit'
));
$form->add('submit', SubmitType::class, [
'label' => 'Submit',
]);
return $form;
}
/**
* @return \Symfony\Component\Form\Form
*/
protected function createEditForm(Person $person, Address $address)
{
$form = $this->createForm(AddressType::class, $address, [
'method' => 'POST',
'action' => $this->generateUrl('chill_person_address_update', [
'person_id' => $person->getId(),
'address_id' => $address->getId(),
]),
'has_no_address' => true,
]);
$form->add('submit', SubmitType::class, [
'label' => 'Submit',
]);
return $form;
}
/**
*
* @param Person $person
* @param int $address_id
* @return Address
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the address id does not exists or is not associated with given person
*
* @return Address
*/
protected function findAddressById(Person $person, $address_id)
{
$address = $this->getDoctrine()->getManager()
->getRepository(Address::class)
->find($address_id)
;
->find($address_id);
if (!$person->getAddresses()->contains($address)) {
throw $this->createAccessDeniedException("Not allowed to see this address");
throw $this->createAccessDeniedException('Not allowed to see this address');
}
return $address;
@@ -311,16 +284,17 @@ class PersonAddressController extends AbstractController
/**
* @param Chill\PersonBundle\Entity\Person $person
*
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
*/
private function validatePerson(Person $person)
{
$errors = $this->validator
->validate($person, null, array('Default'));
->validate($person, null, ['Default']);
$errors_addresses_consistent = $this->validator
->validate($person, null, array('addresses_consistent'));
->validate($person, null, ['addresses_consistent']);
foreach($errors_addresses_consistent as $error) {
foreach ($errors_addresses_consistent as $error) {
$errors->add($error);
}

View File

@@ -1,70 +1,49 @@
<?php
/*
* Copyright (C) 2015-2021 Champs-Libres Coopérative <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Role\Role;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Entity\Address;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Security\Core\Role\Role;
use function array_filter;
use function array_values;
class PersonApiController extends ApiController
{
private AuthorizationHelper $authorizationHelper;
/**
* @param AuthorizationHelper $authorizationHelper
*/
public function __construct(AuthorizationHelper $authorizationHelper)
{
$this->authorizationHelper = $authorizationHelper;
}
protected function createEntity(string $action, Request $request): object
{
$person = parent::createEntity($action, $request);
// TODO temporary hack to allow creation of person with fake center
/* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
new Role(PersonVoter::CREATE));
$person->setCenter($centers[0]); */
return $person;
}
public function personAddressApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]);
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, ['groups' => ['read']]);
}
/**
* @Route("/api/1.0/person/address/suggest/by-person/{person_id}.{_format}",
* name="chill_person_address_suggest_by_person",
* requirements={
* "_format"="json"
* name="chill_person_address_suggest_by_person",
* requirements={
* "_format": "json"
* }
* )
* @ParamConverter("person", options={"id" = "person_id"})
* )
* @ParamConverter("person", options={"id": "person_id"})
*/
public function suggestAddress(Person $person, Request $request, string $_format): Response
{
@@ -81,10 +60,20 @@ class PersonApiController extends ApiController
// remove the actual address
$actual = $person->getCurrentHouseholdAddress();
if (null !== $actual) {
$addresses = \array_filter($addresses, fn($a) => $a !== $actual);
$addresses = array_filter($addresses, fn ($a) => $a !== $actual);
}
return $this->json(\array_values($addresses), Response::HTTP_OK, [], [ 'groups' => [ 'read' ]]);
return $this->json(array_values($addresses), Response::HTTP_OK, [], ['groups' => ['read']]);
}
protected function createEntity(string $action, Request $request): object
{
return parent::createEntity($action, $request);
// TODO temporary hack to allow creation of person with fake center
/* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
new Role(PersonVoter::CREATE));
$person->setCenter($centers[0]); */
}
}

View File

@@ -1,65 +1,46 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Psr\Log\LoggerInterface;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\PersonType;
use Chill\PersonBundle\Form\CreationPersonType;
use Chill\PersonBundle\Form\PersonType;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Search\SimilarPersonMatcher;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Search\SimilarPersonMatcher;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Translation\TranslatorInterface;
use Chill\MainBundle\Search\SearchProvider;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use function hash;
use function implode;
use function in_array;
use function is_array;
final class PersonController extends AbstractController
{
/**
* @var SimilarPersonMatcher
* @var ConfigPersonAltNamesHelper
*/
protected $similarPersonMatcher;
/**
* @var TranslatorInterface
*/
protected $translator;
protected $configPersonAltNameHelper;
/**
* @var EventDispatcherInterface
@@ -72,9 +53,14 @@ final class PersonController extends AbstractController
protected $personRepository;
/**
* @var ConfigPersonAltNamesHelper
* @var SimilarPersonMatcher
*/
protected $configPersonAltNameHelper;
protected $similarPersonMatcher;
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @var EntityManagerInterface
@@ -111,60 +97,28 @@ final class PersonController extends AbstractController
$this->validator = $validator;
$this->em = $em;
$this->security = $security;
}
public function getCFGroup()
{
$cFGroup = null;
$cFDefaultGroup = $this->em->getRepository("ChillCustomFieldsBundle:CustomFieldsDefaultGroup")
->findOneByEntity("Chill\PersonBundle\Entity\Person");
if($cFDefaultGroup) {
$cFGroup = $cFDefaultGroup->getCustomFieldsGroup();
}
return $cFGroup;
}
public function viewAction($person_id)
{
$person = $this->_getPerson($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found on this server");
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person,
"You are not allowed to see this person.");
$event = new PrivacyEvent($person);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillPersonBundle:Person:view.html.twig',
array(
"person" => $person,
"cFGroup" => $this->getCFGroup(),
"alt_names" => $this->configPersonAltNameHelper->getChoices(),
));
}
public function editAction($person_id, Request $request)
{
$person = $this->_getPerson($person_id);
if ($person === null) {
if (null === $person) {
throw $this->createNotFoundException();
}
$this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person,
'You are not allowed to edit this person');
$this->denyAccessUnlessGranted(
'CHILL_PERSON_UPDATE',
$person,
'You are not allowed to edit this person'
);
$form = $this->createForm(PersonType::class, $person,
array(
"cFGroup" => $this->getCFGroup()
)
$form = $this->createForm(
PersonType::class,
$person,
[
'cFGroup' => $this->getCFGroup(),
]
);
$form->handleRequest($request);
@@ -172,28 +126,71 @@ final class PersonController extends AbstractController
if ($form->isSubmitted() && !$form->isValid()) {
$this->get('session')
->getFlashBag()->add('error', $this->translator
->trans('This form contains errors'));
->trans('This form contains errors'));
} elseif ($form->isSubmitted() && $form->isValid()) {
$this->get('session')->getFlashBag()
->add('success',
->add(
'success',
$this->get('translator')
->trans('The person data has been updated')
);
$this->em->flush();
return $this->redirectToRoute('chill_person_view', [
'person_id' => $person->getId()
return $this->redirectToRoute('chill_person_view', [
'person_id' => $person->getId(),
]);
}
return $this->render(
'ChillPersonBundle:Person:edit.html.twig',
['person' => $person, 'form' => $form->createView()]
);
}
return $this->render('ChillPersonBundle:Person:edit.html.twig',
array('person' => $person, 'form' => $form->createView()));
public function getCFGroup()
{
$cFGroup = null;
$cFDefaultGroup = $this->em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup')
->findOneByEntity('Chill\\PersonBundle\\Entity\\Person');
if ($cFDefaultGroup) {
$cFGroup = $cFDefaultGroup->getCustomFieldsGroup();
}
return $cFGroup;
}
/**
* Method for creating a new person
* @Route(
* "/{_locale}/person/household/{person_id}/history",
* name="chill_person_household_person_history",
* methods={"GET", "POST"}
* )
* @ParamConverter("person", options={"id": "person_id"})
*/
public function householdHistoryByPerson(Request $request, Person $person): Response
{
$this->denyAccessUnlessGranted(
'CHILL_PERSON_SEE',
$person,
'You are not allowed to see this person.'
);
$event = new PrivacyEvent($person);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render(
'@ChillPerson/Person/household_history.html.twig',
[
'person' => $person,
]
);
}
/**
* Method for creating a new person.
*
*The controller register data from a previous post on the form, and
* register it in the session.
@@ -201,15 +198,14 @@ final class PersonController extends AbstractController
* The next post compare the data with previous one and, if yes, show a
* review page if there are "alternate persons".
*
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
* @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function newAction(Request $request)
{
$person = new Person();
if (1 === count($this->security->getUser()
->getGroupCenters())) {
->getGroupCenters())) {
$person->setCenter(
$this->security->getUser()
->getGroupCenters()[0]
@@ -218,13 +214,13 @@ final class PersonController extends AbstractController
}
$form = $this->createForm(CreationPersonType::class, $person, [
'validation_groups' => ['create']
'validation_groups' => ['create'],
])->add('editPerson', SubmitType::class, [
'label' => 'Add the person'
'label' => 'Add the person',
])->add('createPeriod', SubmitType::class, [
'label' => 'Add the person and create an accompanying period'
'label' => 'Add the person and create an accompanying period',
])->add('createHousehold', SubmitType::class, [
'label' => 'Add the person and create an household'
'label' => 'Add the person and create an household',
]); // TODO createHousehold form action
$form->handleRequest($request);
@@ -233,14 +229,12 @@ final class PersonController extends AbstractController
$this->lastPostDataReset();
} elseif ($request->getMethod() === Request::METHOD_POST
&& $form->isValid()) {
$alternatePersons = $this->similarPersonMatcher
->matchPerson($person);
if (
FALSE === $this->isLastPostDataChanges($form, $request, true)
||
count($alternatePersons) === 0
false === $this->isLastPostDataChanges($form, $request, true)
|| count($alternatePersons) === 0
) {
$this->em->persist($person);
@@ -249,84 +243,75 @@ final class PersonController extends AbstractController
if ($form->get('createPeriod')->isClicked()) {
return $this->redirectToRoute('chill_person_accompanying_course_new', [
'person_id' => [ $person->getId() ]
'person_id' => [$person->getId()],
]);
}
return $this->redirectToRoute('chill_person_general_edit',
['person_id' => $person->getId()]);
return $this->redirectToRoute(
'chill_person_general_edit',
['person_id' => $person->getId()]
);
}
} elseif ($request->getMethod() === Request::METHOD_POST && !$form->isValid()) {
$this->addFlash('error', $this->translator->trans('This form contains errors'));
}
return $this->render('@ChillPerson/Person/create.html.twig',
return $this->render(
'@ChillPerson/Person/create.html.twig',
[
'form' => $form->createView(),
'alternatePersons' => $alternatePersons ?? []
'alternatePersons' => $alternatePersons ?? [],
]
);
}
private function isLastPostDataChanges(Form $form, Request $request, bool $replace = false): bool
public function viewAction($person_id)
{
/** @var SessionInterface $session */
$session = $this->get('session');
if (!$session->has('last_person_data')) {
return true;
$person = $this->_getPerson($person_id);
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found on this server');
}
$newPost = $this->lastPostDataBuildHash($form, $request);
$this->denyAccessUnlessGranted(
'CHILL_PERSON_SEE',
$person,
'You are not allowed to see this person.'
);
$isChanged = $newPost !== $session->get('last_person_data');
$event = new PrivacyEvent($person);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
if ($replace) {
$session->set('last_person_data', $newPost);
}
return $isChanged ;
}
private function lastPostDataReset(): void
{
$this->get('session')->set('last_person_data', "");
return $this->render(
'ChillPersonBundle:Person:view.html.twig',
[
'person' => $person,
'cFGroup' => $this->getCFGroup(),
'alt_names' => $this->configPersonAltNameHelper->getChoices(),
]
);
}
/**
* build the hash for posted data
* easy getting a person by his id.
*
* For privacy reasons, the data are hashed using sha512
* @param mixed $id
*
* @param Form $form
* @param Request $request
* @return string
* @return \Chill\PersonBundle\Entity\Person
*/
private function lastPostDataBuildHash(Form $form, Request $request): string
private function _getPerson($id)
{
$fields = [];
$ignoredFields = ['form_status', '_token'];
foreach ($request->request->all()[$form->getName()] as $field => $value) {
if (\in_array($field, $ignoredFields)) {
continue;
}
$fields[$field] = \is_array($value) ?
\implode(",", $value) : $value;
}
ksort($fields);
return \hash('sha512', \implode("&", $fields));
return $this->personRepository->find($id);
}
/**
*
* @param \Chill\PersonBundle\Entity\Person $person
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
*/
private function _validatePersonAndAccompanyingPeriod(Person $person)
{
$errors = $this->validator
->validate($person, null, array('creation'));
->validate($person, null, ['creation']);
//validate accompanying periods
$periods = $person->getAccompanyingPeriods();
@@ -336,7 +321,7 @@ final class PersonController extends AbstractController
->validate($period);
//group errors :
foreach($period_errors as $error) {
foreach ($period_errors as $error) {
$errors->add($error);
}
}
@@ -344,39 +329,50 @@ final class PersonController extends AbstractController
return $errors;
}
/**
* easy getting a person by his id
* @return \Chill\PersonBundle\Entity\Person
*/
private function _getPerson($id)
private function isLastPostDataChanges(Form $form, Request $request, bool $replace = false): bool
{
$person = $this->personRepository->find($id);
/** @var SessionInterface $session */
$session = $this->get('session');
return $person;
if (!$session->has('last_person_data')) {
return true;
}
$newPost = $this->lastPostDataBuildHash($form, $request);
$isChanged = $session->get('last_person_data') !== $newPost;
if ($replace) {
$session->set('last_person_data', $newPost);
}
return $isChanged;
}
/**
* build the hash for posted data.
*
* @Route(
* "/{_locale}/person/household/{person_id}/history",
* name="chill_person_household_person_history",
* methods={"GET", "POST"}
* )
* @ParamConverter("person", options={"id" = "person_id"})
* For privacy reasons, the data are hashed using sha512
*/
public function householdHistoryByPerson(Request $request, Person $person): Response
private function lastPostDataBuildHash(Form $form, Request $request): string
{
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person,
"You are not allowed to see this person.");
$fields = [];
$ignoredFields = ['form_status', '_token'];
$event = new PrivacyEvent($person);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
foreach ($request->request->all()[$form->getName()] as $field => $value) {
if (in_array($field, $ignoredFields)) {
continue;
}
$fields[$field] = is_array($value) ?
implode(',', $value) : $value;
}
ksort($fields);
return $this->render(
'@ChillPerson/Person/household_history.html.twig',
[
'person' => $person
]
);
return hash('sha512', implode('&', $fields));
}
private function lastPostDataReset(): void
{
$this->get('session')->set('last_person_data', '');
}
}

View File

@@ -1,29 +1,50 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\ActivityBundle\Entity\Activity;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\EventBundle\Entity\Participation;
use Chill\PersonBundle\Actions\Remove\PersonMove;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonNotDuplicate;
use Chill\PersonBundle\Form\PersonConfimDuplicateType;
use Chill\PersonBundle\Form\PersonFindManuallyDuplicateType;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Search\SimilarPersonMatcher;
use Chill\TaskBundle\Entity\SingleTask;
use http\Exception\InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Translation\TranslatorInterface;
use Chill\ActivityBundle\Entity\Activity;
use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\EventBundle\Entity\Participation;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Chill\TaskBundle\Entity\SingleTask;
class PersonDuplicateController extends Controller
{
/**
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
private $eventDispatcher;
/**
* @var \Chill\PersonBundle\Actions\Remove\PersonMove
*/
private $personMove;
/**
* @var \Chill\PersonBundle\Repository\PersonRepository
*/
private $personRepository;
/**
* @var \Chill\PersonBundle\Search\SimilarPersonMatcher
*/
@@ -34,27 +55,12 @@ class PersonDuplicateController extends Controller
*/
private $translator;
/**
* @var \Chill\PersonBundle\Repository\PersonRepository
*/
private $personRepository;
/**
* @var \Chill\PersonBundle\Actions\Remove\PersonMove
*/
private $personMove;
/**
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
private $eventDispatcher;
public function __construct(
SimilarPersonMatcher $similarPersonMatcher,
TranslatorInterface $translator,
PersonRepository $personRepository,
PersonMove $personMove,
EventDispatcherInterface $eventDispatcher
SimilarPersonMatcher $similarPersonMatcher,
TranslatorInterface $translator,
PersonRepository $personRepository,
PersonMove $personMove,
EventDispatcherInterface $eventDispatcher
) {
$this->similarPersonMatcher = $similarPersonMatcher;
$this->translator = $translator;
@@ -63,29 +69,6 @@ class PersonDuplicateController extends Controller
$this->eventDispatcher = $eventDispatcher;
}
public function viewAction($person_id, PersonNotDuplicateRepository $personNotDuplicateRepository)
{
$person = $this->_getPerson($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found on this server");
}
$this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person,
"You are not allowed to see this person.");
$duplicatePersons = $this->similarPersonMatcher->
matchPerson($person, $personNotDuplicateRepository, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL);
$notDuplicatePersons = $personNotDuplicateRepository->findNotDuplicatePerson($person);
return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [
'person' => $person,
'duplicatePersons' => $duplicatePersons,
'notDuplicatePersons' => $notDuplicatePersons,
]);
}
public function confirmAction($person1_id, $person2_id, Request $request)
{
if ($person1_id === $person2_id) {
@@ -98,17 +81,20 @@ class PersonDuplicateController extends Controller
$person1->counters = $this->_getCounters($person1_id);
$person2->counters = $this->_getCounters($person2_id);
if ($person1 === null) {
throw $this->createNotFoundException("Person with id $person1_id not"
. " found on this server");
if (null === $person1) {
throw $this->createNotFoundException("Person with id {$person1_id} not"
. ' found on this server');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1,
"You are not allowed to see this person.");
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DUPLICATE',
$person1,
'You are not allowed to see this person.'
);
if ($person2 === null) {
throw $this->createNotFoundException("Person with id $person2_id not"
. " found on this server");
if (null === $person2) {
throw $this->createNotFoundException("Person with id {$person2_id} not"
. ' found on this server');
}
$form = $this->createForm(PersonConfimDuplicateType::class);
@@ -116,10 +102,10 @@ class PersonDuplicateController extends Controller
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$event = new PrivacyEvent($person1, array(
$event = new PrivacyEvent($person1, [
'element_class' => Person::class,
'action' => 'move'
));
'action' => 'move',
]);
$event->addPerson($person2);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
@@ -128,7 +114,8 @@ class PersonDuplicateController extends Controller
$connection = $this->getDoctrine()->getConnection();
$connection->beginTransaction();
foreach($sqls as $sql) {
foreach ($sqls as $sql) {
$connection->executeQuery($sql);
}
$connection->commit();
@@ -143,15 +130,68 @@ class PersonDuplicateController extends Controller
]);
}
public function findManuallyDuplicateAction($person_id, Request $request)
{
$person = $this->_getPerson($person_id);
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found on this server');
}
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DUPLICATE',
$person,
'You are not allowed to see this person.'
);
$form = $this->createForm(PersonFindManuallyDuplicateType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$person2 = $form->get('person')->getData();
if (null === $person2) {
throw $this->createNotFoundException("Person with id {$person2->getId}() not"
. ' found on this server');
}
$direction = $form->get('direction')->getData();
if ('starting' === $direction) {
$params = [
'person1_id' => $person->getId(),
'person2_id' => $person2->getId(),
];
} else {
$params = [
'person1_id' => $person2->getId(),
'person2_id' => $person->getId(),
];
}
return $this->redirectToRoute('chill_person_duplicate_confirm', $params);
}
return $this->render('ChillPersonBundle:PersonDuplicate:find_manually.html.twig', [
'person' => $person,
'form' => $form->createView(),
]);
}
public function notDuplicateAction($person1_id, $person2_id)
{
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
$this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1,
"You are not allowed to see this person.");
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DUPLICATE',
$person1,
'You are not allowed to see this person.'
);
$personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
->findOneBy(['person1' => $person1, 'person2' => $person2]);
->findOneBy(['person1' => $person1, 'person2' => $person2]);
if (!$personNotDuplicate instanceof PersonNotDuplicate) {
$personNotDuplicate = new PersonNotDuplicate();
@@ -170,11 +210,14 @@ class PersonDuplicateController extends Controller
{
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
$this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1,
"You are not allowed to see this person.");
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DUPLICATE',
$person1,
'You are not allowed to see this person.'
);
$personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
->findOneBy(['person1' => $person1, 'person2' => $person2]);
->findOneBy(['person1' => $person1, 'person2' => $person2]);
if ($personNotDuplicate instanceof PersonNotDuplicate) {
$this->getDoctrine()->getManager()->remove($personNotDuplicate);
@@ -184,54 +227,56 @@ class PersonDuplicateController extends Controller
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
}
public function findManuallyDuplicateAction($person_id, Request $request)
public function viewAction($person_id, PersonNotDuplicateRepository $personNotDuplicateRepository)
{
$person = $this->_getPerson($person_id);
if ($person === null) {
throw $this->createNotFoundException("Person with id $person_id not"
. " found on this server");
if (null === $person) {
throw $this->createNotFoundException("Person with id {$person_id} not"
. ' found on this server');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person,
"You are not allowed to see this person.");
$this->denyAccessUnlessGranted(
'CHILL_PERSON_DUPLICATE',
$person,
'You are not allowed to see this person.'
);
$form = $this->createForm(PersonFindManuallyDuplicateType::class);
$duplicatePersons = $this->similarPersonMatcher->
matchPerson($person, $personNotDuplicateRepository, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL);
$form->handleRequest($request);
$notDuplicatePersons = $personNotDuplicateRepository->findNotDuplicatePerson($person);
if ($form->isSubmitted() && $form->isValid()) {
$person2 = $form->get('person')->getData();
if ($person2 === null) {
throw $this->createNotFoundException("Person with id $person2->getId() not"
. " found on this server");
}
$direction = $form->get('direction')->getData();
if ($direction === 'starting') {
$params = [
'person1_id' => $person->getId(),
'person2_id' => $person2->getId(),
];
} else {
$params = [
'person1_id' => $person2->getId(),
'person2_id' => $person->getId(),
];
}
return $this->redirectToRoute('chill_person_duplicate_confirm', $params);
}
return $this->render('ChillPersonBundle:PersonDuplicate:find_manually.html.twig', [
return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [
'person' => $person,
'form' => $form->createView(),
'duplicatePersons' => $duplicatePersons,
'notDuplicatePersons' => $notDuplicatePersons,
]);
}
private function _getCounters($id): ?array
{
$em = $this->getDoctrine()->getManager();
$nb_activity = $em->getRepository(Activity::class)->findBy(['person' => $id]);
$nb_document = $em->getRepository(PersonDocument::class)->findBy(['person' => $id]);
$nb_event = $em->getRepository(Participation::class)->findBy(['person' => $id]);
$nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person' => $id]);
$person = $em->getRepository(Person::class)->findOneBy(['id' => $id]);
return [
'nb_activity' => count($nb_activity),
'nb_document' => count($nb_document),
'nb_event' => count($nb_event),
'nb_task' => $nb_task,
'nb_addresses' => count($person->getAddresses()),
];
}
/**
* easy getting a person by his id
* easy getting a person by his id.
*
* @param mixed $id
*/
private function _getPerson($id): ?Person
{
@@ -252,35 +297,16 @@ class PersonDuplicateController extends Controller
$person2 = $this->_getPerson($person2_id);
}
if ($person1 === null) {
throw $this->createNotFoundException("Person with id $person1_id not"
. " found on this server");
if (null === $person1) {
throw $this->createNotFoundException("Person with id {$person1_id} not"
. ' found on this server');
}
if ($person2 === null) {
throw $this->createNotFoundException("Person with id $person2_id not"
. " found on this server");
if (null === $person2) {
throw $this->createNotFoundException("Person with id {$person2_id} not"
. ' found on this server');
}
return [$person1, $person2];
}
private function _getCounters($id): ?array
{
$em = $this->getDoctrine()->getManager();
$nb_activity = $em->getRepository(Activity::class)->findBy(['person'=>$id]);
$nb_document = $em->getRepository(PersonDocument::class)->findBy(['person'=>$id]);
$nb_event = $em->getRepository(Participation::class)->findBy(['person'=>$id]);
$nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person'=>$id]);
$person = $em->getRepository(Person::class)->findOneBy(['id'=>$id]);
return [
'nb_activity' => count($nb_activity),
'nb_document' => count($nb_document),
'nb_event' => count($nb_event),
'nb_task' => $nb_task,
'nb_addresses' => count($person->getAddresses())
];
}
}

View File

@@ -1,4 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Controller;
@@ -6,15 +14,17 @@ namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Repository\Relationships\RelationshipRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use function array_values;
class RelationshipApiController extends ApiController
{
private ValidatorInterface $validator;
private RelationshipRepository $repository;
private ValidatorInterface $validator;
public function __construct(ValidatorInterface $validator, RelationshipRepository $repository)
{
$this->validator = $validator;
@@ -22,13 +32,13 @@ class RelationshipApiController extends ApiController
}
/**
* @ParamConverter("person", options={"id" = "person_id"})
* @ParamConverter("person", options={"id": "person_id"})
*/
public function getRelationshipsByPerson(Person $person)
{
//TODO: add permissions? (voter?)
$relationships = $this->repository->findByPerson($person);
return $this->json(\array_values($relationships), Response::HTTP_OK, [], ['groups' => [ 'read']]);
return $this->json(array_values($relationships), Response::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
@@ -36,7 +43,7 @@ class SocialIssueApiController extends ApiController
protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response
{
$query
->orderBy("GET_JSON_FIELD_BY_KEY(e.title, :locale)", 'ASC')
->orderBy('GET_JSON_FIELD_BY_KEY(e.title, :locale)', 'ASC')
->setParameter(':locale', $request->getLocale());
return null;

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller\SocialWork;
@@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminSocialIssueController
* Controller for social issues
*
* @package Chill\PersonBundle\Controller
* Controller for social issues.
*/
class AdminEvaluationController extends CRUDController
{

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller\SocialWork;
@@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminSocialIssueController
* Controller for social issues
*
* @package Chill\PersonBundle\Controller
* Controller for social issues.
*/
class AdminGoalController extends CRUDController
{

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller\SocialWork;
@@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminSocialIssueController
* Controller for social issues
*
* @package Chill\PersonBundle\Controller
* Controller for social issues.
*/
class AdminResultController extends CRUDController
{

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller\SocialWork;
@@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminSocialIssueController
* Controller for social issues
*
* @package Chill\PersonBundle\Controller
* Controller for social issues.
*/
class AdminSocialActionController extends CRUDController
{

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller\SocialWork;
@@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AdminSocialIssueController
* Controller for social issues
*
* @package Chill\PersonBundle\Controller
* Controller for social issues.
*/
class AdminSocialIssueController extends CRUDController
{

View File

@@ -1,22 +1,26 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
class SocialWorkEvaluationApiController extends AbstractController
{
private PaginatorFactory $paginatorFactory;
/**
* @param PaginatorFactory $paginatorFactory
*/
public function __construct(PaginatorFactory $paginatorFactory)
{
$this->paginatorFactory = $paginatorFactory;
@@ -26,21 +30,21 @@ class SocialWorkEvaluationApiController extends AbstractController
* @Route("/api/1.0/person/social-work/evaluation/by-social-action/{action_id}.json",
* name="chill_person_evaluation_index_by_social_action",
* requirements={
* "_format": "json"
* "_format": "json"
* }
* )
* @ParamConverter("action", options={"id": "action_id"})
* @param SocialAction $action
* @return Response
*/
public function listEvaluationBySocialAction(SocialAction $action): Response
{
$pagination = $this->paginatorFactory->create($action->getEvaluations()->count());
$evaluations = $action->getEvaluations()->slice($pagination->getCurrentPageFirstItemNumber(),
$pagination->getItemsPerPage());
$evaluations = $action->getEvaluations()->slice(
$pagination->getCurrentPageFirstItemNumber(),
$pagination->getItemsPerPage()
);
$collection = new Collection($evaluations, $pagination);
return $this->json($collection, Response::HTTP_OK, [], [ 'groups' => [ 'read' ]]);
return $this->json($collection, Response::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,13 +1,19 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Repository\SocialWork\GoalRepository;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -17,7 +23,6 @@ class SocialWorkGoalApiController extends ApiController
private PaginatorFactory $paginator;
public function __construct(GoalRepository $goalRepository, PaginatorFactory $paginator)
{
$this->goalRepository = $goalRepository;
@@ -28,13 +33,16 @@ class SocialWorkGoalApiController extends ApiController
{
$totalItems = $this->goalRepository->countBySocialActionWithDescendants($action);
$paginator = $this->getPaginatorFactory()->create($totalItems);
$entities = $this->goalRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"],
$paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
$entities = $this->goalRepository->findBySocialActionWithDescendants(
$action,
['id' => 'ASC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]);
return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,12 +1,19 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Repository\SocialWork\ResultRepository;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Repository\SocialWork\ResultRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,29 +26,37 @@ class SocialWorkResultApiController extends ApiController
$this->resultRepository = $resultRepository;
}
public function listByGoal(Request $request, Goal $goal): Response
{
$totalItems = $this->resultRepository->countByGoal($goal);
$paginator = $this->getPaginatorFactory()->create($totalItems);
$entities = $this->resultRepository->findByGoal(
$goal,
['id' => 'ASC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]);
}
public function listBySocialAction(Request $request, SocialAction $action): Response
{
$totalItems = $this->resultRepository->countBySocialActionWithDescendants($action);
$paginator = $this->getPaginatorFactory()->create($totalItems);
$entities = $this->resultRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"],
$paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
$entities = $this->resultRepository->findBySocialActionWithDescendants(
$action,
['id' => 'ASC'],
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]);
}
public function listByGoal(Request $request, Goal $goal): Response
{
$totalItems = $this->resultRepository->countByGoal($goal);
$paginator = $this->getPaginatorFactory()->create($totalItems);
$entities = $this->resultRepository->findByGoal($goal, ["id" => "ASC"],
$paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]);
return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,36 +1,40 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class SocialWorkSocialActionApiController extends ApiController
{
private SocialIssueRepository $socialIssueRepository;
private PaginatorFactory $paginator;
/**
* @param SocialIssueRepository $socialIssueRepository
*/
private SocialIssueRepository $socialIssueRepository;
public function __construct(SocialIssueRepository $socialIssueRepository, PaginatorFactory $paginator)
{
$this->socialIssueRepository = $socialIssueRepository;
$this->paginator = $paginator;
}
public function listBySocialIssueApi($id, Request $request)
{
$socialIssue = $this->socialIssueRepository
->find($id);
if (NULL === $socialIssue) {
throw $this->createNotFoundException("socialIssue not found");
if (null === $socialIssue) {
throw $this->createNotFoundException('socialIssue not found');
}
$socialActions = $socialIssue->getRecursiveSocialActions();
@@ -39,9 +43,7 @@ class SocialWorkSocialActionApiController extends ApiController
$pagination->setItemsPerPage(count($socialActions));
$collection = new Collection($socialActions, $pagination);
return $this->json($collection, JsonResponse::HTTP_OK, [], [ "groups" => [ "read" ]]);
}
return $this->json($collection, JsonResponse::HTTP_OK, [], ['groups' => ['read']]);
}
}

View File

@@ -1,27 +1,33 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Timeline\TimelineBuilder;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Timeline\TimelineBuilder;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
class TimelinePersonController extends AbstractController
{
protected EventDispatcherInterface $eventDispatcher;
protected TimelineBuilder $timelineBuilder;
protected PaginatorFactory $paginatorFactory;
protected TimelineBuilder $timelineBuilder;
public function __construct(
EventDispatcherInterface $eventDispatcher,
TimelineBuilder $timelineBuilder,
@@ -35,37 +41,38 @@ class TimelinePersonController extends AbstractController
public function personAction(Request $request, $person_id)
{
$person = $this->getDoctrine()
->getRepository(Person::class)
->find($person_id);
->getRepository(Person::class)
->find($person_id);
if ($person === NULL) {
if (null === $person) {
throw $this->createNotFoundException();
}
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
$nbItems = $this->timelineBuilder->countItems('person',
[ 'person' => $person ]
);
$nbItems = $this->timelineBuilder->countItems(
'person',
['person' => $person]
);
$paginator = $this->paginatorFactory->create($nbItems);
$event = new PrivacyEvent($person, array('action' => 'timeline'));
$event = new PrivacyEvent($person, ['action' => 'timeline']);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillPersonBundle:Timeline:index.html.twig', array
(
return $this->render(
'ChillPersonBundle:Timeline:index.html.twig',
[
'timeline' => $this->timelineBuilder->getTimelineHTML(
'person',
array('person' => $person),
['person' => $person],
$paginator->getCurrentPage()->getFirstItemNumber(),
$paginator->getItemsPerPage()
),
),
'person' => $person,
'nb_items' => $nbItems,
'paginator' => $paginator
)
'paginator' => $paginator,
]
);
}
}