Commit e0c1720a authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

wip

parent 8aac1eb1
Loading
Loading
Loading
Loading
+240 −0
Changes for bin/entity_elements/Module/config/thing.config.php: 240 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Module;

use Application\Navigation\ApplicationNavigationFactory;
use Laminas\Router\Http\Literal;
use Laminas\Router\Http\Segment;
use Module\Assertion\ThingAssertion;
use Module\Assertion\ThingAssertionFactory;
use Module\Controller\ThingController;
use Module\Controller\ThingControllerFactory;
use Module\Entity\Db\Service\ThingService;
use Module\Entity\Db\Service\ThingServiceFactory;
use Module\Entity\Validator\CotutelleDateValidator;
use Module\Entity\Validator\CotutelleDateValidatorFactory;
use Module\Form\ThingForm;
use Module\Form\ThingFormFactory;
use Module\Hydrator\ThingHydrator;
use Module\Hydrator\ThingHydratorFactory;
use Module\Navigation\ThingMenuVisible;
use Module\Navigation\ThingMenuVisibleFactory;
use Module\Provider\ThingPrivileges;
use UnicaenPrivilege\Guard\PrivilegeController;
use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProvider;

return [
    'bjyauthorize' => [
        'resource_providers' => [
            'BjyAuthorize\Provider\Resource\Config' => [
                'Thing' => [],
            ],
        ],
        'rule_providers' => [
            PrivilegeRuleProvider::class => [
                'allow' => [
                    [
                        'privileges' => [
                            ThingPrivileges::CONSULTER_COTUTELLE_TOUTES,
                            ThingPrivileges::CONSULTER_COTUTELLE_MIENNES,
                            ThingPrivileges::AJOUTER_COTUTELLE_TOUTES,
                            ThingPrivileges::AJOUTER_COTUTELLE_MIENNES,
                            ThingPrivileges::MODIFIER_COTUTELLE_TOUTES,
                            ThingPrivileges::MODIFIER_COTUTELLE_MIENNES,
                            ThingPrivileges::SUPPRIMER_COTUTELLE_TOUTES,
                            ThingPrivileges::SUPPRIMER_COTUTELLE_MIENNES,
                        ],
                        'resources' => ['Thing'],
                        'assertion' => ThingAssertion::class,
                    ],
                ],
            ],
        ],
        'guards' => [
            PrivilegeController::class => [
                [
                    'controller' => ThingController::class,
                    'action' => [
                        'consulter',
                    ],
                    'privileges' => [
                        ThingPrivileges::CONSULTER_COTUTELLE_TOUTES,
                        ThingPrivileges::CONSULTER_COTUTELLE_MIENNES,
                    ],
                    'assertion' => ThingAssertion::class,thing
                ],
                [
                    'controller' => ThingController::class,
                    'action' => [
                        'ajouter',
                    ],
                    'privileges' => [
                        ThingPrivileges::AJOUTER_COTUTELLE_TOUTES,
                        ThingPrivileges::AJOUTER_COTUTELLE_MIENNES,
                    ],
                    'assertion' => ThingAssertion::class,
                ],
                [
                    'controller' => ThingController::class,
                    'action' => [
                        'modifier',
                    ],
                    'privileges' => [
                        ThingPrivileges::MODIFIER_COTUTELLE_TOUTES,
                        ThingPrivileges::MODIFIER_COTUTELLE_MIENNES,
                    ],
                    'assertion' => ThingAssertion::class,
                ],
                [
                    'controller' => ThingController::class,
                    'action' => [
                        'supprimer',
                    ],
                    'privileges' => [
                        ThingPrivileges::SUPPRIMER_COTUTELLE_TOUTES,
                        ThingPrivileges::SUPPRIMER_COTUTELLE_MIENNES,
                    ],
                    'assertion' => ThingAssertion::class,
                ],
                [
                    'controller' => ThingController::class,
                    'action' => [
                        'rechercherEtablissement',
                    ],
                    'privileges' => [
                        ThingPrivileges::AJOUTER_COTUTELLE_TOUTES,
                        ThingPrivileges::AJOUTER_COTUTELLE_MIENNES,
                        ThingPrivileges::MODIFIER_COTUTELLE_TOUTES,
                        ThingPrivileges::MODIFIER_COTUTELLE_MIENNES,
                    ],
                    'assertion' => ThingAssertion::class,
                ],
            ],
        ],
    ],
    'router' => [
        'routes' => [
            'these' => [
                'child_routes' => [
                    'cotutelle' => [
                        'type' => Segment::class,
                        'options' => [
                            'route' => '/cotutelle',
                            'defaults' => [
                                'controller' => ThingController::class,
                            ],
                        ],
                        'may_terminate' => false,
                        'child_routes' => [
                            'ajouter' => [
                                'type' => Segment::class,
                                'options' => [
                                    'route' => '/ajouter/:these',
                                    'constraints' => [
                                        'these' => '\d+',
                                    ],
                                    'defaults' => [
                                        /** @see ThingController::ajouterAction() */
                                        'action' => 'ajouter',
                                    ],
                                ],
                            ],
                            'consulter' => [
                                'type' => Segment::class,
                                'options' => [
                                    'route' => '/consulter/:these',
                                    'constraints' => [
                                        'these' => '\d+',
                                    ],
                                    'defaults' => [
                                        /** @see ThingController::consulterAction() */
                                        'action' => 'consulter',
                                    ],
                                ],
                            ],
                            'modifier' => [
                                'type' => Segment::class,
                                'options' => [
                                    'route' => '/modifier/:thing',
                                    'constraints' => [
                                        'thing' => '\d+',
                                    ],
                                    'defaults' => [
                                        /** @see ThingController::modifierAction() */
                                        'action' => 'modifier',
                                    ],
                                ],
                            ],
                            'supprimer' => [
                                'type' => Segment::class,
                                'options' => [
                                    'route' => '/supprimer/:thing',
                                    'constraints' => [
                                        'thing' => '\d+',
                                    ],
                                    'defaults' => [
                                        /** @see ThingController::supprimerAction() */
                                        'action' => 'supprimer',
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
    'navigation' => [
        'default' => [
            'home' => [
                'pages' => [
                    ApplicationNavigationFactory::THESE_SELECTIONNEE_PAGE_ID => [
                        'pages' => $thesePages = [
                            // DEPTH = 2
                            'these-cotutelle' => [
                                'order' => 10,
                                'label' => 'Cotutelle',
                                'route' => 'these/cotutelle/consulter',
                                'withtarget' => true,
                                'paramsInject' => [
                                    'these',
                                ],
                                'icon' => 'fas fa-globe',
                                'resource' => PrivilegeController::getResourceId(ThingController::class, 'consulter'),
                                'visible' => ThingMenuVisible::class,
                            ],
                        ],
                    ],
                    ApplicationNavigationFactory::MA_THESE_PAGE_ID => [
                        'pages' => $thesePages
                    ],
                ],
            ],
        ],
    ],
    'form_elements' => [
        'factories' => [
            ThingForm::class => ThingFormFactory::class,
        ],
    ],
    'validators' => [
        'factories' => [
        ],
    ],
    'hydrators' => [
        'factories' => [
            ThingHydrator::class  => ThingHydratorFactory::class,
        ],
    ],
    'controllers' => [
        'factories' => [
            ThingController::class => ThingControllerFactory::class,
        ],
    ],
    'service_manager' => [
        'factories' => [
            ThingAssertion::class => ThingAssertionFactory::class,
            ThingService::class => ThingServiceFactory::class,
        ],
    ],
];
 No newline at end of file
+201 −0
Changes for bin/entity_elements/Module/src/Module/Assertion/ThingAssertion.php: 201 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Module\Assertion;

use Application\Assertion\AbstractAssertion;
use Application\Assertion\Exception\FailedAssertionException;
use Laminas\Permissions\Acl\Resource\ResourceInterface;
use These\Assertion\These\AssertAppartenanceTheseTrait;
use These\Entity\Db\These;
use These\Service\These\TheseServiceAwareTrait;
use Module\Entity\Db\Thing;
use Module\Entity\Db\Service\ThingServiceAwareTrait;
use Module\Provider\ThingPrivileges;
use Webmozart\Assert\Assert;

class ThingAssertion extends AbstractAssertion
{
    use TheseServiceAwareTrait;
    use ThingServiceAwareTrait;
    use AssertAppartenanceTheseTrait;

    protected function assertEntity(ResourceInterface $entity, $privilege = null): bool
    {
        if (!parent::assertEntity($entity, $privilege)) {
            return false;
        }

        Assert::isInstanceOf($entity, Thing::class);
        $thing = $entity;
        $these = $thing->getThese();

        try {
            switch ($privilege) {
                case ThingPrivileges::CONSULTER_COTUTELLE_MIENNES:
                case ThingPrivileges::AJOUTER_COTUTELLE_MIENNES:
                case ThingPrivileges::MODIFIER_COTUTELLE_MIENNES:
                case ThingPrivileges::SUPPRIMER_COTUTELLE_MIENNES:
                    $this->assertAppartenanceThese($these);
            }

            switch ($privilege) {
                case ThingPrivileges::AJOUTER_COTUTELLE_TOUTES:
                case ThingPrivileges::AJOUTER_COTUTELLE_MIENNES:
                    $this->assertCotutelleInexistante($these);
            }

            switch ($privilege) {
                case ThingPrivileges::MODIFIER_COTUTELLE_TOUTES:
                case ThingPrivileges::MODIFIER_COTUTELLE_MIENNES:
//                    $this->assertEtatCotutelle($thing, [
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_NEGOCIATION,
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_SIGNATURE,
//                        //Thing::ETAT_ADMINISTRATIF_SIGNE,
//                        //Thing::ETAT_ADMINISTRATIF_PROJET_ABANDONNE,
//                    ]);
            }

            switch ($privilege) {
                case ThingPrivileges::SUPPRIMER_COTUTELLE_TOUTES:
                case ThingPrivileges::SUPPRIMER_COTUTELLE_MIENNES:
//                    $this->assertEtatCotutelle($thing, [
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_NEGOCIATION,
//                        //Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_SIGNATURE,
//                        //Thing::ETAT_ADMINISTRATIF_SIGNE,
//                        Thing::ETAT_ADMINISTRATIF_PROJET_ABANDONNE,
//                    ]);
            }
        } catch (FailedAssertionException $e) {
            if ($e->getMessage()) {
                $this->getServiceMessageCollector()->addMessage($e->getMessage(), __CLASS__);
            }
            return false;
        }

        return true;
    }

    protected function assertController($controller, $action = null, $privilege = null): bool
    {
        if (!parent::assertController($controller, $action, $privilege)) {
            return false;
        }

        // init en fonction de l'action
        $thing = null;
        $these = null;
        switch ($action) {
            case 'consulter':
            case 'ajouter':
                $these = $this->getRequestedThese();
                if ($these === null) {
                    // pas de thèse dispo dans le route match (on est dans ce cas lors de la génération de la navigation)
                    // pas le choix : il faut retourner `true`
                    return true;
                }
                break;

            case 'modifier':
            case 'supprimer':
                $thing = $this->getRequestedThing();
                if ($thing === null) {
                    // pas de cotutelle dispo dans le route match (on est dans ce cas lors de la génération de la navigation)
                    // pas le choix : il faut retourner `true`
                    return true;
                }
                $these = $thing->getThese();
                break;
        }

        try {
            switch ($action) {
                case 'consulter':
                case 'ajouter':
                case 'modifier':
                case 'supprimer':
                    $this->assertAppartenanceThese($these);
            }

            switch ($action) {
                case 'ajouter':
                    $this->assertCotutelleInexistante($these);
                    break;
            }

            switch ($action) {
                case 'modifier':
//                    $this->assertEtatCotutelle($thing, [
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_NEGOCIATION,
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_SIGNATURE,
//                        //Thing::ETAT_ADMINISTRATIF_SIGNE,
//                        //Thing::ETAT_ADMINISTRATIF_PROJET_ABANDONNE,
//                    ]);
                    break;
            }

            switch ($action) {
                case 'supprimer':
//                    $this->assertEtatCotutelle($thing, [
//                        Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_NEGOCIATION,
//                        //Thing::ETAT_ADMINISTRATIF_EN_COURS_DE_SIGNATURE,
//                        //Thing::ETAT_ADMINISTRATIF_SIGNE,
//                        Thing::ETAT_ADMINISTRATIF_PROJET_ABANDONNE,
//                    ]);
                    break;
            }
        } catch (FailedAssertionException $e) {
            if ($e->getMessage()) {
                $this->getServiceMessageCollector()->addMessage($e->getMessage(), __CLASS__);
            }
            return false;
        }

        return true;
    }

    private function getRequestedThese(): ?These
    {
        $these = null;
        if ($id = $this->getRouteMatch()?->getParam('these')) {
            /** @var These $these */
            $these = $this->theseService->getRepository()->find($id);
            Assert::notNull($these);
        }

        return $these;
    }

    private function getRequestedThing(): ?Thing
    {
        $thing = null;
        if ($id = $this->getRouteMatch()?->getParam('thing')) {
            /** @var Thing $thing */
            $thing = $this->thingService->getRepository()->find($id);
            Assert::notNull($thing);
        }

        return $thing;
    }

    /**
     * @throws \Application\Assertion\Exception\FailedAssertionException
     */
    private function assertCotutelleInexistante(These $these): void
    {
        $this->assertTrue(
            $these->getCotutelle() === null,
            "Une cotutelle existe déjà sur cette thèse."
        );
    }

    /**
     * @throws \Application\Assertion\Exception\FailedAssertionException
     */
    private function assertEtatCotutelle(Thing $thing, array $etatsPossibles): void
    {
        $this->assertTrue(
            in_array($thing->getEtatAdministratif(), $etatsPossibles),
            "L'état administratif de cette cotutelle ne permet plus sa modification."
        );
    }
}
 No newline at end of file
+50 −0
Changes for bin/entity_elements/Module/src/Module/Assertion/ThingAssertionFactory.php: 50 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Module\Assertion;

use Application\Assertion\AbstractAssertion;
use Psr\Container\ContainerInterface;
use These\Service\These\TheseService;
use Module\Entity\Db\Service\ThingService;
use UnicaenAuthentification\Service\UserContext;

class ThingAssertionFactory
{
    /**
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function __invoke(ContainerInterface $container): ThingAssertion
    {
        $assertion = new ThingAssertion();

        /** @var \These\Service\These\TheseService $theseService */
        $theseService = $container->get(TheseService::class);
        $assertion->setTheseService($theseService);

        /** @var \Thing\Entity\Db\Service\ThingService $thingService */
        $thingService = $container->get(ThingService::class);
        $assertion->setThingService($thingService);

        $this->injectCommons($assertion, $container);

        return $assertion;
    }

    /**
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     */
    protected function injectCommons(AbstractAssertion $assertion, ContainerInterface $container): void
    {
        $authorizeService = $container->get('BjyAuthorize\Service\Authorize');
        $mvcEvent = $container->get('Application')->getMvcEvent();
        $userContext = $container->get(UserContext::class);
        $messageCollector = $container->get('MessageCollector');

        $assertion->setServiceAuthorize($authorizeService);
        $assertion->setMvcEvent($mvcEvent);
        $assertion->setUserContextService($userContext);
        $assertion->setServiceMessageCollector($messageCollector);
    }
}
 No newline at end of file
+152 −0
Changes for bin/entity_elements/Module/src/Module/Controller/ThingController.php: 152 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Module\Controller;

use Application\Controller\AbstractController;
use Exception;
use Laminas\Http\Response;
use Laminas\View\Model\ViewModel;
use Structure\Service\Etablissement\EtablissementServiceAwareTrait;
use These\Entity\Db\These;
use These\Service\These\TheseServiceAwareTrait;
use Module\Entity\Db\Thing;
use Module\Entity\Db\Service\ThingServiceAwareTrait;
use Module\Form\ThingForm;
use Webmozart\Assert\Assert;

class ThingController extends AbstractController
{
    use TheseServiceAwareTrait;
    use ThingServiceAwareTrait;
    use EtablissementServiceAwareTrait;

    private These $these;
    protected ?Thing $thing;
    protected ThingForm $thingForm;

    public function setThingForm(ThingForm $thingForm): void
    {
        $this->thingForm = $thingForm;
    }

    public function consulterAction(): ViewModel
    {
        $vm = new ViewModel();

        $this->these = $this->getRequestedThese();
        $this->thing = $this->thingService->getRepository()->findOneByThese($this->these);

        $vm->setVariables([
            'these' => $this->these,
            'thing' => $this->thing,
        ]);

        return $vm;
    }

    public function ajouterAction(): Response|ViewModel
    {
        $this->these = $this->getRequestedThese();
        $this->thing = new Thing($this->these);

        return $this->ajouterModifier();
    }

    public function modifierAction(): Response|ViewModel
    {
        $this->thing = $this->getRequestedThing();
        $this->these = $this->thing->getThese();

        return $this->ajouterModifier();
    }

    private function ajouterModifier(): Response|ViewModel
    {
        $this->thingForm->setAttribute('action', $this->url()->fromRoute(reuseMatchedParams: true));
        $this->thingForm->bind($this->thing);

        $request = $this->getRequest();
        if ($request->isPost()) {
            $data = $request->getPost();
            $this->thingForm->setData($data);
            if ($this->thingForm->isValid()) {
                try {
                    $this->saveThing();
                    $this->flashMessenger()->addSuccessMessage(sprintf(
                        "La cotutelle pour la thèse de %s a été enregistrée avec succès.",
                        $this->thing->getThese()->getDoctorant()
                    ));
                    return $this->redirect()->toRoute(
                        'these/cotutelle/consulter',
                        ['these' => $this->these->getId(), 'thing' => $this->thing->getId()],
                        reuseMatchedParams: true
                    );
                } catch (Exception $e) {
                    $this->flashMessenger()->addErrorMessage(sprintf(
                        "Impossible d'enregistrer la cotutelle pour la thèse de %s ! " . $e->getMessage(),
                        $this->thing->getThese()->getDoctorant()
                    ));
                }
//                if (!$request->isXmlHttpRequest()) {
//                    return $this->redirect()->toUrl($this->urlIdentite());
//                }
            }
        }

        $vm = new ViewModel();
        $vm->setVariables([
            'form' => $this->thingForm,
            'title' => $this->thing->getId() ? "Modification de cotutelle" : "Déclaration d'une cotutelle",
        ]);
        $vm->setTemplate("these-cotutelle/these-cotutelle/modifier");

        return $vm;
    }

    public function supprimerAction(): Response
    {
        $this->thing = $this->getRequestedThing();

        $this->thing->historiser($this->userContextService->getDbUser());

        try {
            $this->thingService->saveThing($this->thing);
            $this->flashMessenger()->addSuccessMessage(sprintf(
                "La cotutelle pour la thèse de %s a été supprimée (historisée).",
                $this->thing->getThese()->getDoctorant()
            ));
        } catch (Exception $e) {
            $this->flashMessenger()->addErrorMessage(sprintf(
                "Impossible de supprimer la cotutelle pour la thèse de %s ! " . $e->getMessage(),
                $this->thing->getThese()->getDoctorant()
            ));
        }

        return $this->redirect()->toRoute('these/identite', ['these' => $this->thing->getThese()->getId()]);
    }

    /**
     * @throws \Exception
     */
    private function saveThing(): void
    {
        $this->thingService->saveThing($this->thing);

    }

    private function getRequestedThese(): These
    {
        /** @var \These\Entity\Db\These $these */
        $these = $this->theseService->getRepository()->find($this->params('these'));
        Assert::notNull($these);
        return $these;
    }

    private function getRequestedThing(): Thing
    {
        /** @var \Thing\Entity\Db\Thing $thing */
        $thing = $this->thingService->getRepository()->find($this->params('thing'));
        Assert::notNull($thing);
        return $thing;
    }
}
 No newline at end of file
+36 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading