diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ccdfc90c12d139e3d990021c89110437fc44b34..3a251c332ebb26bfd8c8d839d1ecef900bcf02d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Journal des modifications ========================= +6.0.4 +----- +- [FIX] Recherche de rapports d'Activité/CSI/Mi-parcours : les filtres Établissement/ED/UR géraient mal la subsitution de structures. +- Changement de la page de couverture pour tenir compte de la co-accréditation +- Module Soutenance : Possibilité pour les structures de révoquer leur validation (avec modal de confirmation) + 6.0.3 ----- - [FIX] Signature de méthode setObject() modifiée en PHP8 dans Doctrine\Laminas\Hydrator\Strategy\AbstractCollectionStrategy. diff --git a/data/SQL/profil.sql b/data/SQL/profil.sql deleted file mode 100755 index d3d5bfaccfb1042d0e6c89d47affaa5e4a35ff9c..0000000000000000000000000000000000000000 --- a/data/SQL/profil.sql +++ /dev/null @@ -1,58 +0,0 @@ - -rename ROLE_MODELE to PROFIL; -rename ROLE_PRIVILEGE_MODELE to PROFIL_PRIVILEGE; - -alter table PROFIL add description varchar2(1024); - -create sequence PROFIL_ID_SEQ; - --- --- Avance d'une sequence. --- -declare - maxid integer; - seqnextval integer; -begin - select max(PROFIL.id) into maxid from PROFIL; - LOOP - select PROFIL_ID_SEQ.nextval into seqnextval from dual; - EXIT WHEN seqnextval >= maxid; - END LOOP; -end; - -create unique index PROFIL_ROLE_ID_uindex on PROFIL (ROLE_ID); - -truncate table PROFIL_PRIVILEGE; - -alter table PROFIL modify STructure_type null; - -alter table PROFIL_PRIVILEGE drop constraint ROLE_PRIV_MOD_PK; -alter table PROFIL_PRIVILEGE drop column ROLE_CODE; -alter table PROFIL_PRIVILEGE add PROFIL_ID number; -alter table PROFIL_PRIVILEGE add constraint PROFIL_PRIVILEGE_PROFIL_ID_fk foreign key (PROFIL_ID) references PROFIL; -alter table PROFIL_PRIVILEGE add constraint PROFIL_PRIVILEGE_PK primary key (PROFIL_ID, PRIVILEGE_ID); - -create table PROFIL_TO_ROLE ( - PROFIL_ID integer not null constraint PROFIL_TO_ROLE_PROFIL_ID_fk references PROFIL, - ROLE_ID integer not null constraint PROFIL_TO_ROLE_ROLE_ID_fk references ROLE, - constraint PROFIL_TO_ROLE_pk primary key (PROFIL_ID, ROLE_ID) -); - --- INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (1, 'Unité de recherche', 'UR', 3, null); --- INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (2, 'École doctorale', 'ED', 2, null); --- INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (3, 'Administrateur', 'ADMIN', 1, 'Administrateur d''établissement'); --- INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (4, 'Maison du doctorat', 'BDD', 1, null); --- INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (5, 'Bibliothèque universitaire', 'BU', 1, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (6, 'Administrateur technique', 'ADMIN_TECH', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (7, 'Doctorant', 'DOCTORANT', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (8, 'Observateur', 'OBSERV', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (9, 'Directeur', 'D', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (10, 'Co-directeur', 'K', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (11, 'Rapporteur', 'R', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (12, 'Membre', 'M', null, null); -INSERT INTO PROFIL (ID, LIBELLE, ROLE_ID, STRUCTURE_TYPE, DESCRIPTION) VALUES (61, 'Doctorant sans dépôt', 'NODEPOT', null, 'Rôle de doctorant temporaire'); - -INSERT INTO PRIVILEGE (ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) VALUES (36, 19, 'consultation-toutes-structures', 'Consultation de toutes les substitutions', 200); -INSERT INTO PRIVILEGE (ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) VALUES (37, 19, 'consultation-sa-structure', 'Consultation de la substitution de sa structure', 300); -INSERT INTO PRIVILEGE (ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) VALUES (38, 19, 'modification-toutes-structures', 'Modification de toutes les substitutions ', 400); -INSERT INTO PRIVILEGE (ID, CATEGORIE_ID, CODE, LIBELLE, ORDRE) VALUES (39, 19, 'modification-sa-structure', 'Modification de la substitution de sa structure', 500); diff --git a/doc/release-notes/v6.0.4.md b/doc/release-notes/v6.0.4.md new file mode 100644 index 0000000000000000000000000000000000000000..1368647c6624f664df0b96726d3f3ff9a3deedb7 --- /dev/null +++ b/doc/release-notes/v6.0.4.md @@ -0,0 +1,69 @@ +# Version 6.0.4 + +## 1. Sur le serveur d'application + +*Rappel : depuis la version 6.0.0, la version de PHP requise est la 8.0.* + +- Placez-vous dans le répertoire de l'application puis lancez la commande suivante + pour installer la nouvelle version : + +```bash +git fetch --tags && git checkout --force 6.0.4 && bash ./install.sh +``` + +- Rechargez le moteur PHP, exemple : + +```bash +systemctl reload php8.0-fpm +``` + +## 2. Dans la base de données + +```postgresql +-- Ajout du privilège pour revoquer +INSERT INTO privilege (categorie_id, code, libelle, ordre) +WITH d(code, lib, ordre) AS ( + SELECT 'proposition-revoquer-structure', 'Révoquer la validation (structure) de la proposition', 34 +) +SELECT cp.id, d.code, d.lib, d.ordre +FROM d +JOIN categorie_privilege cp ON cp.CODE = 'soutenance'; + +--Ajout au profil +INSERT INTO PROFIL_PRIVILEGE (PRIVILEGE_ID, PROFIL_ID) +with data(categ, priv) as ( + select 'soutenance'::text, 'proposition-revoquer-structure'::text +) +select p.id as PRIVILEGE_ID, profil.id as PROFIL_ID +from data + join PROFIL on profil.ROLE_ID in ('RESP_ED', 'RESP_UR', 'BDD') + join CATEGORIE_PRIVILEGE cp on cp.CODE = data.categ + join PRIVILEGE p on p.CATEGORIE_ID = cp.id and p.code = data.priv +where not exists ( + select * from PROFIL_PRIVILEGE where PRIVILEGE_ID = p.id and PROFIL_ID = profil.id +); + +INSERT INTO PROFIL_PRIVILEGE (PRIVILEGE_ID, PROFIL_ID) +with data(categ, priv) as ( + select 'missionenseignement'::text, 'missionenseignement_modifier'::text +) +select p.id as PRIVILEGE_ID, profil.id as PROFIL_ID +from data + join PROFIL on profil.ROLE_ID in ('ADMIN_TECH', 'GEST_FORMATION', 'BDD', 'ADMIN') + join CATEGORIE_PRIVILEGE cp on cp.CODE = data.categ + join PRIVILEGE p on p.CATEGORIE_ID = cp.id and p.code = data.priv +where not exists ( + select * from PROFIL_PRIVILEGE where PRIVILEGE_ID = p.id and PROFIL_ID = profil.id +); + +insert into ROLE_PRIVILEGE (ROLE_ID, PRIVILEGE_ID) +select p2r.ROLE_ID, pp.PRIVILEGE_ID +from PROFIL_TO_ROLE p2r + join profil pr on pr.id = p2r.PROFIL_ID + join PROFIL_PRIVILEGE pp on pp.PROFIL_ID = pr.id +where not exists ( + select * from role_privilege where role_id = p2r.role_id and privilege_id = pp.privilege_id +); + + +``` \ No newline at end of file diff --git a/module/Application/src/Application/Service/Rapport/RapportSearchService.php b/module/Application/src/Application/Service/Rapport/RapportSearchService.php index a70cf1088df5b03727c23d1670ed2d270bf6c120..8b4597d05a239880ce536a775446121b7d763d50 100644 --- a/module/Application/src/Application/Service/Rapport/RapportSearchService.php +++ b/module/Application/src/Application/Service/Rapport/RapportSearchService.php @@ -83,7 +83,7 @@ class RapportSearchService extends SearchService $etablissementInscrFilter = $this->getEtablissementTheseSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('etab.sourceCode = :sourceCodeEtab OR etab_structureSubstituante.sourceCode = :sourceCodeEtab') + ->andWhere('etab.sourceCode = :sourceCodeEtab OR etab_substituant.sourceCode = :sourceCodeEtab') ->setParameter('sourceCodeEtab', $filter->getValue()); }) ->setDataProvider(function() { @@ -96,7 +96,7 @@ class RapportSearchService extends SearchService $uniteRechercheFilter = $this->getUniteRechercheSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('ur.sourceCode = :sourceCodeUR OR ur_structureSubstituante.sourceCode = :sourceCodeUR') + ->andWhere('ur.sourceCode = :sourceCodeUR OR ur_substituant.sourceCode = :sourceCodeUR') ->setParameter('sourceCodeUR', $filter->getValue()); }) ->setDataProvider(function() { @@ -105,7 +105,7 @@ class RapportSearchService extends SearchService $ecoleDoctoraleFilter = $this->getEcoleDoctoraleSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('ed.sourceCode = :sourceCodeED OR ed_structureSubstituante.sourceCode = :sourceCodeED') + ->andWhere('ed.sourceCode = :sourceCodeED OR ed_substituant.sourceCode = :sourceCodeED') ->setParameter('sourceCodeED', $filter->getValue()); }) ->setDataProvider(function() { @@ -318,7 +318,10 @@ class RapportSearchService extends SearchService ->leftJoin('ur.structure', 'ur_structure')->addSelect('ur_structure') ->leftJoinStructureSubstituante('etab_structure', 'etab_structureSubstituante') ->leftJoinStructureSubstituante('ed_structure', 'ed_structureSubstituante') - ->leftJoinStructureSubstituante('ur_structure', 'ur_structureSubstituante'); + ->leftJoinStructureSubstituante('ur_structure', 'ur_structureSubstituante') + ->leftJoin('etab_structureSubstituante.etablissement', 'etab_substituant')->addSelect('etab_substituant') + ->leftJoin('ed_structureSubstituante.ecoleDoctorale', 'ed_substituant')->addSelect('ed_substituant') + ->leftJoin('ur_structureSubstituante.uniteRecherche', 'ur_substituant')->addSelect('ur_substituant'); if ($this->typeRapport !== null) { $qb->andWhere('tr = :type')->setParameter('type', $this->typeRapport); diff --git a/module/Application/view/application/utilisateur/lier-individu.phtml b/module/Application/view/application/utilisateur/lier-individu.phtml index 4d78f8aa4e9c198a8ae59980a4ac66c8d314c09b..340d22aea66286e1f2c4abfb46a29e0b2838caa9 100644 --- a/module/Application/view/application/utilisateur/lier-individu.phtml +++ b/module/Application/view/application/utilisateur/lier-individu.phtml @@ -16,7 +16,7 @@ use Application\Entity\Db\Utilisateur; use UnicaenApp\Form\Element\SearchAndSelect; ?> -<?php if ($individu !== null and $utilisateur !== null and $utilisateur->getIndividu() === $individu) : ?> +<?php if (isset($individu) and $utilisateur !== null and $utilisateur->getIndividu() === $individu) : ?> <div class="alert alert-success"> Le compte utilisateur « <?php echo $utilisateur->getDisplayName(); ?> » @@ -51,7 +51,7 @@ use UnicaenApp\Form\Element\SearchAndSelect; </div> </div> - <?php if ($individu) : ?> + <?php if (isset($individu)) : ?> <div class="box card"> <div class="card-header bg-dark text-white"> <h2 class="first"> @@ -168,7 +168,7 @@ use UnicaenApp\Form\Element\SearchAndSelect; <?php echo $this->ajouterIndividuChildView ?> - <?php elseif ($individu === null) : ?> + <?php elseif (!isset($individu)) : ?> <form method="post" action="<?php echo $this->url('utilisateur/lier-individu', ['utilisateur' => $utilisateur->getId()], [], true); ?>"> diff --git a/module/Depot/view/depot/depot/page-de-couverture/pagedecouverture.phtml b/module/Depot/view/depot/depot/page-de-couverture/pagedecouverture.phtml index 0dfe1a74485b3a51b8b7b3d6a35c87946fdc9932..abd0ea9e74327e3ce43509415aa5360d8d529db8 100644 --- a/module/Depot/view/depot/depot/page-de-couverture/pagedecouverture.phtml +++ b/module/Depot/view/depot/depot/page-de-couverture/pagedecouverture.phtml @@ -18,16 +18,49 @@ use Application\View\Renderer\PhpRenderer; */ ?> -<!-- SECTION DU LOGO DE LA COMUE --------------------------------------------------------------------------------------> -<div style="text-align: center; margin-bottom: 30px;"> +<!-- HEADER NORMAND ---------------------------------------------------------------------------------------------------> +<!-- + A GAUCHE >>> LE LOGO DE LA COMUE + A DROITE >>> LE LOGO DE L'ETABLISSEMENT D'INSCRIPTION +--> + +<style> + .logo-header { + border: 2px hotpink solid; + max-height: 5cm; + max-width: 5cm; + } +</style> + +<?php if ($informations->getLogoCOMUE() !== null): ?> + <table style="border:none;" class="logos"> + <tr> + <td> + <?php if ($informations->getLogoCOMUE() !== null): ?> + <img src="<?php echo $informations->getLogoCOMUE() ?>" alt="Logo de la COMUE" class="logo-header"/> + <?php else: ?> + <span style='background-color:red;'> Logo de la COMUE. </span> + <?php endif; ?> + </td> + <td> + <?php if ($informations->getLogoEtablissement() !== null): ?> + <img src="<?php echo $informations->getLogoEtablissement() ?>" alt="Logo de l'établissement d'inscription" class="logo-header"/> + <?php else: ?> + <span style='background-color:red;'> Logo de l'établissement non renseigné. </span> + <?php endif; ?> + </td> + </tr> + </table> +<?php else : ?> <div class='logo-comue'> - <?php if ($informations->getLogoCOMUE() !== null): ?> - <img src="<?php echo $informations->getLogoCOMUE() ?>"/> + <?php if ($informations->getLogoEtablissement() !== null): ?> + <img src="<?php echo $informations->getLogoEtablissement() ?>" alt="Logo de l'établissement d'inscription"/> <?php else: ?> - <span style='background-color:red;'> COMUE ou logo de la COMUE non renseigné. </span> + <span style='background-color:red;'> Logo de l'établissement non renseigné. </span> <?php endif; ?> </div> -</div> +<?php endif; ?> + <!-- ENTETE DE LA PAGE DE COUVERTURE ----------------------------------------------------------------------------------> <div class='bandeau-these'> @@ -139,13 +172,6 @@ use Application\View\Renderer\PhpRenderer; <div class="logos"> <table style="border:none;" class="logos"> <tr> - <td> - <?php if ($informations->getLogoEtablissement()): ?> - <img class="logo_small" src="<?php echo $informations->getLogoEtablissement() ?>"/> - <?php else: ?> - <span style='background-color:red;'> Établissement d'inscription ou logo d'établissement non renseigné. </span> - <?php endif; ?> - </td> <?php if ($informations->isAssocie()): ?> <td> <?php if ($informations->getLogoAssocie()): ?> diff --git a/module/Individu/view/individu/individu/partial/dl.phtml b/module/Individu/view/individu/individu/partial/dl.phtml index 58fe36248d5c44fabed45016bc7bea75bef6dfa1..0242d7da038e4e183b2bde8bdd60bbf45c50ca2d 100644 --- a/module/Individu/view/individu/individu/partial/dl.phtml +++ b/module/Individu/view/individu/individu/partial/dl.phtml @@ -3,6 +3,8 @@ * @var \Individu\Entity\Db\Individu $individu * @var bool $verbose */ + +if (!isset($verbose)) $verbose = false; ?> <dl class="row"> <?php if ($individu->getCivilite()): ?> diff --git a/module/RapportActivite/src/RapportActivite/Service/Search/RapportActiviteSearchService.php b/module/RapportActivite/src/RapportActivite/Service/Search/RapportActiviteSearchService.php index e7d68ff540d0775903793caa425a4530a39d003f..0ef95347407bf3b2503e25e1c19d74158bcd0ed3 100644 --- a/module/RapportActivite/src/RapportActivite/Service/Search/RapportActiviteSearchService.php +++ b/module/RapportActivite/src/RapportActivite/Service/Search/RapportActiviteSearchService.php @@ -76,19 +76,19 @@ class RapportActiviteSearchService extends SearchService $etablissementInscrFilter = $this->getEtablissementTheseSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('etab.sourceCode = :sourceCodeEtab OR etab_structureSubstituante.sourceCode = :sourceCodeEtab') + ->andWhere('etab.sourceCode = :sourceCodeEtab OR etab_substituant.sourceCode = :sourceCodeEtab') ->setParameter('sourceCodeEtab', $filter->getValue()); }); $ecoleDoctoraleFilter = $this->getEcoleDoctoraleSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('ed.sourceCode = :sourceCodeED OR ed_structureSubstituante.sourceCode = :sourceCodeED') + ->andWhere('ed.sourceCode = :sourceCodeED OR ed_substituant.sourceCode = :sourceCodeED') ->setParameter('sourceCodeED', $filter->getValue()); }); $uniteRechercheFilter = $this->getUniteRechercheSearchFilter() ->setQueryBuilderApplier(function (SelectSearchFilter $filter, DefaultQueryBuilder $qb) { $qb - ->andWhere('ur.sourceCode = :sourceCodeUR OR ur_structureSubstituante.sourceCode = :sourceCodeUR') + ->andWhere('ur.sourceCode = :sourceCodeUR OR ur_substituant.sourceCode = :sourceCodeUR') ->setParameter('sourceCodeUR', $filter->getValue()); }); $origineFinancementFilter = $this->getOrigineFinancementSearchFilter(); @@ -156,7 +156,10 @@ class RapportActiviteSearchService extends SearchService ->leftJoin('ur.structure', 'ur_structure')->addSelect('ur_structure') ->leftJoinStructureSubstituante('etab_structure', 'etab_structureSubstituante') ->leftJoinStructureSubstituante('ed_structure', 'ed_structureSubstituante') - ->leftJoinStructureSubstituante('ur_structure', 'ur_structureSubstituante'); + ->leftJoinStructureSubstituante('ur_structure', 'ur_structureSubstituante') + ->leftJoin('etab_structureSubstituante.etablissement', 'etab_substituant') + ->leftJoin('ed_structureSubstituante.ecoleDoctorale', 'ed_substituant') + ->leftJoin('ur_structureSubstituante.uniteRecherche', 'ur_substituant'); return $qb; } diff --git a/module/Soutenance/config/others/proposition.config.php b/module/Soutenance/config/others/proposition.config.php index a0213560ed0d2f0bdabc07a72d939e79d3882ca8..55e6f2ed6567130ebf6ad02d617bd87c7ce88e2a 100644 --- a/module/Soutenance/config/others/proposition.config.php +++ b/module/Soutenance/config/others/proposition.config.php @@ -60,6 +60,7 @@ return [ PropositionPrivileges::PROPOSITION_VALIDER_ED, PropositionPrivileges::PROPOSITION_VALIDER_UR, PropositionPrivileges::PROPOSITION_VALIDER_BDD, + PropositionPrivileges::PROPOSITION_REVOQUER_STRUCTURE, PropositionPrivileges::PROPOSITION_PRESIDENCE, PropositionPrivileges::PROPOSITION_DECLARATION_HONNEUR_VALIDER, @@ -137,6 +138,15 @@ return [ PropositionPrivileges::PROPOSITION_VALIDER_BDD, ], ], + [ + 'controller' => PropositionController::class, + 'action' => [ + 'revoquer-structure', + ], + 'privileges' => [ + PropositionPrivileges::PROPOSITION_REVOQUER_STRUCTURE, + ], + ], [ 'controller' => PropositionController::class, 'action' => [ @@ -378,17 +388,31 @@ return [ 'options' => [ 'route' => '/valider-structure', 'defaults' => [ + /** @see PropositionController::validerStructureAction() */ 'controller' => PropositionController::class, 'action' => 'valider-structure', ], ], ], + 'revoquer-structure' => [ + 'type' => Segment::class, + 'may_terminate' => true, + 'options' => [ + 'route' => '/revoquer-structure', + 'defaults' => [ + /** @see PropositionController::revoquerStructureAction() */ + 'controller' => PropositionController::class, + 'action' => 'revoquer-structure', + ], + ], + ], 'refuser-structure' => [ 'type' => Segment::class, 'may_terminate' => true, 'options' => [ 'route' => '/refuser-PropositionController', 'defaults' => [ + /** @see PropositionController::refuserStructureAction() */ 'controller' => PropositionController::class, 'action' => 'refuser-structure', ], diff --git a/module/Soutenance/src/Soutenance/Assertion/PropositionAssertion.php b/module/Soutenance/src/Soutenance/Assertion/PropositionAssertion.php index 27b09d2ab38d84c7e7743a209bc0725c239f6fd0..0831dad490223e933575260ff4266c4ce612140c 100644 --- a/module/Soutenance/src/Soutenance/Assertion/PropositionAssertion.php +++ b/module/Soutenance/src/Soutenance/Assertion/PropositionAssertion.php @@ -2,6 +2,7 @@ namespace Soutenance\Assertion; +use Soutenance\Entity\Etat; use These\Entity\Db\Acteur; use Application\Entity\Db\Role; use These\Entity\Db\These; @@ -211,6 +212,21 @@ class PropositionAssertion implements AssertionInterface { default: return false; } + case PropositionPrivileges::PROPOSITION_REVOQUER_STRUCTURE: + if ($proposition->getEtat()->getCode() !== Etat::EN_COURS && $proposition->getEtat()->getCode() !== Etat::ETABLISSEMENT) return false; + switch ($role) { + case Role::CODE_BDD : + $validations_BDD = $this->getValidationService()->getRepository()->findValidationByCodeAndThese(TypeValidation::CODE_VALIDATION_PROPOSITION_BDD, $these); + return (!empty($validations_BDD) && $structure === $theseEtablissementStructure); + case Role::CODE_RESP_UR : + $validations_UNITE = $this->getValidationService()->getRepository()->findValidationByCodeAndThese(TypeValidation::CODE_VALIDATION_PROPOSITION_UR, $these); + return (!empty($validations_UNITE) && $structure === $these->getUniteRecherche()->getStructure()); + case Role::CODE_RESP_ED : + $validations_ED = $this->getValidationService()->getRepository()->findValidationByCodeAndThese(TypeValidation::CODE_VALIDATION_PROPOSITION_ED, $these); + return (!empty($validations_ED) && $structure === $these->getEcoleDoctorale()->getStructure()); + default: + return false; + } case PropositionPrivileges::PROPOSITION_PRESIDENCE: switch($role) { case Role::CODE_BDD : diff --git a/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php b/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php index bfd6e03ee557340fbfc8927d169638a650a0b3f0..60864591b6d7ad519ce5011cc6dc45c30237a5f3 100644 --- a/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php +++ b/module/Soutenance/src/Soutenance/Controller/PresoutenanceController.php @@ -11,12 +11,15 @@ use Application\Service\Role\RoleServiceAwareTrait; use Application\Service\Source\SourceServiceAwareTrait; use Application\Service\Utilisateur\UtilisateurServiceAwareTrait; use DateInterval; +use Doctrine\ORM\Exception\ORMException; +use Exception; use Fichier\Entity\Db\NatureFichier; use Fichier\Service\Fichier\FichierServiceAwareTrait; use Fichier\Service\Fichier\FichierStorageServiceAwareTrait; use Fichier\Service\Storage\Adapter\Exception\StorageAdapterException; use Individu\Entity\Db\Individu; use Individu\Service\IndividuServiceAwareTrait; +use JetBrains\PhpStorm\NoReturn; use Laminas\Http\Response; use Laminas\Mvc\Plugin\FlashMessenger\FlashMessenger; use Laminas\View\Model\ViewModel; @@ -118,6 +121,13 @@ class PresoutenanceController extends AbstractController $validationBDD = $this->getValidationService()->getRepository()->findValidationByCodeAndThese(TypeValidation::CODE_VALIDATION_PROPOSITION_BDD, $these); $validationPDC = $this->getValidationService()->getRepository()->findValidationByCodeAndThese(TypeValidation::CODE_PAGE_DE_COUVERTURE, $these); + /** Parametres ---------------------------------------------------------------------------------------------- */ + try { + $deadline = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DELAI_RETOUR); + } catch (Exception $e) { + throw new RuntimeException("Une erreur est survenue lors de la récupération de la valeur d'un paramètre", 0 , $e); + } + return new ViewModel([ 'these' => $these, 'proposition' => $proposition, @@ -132,7 +142,7 @@ class PresoutenanceController extends AbstractController 'justificatifsOk' => $justificatifsOk, 'justificatifs' => $justificatifs, - 'deadline' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DELAI_RETOUR), + 'deadline' => $deadline, 'autorisation' => $autorisation, 'pv' => $pv, @@ -182,11 +192,11 @@ class PresoutenanceController extends AbstractController $membres = $proposition->getMembres(); $membre = $this->getMembreService()->getRequestedMembre($this); - /** Ici on prépare la liste des acteurs correspondant aux différents rôles pour le Select du formulaire + /** Ici, on prépare la liste des acteurs correspondant aux différents rôles pour le Select du formulaire * d'association. On part du principe : * - qu'un Rapporteur du jury est Rapporteur et Membre du jury, - * - qu'un Rapporteur absent est Rapporteur, - * - qu'un Membre du jury est Membre du jury. + * - qu'un Rapporteur absent est Rapporteur, + * - qu'un Membre du jury est Membre du jury. */ $acteurs = $this->getActeurService()->getRepository()->findActeurByThese($these); $acteurs = array_filter($acteurs, function (Acteur $a) { return $a->estNonHistorise();}); @@ -235,7 +245,7 @@ class PresoutenanceController extends AbstractController $acteur = $this->getActeurService()->getRepository()->find($acteurId); $individu = $acteur->getIndividu(); - if (!$acteur) throw new RuntimeException("Aucun acteur à associer !"); + if (! isset($acteur)) throw new RuntimeException("Aucun acteur à associer !"); //mise à jour du membre de soutenance $membre->setActeur($acteur); @@ -455,7 +465,7 @@ class PresoutenanceController extends AbstractController } /** Document pour la signature en présidence */ - public function procesVerbalSoutenanceAction() + #[NoReturn] public function procesVerbalSoutenanceAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -473,7 +483,7 @@ class PresoutenanceController extends AbstractController exit; } - public function avisSoutenanceAction() + #[NoReturn] public function avisSoutenanceAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -491,7 +501,7 @@ class PresoutenanceController extends AbstractController exit; } - public function rapportSoutenanceAction() + #[NoReturn] public function rapportSoutenanceAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -509,7 +519,7 @@ class PresoutenanceController extends AbstractController exit; } - public function rapportTechniqueAction() + #[NoReturn] public function rapportTechniqueAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -589,7 +599,7 @@ class PresoutenanceController extends AbstractController } /** Document pour la signature en présidence */ - public function convocationsAction() + #[NoReturn] public function convocationsAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -617,7 +627,7 @@ class PresoutenanceController extends AbstractController exit; } - public function convocationDoctorantAction() + #[NoReturn] public function convocationDoctorantAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -643,7 +653,7 @@ class PresoutenanceController extends AbstractController exit; } - public function convocationMembreAction() + #[NoReturn] public function convocationMembreAction(): void { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -840,30 +850,34 @@ class PresoutenanceController extends AbstractController $proposition = $this->getPropositionService()->findOneForThese($these); $membres = $proposition->getMembres(); - foreach ($membres as $membre) { - /** @var Acteur $acteur */ - $source_code_acteur = 'SyGAL_Simulation_Rapporteur_' . $membre->getId(); - $acteur = $this->getActeurService()->getRepository()->findOneBy(['sourceCode' => $source_code_acteur]); - if ($acteur !== null) { - $this->getActeurService()->getEntityManager()->remove($acteur); - $this->getActeurService()->getEntityManager()->flush($acteur); - } + try { + foreach ($membres as $membre) { + /** @var Acteur $acteur */ + $source_code_acteur = 'SyGAL_Simulation_Rapporteur_' . $membre->getId(); + $acteur = $this->getActeurService()->getRepository()->findOneBy(['sourceCode' => $source_code_acteur]); + if ($acteur !== null) { + $this->getActeurService()->getEntityManager()->remove($acteur); + $this->getActeurService()->getEntityManager()->flush($acteur); + } - /** @var Acteur $acteur */ - $source_code_acteur = 'SyGAL_Simulation_Membre_' . $membre->getId(); - $acteur = $this->getActeurService()->getRepository()->findOneBy(['sourceCode' => $source_code_acteur]); - if ($acteur !== null) { - $this->getActeurService()->getEntityManager()->remove($acteur); - $this->getActeurService()->getEntityManager()->flush($acteur); - } + /** @var Acteur $acteur */ + $source_code_acteur = 'SyGAL_Simulation_Membre_' . $membre->getId(); + $acteur = $this->getActeurService()->getRepository()->findOneBy(['sourceCode' => $source_code_acteur]); + if ($acteur !== null) { + $this->getActeurService()->getEntityManager()->remove($acteur); + $this->getActeurService()->getEntityManager()->flush($acteur); + } - /** @var Individu $source_code_individu */ - $source_code_individu = 'SyGAL_Simulation_' . $membre->getId(); - $individu = $this->getIndividuService()->getRepository()->findOneBy(['sourceCode' => $source_code_individu]); - if ($individu !== null) { - $this->getActeurService()->getEntityManager()->remove($individu); - $this->getActeurService()->getEntityManager()->flush($individu); + /** @var Individu $source_code_individu */ + $source_code_individu = 'SyGAL_Simulation_' . $membre->getId(); + $individu = $this->getIndividuService()->getRepository()->findOneBy(['sourceCode' => $source_code_individu]); + if ($individu !== null) { + $this->getActeurService()->getEntityManager()->remove($individu); + $this->getActeurService()->getEntityManager()->flush($individu); + } } + } catch (ORMException $e) { + throw new RuntimeException("Un problème est survenu en Base de donnée", 0 , $e); } return $this->redirect()->toRoute('soutenance/presoutenance', ['these' => $these->getId()], [], true); diff --git a/module/Soutenance/src/Soutenance/Controller/PropositionController.php b/module/Soutenance/src/Soutenance/Controller/PropositionController.php index c04a360dca2d58f44ef142415265c3d6513b07a3..8b7dd6a8e17258affb57c9bd2530e3ce6c361665 100644 --- a/module/Soutenance/src/Soutenance/Controller/PropositionController.php +++ b/module/Soutenance/src/Soutenance/Controller/PropositionController.php @@ -5,8 +5,10 @@ namespace Soutenance\Controller; use Application\Controller\AbstractController; use Application\Entity\Db\Role; use Application\Entity\Db\Utilisateur; +use Application\Entity\Db\Validation; use Application\Service\Role\RoleServiceAwareTrait; use Application\Service\UserContextServiceAwareTrait; +use Exception; use Fichier\Entity\Db\NatureFichier; use Fichier\Service\Fichier\FichierStorageServiceAwareTrait; use Individu\Entity\Db\Individu; @@ -133,32 +135,20 @@ class PropositionController extends AbstractController /** @var IndividuRole[] $ecoleResponsables */ $ecoleResponsables = []; if ($these->getEcoleDoctorale() !== null) { - // todo : utiliser findIndividuRoleByStructure(..., null, $these->getEtablissement()) - $ecoleResponsables = $this->getRoleService()->findIndividuRoleByStructure($these->getEcoleDoctorale()->getStructure()); - $ecoleResponsables = array_filter($ecoleResponsables, function (IndividuRole $ir) use ($these) { - return $ir->getIndividu()->getEtablissement() and $ir->getIndividu()->getEtablissement()->getId() === $these->getEtablissement()->getId(); - }); + $ecoleResponsables = $this->getRoleService()->findIndividuRoleByStructure($these->getEcoleDoctorale()->getStructure(), null, $these->getEtablissement()); } /** @var IndividuRole[] $uniteResponsables */ $uniteResponsables = []; if ($these->getUniteRecherche() !== null) { - // todo : utiliser findIndividuRoleByStructure(..., null, $these->getEtablissement()) - $uniteResponsables = $this->getRoleService()->findIndividuRoleByStructure($these->getUniteRecherche()->getStructure()); - $uniteResponsables = array_filter($uniteResponsables, function (IndividuRole $ir) use ($these) { - return $ir->getIndividu()->getEtablissement() and $ir->getIndividu()->getEtablissement()->getId() === $these->getEtablissement()->getId(); - }); + $uniteResponsables = $this->getRoleService()->findIndividuRoleByStructure($these->getUniteRecherche()->getStructure(), null, $these->getEtablissement()); } /** @var IndividuRole[] $etablissementResponsables */ $etablissementResponsables = []; if ($these->getEtablissement() !== null) { - // todo : utiliser findIndividuRoleByStructure(..., Role::CODE_BDD, $these->getEtablissement()) - $etablissementResponsables = $this->roleService->findIndividuRoleByStructure($these->getEtablissement()->getStructure()); + $etablissementResponsables = $this->roleService->findIndividuRoleByStructure($these->getEtablissement()->getStructure(), null, $these->getEtablissement()); $etablissementResponsables = array_filter($etablissementResponsables, function (IndividuRole $ir) { return $ir->getRole()->getCode() === Role::CODE_BDD; }); - $etablissementResponsables = array_filter($etablissementResponsables, function (IndividuRole $ir) use ($these) { - return $ir->getIndividu()->getEtablissement() and $ir->getIndividu()->getEtablissement()->getId() === $these->getEtablissement()->getId(); - }); } $informationsOk = true; $directeurs = $this->getActeurService()->getRepository()->findEncadrementThese($these); @@ -201,6 +191,18 @@ class PropositionController extends AbstractController /** Récupération des éléments liés au bloc 'intégrité scientifique' */ $attestationsIntegriteScientifique = $this->getJustificatifService()->getJustificatifsByPropositionAndNature($proposition, NatureFichier::CODE_FORMATION_INTEGRITE_SCIENTIFIQUE); + /** Paramètres ---------------------------------------------------------------------------------------------- */ + + try { + $FORMULAIRE_DELOCALISATION = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_DELOCALISATION); + $FORMULAIRE_DELEGUATION = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_DELEGATION_SIGNATURE); + $FORMULAIRE_DEMANDE_LABEL = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_LABEL_EUROPEEN); + $FORMULAIRE_DEMANDE_ANGLAIS = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_REDACTION_ANGLAIS); + $FORMULAIRE_DEMANDE_CONFIDENTIALITE = $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_CONFIDENTIALITE); + } catch (Exception $e) { + throw new RuntimeException("Une erreur est survenue lors de la récupération de paramètre.",0,$e); + } + return new ViewModel([ 'these' => $these, 'proposition' => $proposition, @@ -224,11 +226,11 @@ class PropositionController extends AbstractController 'informationsOk' => $informationsOk, 'avis' => $this->getAvisService()->getAvisByThese($these), - 'FORMULAIRE_DELOCALISATION' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_DELOCALISATION), - 'FORMULAIRE_DELEGUATION' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_DELEGATION_SIGNATURE), - 'FORMULAIRE_DEMANDE_LABEL' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_LABEL_EUROPEEN), - 'FORMULAIRE_DEMANDE_ANGLAIS' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_REDACTION_ANGLAIS), - 'FORMULAIRE_DEMANDE_CONFIDENTIALITE' => $this->getParametreService()->getValeurForParametre(SoutenanceParametres::CATEGORIE, SoutenanceParametres::DOC_CONFIDENTIALITE), + 'FORMULAIRE_DELOCALISATION' => $FORMULAIRE_DELOCALISATION, + 'FORMULAIRE_DELEGUATION' => $FORMULAIRE_DELEGUATION, + 'FORMULAIRE_DEMANDE_LABEL' => $FORMULAIRE_DEMANDE_LABEL, + 'FORMULAIRE_DEMANDE_ANGLAIS' => $FORMULAIRE_DEMANDE_ANGLAIS, + 'FORMULAIRE_DEMANDE_CONFIDENTIALITE' => $FORMULAIRE_DEMANDE_CONFIDENTIALITE, ]); } @@ -485,7 +487,7 @@ class PropositionController extends AbstractController } - public function validerStructureAction() + public function validerStructureAction(): Response|ViewModel { $these = $this->requestedThese(); $proposition = $this->getPropositionService()->findOneForThese($these); @@ -548,6 +550,67 @@ class PropositionController extends AbstractController } + public function revoquerStructureAction(): ViewModel + { + $these = $this->requestedThese(); + $proposition = $this->getPropositionService()->findOneForThese($these); + + /** + * @var Role $role + * @var Individu $individu + */ + $role = $this->userContextService->getSelectedIdentityRole(); + + /** NOTE: pas de break ici pour dévalider en cascade */ + $validations = []; + switch ($role->getCode()) { + case Role::CODE_RESP_UR : + $validations = array_merge($validations, $this->getValidationService()->getRepository()->findValidationByCodeAndThese(\Application\Entity\Db\TypeValidation::CODE_VALIDATION_PROPOSITION_UR,$these)); + case Role::CODE_RESP_ED : + $validations = array_merge($validations, $this->getValidationService()->getRepository()->findValidationByCodeAndThese(\Application\Entity\Db\TypeValidation::CODE_VALIDATION_PROPOSITION_ED,$these)); + case Role::CODE_BDD : + $validations = array_merge($validations, $this->getValidationService()->getRepository()->findValidationByCodeAndThese(\Application\Entity\Db\TypeValidation::CODE_VALIDATION_PROPOSITION_BDD,$these)); + } + + + $validationsListing = "<ul>"; + if (!empty($validations)) { + /** @var Validation $v */ + foreach ($validations as $v) { + $validationsListing .= "<li>" . $v->getTypeValidation()->getLibelle() . " faite par" . $v->getHistoCreateur()->getDisplayName(). " le". $v->getHistoCreation()->format('d/m/y à H:i')."</li>"; + } + } + $validationsListing .= "</ul>"; + + $request = $this->getRequest(); + if ($request->isPost()) { + $data = $request->getPost(); + if ($data["reponse"] === "oui") { + if (!empty($validations)) { + foreach ($validations as $v) { + $this->getValidationService()->historise($v); + } + } + $etat = $this->getPropositionService()->findPropositionEtatByCode(Etat::EN_COURS); + $proposition->setEtat($etat); + $this->getPropositionService()->update($proposition); + } + } + + $this->getHorodatageService()->addHorodatage($proposition, HorodatageService::TYPE_VALIDATION, "Révocation " . $role->getCode()); + + $vm = new ViewModel(); + if (!empty($validations)) { + $vm->setTemplate('default/confirmation'); + $vm->setVariables([ + 'title' => "Révocation de votre validation", + 'text' => "Cette révocation annulera les validations suivantes : " . $validationsListing . "Êtes-vous sûr·e de vouloir continuer ?", + 'action' => $this->url()->fromRoute('soutenance/proposition/revoquer-structure', ["these" => $these->getId()], [], true), + ]); + } + return $vm; + } + public function refuserStructureAction(): ViewModel { $these = $this->requestedThese(); diff --git a/module/Soutenance/src/Soutenance/Provider/Privilege/PropositionPrivileges.php b/module/Soutenance/src/Soutenance/Provider/Privilege/PropositionPrivileges.php index fcd9c56260870c76a981ecab28bfb1818b768f2d..754aafa71076112593a2786156493cf47e63d9c1 100644 --- a/module/Soutenance/src/Soutenance/Provider/Privilege/PropositionPrivileges.php +++ b/module/Soutenance/src/Soutenance/Provider/Privilege/PropositionPrivileges.php @@ -18,4 +18,5 @@ class PropositionPrivileges extends Privileges const PROPOSITION_SURSIS = 'soutenance-proposition-sursis'; const PROPOSITION_DECLARATION_HONNEUR_VALIDER = 'soutenance-declaration-honneur-valider'; const PROPOSITION_DECLARATION_HONNEUR_REVOQUER = 'soutenance-declaration-honneur-revoquer'; + const PROPOSITION_REVOQUER_STRUCTURE = 'soutenance-proposition-revoquer-structure'; } \ No newline at end of file diff --git a/module/Soutenance/view/soutenance/proposition/partial/validations-structures.phtml b/module/Soutenance/view/soutenance/proposition/partial/validations-structures.phtml index 78d39d17ba91d2cf19d06f2378005cde4cab9a98..4f81148025e5d95304a33446644c14d1dce5a78a 100644 --- a/module/Soutenance/view/soutenance/proposition/partial/validations-structures.phtml +++ b/module/Soutenance/view/soutenance/proposition/partial/validations-structures.phtml @@ -3,6 +3,7 @@ * @var Proposition $proposition * @var Validation[][] $validations * @var boolean $canStructureValider + * @var boolean $canStructureRevoquer * @var boolean $canPresidence */ @@ -119,6 +120,16 @@ $these = $proposition->getThese(); </a> </p> <?php endif; ?> + + <?php if ($canStructureRevoquer): ?> + <p> + <a <?php /** @see \Soutenance\Controller\PropositionController::revoquerStructureAction(); */ ?> + href="<?php echo $this->url('soutenance/proposition/revoquer-structure', ['these' => $these->getId()], [], true); ?>" + class="btn btn-warning action ajax-modal" data-event="modification"> + <span class="icon icon-unchecked"></span> Révoquer la validation + </a> + </p> + <?php endif; ?> </div> </div> </div> diff --git a/module/Soutenance/view/soutenance/proposition/proposition.phtml b/module/Soutenance/view/soutenance/proposition/proposition.phtml index 3df82acd3cdfc5aa673a6abb2aae77228eb02120..7e1d1fd09af6c54c3857af482526b45e92399a88 100644 --- a/module/Soutenance/view/soutenance/proposition/proposition.phtml +++ b/module/Soutenance/view/soutenance/proposition/proposition.phtml @@ -169,12 +169,16 @@ echo $this->partial('partial/validations-acteurs', [ $canStructureValider = $isOk && $this->isAllowed($these, PropositionPrivileges::PROPOSITION_VALIDER_UR) || $this->isAllowed($these, PropositionPrivileges::PROPOSITION_VALIDER_ED) || $this->isAllowed($these, PropositionPrivileges::PROPOSITION_VALIDER_BDD); + +$canStructureRevoquer = $isOk && $this->isAllowed($these, PropositionPrivileges::PROPOSITION_REVOQUER_STRUCTURE); + $canPresidence = $this->isAllowed($these, PropositionPrivileges::PROPOSITION_PRESIDENCE); echo $this->partial('partial/validations-structures', [ 'proposition' => $proposition, 'validations' => $validations, 'canStructureValider' => $canStructureValider, + 'canStructureRevoquer' => $canStructureRevoquer, 'canPresidence' => $canPresidence, ]); ?> diff --git a/module/Structure/src/Structure/Form/Hydrator/EcoleDoctoraleHydrator.php b/module/Structure/src/Structure/Form/Hydrator/EcoleDoctoraleHydrator.php index bef30331a041bb0de758d23e29223fdf31ac27bc..59f963dd8fc878d9558dcd437caaf29737786ee6 100644 --- a/module/Structure/src/Structure/Form/Hydrator/EcoleDoctoraleHydrator.php +++ b/module/Structure/src/Structure/Form/Hydrator/EcoleDoctoraleHydrator.php @@ -30,7 +30,7 @@ class EcoleDoctoraleHydrator extends StructureHydrator $theme = (isset($data['theme']) and trim($data['theme']) !== '') ? trim($data['theme']) : null; $offreThese = (isset($data['offre-these']) and trim($data['offre-these']) !== '') ? trim($data['offre-these']) : null; - if ($data['id'] === "") $data['id'] = null; + if (!isset($data['id']) || $data['id'] === "") $data['id'] = null; /** @var EcoleDoctorale $object */ $object = parent::hydrate($data, $ed); diff --git a/module/Structure/src/Structure/Form/Hydrator/EtablissementHydrator.php b/module/Structure/src/Structure/Form/Hydrator/EtablissementHydrator.php index 5c86309f96a00c568d964b3c29064e390d8e269b..d97d02f3e05dc5fd9b08ecf1b4b103c03f3a3558 100644 --- a/module/Structure/src/Structure/Form/Hydrator/EtablissementHydrator.php +++ b/module/Structure/src/Structure/Form/Hydrator/EtablissementHydrator.php @@ -35,7 +35,7 @@ class EtablissementHydrator extends StructureHydrator */ public function hydrate(array $data, $etablissement): Etablissement { - if ($data['id'] === "") $data['id'] = null; + if (!isset($data['id']) || $data['id'] === "") $data['id'] = null; /** @var Etablissement $object */ $object = parent::hydrate($data, $etablissement); diff --git a/module/Structure/src/Structure/Form/Hydrator/StructureHydrator.php b/module/Structure/src/Structure/Form/Hydrator/StructureHydrator.php index 3a311d950735a322d975cce19e1c61dc296c35e6..f65626500f594133fee341ee37f2a24e8339c227 100644 --- a/module/Structure/src/Structure/Form/Hydrator/StructureHydrator.php +++ b/module/Structure/src/Structure/Form/Hydrator/StructureHydrator.php @@ -41,7 +41,7 @@ abstract class StructureHydrator extends DoctrineObject $object->getStructure()->setCode($data['code']); $object->getStructure()->setIdRef($data['id_ref']); $object->getStructure()->setIdHal($data['id_hal']); - $object->getStructure()->setCheminLogo($data['cheminLogo']); + $object->getStructure()->setCheminLogo($data['cheminLogo']??null); $object->getStructure()->setEstFermee(isset($data['estFerme']) and $data['estFerme'] === "1"); return $object; diff --git a/module/Structure/src/Structure/Form/Hydrator/UniteRechercheHydrator.php b/module/Structure/src/Structure/Form/Hydrator/UniteRechercheHydrator.php index 59012bfe91c00155d4d5248d38fbb9a1d27c181e..8f94fae49a159fd668d28568232124a832568add 100644 --- a/module/Structure/src/Structure/Form/Hydrator/UniteRechercheHydrator.php +++ b/module/Structure/src/Structure/Form/Hydrator/UniteRechercheHydrator.php @@ -26,7 +26,7 @@ class UniteRechercheHydrator extends StructureHydrator */ public function hydrate(array $data, $ur): UniteRecherche { - if ($data['id'] === "") $data['id'] = null; + if (!isset($data['id']) || $data['id'] === "") $data['id'] = null; /** @var UniteRecherche $object */ $object = parent::hydrate($data, $ur); diff --git a/module/These/src/These/Service/FichierThese/PdcData.php b/module/These/src/These/Service/FichierThese/PdcData.php index fafc149008ceac66c93288264a44897eee901693..2a66b7d7574cd81bd61bb9acd19aa3d6bd8c6675 100644 --- a/module/These/src/These/Service/FichierThese/PdcData.php +++ b/module/These/src/These/Service/FichierThese/PdcData.php @@ -9,8 +9,7 @@ use These\Entity\Db\Acteur; /** Les informations ici sont des chaines de caractères */ class PdcData { - /** @var string */ - private $titre; + private ?string $titre = null; /** @var string */ private $specialite; /** @var string */