endpoint for recent accompanying period attributions

This commit is contained in:
Julien Fastré 2022-01-28 15:39:37 +01:00
parent fcd5fba13e
commit 292c9380ad
6 changed files with 132 additions and 19 deletions

View File

@ -239,7 +239,7 @@ final class NotificationRepository implements ObjectRepository
->setParameter('relatedEntityId', $relatedEntityId)
->setParameter('user', $user);
return $qb->getQuery()->getResult();
return $qb;
}
private function queryByAddressee(User $addressee, bool $countQuery = false): QueryBuilder

View File

@ -13,7 +13,9 @@ namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
@ -23,8 +25,11 @@ use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use DateInterval;
use DateTimeImmutable;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
@ -32,13 +37,14 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Registry;
use function array_values;
use function count;
@ -46,6 +52,8 @@ final class AccompanyingCourseApiController extends ApiController
{
private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository;
private AccompanyingPeriodRepository $accompanyingPeriodRepository;
private EventDispatcherInterface $eventDispatcher;
private ReferralsSuggestionInterface $referralAvailable;
@ -55,17 +63,19 @@ final class AccompanyingCourseApiController extends ApiController
private ValidatorInterface $validator;
public function __construct(
EventDispatcherInterface $eventDispatcher,
ValidatorInterface $validator,
Registry $registry,
AccompanyingPeriodRepository $accompanyingPeriodRepository,
AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository,
ReferralsSuggestionInterface $referralAvailable
EventDispatcherInterface $eventDispatcher,
ReferralsSuggestionInterface $referralAvailable,
Registry $registry,
ValidatorInterface $validator
) {
$this->eventDispatcher = $eventDispatcher;
$this->validator = $validator;
$this->registry = $registry;
$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
$this->eventDispatcher = $eventDispatcher;
$this->referralAvailable = $referralAvailable;
$this->registry = $registry;
$this->validator = $validator;
}
public function commentApi($id, Request $request, string $_format): Response
@ -99,6 +109,57 @@ final class AccompanyingCourseApiController extends ApiController
]);
}
/**
* @Route("/api/1.0/person/accompanying-course/list/by-recent-attributions")
*/
public function findMyRecentCourseAttribution(Request $request): JsonResponse
{
$this->denyAccessUnlessGranted('ROLE_USER');
$user = $this->getUser();
if (!$user instanceof User) {
throw new AccessDeniedException();
}
$since = (new DateTimeImmutable('now'))->sub(new DateInterval('P15D'));
$total = $this->accompanyingPeriodRepository->countByRecentUserHistory($user, $since);
if ($request->query->getBoolean('countOnly', false)) {
return new JsonResponse(
$this->getSerializer()->serialize(new Counter($total), 'json'),
JsonResponse::HTTP_OK,
[],
true
);
}
$paginator = $this->getPaginatorFactory()->create($total);
if (0 === $total) {
return new JsonResponse(
$this->getSerializer()->serialize(new Collection([], $paginator), 'json'),
JsonResponse::HTTP_OK,
[],
true
);
}
$courses = $this->accompanyingPeriodRepository->findByRecentUserHistory(
$user,
$since,
$paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber()
);
return new JsonResponse(
$this->getSerializer()->serialize(new Collection($courses, $paginator), 'json', ['groups' => ['read']]),
JsonResponse::HTTP_OK,
[],
true
);
}
/**
* @ParamConverter("person", options={"id": "person_id"})
*/

View File

@ -338,7 +338,8 @@ class AccompanyingPeriod implements
private ?User $user = null;
/**
* @ORM\OneToMany(targetEntity=UserHistory::class, mappedBy="accompanyingPeriod")
* @ORM\OneToMany(targetEntity=UserHistory::class, mappedBy="accompanyingPeriod", orphanRemoval=true,
* cascade={"persist", "remove"})
*
* @var Collection|UserHistory[]
*/
@ -1226,15 +1227,15 @@ class AccompanyingPeriod implements
if ($this->user !== $user) {
$this->userPrevious = $this->user;
if (null !== $user) {
$this->userHistories->add(new UserHistory($this, $user));
}
foreach ($this->userHistories as $history) {
if (null === $history->getEndDate()) {
$history->setEndDate(new DateTimeImmutable('now'));
}
}
if (null !== $user) {
$this->userHistories->add(new UserHistory($this, $user));
}
}
$this->user = $user;

View File

@ -11,16 +11,21 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("chill_person_accompanying_period_user_history")
*/
class UserHistory
class UserHistory implements TrackCreationInterface
{
use TrackCreationTrait;
/**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="userHistories")
* @ORM\JoinColumn(nullable=false)
@ -30,7 +35,7 @@ class UserHistory
/**
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": null})
*/
private ?\DateTimeImmutable $endDate = null;
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\Id
@ -42,7 +47,7 @@ class UserHistory
/**
* @ORM\Column(type="datetime_immutable", nullable=false)
*/
private \DateTimeImmutable $startDate;
private DateTimeImmutable $startDate;
/**
* @ORM\ManyToOne(targetEntity=User::class)
@ -50,9 +55,9 @@ class UserHistory
*/
private User $user;
public function __construct(AccompanyingPeriod $accompanyingPeriod, User $user, ?\DateTimeImmutable $startDate = null)
public function __construct(AccompanyingPeriod $accompanyingPeriod, User $user, ?DateTimeImmutable $startDate = null)
{
$this->startDate = $startDate ?? new \DateTimeImmutable('now');
$this->startDate = $startDate ?? new DateTimeImmutable('now');
$this->accompanyingPeriod = $accompanyingPeriod;
$this->user = $user;
}

View File

@ -11,7 +11,9 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
@ -26,6 +28,13 @@ final class AccompanyingPeriodRepository implements ObjectRepository
$this->repository = $entityManager->getRepository(AccompanyingPeriod::class);
}
public function countByRecentUserHistory(User $user, DateTimeImmutable $since): int
{
$qb = $this->buildQueryByRecentUserHistory($user, $since);
return $qb->select('count(a)')->getQuery()->getSingleScalarResult();
}
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
{
return $this->repository->createQueryBuilder($alias, $indexBy);
@ -49,6 +58,21 @@ final class AccompanyingPeriodRepository implements ObjectRepository
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
/**
* @return array|AccompanyingPeriod[]
*/
public function findByRecentUserHistory(User $user, DateTimeImmutable $since, ?int $limit = 20, ?int $offset = 0): array
{
$qb = $this->buildQueryByRecentUserHistory($user, $since);
return $qb->select('a')
->distinct(true)
->getQuery()
->setMaxResults($limit)
->setFirstResult($offset)
->getResult();
}
public function findOneBy(array $criteria): ?AccompanyingPeriod
{
return $this->findOneBy($criteria);
@ -58,4 +82,19 @@ final class AccompanyingPeriodRepository implements ObjectRepository
{
return AccompanyingPeriod::class;
}
private function buildQueryByRecentUserHistory(User $user, DateTimeImmutable $since): QueryBuilder
{
$qb = $this->repository->createQueryBuilder('a');
$qb
->join('a.userHistories', 'userHistory')
->where($qb->expr()->eq('a.user', ':user'))
->andWhere($qb->expr()->gte('userHistory.startDate', ':since'))
->andWhere($qb->expr()->isNull('userHistory.endDate'))
->setParameter('user', $user)
->setParameter('since', $since);
return $qb;
}
}

View File

@ -40,5 +40,12 @@ final class Version20220128133039 extends AbstractMigration
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ADD CHECK (startdate <= enddate)');
$this->addSql('INSERT INTO chill_person_accompanying_period_user_history (id, user_id, accompanyingperiod_id, startDate, endDate) ' .
'SELECT nextval(\'chill_person_accompanying_period_user_history_id_seq\'), user_id, id, openingDate, null FROM chill_person_accompanying_period WHERE user_id IS NOT NULL');
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL;');
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ADD createdBy_id INT DEFAULT NULL;');
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ALTER user_id SET NOT NULL;');
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ALTER accompanyingperiod_id SET NOT NULL;');
$this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_user_history.createdAt IS \'(DC2Type:datetime_immutable)\';');
$this->addSql('ALTER TABLE chill_person_accompanying_period_user_history ADD CONSTRAINT FK_6C258C493174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;');
$this->addSql('CREATE INDEX IDX_6C258C493174800F ON chill_person_accompanying_period_user_history (createdBy_id);');
}
}