Loading module/Formation/src/Formation/Entity/Db/Interfaces/HasTypeInterface.php +5 −0 Changes for module/Formation/src/Formation/Entity/Db/Interfaces/HasTypeInterface.php: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,11 @@ interface HasTypeInterface { const TYPE_SPECIFIQUE = 'S'; const TYPE_TRANSVERSALE = 'T'; const TYPES = [ self::TYPE_SPECIFIQUE => "Spécifique", self::TYPE_TRANSVERSALE => "Transversale", ]; public function getType() : ?string; public function setType(?string $type) : HasTypeInterface; Loading module/Formation/src/Formation/Entity/Db/Repository/SessionRepository.php +15 −0 Changes for module/Formation/src/Formation/Entity/Db/Repository/SessionRepository.php: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Application\Entity\Db\Repository\DefaultEntityRepository; use Application\QueryBuilder\DefaultQueryBuilder; use DateTime; use Doctorant\Entity\Db\Doctorant; use Doctrine\ORM\Query\Expr\Join; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Formation; use Formation\Entity\Db\Session; Loading Loading @@ -206,4 +207,18 @@ class SessionRepository extends DefaultEntityRepository return $qb->getQuery()->getResult(); } public function fetchDistinctAnneesUnivSessions(string $champ='id', string $ordre='ASC', bool $keep_histo = false) : array { $qb = $this->createQueryBuilder('session') ->distinct() ->select("YEAR(seance.debut) as annee") ->orderBy("annee", $ordre); if (!$keep_histo) $qb = $qb->andWhere('session.histoDestruction IS NULL'); return array_map(function($value) { return current($value); }, $qb->getQuery()->getScalarResult()); } } No newline at end of file module/Formation/src/Formation/Service/Session/Search/SessionSearchService.php +90 −3 Changes for module/Formation/src/Formation/Service/Session/Search/SessionSearchService.php: 90 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Formation\Service\Session\Search; use Application\Entity\AnneeUniv; use Application\QueryBuilder\DefaultQueryBuilder; use Application\Search\Filter\SearchFilter; use Application\Search\Filter\SelectSearchFilter; Loading @@ -9,9 +10,11 @@ use Application\Search\Filter\StrReducedTextSearchFilter; use Application\Search\Filter\TextSearchFilter; use Application\Search\SearchService; use Application\Search\Sorter\SearchSorter; use Application\Service\AnneeUniv\AnneeUnivServiceAwareTrait; use Doctrine\ORM\QueryBuilder; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Interfaces\HasModaliteInterface; use Formation\Entity\Db\Interfaces\HasTypeInterface; use Formation\Entity\Db\Repository\EtatRepositoryAwareTrait; use Formation\Entity\Db\Repository\FormationRepositoryAwareTrait; use Formation\Entity\Db\Repository\SessionRepositoryAwareTrait; Loading @@ -23,6 +26,7 @@ class SessionSearchService extends SearchService use FormationRepositoryAwareTrait; use EtatRepositoryAwareTrait; use SessionRepositoryAwareTrait; use AnneeUnivServiceAwareTrait; use EtablissementServiceAwareTrait; Loading @@ -32,6 +36,9 @@ class SessionSearchService extends SearchService const NAME_responsable = 'responsable'; const NAME_site = 'site'; const NAME_structure = 'structure'; const NAME_anneeUniv = 'anneeUniv'; const NAME_type = 'type'; public function init() { Loading @@ -41,6 +48,8 @@ class SessionSearchService extends SearchService $libelleFilter = $this->createLibelleFilter()->setWhereField('formation.libelle'); $responsableFilter = $this->createResponsableFilter(); $modaliteFilter = $this->createModaliteFilter(); $anneeUnivFilter = $this->createAnneeUnivFilter(); $typeFilter = $this->createTypeFilter(); $siteFilter->setDataProvider(fn() => $this->etablissementService->getRepository()->findAllEtablissementsInscriptions(true)); $structureFilter->setDataProvider(fn() => $this->formationRepository->fetchListeStructures()); Loading @@ -50,6 +59,13 @@ class SessionSearchService extends SearchService array_map(fn(Etat $e) => $e->getCode(), $etats = $this->etatRepository->findBy([], ['ordre' => 'asc'])), $etats )); $anneeUnivFilter->setDataProvider(function(SelectSearchFilter $filter) { return $this->fetchAnneesUniv($filter); }); $typeFilter->setData(HasTypeInterface::TYPES); $annee = $this->anneeUnivService->courante(); $debut = $this->anneeUnivService->computeDateDebut($annee); $this->addFilters([ $siteFilter, Loading @@ -58,10 +74,12 @@ class SessionSearchService extends SearchService $libelleFilter, $etatFilter, $modaliteFilter, $anneeUnivFilter->setDefaultValue($debut->format('Y'))->setAllowsEmptyOption(false), $typeFilter ]); $this->addSorters([ $this->createLibelleSorter()->setOrderByField('formation.libelle')->setIsDefault(), $this->createLibelleSorter(), $this->createSiteSorter(), $this->createStructureSorter(), $this->createResponsableSorter(), Loading @@ -72,8 +90,12 @@ class SessionSearchService extends SearchService public function createQueryBuilder(): QueryBuilder { // ATTENTION à bien sélectionner les relations utilisées par les filtres/tris et parcourues côté vue. return $this->sessionRepository->createQueryBuilder('s'); $queryBuilder = $this->sessionRepository->createQueryBuilder('s'); $queryBuilder->select('s'); $queryBuilder->addOrderBy('CASE WHEN seance.fin IS NULL THEN 1 ELSE 0 END', 'ASC'); $queryBuilder->addOrderBy('seance.debut', 'DESC'); return $queryBuilder; } /********************************** FILTERS ****************************************/ Loading Loading @@ -127,6 +149,37 @@ class SessionSearchService extends SearchService return $filter; } /** * @return SelectSearchFilter */ private function createAnneeUnivFilter(): SelectSearchFilter { $filter = new SelectSearchFilter( "An. univ.", self::NAME_anneeUniv ); $filter->setQueryBuilderApplier(function(SearchFilter $filter, QueryBuilder $qb, string $alias = 'session') { $filterValue = $filter->getValue(); $annee = $filterValue === 'NULL' ? $this->anneeUnivService->courante() : AnneeUniv::fromPremiereAnnee((int)$filterValue); $debut = $this->anneeUnivService->computeDateDebut($annee); $fin = $this->anneeUnivService->computeDateFin($annee); if ($filterValue === 'NULL') { if ($debut !== null && $fin !== null) { $qb->andWhere('seance.debut >= :debut')->setParameter('debut', $debut) ->andWhere('seance.fin <= :fin')->setParameter('fin', $fin); } } else { if ($debut !== null && $fin !== null) { $qb->andWhere('seance.debut >= :debut')->setParameter('debut', $debut) ->andWhere('seance.fin <= :fin')->setParameter('fin', $fin); } } }); return $filter; } private function createLibelleFilter(): TextSearchFilter { $filter = new StrReducedTextSearchFilter("Libellé", self::NAME_libelle); Loading @@ -135,6 +188,40 @@ class SessionSearchService extends SearchService return $filter; } private function createTypeFilter(): SelectSearchFilter { $filter = new SelectSearchFilter("Type", self::NAME_type); $filter->setQueryBuilderApplier(function(SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb ->andWhere("s.type = :type") ->setParameter('type', $filter->getValue()); }); return $filter; } /********************************** FILTERS ****************************************/ private function fetchAnneesUniv(SelectSearchFilter $filter): array { $anneeUnivCourante = $this->anneeUnivService->courante(); $anneeCourante = new \DateTime(); $anneeCourante = $anneeCourante->format('Y'); $annees = $this->sessionRepository->fetchDistinctAnneesUnivSessions(); $anneesUniv = []; foreach($annees as $annee){ if (! is_numeric($annee)) continue; if($anneeCourante === $annee){ if(!in_array($anneeUnivCourante, $anneesUniv)) $anneesUniv[] = $anneeUnivCourante; continue; } $anneesUniv[$annee] = AnneeUniv::fromPremiereAnnee($annee); } return $anneesUniv; } /********************************** SORTERS ****************************************/ Loading module/Formation/src/Formation/Service/Session/Search/SessionSearchServiceFactory.php +5 −0 Changes for module/Formation/src/Formation/Service/Session/Search/SessionSearchServiceFactory.php: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Formation\Service\Session\Search; use Application\Service\AnneeUniv\AnneeUnivService; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Formation; use Formation\Entity\Db\Session; Loading Loading @@ -38,6 +39,10 @@ class SessionSearchServiceFactory implements FactoryInterface $etablissementService = $container->get(EtablissementService::class); $service->setEtablissementService($etablissementService); /** @var AnneeUnivService $anneeUnivService */ $anneeUnivService = $container->get(AnneeUnivService::class); $service->setAnneeUnivService($anneeUnivService); return $service; } } No newline at end of file module/Formation/view/formation/session/recherche/index.phtml +10 −16 Changes for module/Formation/view/formation/session/recherche/index.phtml: 10 added lines, 16 removed lines. Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <th> Sessions </th> <th> <th style="max-width: 6rem;"> <a href="<?php echo $s = $this->sortable(SessionSearchService::NAME_site) ?>" title="<?php echo $this->translate("Établissement organisateur") ?> "> <?php echo $this->translate("Établissement organisateur") ?>* Loading @@ -78,7 +78,7 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <?php echo $this->translate("État") ?> </a> <?php echo $s->icon() ?> </th> <th>Séances</th> <th style="min-width: 14rem;">Séances</th> <th style="min-width: 9rem;">Inscriptions</th> <th style="min-width: 4rem;">Action</th> </tr> Loading Loading @@ -122,26 +122,20 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <td> <?php echo $this->modalite($session); ?> </td> <td> <?php echo $this->type($session); ?> </td> <td> <?php echo $this->etat($session); ?> </td> <td> <!-- Seances -----------------------------------------------------------------------------------------> <td style="min-width: 17rem;"> <!-- Seances -----------------------------------------------------------------------------------------> <?php echo count($session->getSeances()); ?> séance<?php if (count($session->getSeances())>1) echo "s"; ?> (<?php echo $session->getDuree(); ?> h.) <br> <strong>Période :</strong> <ul> <?php /** @var Seance[] $seances */ $seances = $session->getSeances()->toArray(); usort($seances, function (Seance $a, Seance $b) { return $a->getDebut() > $b->getDebut();}); ?> <?php foreach ($seances as $seance) : ?> <li> <?php echo $seance->getDebut()->format('d/m/Y'); ?> <?php echo $seance->getDebut()->format('H:i') ; ?> → <?php echo $seance->getFin()->format('H:i') ; ?> - <?php echo $seance->getLieu() ; ?> <?php if ($session->getDateDebut() and $session->getDateFin()) : ?> <?php echo $session->getDateDebut()->format('d/m/Y à H:i'); ?> → <?php echo $session->getDateFin()->format('d/m/Y à H:i'); ?> <?php else : ?> À déterminer <?php endif; ?> </li> <?php endforeach; ?> </ul> </td> <td> <!-- Inscriptions ------------------------------------------------------------------------------------> Loading Loading
module/Formation/src/Formation/Entity/Db/Interfaces/HasTypeInterface.php +5 −0 Changes for module/Formation/src/Formation/Entity/Db/Interfaces/HasTypeInterface.php: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,11 @@ interface HasTypeInterface { const TYPE_SPECIFIQUE = 'S'; const TYPE_TRANSVERSALE = 'T'; const TYPES = [ self::TYPE_SPECIFIQUE => "Spécifique", self::TYPE_TRANSVERSALE => "Transversale", ]; public function getType() : ?string; public function setType(?string $type) : HasTypeInterface; Loading
module/Formation/src/Formation/Entity/Db/Repository/SessionRepository.php +15 −0 Changes for module/Formation/src/Formation/Entity/Db/Repository/SessionRepository.php: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Application\Entity\Db\Repository\DefaultEntityRepository; use Application\QueryBuilder\DefaultQueryBuilder; use DateTime; use Doctorant\Entity\Db\Doctorant; use Doctrine\ORM\Query\Expr\Join; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Formation; use Formation\Entity\Db\Session; Loading Loading @@ -206,4 +207,18 @@ class SessionRepository extends DefaultEntityRepository return $qb->getQuery()->getResult(); } public function fetchDistinctAnneesUnivSessions(string $champ='id', string $ordre='ASC', bool $keep_histo = false) : array { $qb = $this->createQueryBuilder('session') ->distinct() ->select("YEAR(seance.debut) as annee") ->orderBy("annee", $ordre); if (!$keep_histo) $qb = $qb->andWhere('session.histoDestruction IS NULL'); return array_map(function($value) { return current($value); }, $qb->getQuery()->getScalarResult()); } } No newline at end of file
module/Formation/src/Formation/Service/Session/Search/SessionSearchService.php +90 −3 Changes for module/Formation/src/Formation/Service/Session/Search/SessionSearchService.php: 90 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Formation\Service\Session\Search; use Application\Entity\AnneeUniv; use Application\QueryBuilder\DefaultQueryBuilder; use Application\Search\Filter\SearchFilter; use Application\Search\Filter\SelectSearchFilter; Loading @@ -9,9 +10,11 @@ use Application\Search\Filter\StrReducedTextSearchFilter; use Application\Search\Filter\TextSearchFilter; use Application\Search\SearchService; use Application\Search\Sorter\SearchSorter; use Application\Service\AnneeUniv\AnneeUnivServiceAwareTrait; use Doctrine\ORM\QueryBuilder; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Interfaces\HasModaliteInterface; use Formation\Entity\Db\Interfaces\HasTypeInterface; use Formation\Entity\Db\Repository\EtatRepositoryAwareTrait; use Formation\Entity\Db\Repository\FormationRepositoryAwareTrait; use Formation\Entity\Db\Repository\SessionRepositoryAwareTrait; Loading @@ -23,6 +26,7 @@ class SessionSearchService extends SearchService use FormationRepositoryAwareTrait; use EtatRepositoryAwareTrait; use SessionRepositoryAwareTrait; use AnneeUnivServiceAwareTrait; use EtablissementServiceAwareTrait; Loading @@ -32,6 +36,9 @@ class SessionSearchService extends SearchService const NAME_responsable = 'responsable'; const NAME_site = 'site'; const NAME_structure = 'structure'; const NAME_anneeUniv = 'anneeUniv'; const NAME_type = 'type'; public function init() { Loading @@ -41,6 +48,8 @@ class SessionSearchService extends SearchService $libelleFilter = $this->createLibelleFilter()->setWhereField('formation.libelle'); $responsableFilter = $this->createResponsableFilter(); $modaliteFilter = $this->createModaliteFilter(); $anneeUnivFilter = $this->createAnneeUnivFilter(); $typeFilter = $this->createTypeFilter(); $siteFilter->setDataProvider(fn() => $this->etablissementService->getRepository()->findAllEtablissementsInscriptions(true)); $structureFilter->setDataProvider(fn() => $this->formationRepository->fetchListeStructures()); Loading @@ -50,6 +59,13 @@ class SessionSearchService extends SearchService array_map(fn(Etat $e) => $e->getCode(), $etats = $this->etatRepository->findBy([], ['ordre' => 'asc'])), $etats )); $anneeUnivFilter->setDataProvider(function(SelectSearchFilter $filter) { return $this->fetchAnneesUniv($filter); }); $typeFilter->setData(HasTypeInterface::TYPES); $annee = $this->anneeUnivService->courante(); $debut = $this->anneeUnivService->computeDateDebut($annee); $this->addFilters([ $siteFilter, Loading @@ -58,10 +74,12 @@ class SessionSearchService extends SearchService $libelleFilter, $etatFilter, $modaliteFilter, $anneeUnivFilter->setDefaultValue($debut->format('Y'))->setAllowsEmptyOption(false), $typeFilter ]); $this->addSorters([ $this->createLibelleSorter()->setOrderByField('formation.libelle')->setIsDefault(), $this->createLibelleSorter(), $this->createSiteSorter(), $this->createStructureSorter(), $this->createResponsableSorter(), Loading @@ -72,8 +90,12 @@ class SessionSearchService extends SearchService public function createQueryBuilder(): QueryBuilder { // ATTENTION à bien sélectionner les relations utilisées par les filtres/tris et parcourues côté vue. return $this->sessionRepository->createQueryBuilder('s'); $queryBuilder = $this->sessionRepository->createQueryBuilder('s'); $queryBuilder->select('s'); $queryBuilder->addOrderBy('CASE WHEN seance.fin IS NULL THEN 1 ELSE 0 END', 'ASC'); $queryBuilder->addOrderBy('seance.debut', 'DESC'); return $queryBuilder; } /********************************** FILTERS ****************************************/ Loading Loading @@ -127,6 +149,37 @@ class SessionSearchService extends SearchService return $filter; } /** * @return SelectSearchFilter */ private function createAnneeUnivFilter(): SelectSearchFilter { $filter = new SelectSearchFilter( "An. univ.", self::NAME_anneeUniv ); $filter->setQueryBuilderApplier(function(SearchFilter $filter, QueryBuilder $qb, string $alias = 'session') { $filterValue = $filter->getValue(); $annee = $filterValue === 'NULL' ? $this->anneeUnivService->courante() : AnneeUniv::fromPremiereAnnee((int)$filterValue); $debut = $this->anneeUnivService->computeDateDebut($annee); $fin = $this->anneeUnivService->computeDateFin($annee); if ($filterValue === 'NULL') { if ($debut !== null && $fin !== null) { $qb->andWhere('seance.debut >= :debut')->setParameter('debut', $debut) ->andWhere('seance.fin <= :fin')->setParameter('fin', $fin); } } else { if ($debut !== null && $fin !== null) { $qb->andWhere('seance.debut >= :debut')->setParameter('debut', $debut) ->andWhere('seance.fin <= :fin')->setParameter('fin', $fin); } } }); return $filter; } private function createLibelleFilter(): TextSearchFilter { $filter = new StrReducedTextSearchFilter("Libellé", self::NAME_libelle); Loading @@ -135,6 +188,40 @@ class SessionSearchService extends SearchService return $filter; } private function createTypeFilter(): SelectSearchFilter { $filter = new SelectSearchFilter("Type", self::NAME_type); $filter->setQueryBuilderApplier(function(SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb ->andWhere("s.type = :type") ->setParameter('type', $filter->getValue()); }); return $filter; } /********************************** FILTERS ****************************************/ private function fetchAnneesUniv(SelectSearchFilter $filter): array { $anneeUnivCourante = $this->anneeUnivService->courante(); $anneeCourante = new \DateTime(); $anneeCourante = $anneeCourante->format('Y'); $annees = $this->sessionRepository->fetchDistinctAnneesUnivSessions(); $anneesUniv = []; foreach($annees as $annee){ if (! is_numeric($annee)) continue; if($anneeCourante === $annee){ if(!in_array($anneeUnivCourante, $anneesUniv)) $anneesUniv[] = $anneeUnivCourante; continue; } $anneesUniv[$annee] = AnneeUniv::fromPremiereAnnee($annee); } return $anneesUniv; } /********************************** SORTERS ****************************************/ Loading
module/Formation/src/Formation/Service/Session/Search/SessionSearchServiceFactory.php +5 −0 Changes for module/Formation/src/Formation/Service/Session/Search/SessionSearchServiceFactory.php: 5 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Formation\Service\Session\Search; use Application\Service\AnneeUniv\AnneeUnivService; use Formation\Entity\Db\Etat; use Formation\Entity\Db\Formation; use Formation\Entity\Db\Session; Loading Loading @@ -38,6 +39,10 @@ class SessionSearchServiceFactory implements FactoryInterface $etablissementService = $container->get(EtablissementService::class); $service->setEtablissementService($etablissementService); /** @var AnneeUnivService $anneeUnivService */ $anneeUnivService = $container->get(AnneeUnivService::class); $service->setAnneeUnivService($anneeUnivService); return $service; } } No newline at end of file
module/Formation/view/formation/session/recherche/index.phtml +10 −16 Changes for module/Formation/view/formation/session/recherche/index.phtml: 10 added lines, 16 removed lines. Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <th> Sessions </th> <th> <th style="max-width: 6rem;"> <a href="<?php echo $s = $this->sortable(SessionSearchService::NAME_site) ?>" title="<?php echo $this->translate("Établissement organisateur") ?> "> <?php echo $this->translate("Établissement organisateur") ?>* Loading @@ -78,7 +78,7 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <?php echo $this->translate("État") ?> </a> <?php echo $s->icon() ?> </th> <th>Séances</th> <th style="min-width: 14rem;">Séances</th> <th style="min-width: 9rem;">Inscriptions</th> <th style="min-width: 4rem;">Action</th> </tr> Loading Loading @@ -122,26 +122,20 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <td> <?php echo $this->modalite($session); ?> </td> <td> <?php echo $this->type($session); ?> </td> <td> <?php echo $this->etat($session); ?> </td> <td> <!-- Seances -----------------------------------------------------------------------------------------> <td style="min-width: 17rem;"> <!-- Seances -----------------------------------------------------------------------------------------> <?php echo count($session->getSeances()); ?> séance<?php if (count($session->getSeances())>1) echo "s"; ?> (<?php echo $session->getDuree(); ?> h.) <br> <strong>Période :</strong> <ul> <?php /** @var Seance[] $seances */ $seances = $session->getSeances()->toArray(); usort($seances, function (Seance $a, Seance $b) { return $a->getDebut() > $b->getDebut();}); ?> <?php foreach ($seances as $seance) : ?> <li> <?php echo $seance->getDebut()->format('d/m/Y'); ?> <?php echo $seance->getDebut()->format('H:i') ; ?> → <?php echo $seance->getFin()->format('H:i') ; ?> - <?php echo $seance->getLieu() ; ?> <?php if ($session->getDateDebut() and $session->getDateFin()) : ?> <?php echo $session->getDateDebut()->format('d/m/Y à H:i'); ?> → <?php echo $session->getDateFin()->format('d/m/Y à H:i'); ?> <?php else : ?> À déterminer <?php endif; ?> </li> <?php endforeach; ?> </ul> </td> <td> <!-- Inscriptions ------------------------------------------------------------------------------------> Loading