From 26002f1a1f0a50ba5dd7c57d9ebe6acf5851c257 Mon Sep 17 00:00:00 2001 From: gauthierb <gauthierb@d57fa8bc-6af1-4de9-8b7d-78e900e231e7> Date: Wed, 30 Apr 2014 15:54:09 +0000 Subject: [PATCH] =?UTF-8?q?Travail=20sur=20les=20r=C3=B4les=20issus=20de?= =?UTF-8?q?=20la=20BDD,=20de=20la=20=20possibilit=C3=A9=20de=20s=C3=A9lect?= =?UTF-8?q?ionner=20le=20r=C3=B4le=20courant.=20Travail=20sur=20le=20princ?= =?UTF-8?q?ipe=20des=20finders=20"contextualis=C3=A9s",=20=C3=A0=20discute?= =?UTF-8?q?r.=20Correction=20bugs.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.lock | 68 ++-- doc/profils.ods | Bin 0 -> 12379 bytes doc/workflow.odp | Bin 0 -> 20609 bytes module/Application/Module.php | 15 - .../Application/config/intervenant.config.php | 5 +- module/Application/config/module.config.php | 34 +- module/Application/config/service.config.php | 17 +- .../src/Application/Acl/DbRole.php | 129 +++++++ .../src/Application/Acl/IntervenantRole.php | 29 ++ .../Application/Controller/DemoController.php | 2 +- .../Controller/IntervenantController.php | 14 +- .../Application/Controller/Plugin/Context.php | 4 +- .../ServiceReferentielController.php | 184 ++++++---- .../Entity/Db/Finder/AbstractFinder.php | 64 ++++ ...rvenantPermanentWithServiceReferentiel.php | 84 +++++ .../Db/Finder/FinderServiceReferentiel.php | 66 ++++ .../Application.Entity.Db.Personnel.dcm.xml | 1 + .../Application.Entity.Db.Service.dcm.xml | 3 +- .../Application.Entity.Db.TypeRole.dcm.xml | 1 + ...cation.Entity.Db.ValidationService.dcm.xml | 41 +++ .../src/Application/Entity/Db/Personnel.php | 189 ++-------- .../Db/Repository/IntervenantRepository.php | 16 +- .../ServiceReferentielRepository.php | 101 ------ .../src/Application/Entity/Db/TypeRole.php | 48 +-- .../src/Application/Entity/Db/Utilisateur.php | 1 - .../Entity/Db/ValidationService.php | 335 ++++++++++++++++++ .../src/Application/Form/Service/Saisie.php | 4 +- .../Provider/Identity/IdentityProvider.php | 78 +++- .../Identity/IdentityProviderFactory.php | 27 ++ .../Provider/Role/RoleProvider.php | 59 ++- .../Application/Service/AbstractService.php | 22 +- .../src/Application/Service/Context.php | 182 ---------- .../Service/ContextAwareInterface.php | 19 - .../Application/Service/ContextAwareTrait.php | 36 -- .../Application/Service/ContextProvider.php | 80 +++++ .../Service/ContextProviderAwareInterface.php | 27 ++ .../Service/ContextProviderAwareTrait.php | 40 +++ .../src/Application/Service/GlobalContext.php | 111 ++++++ .../src/Application/Service/Intervenant.php | 74 +++- .../Service/IntervenantFactory.php | 29 ++ .../Service/ServiceReferentiel.php | 87 ++++- .../Service/ServiceReferentielFactory.php | 29 ++ .../Application/Service/ValidationService.php | 16 + .../Application/View/Helper/Service/Ligne.php | 27 +- .../View/Helper/Service/LigneFactory.php | 28 ++ .../Application/View/Helper/Service/Liste.php | 19 +- .../View/Helper/Service/ListeFactory.php | 28 ++ .../View/Helper/ServiceReferentiel/Dl.php | 16 +- .../View/Helper/ServiceReferentiel/Ligne.php | 77 ++-- .../ServiceReferentiel/LigneFactory.php | 28 ++ .../View/Helper/ServiceReferentiel/Liste.php | 97 ++--- .../ServiceReferentiel/ListeFactory.php | 28 ++ .../application/intervenant/choisir.phtml | 3 +- .../service-referentiel/index.phtml | 27 +- .../service-referentiel/saisir.phtml | 2 +- .../service-referentiel/suppression.phtml | 7 - .../service-referentiel/supprimer.phtml | 14 + .../src/Common/Exception/DomainException.php | 13 + public/js/app.js | 97 +---- 59 files changed, 1933 insertions(+), 949 deletions(-) create mode 100644 doc/profils.ods create mode 100644 doc/workflow.odp create mode 100644 module/Application/src/Application/Acl/DbRole.php create mode 100644 module/Application/src/Application/Acl/IntervenantRole.php create mode 100644 module/Application/src/Application/Entity/Db/Finder/AbstractFinder.php create mode 100644 module/Application/src/Application/Entity/Db/Finder/FinderIntervenantPermanentWithServiceReferentiel.php create mode 100644 module/Application/src/Application/Entity/Db/Finder/FinderServiceReferentiel.php create mode 100644 module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.ValidationService.dcm.xml create mode 100644 module/Application/src/Application/Entity/Db/ValidationService.php create mode 100644 module/Application/src/Application/Provider/Identity/IdentityProviderFactory.php delete mode 100644 module/Application/src/Application/Service/Context.php delete mode 100644 module/Application/src/Application/Service/ContextAwareInterface.php delete mode 100644 module/Application/src/Application/Service/ContextAwareTrait.php create mode 100644 module/Application/src/Application/Service/ContextProvider.php create mode 100644 module/Application/src/Application/Service/ContextProviderAwareInterface.php create mode 100644 module/Application/src/Application/Service/ContextProviderAwareTrait.php create mode 100644 module/Application/src/Application/Service/GlobalContext.php create mode 100644 module/Application/src/Application/Service/IntervenantFactory.php create mode 100644 module/Application/src/Application/Service/ServiceReferentielFactory.php create mode 100644 module/Application/src/Application/Service/ValidationService.php create mode 100644 module/Application/src/Application/View/Helper/Service/LigneFactory.php create mode 100644 module/Application/src/Application/View/Helper/Service/ListeFactory.php create mode 100644 module/Application/src/Application/View/Helper/ServiceReferentiel/LigneFactory.php create mode 100644 module/Application/src/Application/View/Helper/ServiceReferentiel/ListeFactory.php delete mode 100644 module/Application/view/application/service-referentiel/suppression.phtml create mode 100644 module/Application/view/application/service-referentiel/supprimer.phtml create mode 100644 module/Common/src/Common/Exception/DomainException.php diff --git a/composer.lock b/composer.lock index 47e4ab049c..f5a53c8f4a 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "c4b1706ae7945df7afa01fe214591cda", + "hash": "da3eba423b417df609189e5af2dfb2ba", "packages": [ { "name": "bjyoungblood/bjy-authorize", @@ -701,7 +701,7 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", + "homepage": "http://jmsyst.com", "role": "Developer of wrapped JMSSerializerBundle" } ], @@ -1072,7 +1072,7 @@ "source": { "type": "svn", "url": "https://svn.unicaen.fr/svn/UnicaenApp", - "reference": "/trunk/@441" + "reference": "/trunk/@474" }, "require": { "doctrine/doctrine-orm-module": ">=0.7", @@ -1474,17 +1474,17 @@ }, { "name": "zendframework/zend-db", - "version": "2.3.0", + "version": "2.3.1", "target-dir": "Zend/Db", "source": { "type": "git", "url": "https://github.com/zendframework/Component_ZendDb.git", - "reference": "37d573ea83b9573e2247c36fac7b370283ca673e" + "reference": "29bb7f1ceacb32fa3e1c122bc3d14da6490aba2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/Component_ZendDb/zipball/37d573ea83b9573e2247c36fac7b370283ca673e", - "reference": "37d573ea83b9573e2247c36fac7b370283ca673e", + "url": "https://api.github.com/repos/zendframework/Component_ZendDb/zipball/29bb7f1ceacb32fa3e1c122bc3d14da6490aba2c", + "reference": "29bb7f1ceacb32fa3e1c122bc3d14da6490aba2c", "shasum": "" }, "require": { @@ -1503,8 +1503,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev", - "dev-develop": "2.3-dev" + "dev-master": "2.3-dev", + "dev-develop": "2.4-dev" } }, "autoload": { @@ -1520,7 +1520,7 @@ "db", "zf2" ], - "time": "2014-03-12 17:04:30" + "time": "2014-04-15 15:29:07" }, { "name": "zendframework/zend-escaper", @@ -2992,16 +2992,16 @@ }, { "name": "zf-commons/zfc-user", - "version": "0.1.2", + "version": "0.1.3", "source": { "type": "git", "url": "https://github.com/ZF-Commons/ZfcUser.git", - "reference": "7425ea50733caeeaeaeaa77ea7e910dab3434493" + "reference": "db5b39df5f640c86299c74f46a91869c09c9a3ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ZF-Commons/ZfcUser/zipball/7425ea50733caeeaeaeaa77ea7e910dab3434493", - "reference": "7425ea50733caeeaeaeaa77ea7e910dab3434493", + "url": "https://api.github.com/repos/ZF-Commons/ZfcUser/zipball/db5b39df5f640c86299c74f46a91869c09c9a3ed", + "reference": "db5b39df5f640c86299c74f46a91869c09c9a3ed", "shasum": "" }, "require": { @@ -3009,20 +3009,33 @@ "zendframework/zend-authentication": "~2.1", "zendframework/zend-crypt": "~2.1", "zendframework/zend-form": "~2.1", + "zendframework/zend-http": "~2.1", "zendframework/zend-inputfilter": "~2.1", "zendframework/zend-loader": "~2.1", "zendframework/zend-modulemanager": "~2.1", "zendframework/zend-mvc": "~2.1", "zendframework/zend-servicemanager": "~2.1", + "zendframework/zend-session": "~2.1", "zendframework/zend-stdlib": "~2.1", "zendframework/zend-validator": "~2.1", "zendframework/zend-view": "~2.1", "zf-commons/zfc-base": "0.*" }, + "require-dev": { + "phpmd/phpmd": "1.4.*", + "phpunit/phpunit": ">=3.7,<4", + "squizlabs/php_codesniffer": "1.4.*", + "zendframework/zend-captcha": "~2.1" + }, "suggest": { - "zendframework/zend-session": "To use the default authentication adapter." + "zendframework/zend-captcha": "Zend\\Captcha if you want to use the captcha component" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1.x-dev" + } + }, "autoload": { "psr-0": { "ZfcUser": "src/" @@ -3032,6 +3045,9 @@ ] }, "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], "authors": [ { "name": "Kyle Spraggs", @@ -3049,20 +3065,20 @@ "keywords": [ "zf2" ], - "time": "2013-05-02 12:33:31" + "time": "2014-04-17 10:31:44" }, { "name": "zf-commons/zfc-user-doctrine-orm", - "version": "0.1.2", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/ZF-Commons/ZfcUserDoctrineORM.git", - "reference": "731e7807857c6fb12f1ad7f37694dea3855a226a" + "reference": "17efcb024e8f628ba777b5bbbb6201821ac14dfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ZF-Commons/ZfcUserDoctrineORM/zipball/731e7807857c6fb12f1ad7f37694dea3855a226a", - "reference": "731e7807857c6fb12f1ad7f37694dea3855a226a", + "url": "https://api.github.com/repos/ZF-Commons/ZfcUserDoctrineORM/zipball/17efcb024e8f628ba777b5bbbb6201821ac14dfd", + "reference": "17efcb024e8f628ba777b5bbbb6201821ac14dfd", "shasum": "" }, "require": { @@ -3105,7 +3121,7 @@ "keywords": [ "zf2" ], - "time": "2014-04-04 19:57:32" + "time": "2014-04-17 19:39:44" } ], "packages-dev": [ @@ -3355,16 +3371,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.34", + "version": "3.7.35", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "248d6ce95e6ca7f0e3135252c0b984bbe1f52f19" + "reference": "83f9537e46346f75ed6925441ac259453213c7cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/248d6ce95e6ca7f0e3135252c0b984bbe1f52f19", - "reference": "248d6ce95e6ca7f0e3135252c0b984bbe1f52f19", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83f9537e46346f75ed6925441ac259453213c7cc", + "reference": "83f9537e46346f75ed6925441ac259453213c7cc", "shasum": "" }, "require": { @@ -3425,7 +3441,7 @@ "testing", "xunit" ], - "time": "2014-03-28 11:04:36" + "time": "2014-04-21 06:25:54" }, { "name": "phpunit/phpunit-mock-objects", diff --git a/doc/profils.ods b/doc/profils.ods new file mode 100644 index 0000000000000000000000000000000000000000..c6f301515d707741aaeded08c6451c3c54106da1 GIT binary patch literal 12379 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 XHNcyd4WxjJfs3JriGksyE{F#J;@z!i literal 0 HcmV?d00001 diff --git a/doc/workflow.odp b/doc/workflow.odp new file mode 100644 index 0000000000000000000000000000000000000000..3d95a4c43ab18fb7c9a73f2e351d2be0250a0cd1 GIT binary patch literal 20609 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 literal 0 HcmV?d00001 diff --git a/module/Application/Module.php b/module/Application/Module.php index 650c67cdaa..1a23103b5e 100755 --- a/module/Application/Module.php +++ b/module/Application/Module.php @@ -98,19 +98,4 @@ class Module implements ControllerPluginProviderInterface, ViewHelperProviderInt ), ); } - - /** - * - * @return array - * @see ServiceProviderInterface - */ - public function getServiceConfig() - { - return array( - 'invokables' => array( - 'ApplicationOffreFormation' => 'Application\\Service\\OffreFormation', - 'ApplicationIntervenant' => 'Application\\Service\\Intervenant', - ), - ); - } } diff --git a/module/Application/config/intervenant.config.php b/module/Application/config/intervenant.config.php index f06352328a..c684a189a0 100644 --- a/module/Application/config/intervenant.config.php +++ b/module/Application/config/intervenant.config.php @@ -105,7 +105,10 @@ return array( ), 'service_manager' => array( 'invokables' => array( - 'ApplicationIntervenant' => 'Application\\Service\\Intervenant', + 'ApplicationOffreFormation' => 'Application\\Service\\OffreFormation', + ), + 'factories' => array( + 'ApplicationIntervenant' => 'Application\\Service\\IntervenantFactory', ), ), ); \ No newline at end of file diff --git a/module/Application/config/module.config.php b/module/Application/config/module.config.php index 0035747fc9..a72e13bb82 100755 --- a/module/Application/config/module.config.php +++ b/module/Application/config/module.config.php @@ -108,7 +108,7 @@ $main = array( 'identity_providers' => array( // 200 => 'UnicaenAuth\Provider\Identity\Db', // 100 => 'UnicaenAuth\Provider\Identity\Ldap', - 50 => 'IdentityProvider' + 50 => 'ApplicationIdentityProvider' ), ), 'bjyauthorize' => array( @@ -121,32 +121,32 @@ $main = array( /** * Rôles issus de l'annuaire LDAP */ - 'UnicaenAuth\Provider\Role\Config' => array( - // intervant = rôle de base - 'intervenant' => array('name' => "Intervenant", 'children' => array( - // gestionnaires de composantes - 'cn=ucbn_composantes_responsables,ou=groups,dc=unicaen,dc=fr' => array('name' => "Responsable de composante", 'children' => array( - // directeurs de composantes - 'cn=ucbn_composantes_directeurs,ou=groups,dc=unicaen,dc=fr' => array('name' => "Directeur de composante", 'children' => array( - // administrateur de l'appli - 'cn=admin_cartagen,ou=groups,dc=unicaen,dc=fr', - )), - )), - )), - ), +// 'UnicaenAuth\Provider\Role\Config' => array( +// // intervant = rôle de base +// 'intervenant' => array('name' => "Intervenant", 'children' => array( +// // gestionnaires de composantes +// 'cn=ucbn_composantes_responsables,ou=groups,dc=unicaen,dc=fr' => array('name' => "Responsable de composante", 'children' => array( +// // directeurs de composantes +// 'cn=ucbn_composantes_directeurs,ou=groups,dc=unicaen,dc=fr' => array('name' => "Directeur de composante", 'children' => array( +// // administrateur de l'appli +//// 'cn=admin_cartagen,ou=groups,dc=unicaen,dc=fr', +// )), +// )), +// )), +// ), ), ), 'service_manager' => array( 'invokables' => array( 'Common\ORM\Event\Listeners\HistoriqueListener' => 'Common\ORM\Event\Listeners\HistoriqueListener', 'Common\ORM\Event\Listeners\ValiditeListener' => 'Common\ORM\Event\Listeners\ValiditeListener', - 'ApplicationContext' => 'Application\\Service\\Context', + 'ApplicationContextProvider' => 'Application\\Service\\ContextProvider', 'ApplicationParametres' => 'Application\\Service\\Parametres', 'ApplicationTypeIntervention' => 'Application\\Service\\TypeIntervention', - 'IdentityProvider' => 'Application\Provider\Identity\IdentityProvider', ), 'factories' => array( - 'ApplicationRoleProvider' => 'Application\Provider\Role\RoleProviderFactory', + 'ApplicationRoleProvider' => 'Application\Provider\Role\RoleProviderFactory', + 'ApplicationIdentityProvider' => 'Application\Provider\Identity\IdentityProviderFactory', ), ), 'view_helpers' => array( diff --git a/module/Application/config/service.config.php b/module/Application/config/service.config.php index 232cb2a390..89c8b52152 100644 --- a/module/Application/config/service.config.php +++ b/module/Application/config/service.config.php @@ -164,10 +164,13 @@ return array( 'service_manager' => array( 'invokables' => array( 'ApplicationService' => 'Application\\Service\\Service', - 'ApplicationServiceReferentiel' => 'Application\\Service\\ServiceReferentiel', + 'ApplicationServiceValidation' => 'Application\\Service\\ServiceValidation', 'ApplicationPeriode' => 'Application\\Service\\Periode', 'ApplicationMotifNonPaiement' => 'Application\\Service\\MotifNonPaiement', - 'FormServiceRechercheHydrator' => 'Application\Form\Service\RechercheHydrator' + 'FormServiceRechercheHydrator' => 'Application\Form\Service\RechercheHydrator', + ), + 'factories' => array( + 'ApplicationServiceReferentiel' => 'Application\\Service\\ServiceReferentielFactory', ), ), 'form_elements' => array( @@ -178,11 +181,13 @@ return array( 'view_helpers' => array( 'invokables' => array( 'serviceDl' => 'Application\View\Helper\Service\Dl', - 'serviceListe' => 'Application\View\Helper\Service\Liste', - 'serviceLigne' => 'Application\View\Helper\Service\Ligne', 'serviceReferentielDl' => 'Application\View\Helper\ServiceReferentiel\Dl', - 'serviceReferentielListe' => 'Application\View\Helper\ServiceReferentiel\Liste', - 'serviceReferentielLigne' => 'Application\View\Helper\ServiceReferentiel\Ligne', + ), + 'factories' => array( + 'serviceListe' => 'Application\View\Helper\Service\ListeFactory', + 'serviceLigne' => 'Application\View\Helper\Service\LigneFactory', + 'serviceReferentielListe' => 'Application\View\Helper\ServiceReferentiel\ListeFactory', + 'serviceReferentielLigne' => 'Application\View\Helper\ServiceReferentiel\LigneFactory', ), ), ); diff --git a/module/Application/src/Application/Acl/DbRole.php b/module/Application/src/Application/Acl/DbRole.php new file mode 100644 index 0000000000..2fd70bae82 --- /dev/null +++ b/module/Application/src/Application/Acl/DbRole.php @@ -0,0 +1,129 @@ +<?php + +namespace Application\Acl; + +use Zend\Permissions\Acl\Role\RoleInterface; +use BjyAuthorize\Acl\HierarchicalRoleInterface; +use Application\Entity\Db\TypeRole; +use Application\Entity\Db\Structure; + +class DbRole implements RoleInterface, HierarchicalRoleInterface +{ + /** + * @var TypeRole + */ + protected $typeRole; + + /** + * @var Structure + */ + protected $structure; + + /** + * @var string + */ + protected $roleId; + + /** + * @var DbRole + */ + protected $parent; + + /** + * Constructeur. + * + * @param TypeRole $typeRole + * @param Structure $structure + */ + public function __construct(TypeRole $typeRole, Structure $structure, DbRole $parent = null) + { + $this->typeRole = $typeRole; + $this->structure = $structure; + $this->parent = $parent; + } + + /** + * Retourne la représentation littérale de cet objet. + * + * @return string + */ + public function __toString() + { + return sprintf("%s (%s)", $this->getTypeRole(), $this->getStructure()); + } + + /** + * Returns the string identifier of the Role + * + * @return string + */ + public function getRoleId() + { + if (null === $this->roleId) { + $this->roleId = static::createRoleId($this->getTypeRole(), $this->getStructure()); + } + return $this->roleId; + } + + /** + * Fabrique un id de rôle au format utilisé par cette classe de rôle. + * + * @param \Application\Entity\Db\TypeRole $typeRole + * @param \Application\Entity\Db\Structure $structure + * @return string + */ + static public function createRoleId(TypeRole $typeRole, Structure $structure) + { + return sprintf("%s_%s", $typeRole->getCode(), $structure->getSourceCode()); + } + + /** + * Get the parent role + * + * @return \Zend\Permissions\Acl\Role\RoleInterface|null + */ + public function getParent() + { + return $this->parent; + } + + /** + * + * @return TypeRole + */ + public function getTypeRole() + { + return $this->typeRole; + } + + /** + * + * @return Structure + */ + public function getStructure() + { + return $this->structure; + } + + /** + * + * @param \Application\Entity\Db\TypeRole $typeRole + * @return \Application\Provider\Role\DbRole + */ + public function setTypeRole(TypeRole $typeRole) + { + $this->typeRole = $typeRole; + return $this; + } + + /** + * + * @param \Application\Entity\Db\Structure $structure + * @return \Application\Provider\Role\DbRole + */ + public function setStructure(Structure $structure) + { + $this->structure = $structure; + return $this; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Acl/IntervenantRole.php b/module/Application/src/Application/Acl/IntervenantRole.php new file mode 100644 index 0000000000..f172978655 --- /dev/null +++ b/module/Application/src/Application/Acl/IntervenantRole.php @@ -0,0 +1,29 @@ +<?php + +namespace Application\Acl; + +use UnicaenAuth\Acl\NamedRole; + +/** + * Description of IntervenantRole + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class IntervenantRole extends NamedRole +{ + const ROLE_ID = "intervenant"; + + /** + * Constructeur. + * + * @param string|null $id + * @param RoleInterface|string|null $parent + * @param string $name + * @param string $description + * @param bool $selectable + */ + public function __construct($id = null, $parent = null, $name = null, $description = null, $selectable = true) + { + parent::__construct($id = self::ROLE_ID, $parent = 'user', $name = "Intervenant", $description, $selectable); + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Controller/DemoController.php b/module/Application/src/Application/Controller/DemoController.php index 8fc8ebdd40..be0417a17d 100755 --- a/module/Application/src/Application/Controller/DemoController.php +++ b/module/Application/src/Application/Controller/DemoController.php @@ -44,7 +44,7 @@ class DemoController extends AbstractActionController return array('fs' => $fs); } - + /** * * @return \Zend\View\Model\ViewModel diff --git a/module/Application/src/Application/Controller/IntervenantController.php b/module/Application/src/Application/Controller/IntervenantController.php index fefcd2a8d0..fcc028638e 100644 --- a/module/Application/src/Application/Controller/IntervenantController.php +++ b/module/Application/src/Application/Controller/IntervenantController.php @@ -61,7 +61,9 @@ class IntervenantController extends AbstractActionController $interv->setValue($f->filter($intervenant)); } $form = new \Zend\Form\Form('search'); - $form->setAttributes(array('class' => 'intervenant-rech')); + $form->setAttributes(array( + 'action' => $this->getRequest()->getRequestUri(), + 'class' => 'intervenant-rech')); $form->add($interv); if ($this->getRequest()->isPost()) { @@ -88,16 +90,8 @@ class IntervenantController extends AbstractActionController if (!($sourceCode = $this->params()->fromQuery('sourceCode', $this->params()->fromPost('sourceCode')))) { throw new LogicException("Aucun code source d'intervenant spécifié."); } - if (($intervenant = $this->intervenant()->getRepo()->findBySourceCode($sourceCode))) { - throw new RuntimeException("L'intervenant spécifié a déjà été importé : sourceCode = $sourceCode."); - } - $import = $this->getServiceLocator()->get('importProcessusImport'); /* @var $import \Import\Processus\Import */ - $import->intervenant($sourceCode); - - if (!($intervenant = $this->intervenant()->getRepo()->findOneBySourceCode($sourceCode))) { - throw new RuntimeException("L'intervenant suivant est introuvable après import : sourceCode = $sourceCode."); - } + $intervenant = $this->getServiceLocator()->get('ApplicationIntervenant')->importer($sourceCode); $view = new \Zend\View\Model\ViewModel(); $view->setVariables(array('intervenant' => $intervenant)); diff --git a/module/Application/src/Application/Controller/Plugin/Context.php b/module/Application/src/Application/Controller/Plugin/Context.php index 2327f44ce6..82481a1eae 100644 --- a/module/Application/src/Application/Controller/Plugin/Context.php +++ b/module/Application/src/Application/Controller/Plugin/Context.php @@ -222,12 +222,12 @@ class Context extends \Zend\Mvc\Controller\Plugin\Params implements ServiceLocat } /** - * @return \Application\Service\Context + * @return \Application\Service\GlobalContext */ public function getGlobalContext() { if (null === $this->context) { - $this->context = $this->sl->get('ApplicationContext'); + $this->context = $this->sl->get('ApplicationContextProvider')->getGlobalContext(); } return $this->context; } diff --git a/module/Application/src/Application/Controller/ServiceReferentielController.php b/module/Application/src/Application/Controller/ServiceReferentielController.php index c8779b0602..587ab7fb6e 100644 --- a/module/Application/src/Application/Controller/ServiceReferentielController.php +++ b/module/Application/src/Application/Controller/ServiceReferentielController.php @@ -7,6 +7,8 @@ use Doctrine\Common\Collections\ArrayCollection; use Common\Exception\MessageException; use Common\Exception\RuntimeException; use Common\Exception\LogicException; +use Application\Service\ContextProviderAwareInterface; +use Application\Service\ContextProviderAwareTrait; use Application\Form\Service\Saisie; use Application\Entity\Db\ServiceReferentiel; use Application\Exception\DbException; @@ -21,28 +23,49 @@ use Application\Form\ServiceReferentiel\FonctionServiceReferentielFieldset; * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class ServiceReferentielController extends AbstractActionController +class ServiceReferentielController extends AbstractActionController implements ContextProviderAwareInterface { + use ContextProviderAwareTrait; + + /** + * @return \Application\Service\ServiceReferentiel + */ + public function getContextProvider() + { + return $this->getServiceLocator()->get('ApplicationContextProvider'); + } + /** - * @return \Application\Service\Service + * @return \Application\Service\ServiceReferentiel */ - public function getServiceReferentielService() + public function getServiceServiceReferentiel() { return $this->getServiceLocator()->get('ApplicationServiceReferentiel'); } + + /** + * @return \Application\Service\Intervenant + */ + public function getServiceIntervenant() + { + return $this->getServiceLocator()->get('ApplicationIntervenant'); + } public function indexAction() { - $service = $this->getServiceReferentielService(); - $context = $this->context()->getGlobalContext(); - $qb = $service->finderByContext($context); - $annee = $context->getAnnee(); - $services = $qb->getQuery()->execute(); + $service = $this->getServiceServiceReferentiel(); + $cp = $this->getContextProvider(); + $annee = $cp->getGlobalContext()->getAnnee(); + $criteria = array(); +// $criteria = array('structure' => $this->em()->find('Application\Entity\Db\Structure', 8494)); + $services = $service->getFinder($criteria) + ->orderBy("i.nomUsuel, s.libelleCourt") + ->getQuery()->execute(); $listeViewModel = new \Zend\View\Model\ViewModel(); $listeViewModel ->setTemplate('application/service-referentiel/voir-liste') - ->setVariables(compact('services', 'context')); + ->setVariables(compact('services')); $viewModel = new \Zend\View\Model\ViewModel(); $viewModel @@ -54,7 +77,7 @@ class ServiceReferentielController extends AbstractActionController public function voirAction() { - $service = $this->getServiceReferentielService(); + $service = $this->getServiceServiceReferentiel(); if (!($id = $this->params()->fromRoute('id', $this->params()->fromPost('id')))) { throw new LogicException("Aucun identifiant de service spécifié."); } @@ -67,13 +90,14 @@ class ServiceReferentielController extends AbstractActionController public function voirListeAction() { - $service = $this->getServiceReferentielService(); - $context = $this->context()->getGlobalContext(); - $qb = $service->finderByContext($context); - $annee = $context->getAnnee(); - $services = $qb->getQuery()->execute(); + $service = $this->getServiceServiceReferentiel(); + $criteria = array(); +// $criteria = array('structure' => $this->em()->find('Application\Entity\Db\Structure', 8474)); + $services = $service->getFinder($criteria) + ->orderBy("i.nomUsuel, s.libelleCourt") + ->getQuery()->execute(); - return compact('annee', 'services', 'context'); + return compact('services'); } public function voirLigneAction() @@ -81,7 +105,7 @@ class ServiceReferentielController extends AbstractActionController $id = (int)$this->params()->fromRoute('id',0); $details = 1 == (int)$this->params()->fromQuery('details',0); $onlyContent = 1 == (int)$this->params()->fromQuery('only-content',0); - $service = $this->getServiceReferentielService(); + $service = $this->getServiceServiceReferentiel(); $entity = $service->getRepo()->find($id); $context = $service->getGlobalContext(); $details = false; @@ -89,27 +113,30 @@ class ServiceReferentielController extends AbstractActionController return compact('entity', 'context', 'details', 'onlyContent'); } - public function suppressionAction() + public function supprimerAction() { - $id = (int)$this->params()->fromRoute('id',0); - $service = $this->getServiceReferentielService(); - $entity = $service->getRepo()->find($id); - $errors = array(); + $id = $this->params()->fromRoute('id'); + $entity = $this->em()->find('Application\Entity\Db\ServiceReferentiel', $id); + $title = "Suppression de service référentiel"; + $form = new \Application\Form\Supprimer('suppr'); + $viewModel = new \Zend\View\Model\ViewModel(); - try{ - $entity->setHistoDestruction(new \DateTime); - $this->em()->flush(); - }catch(\Exception $e){ - $e = DbException::translate($e); - $errors[] = $e->getMessage(); + $form->setAttribute('action', $this->getRequest()->getRequestUri()); + + if ($this->getRequest()->isPost()) { + $errors = array(); + try { + $this->getServiceServiceReferentiel()->delete($entity); + } + catch (\Exception $e){ + $e = DbException::translate($e); + $errors[] = $e->getMessage(); + } + $viewModel->setVariable('errors', $errors); } - $terminal = $this->getRequest()->isXmlHttpRequest(); - $viewModel = new \Zend\View\Model\ViewModel(); - $viewModel - ->setTemplate('application/service/suppression') - ->setVariables(compact('entity', 'context','errors')); - + $viewModel->setVariables(compact('entity', 'title', 'form')); + return $viewModel; } @@ -121,7 +148,8 @@ class ServiceReferentielController extends AbstractActionController */ protected function getIntervenant($import = true) { - $sourceCode = $this->params()->fromQuery('sourceCode'); + $sourceCode = $this->params()->fromQuery('sourceCode'); + $intervenant = null; if ($sourceCode) { // test d'existence de l'intervenant et import éventuel @@ -131,72 +159,86 @@ class ServiceReferentielController extends AbstractActionController throw new RuntimeException("Intervenant spécifié introuvable (sourceCode = $sourceCode)."); } // import de l'intervenant - $viewModel = $this->importerAction(); /* @var $viewModel \Zend\View\Model\ViewModel */ - $intervenant = $viewModel->getVariable('intervenant'); + $intervenant = $this->getServiceLocator()->get('ApplicationIntervenant')->importer($sourceCode); } return $intervenant; } - $context = $this->context()->getGlobalContext(); + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); - if (!($intervenant = $context->getIntervenant())) { - throw new RuntimeException("Aucun intervenant spécifié dans le contexte."); + if ($role instanceof \Application\Acl\IntervenantRole) { + $intervenant = $context->getIntervenant(); } return $intervenant; } + /** + * Redirection vers le choix d'un intervenant (action qui redirigera vers l'action + * courante une fois l'intervenant choisi). + * + * @param \Application\Entity\Db\Intervenant $intervenant Intervenant pré-choisi + * @return \Zend\Http\Response + */ + protected function redirectToChoisirIntervenant(\Application\Entity\Db\Intervenant $intervenant = null) + { + $modal = $this->params()->fromQuery('modal'); + $redirect = $this->url()->fromRoute( + null, + array(), + array('query' => array('sourceCode' => '__sourceCode__', 'modal' => $modal)), + true); + + if ($intervenant) { + $intervenant = $intervenant->getSourceCode(); + } + + return $this->redirect()->toRoute( + 'intervenant/default', + array('action' => 'choisir'), + array('query' => array('intervenant' => $intervenant, 'redirect' => $redirect, 'modal' => $modal))); + } + /** * * @return \Zend\View\Model\ViewModel */ public function saisirAction() { - $sourceCode = $this->params()->fromQuery('sourceCode'); $import = $this->params()->fromQuery('import', true); - $service = $this->getServiceReferentielService(); - $context = $this->context()->getGlobalContext(); + $context = $this->getContextProvider()->getGlobalContext(); $isAjax = $this->getRequest()->isXmlHttpRequest(); $intervenant = $this->getIntervenant($import); // si aucun intervenant spécifié, redirection vers le choix d'un intervenant (action qui redirigera ici une fois l'intervenant choisi) if (!$intervenant) { - if ($isAjax) { - throw new RuntimeException("Aucun intervenant spécifié."); - } - $redirect = $this->url()->fromRoute('intervenant/default', array(), array('query' => array('sourceCode' => '__sourceCode__')), true); - return $this->redirect()->toRoute( - 'intervenant/default', array('action' => 'choisir'), array('query' => array('redirect' => $redirect))); + return $this->redirectToChoisirIntervenant(); } - // verif type d'intervenant - if (!$intervenant instanceof IntervenantPermanent) { - $message = "La saisie de service référentiel n'est possible que pour les intervenants permanents."; - if ($isAjax) { - throw new MessageException($message); - } + // verifications concernant l'intervenant + try { + $this->getServiceIntervenant()->checkIntervenantForServiceReferentiel($intervenant); + } + catch (\Common\Exception\DomainException $exc) { + $message = $exc->getMessage(); $this->flashMessenger()->addErrorMessage($message); - $redirect = $this->url()->fromRoute('intervenant/default', array(), array('query' => array('sourceCode' => '__sourceCode__')), true); - return $this->redirect()->toRoute('intervenant/default', - array('action' => 'choisir'), - array('query' => array('intervenant' => $intervenant->getId(), 'redirect' => $redirect))); + + return $this->redirectToChoisirIntervenant($intervenant); } - // fetch avec jointures - $qb = $this->em()->getRepository('Application\Entity\Db\IntervenantPermanent')->createQueryBuilder('ip'); - $qb - ->leftJoin('ip.serviceReferentiel', 'sr') - ->leftJoin('sr.fonction', 'fr') - ->where('ip.id = :id') - ->orderBy('sr.id') - ->setParameter('id', $intervenant->getId()); /* @var $intervenant IntervenantPermanent */ - $intervenant = $qb->getQuery()->getOneOrNullResult(); - $this->em()->getFilters()->enable("historique"); +// var_dump(get_class($intervenant)); + + // fetch intervenant avec jointures + $qb = $this->getServiceIntervenant()->getFinderIntervenantPermanentWithServiceReferentiel(); + $qb->setIntervenant($intervenant); + $intervenant = $qb->getQuery()->getOneOrNullResult(); +// var_dump($qb->getQuery()->getDQL(), $qb->getQuery()->getParameters()); $repoFonctionReferentiel = $this->em()->getRepository('Application\Entity\Db\FonctionReferentiel'); /* @var $repoFonctionReferentiel \Doctrine\ORM\EntityRepository */ - $repoElementPedagogique = $this->em()->getRepository('Application\Entity\Db\ElementPedagogique'); /* @var $repoElementPedagogique \Application\Entity\Db\Repository\ElementPedagogiqueRepository */ + $repoElementPedagogique = $this->em()->getRepository('Application\Entity\Db\ElementPedagogique'); /* @var $repoElementPedagogique \Application\Entity\Db\Repository\ElementPedagogiqueRepository */ $annee = $context->getAnnee(); @@ -219,7 +261,7 @@ class ServiceReferentielController extends AbstractActionController } $form = new \Application\Form\ServiceReferentiel\AjouterModifier(); - $form->setAttribute('action', $this->url()->fromRoute(null, array(), array(), true)); + $form->setAttribute('action', $this->getRequest()->getRequestUri()); $form->getBaseFieldset()->getHydrator()->setAnnee($annee); $form->bind($intervenant); diff --git a/module/Application/src/Application/Entity/Db/Finder/AbstractFinder.php b/module/Application/src/Application/Entity/Db/Finder/AbstractFinder.php new file mode 100644 index 0000000000..97991c80d0 --- /dev/null +++ b/module/Application/src/Application/Entity/Db/Finder/AbstractFinder.php @@ -0,0 +1,64 @@ +<?php + +namespace Application\Entity\Db\Finder; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use Application\Service\ContextProviderAwareTrait; +use Application\Service\ContextProvider; + +/** + * Description of Intervenant + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +abstract class AbstractFinder extends QueryBuilder +{ + use ContextProviderAwareTrait; + + protected $queryCreated = false; + protected $globalContextApplied = false; + + /** + * + * @param EntityManager $em + * @param ContextProvider $contextProvider + */ + public function __construct(EntityManager $em, ContextProvider $contextProvider = null) + { + parent::__construct($em); + + $this->setContextProvider($contextProvider); + } + + /** + * + * @return self + */ + abstract protected function createQuery(); + + /** + * + * @return self + */ + abstract protected function applyGlobalContext(); + + /** + * + * @return Query + */ + public function getQuery() + { + if (!$this->queryCreated) { + $this->createQuery(); + $this->queryCreated = true; + } + if (!$this->globalContextApplied) { + $this->applyGlobalContext(); + $this->globalContextApplied = true; + } + + return parent::getQuery(); + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Entity/Db/Finder/FinderIntervenantPermanentWithServiceReferentiel.php b/module/Application/src/Application/Entity/Db/Finder/FinderIntervenantPermanentWithServiceReferentiel.php new file mode 100644 index 0000000000..8866cd5c07 --- /dev/null +++ b/module/Application/src/Application/Entity/Db/Finder/FinderIntervenantPermanentWithServiceReferentiel.php @@ -0,0 +1,84 @@ +<?php + +namespace Application\Entity\Db\Finder; + +use Application\Acl\DbRole; +use Application\Acl\IntervenantRole; +use Application\Entity\Db\IntervenantPermanent; + +/** + * Requêteur contextualisé d'intervenants permanents. + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + * @see \Application\Service\ContextProvider + */ +class FinderIntervenantPermanentWithServiceReferentiel extends AbstractFinder +{ + /** + * + * @param int|IntervenantPermanent $intervenant + * @return self + */ + public function setIntervenant($intervenant) + { + if ($intervenant instanceof IntervenantPermanent) { + $intervenant = $intervenant->getId(); + } + + $this + ->andWhere('i.id = :id') + ->setParameter('id', $intervenant); + + return $this; + } + + /** + * + * @return self + */ + protected function createQuery() + { + $this + ->select('i') + ->from('Application\Entity\Db\IntervenantPermanent', 'i') + ->leftJoin('i.serviceReferentiel', 'sr') + ->leftJoin('sr.fonction', 'fr') + ->leftJoin('sr.structure', 's') + ->orderBy('s.libelleCourt'); + + return $this; + } + + /** + * + * @return self + */ + protected function applyGlobalContext() + { + if (!$this->getContextProvider()) { + return $this; + } + + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + + if ($role instanceof IntervenantRole) { +// $this +// ->andWhere("sr.intervenant = :intervenant") +// ->setParameter('intervenant', $context->getIntervenant()); + } + elseif ($role instanceof DbRole) { + $this + ->andWhere("sr.structure = :structureResp") + ->setParameter('structureResp', $role->getStructure()); + } + + if (($annee = $context->getAnnee())) { + $this + ->andWhere("sr.annee = :annee or sr.annee is null") // because left join + ->setParameter('annee', $annee); + } + + return $this; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Entity/Db/Finder/FinderServiceReferentiel.php b/module/Application/src/Application/Entity/Db/Finder/FinderServiceReferentiel.php new file mode 100644 index 0000000000..4ea18772ea --- /dev/null +++ b/module/Application/src/Application/Entity/Db/Finder/FinderServiceReferentiel.php @@ -0,0 +1,66 @@ +<?php + +namespace Application\Entity\Db\Finder; + +use Application\Acl\DbRole; +use Application\Acl\IntervenantRole; + +/** + * Requêteur contextualisé de services référentiels. + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + * @see \Application\Service\ContextProvider + */ +class FinderServiceReferentiel extends AbstractFinder +{ + /** + * + * @return self + */ + protected function createQuery() + { + $this + ->select('sr') + ->from("Application\Entity\Db\ServiceReferentiel", 'sr') + ->join("sr.structure", 's') + ->join("sr.intervenant", 'i') + ->join("sr.fonction", 'f') + ->orderBy("i.nomUsuel, s.libelleCourt"); + + return $this; + } + + /** + * + * @return self + */ + protected function applyGlobalContext() + { + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + + if ($role instanceof IntervenantRole) { + $this + ->andWhere("sr.intervenant = :intervenant") + ->setParameter('intervenant', $context->getIntervenant()); + } + elseif ($role instanceof DbRole) { + $e = $this->expr()->orX( + "sr.structure = :structureResp", + "s2.structureNiv2 = :structureResp" + ); + $this + ->join("i.structure", 's2') + ->andWhere($e) + ->setParameter('structureResp', $role->getStructure()); + } + + if (($annee = $context->getAnnee())) { + $this + ->andWhere("sr.annee = :annee") + ->setParameter('annee', $annee); + } + + return $this; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Personnel.dcm.xml b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Personnel.dcm.xml index 35af21769b..7cfc603d4a 100644 --- a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Personnel.dcm.xml +++ b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Personnel.dcm.xml @@ -55,5 +55,6 @@ <join-column name="CIVILITE_ID" referenced-column-name="ID"/> </join-columns> </many-to-one> + <one-to-many field="role" target-entity="Application\Entity\Db\Role" mapped-by="personnel" /> </entity> </doctrine-mapping> diff --git a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Service.dcm.xml b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Service.dcm.xml index 45aba4759c..8bca68ed46 100644 --- a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Service.dcm.xml +++ b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.Service.dcm.xml @@ -68,7 +68,8 @@ <join-column name="ANNEE_ID" referenced-column-name="ID"/> </join-columns> </many-to-one> - <!-- NB: Ajout de la relation Volume horaire à la main --> + <!-- NB: Ajout de relations à la main --> <one-to-many field="volumeHoraire" target-entity="Application\Entity\Db\VolumeHoraire" mapped-by="service" /> + <one-to-many field="validationService" target-entity="Application\Entity\Db\ValidationService" mapped-by="service" /> </entity> </doctrine-mapping> diff --git a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.TypeRole.dcm.xml b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.TypeRole.dcm.xml index 24a23156ca..1b60f5aeed 100644 --- a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.TypeRole.dcm.xml +++ b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.TypeRole.dcm.xml @@ -34,5 +34,6 @@ <join-column name="HISTO_CREATEUR_ID" referenced-column-name="ID"/> </join-columns> </many-to-one> + <one-to-many field="role" target-entity="Application\Entity\Db\Role" mapped-by="type" /> </entity> </doctrine-mapping> diff --git a/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.ValidationService.dcm.xml b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.ValidationService.dcm.xml new file mode 100644 index 0000000000..e20024de03 --- /dev/null +++ b/module/Application/src/Application/Entity/Db/Mapping/Application.Entity.Db.ValidationService.dcm.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + <entity name="Application\Entity\Db\ValidationService" table="VALIDATION_SERVICE"> + <indexes> + <index name="IDX_E59109EDE8EF239" columns="SERVICE_ID"/> + <index name="IDX_E59109E59860CDC" columns="HISTO_CREATEUR_ID"/> + <index name="IDX_E59109E7E9E2204" columns="HISTO_DESTRUCTEUR_ID"/> + <index name="IDX_E59109E63F06898" columns="HISTO_MODIFICATEUR_ID"/> + </indexes> + <id name="id" type="integer" column="ID"> + <generator strategy="SEQUENCE"/> + </id> + <field name="commentaires" type="string" column="COMMENTAIRES" length="200" nullable="true"/> + <field name="dateConseil" type="datetime" column="DATE_CONSEIL" nullable="true"/> + <field name="description" type="string" column="DESCRIPTION" length="200" nullable="false"/> + <field name="histoCreation" type="datetime" column="HISTO_CREATION" nullable="false"/> + <field name="histoDestruction" type="datetime" column="HISTO_DESTRUCTION" nullable="true"/> + <field name="histoModification" type="datetime" column="HISTO_MODIFICATION" nullable="false"/> + <field name="ordre" type="integer" column="ORDRE" nullable="true"/> + <many-to-one field="histoModificateur" target-entity="Application\Entity\Db\Utilisateur"> + <join-columns> + <join-column name="HISTO_MODIFICATEUR_ID" referenced-column-name="ID"/> + </join-columns> + </many-to-one> + <many-to-one field="histoDestructeur" target-entity="Application\Entity\Db\Utilisateur"> + <join-columns> + <join-column name="HISTO_DESTRUCTEUR_ID" referenced-column-name="ID"/> + </join-columns> + </many-to-one> + <many-to-one field="histoCreateur" target-entity="Application\Entity\Db\Utilisateur"> + <join-columns> + <join-column name="HISTO_CREATEUR_ID" referenced-column-name="ID"/> + </join-columns> + </many-to-one> + <many-to-one field="service" target-entity="Application\Entity\Db\Service"> + <join-columns> + <join-column name="SERVICE_ID" referenced-column-name="ID"/> + </join-columns> + </many-to-one> + </entity> +</doctrine-mapping> diff --git a/module/Application/src/Application/Entity/Db/Personnel.php b/module/Application/src/Application/Entity/Db/Personnel.php index da80cf3082..59f9e11f79 100644 --- a/module/Application/src/Application/Entity/Db/Personnel.php +++ b/module/Application/src/Application/Entity/Db/Personnel.php @@ -2,33 +2,18 @@ namespace Application\Entity\Db; -use Doctrine\ORM\Mapping as ORM; - /** * Personnel */ -class Personnel +class Personnel implements HistoriqueAwareInterface { + use HistoriqueAwareTrait; + /** * @var string */ protected $email; - /** - * @var \DateTime - */ - protected $histoCreation; - - /** - * @var \DateTime - */ - protected $histoDestruction; - - /** - * @var \DateTime - */ - protected $histoModification; - /** * @var string */ @@ -75,25 +60,22 @@ class Personnel protected $structure; /** - * @var \Application\Entity\Db\Utilisateur - */ - protected $histoModificateur; - - /** - * @var \Application\Entity\Db\Utilisateur + * @var \Application\Entity\Db\Civilite */ - protected $histoDestructeur; + protected $civilite; /** - * @var \Application\Entity\Db\Utilisateur + * @var \Doctrine\Common\Collections\Collection */ - protected $histoCreateur; + protected $role; /** - * @var \Application\Entity\Db\Civilite + * */ - protected $civilite; - + public function __construct() + { + $this->role = new \Doctrine\Common\Collections\ArrayCollection(); + } /** * Set email @@ -118,75 +100,6 @@ class Personnel return $this->email; } - /** - * Set histoCreation - * - * @param \DateTime $histoCreation - * @return Personnel - */ - public function setHistoCreation($histoCreation) - { - $this->histoCreation = $histoCreation; - - return $this; - } - - /** - * Get histoCreation - * - * @return \DateTime - */ - public function getHistoCreation() - { - return $this->histoCreation; - } - - /** - * Set histoDestruction - * - * @param \DateTime $histoDestruction - * @return Personnel - */ - public function setHistoDestruction($histoDestruction) - { - $this->histoDestruction = $histoDestruction; - - return $this; - } - - /** - * Get histoDestruction - * - * @return \DateTime - */ - public function getHistoDestruction() - { - return $this->histoDestruction; - } - - /** - * Set histoModification - * - * @param \DateTime $histoModification - * @return Personnel - */ - public function setHistoModification($histoModification) - { - $this->histoModification = $histoModification; - - return $this; - } - - /** - * Get histoModification - * - * @return \DateTime - */ - public function getHistoModification() - { - return $this->histoModification; - } - /** * Set nomPatronymique * @@ -382,94 +295,58 @@ class Personnel } /** - * Set histoModificateur - * - * @param \Application\Entity\Db\Utilisateur $histoModificateur - * @return Personnel - */ - public function setHistoModificateur(\Application\Entity\Db\Utilisateur $histoModificateur = null) - { - $this->histoModificateur = $histoModificateur; - - return $this; - } - - /** - * Get histoModificateur - * - * @return \Application\Entity\Db\Utilisateur - */ - public function getHistoModificateur() - { - return $this->histoModificateur; - } - - /** - * Set histoDestructeur + * Set civilite * - * @param \Application\Entity\Db\Utilisateur $histoDestructeur + * @param \Application\Entity\Db\Civilite $civilite * @return Personnel */ - public function setHistoDestructeur(\Application\Entity\Db\Utilisateur $histoDestructeur = null) + public function setCivilite(\Application\Entity\Db\Civilite $civilite = null) { - $this->histoDestructeur = $histoDestructeur; + $this->civilite = $civilite; return $this; } /** - * Get histoDestructeur + * Get civilite * - * @return \Application\Entity\Db\Utilisateur + * @return \Application\Entity\Db\Civilite */ - public function getHistoDestructeur() + public function getCivilite() { - return $this->histoDestructeur; + return $this->civilite; } /** - * Set histoCreateur + * Add role * - * @param \Application\Entity\Db\Utilisateur $histoCreateur - * @return Personnel + * @param \Application\Entity\Db\Role $role + * @return TypeRole */ - public function setHistoCreateur(\Application\Entity\Db\Utilisateur $histoCreateur = null) + public function addRole(\Application\Entity\Db\Role $role) { - $this->histoCreateur = $histoCreateur; + $this->role[] = $role; return $this; } /** - * Get histoCreateur - * - * @return \Application\Entity\Db\Utilisateur - */ - public function getHistoCreateur() - { - return $this->histoCreateur; - } - - /** - * Set civilite + * Remove role * - * @param \Application\Entity\Db\Civilite $civilite - * @return Personnel + * @param \Application\Entity\Db\Role $role */ - public function setCivilite(\Application\Entity\Db\Civilite $civilite = null) + public function removeRole(\Application\Entity\Db\Role $role) { - $this->civilite = $civilite; - - return $this; + $this->role->removeElement($role); } /** - * Get civilite + * Get role * - * @return \Application\Entity\Db\Civilite + * @return \Doctrine\Common\Collections\Collection */ - public function getCivilite() + public function getRole() { - return $this->civilite; + return $this->role; } } diff --git a/module/Application/src/Application/Entity/Db/Repository/IntervenantRepository.php b/module/Application/src/Application/Entity/Db/Repository/IntervenantRepository.php index 9f0701b55c..b5b3c1aef8 100644 --- a/module/Application/src/Application/Entity/Db/Repository/IntervenantRepository.php +++ b/module/Application/src/Application/Entity/Db/Repository/IntervenantRepository.php @@ -12,20 +12,6 @@ use Doctrine\ORM\EntityRepository; */ class IntervenantRepository extends EntityRepository { - /** - * Recherche par : - * - id source exact (numéro Harpege ou autre), - * - ou nom usuel (et prénom), - * - ou nom patronymique (et prénom). - * - * @param string $term - * @return \Application\Entity\Db\Intervenant[] - */ - public function findByNomPrenomIdQueryBuilder($term) - { - - } - /** * Recherche par : * - id source exact (numéro Harpege ou autre), @@ -69,4 +55,4 @@ class IntervenantRepository extends EntityRepository return $qb->getQuery()->execute(); } -} \ No newline at end of file +} diff --git a/module/Application/src/Application/Entity/Db/Repository/ServiceReferentielRepository.php b/module/Application/src/Application/Entity/Db/Repository/ServiceReferentielRepository.php index ab9eefaf51..a16dc1c36d 100644 --- a/module/Application/src/Application/Entity/Db/Repository/ServiceReferentielRepository.php +++ b/module/Application/src/Application/Entity/Db/Repository/ServiceReferentielRepository.php @@ -3,11 +3,6 @@ namespace Application\Entity\Db\Repository; use Doctrine\ORM\EntityRepository; -use Common\Exception\RuntimeException; -use Common\Exception\InvalidArgumentException; -use Application\Entity\Db\Intervenant; -use Application\Entity\Db\IntervenantPermanent; -use Application\Entity\Db\Annee; /** * ServiceReferentielRepository @@ -17,101 +12,5 @@ use Application\Entity\Db\Annee; */ class ServiceReferentielRepository extends EntityRepository { - /** - * - * @param \Application\Entity\Db\Intervenant $intervenant - * @param \Application\Entity\Db\Annee $annee - * @param type $data - * @return \Application\Entity\Db\Repository\ServiceReferentielRepository - */ - public function createServiceReferentiel(Intervenant $intervenant, Annee $annee, $data) - { - $data = $this->normalizeServiceReferentielUpdateData($data); - - $sr = new \Application\Entity\Db\ServiceReferentiel(); - $sr - ->setAnnee($annee) - ->setFonction($data['fonction']) - ->setHeures($data['heures']) - ->setIntervenant($intervenant); - - $intervenant->addServiceReferentiel($sr); - - $this->getEntityManager()->persist($sr); - - return $this; - } - /** - * - * @param \Application\Entity\Db\Intervenant $intervenant - * @param \Application\Entity\Db\Annee $annee - * @return \Application\Entity\Db\Repository\ServiceReferentielRepository - * @throws InvalidArgumentException - */ - public function updateServicesReferentiel(Intervenant $intervenant, Annee $annee, array $data = array()) - { - if (!$intervenant instanceof IntervenantPermanent) { - throw new InvalidArgumentException("Impossible de saisir un service référentiel pour un intervenant autre que permanent. " . - "Intervenant spécifié : $intervenant (id = {$intervenant->getId()})."); - } - - $em = $this->getEntityManager(); - - $em->getConnection()->beginTransaction(); - try { - foreach ($intervenant->getServiceReferentiel($annee) as $serviceReferentiel) { - $intervenant->removeServiceReferentiel($serviceReferentiel); - $em->remove($serviceReferentiel); - } - $em->flush(); - if ($data) { - foreach ($data as $value) { - $this->createServiceReferentiel($intervenant, $annee, $value); - } - $em->flush(); - } - $em->getConnection()->commit(); - } - catch (\Exception $e) { - $em->getConnection()->rollback(); - $em->close(); - throw $e; - } - - return $this; - } - - /** - * - * @param array $data - * @return array - * @throws InvalidArgumentException - * @throws RuntimeException - */ - protected function normalizeServiceReferentielUpdateData($data) - { - if (!is_array($data)) { - throw new InvalidArgumentException("Un tableau est attendu."); - } - if (!isset($data[$key = 'fonction'])) { - throw new InvalidArgumentException("Clé '$key' introuvable dans les données spécifiées."); - } - if (!isset($data[$key = 'heures'])) { - throw new InvalidArgumentException("Clé '$key' introuvable dans les données spécifiées."); - } - - $fonctionId = $data['fonction']; - $heures = $data['heures']; - - $f = $this->getEntityManager()->getRepository('Application\Entity\Db\FonctionReferentiel')->find($fonctionId); - if (!$f) { - throw new RuntimeException("Fonction référentiel introuvable avec l'id '$fonctionId'."); - } - - return array( - 'fonction' => $f, - 'heures' => (float) $heures, - ); - } } \ No newline at end of file diff --git a/module/Application/src/Application/Entity/Db/TypeRole.php b/module/Application/src/Application/Entity/Db/TypeRole.php index 68103ad741..f504d17f8f 100644 --- a/module/Application/src/Application/Entity/Db/TypeRole.php +++ b/module/Application/src/Application/Entity/Db/TypeRole.php @@ -11,26 +11,6 @@ class TypeRole implements HistoriqueAwareInterface, RoleInterface { use HistoriqueAwareTrait; - /** - * Returns the string identifier of the Role - * - * @return string - */ - public function getRoleId() - { - return $this->getCode(); - } - - /** - * Retourne la représentation littérale de cet objet. - * - * @return string - */ - public function __toString() - { - return $this->getLibelle(); - } - /** * @var string */ @@ -61,6 +41,34 @@ class TypeRole implements HistoriqueAwareInterface, RoleInterface */ protected $role; + /** + * + */ + public function __construct() + { + $this->role = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Returns the string identifier of the Role + * + * @return string + */ + public function getRoleId() + { + return $this->getCode(); + } + + /** + * Retourne la représentation littérale de cet objet. + * + * @return string + */ + public function __toString() + { + return $this->getLibelle(); + } + /** * Set code * diff --git a/module/Application/src/Application/Entity/Db/Utilisateur.php b/module/Application/src/Application/Entity/Db/Utilisateur.php index 6d38105693..7b5c5f65bf 100644 --- a/module/Application/src/Application/Entity/Db/Utilisateur.php +++ b/module/Application/src/Application/Entity/Db/Utilisateur.php @@ -2,7 +2,6 @@ namespace Application\Entity\Db; -use Doctrine\ORM\Mapping as ORM; use BjyAuthorize\Provider\Role\ProviderInterface; use ZfcUser\Entity\UserInterface; diff --git a/module/Application/src/Application/Entity/Db/ValidationService.php b/module/Application/src/Application/Entity/Db/ValidationService.php new file mode 100644 index 0000000000..dcdad96193 --- /dev/null +++ b/module/Application/src/Application/Entity/Db/ValidationService.php @@ -0,0 +1,335 @@ +<?php + +namespace Application\Entity\Db; + +use Doctrine\ORM\Mapping as ORM; + +/** + * ValidationService + */ +class ValidationService implements HistoriqueAwareInterface +{ + /** + * @var string + */ + protected $commentaires; + + /** + * @var \DateTime + */ + protected $dateConseil; + + /** + * @var string + */ + protected $description; + + /** + * @var \DateTime + */ + protected $histoCreation; + + /** + * @var \DateTime + */ + protected $histoDestruction; + + /** + * @var \DateTime + */ + protected $histoModification; + + /** + * @var integer + */ + protected $ordre; + + /** + * @var integer + */ + protected $id; + + /** + * @var \Application\Entity\Db\Utilisateur + */ + protected $histoModificateur; + + /** + * @var \Application\Entity\Db\Utilisateur + */ + protected $histoDestructeur; + + /** + * @var \Application\Entity\Db\Utilisateur + */ + protected $histoCreateur; + + /** + * @var \Application\Entity\Db\Service + */ + protected $service; + + + /** + * Set commentaires + * + * @param string $commentaires + * @return ValidationService + */ + public function setCommentaires($commentaires) + { + $this->commentaires = $commentaires; + + return $this; + } + + /** + * Get commentaires + * + * @return string + */ + public function getCommentaires() + { + return $this->commentaires; + } + + /** + * Set dateConseil + * + * @param \DateTime $dateConseil + * @return ValidationService + */ + public function setDateConseil($dateConseil) + { + $this->dateConseil = $dateConseil; + + return $this; + } + + /** + * Get dateConseil + * + * @return \DateTime + */ + public function getDateConseil() + { + return $this->dateConseil; + } + + /** + * Set description + * + * @param string $description + * @return ValidationService + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * Get description + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set histoCreation + * + * @param \DateTime $histoCreation + * @return ValidationService + */ + public function setHistoCreation($histoCreation) + { + $this->histoCreation = $histoCreation; + + return $this; + } + + /** + * Get histoCreation + * + * @return \DateTime + */ + public function getHistoCreation() + { + return $this->histoCreation; + } + + /** + * Set histoDestruction + * + * @param \DateTime $histoDestruction + * @return ValidationService + */ + public function setHistoDestruction($histoDestruction) + { + $this->histoDestruction = $histoDestruction; + + return $this; + } + + /** + * Get histoDestruction + * + * @return \DateTime + */ + public function getHistoDestruction() + { + return $this->histoDestruction; + } + + /** + * Set histoModification + * + * @param \DateTime $histoModification + * @return ValidationService + */ + public function setHistoModification($histoModification) + { + $this->histoModification = $histoModification; + + return $this; + } + + /** + * Get histoModification + * + * @return \DateTime + */ + public function getHistoModification() + { + return $this->histoModification; + } + + /** + * Set ordre + * + * @param integer $ordre + * @return ValidationService + */ + public function setOrdre($ordre) + { + $this->ordre = $ordre; + + return $this; + } + + /** + * Get ordre + * + * @return integer + */ + public function getOrdre() + { + return $this->ordre; + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set histoModificateur + * + * @param \Application\Entity\Db\Utilisateur $histoModificateur + * @return ValidationService + */ + public function setHistoModificateur(\Application\Entity\Db\Utilisateur $histoModificateur = null) + { + $this->histoModificateur = $histoModificateur; + + return $this; + } + + /** + * Get histoModificateur + * + * @return \Application\Entity\Db\Utilisateur + */ + public function getHistoModificateur() + { + return $this->histoModificateur; + } + + /** + * Set histoDestructeur + * + * @param \Application\Entity\Db\Utilisateur $histoDestructeur + * @return ValidationService + */ + public function setHistoDestructeur(\Application\Entity\Db\Utilisateur $histoDestructeur = null) + { + $this->histoDestructeur = $histoDestructeur; + + return $this; + } + + /** + * Get histoDestructeur + * + * @return \Application\Entity\Db\Utilisateur + */ + public function getHistoDestructeur() + { + return $this->histoDestructeur; + } + + /** + * Set histoCreateur + * + * @param \Application\Entity\Db\Utilisateur $histoCreateur + * @return ValidationService + */ + public function setHistoCreateur(\Application\Entity\Db\Utilisateur $histoCreateur = null) + { + $this->histoCreateur = $histoCreateur; + + return $this; + } + + /** + * Get histoCreateur + * + * @return \Application\Entity\Db\Utilisateur + */ + public function getHistoCreateur() + { + return $this->histoCreateur; + } + + /** + * Set service + * + * @param \Application\Entity\Db\Service $service + * @return ValidationService + */ + public function setService(\Application\Entity\Db\Service $service = null) + { + $this->service = $service; + + return $this; + } + + /** + * Get service + * + * @return \Application\Entity\Db\Service + */ + public function getService() + { + return $this->service; + } +} diff --git a/module/Application/src/Application/Form/Service/Saisie.php b/module/Application/src/Application/Form/Service/Saisie.php index 01870fa8c7..0538ab557b 100644 --- a/module/Application/src/Application/Form/Service/Saisie.php +++ b/module/Application/src/Application/Form/Service/Saisie.php @@ -32,7 +32,9 @@ class Saisie extends Form implements \Zend\InputFilter\InputFilterProviderInterf { parent::__construct('service'); - $this->etablissement = $serviceLocator->get('applicationContext')->etablissement; + $globalContext = $serviceLocator->get('ApplicationContextProvider')->getGlobalContext(); + + $this->etablissement = $globalContext->getEtablissement(); $this ->setAttribute('method', 'post') ->setAttribute('class', 'service') diff --git a/module/Application/src/Application/Provider/Identity/IdentityProvider.php b/module/Application/src/Application/Provider/Identity/IdentityProvider.php index 3e9aeea2ae..9266a8602e 100644 --- a/module/Application/src/Application/Provider/Identity/IdentityProvider.php +++ b/module/Application/src/Application/Provider/Identity/IdentityProvider.php @@ -1,20 +1,41 @@ <?php namespace Application\Provider\Identity; +use Zend\ServiceManager\ServiceLocatorAwareInterface; +use Zend\ServiceManager\ServiceLocatorAwareTrait; +use Doctrine\ORM\EntityManager; use UnicaenAuth\Provider\Identity\ChainableProvider; +use UnicaenApp\Service\EntityManagerAwareInterface; +use Application\Acl\IntervenantRole; +use Application\Acl\DbRole; +use UnicaenApp\Service\EntityManagerAwareTrait; /** - * Classe de fournisseur d'identité issue de l'annuaire Ldap. - * - * Retourne les rôles correspondant aux groupes LDAP auxquels appartient l'entité LDAP authentifiée. - * NB : - * - Les ACL sont fournies par le service d'authorisation du module BjyAuthorize - * - L'identité authentifiée est fournie par le service d'authentification. + * Classe chargée de fournir les rôles que possède l'identité authentifiée. * * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> */ -class IdentityProvider implements ChainableProvider +class IdentityProvider implements ServiceLocatorAwareInterface, ChainableProvider, EntityManagerAwareInterface { + use ServiceLocatorAwareTrait; + use EntityManagerAwareTrait; + + /** + * @var array + */ + protected $roles; + + /** + * Constructeur. + * + * @param EntityManager $entityManager + */ + public function __construct(EntityManager $entityManager) + { + $this->setEntityManager($entityManager); + $this->getEntityManager()->getFilters()->enable('historique'); + } + /** * {@inheritDoc} */ @@ -28,6 +49,47 @@ class IdentityProvider implements ChainableProvider */ public function getIdentityRoles() { - return array('intervenant'); + if (null === $this->roles) { + $this->roles = array(); + + if (!$this->getServiceLocator()->get('AuthUserContext')->getIdentity()) { + return $this->roles; + } + + /** + * Rôles que possède l'utilisateur dans la base de données. + */ + $this->roles = array_merge($this->roles, $this->getDbRoles()); + + /** + * Tout le monde possède le rôle "intervenant" + */ + $this->roles[] = new IntervenantRole(); + } + +// var_dump($this->roles); + + return $this->roles; + } + + /** + * Fetch dans la base de données les rôles que possède l'utilisateur sur une structure précise. + * + * @return array Id des rôles trouvés + */ + protected function getDbRoles() + { + $dbUser = $this->getServiceLocator()->get('AuthUserContext')->getDbUser(); /* @var $dbUser \Application\Entity\Db\Utilisateur */ + + if (!$dbUser) { + return array(); + } + + $roles = array(); + foreach ($dbUser->getPersonnel()->getRole() as $role) { /* @var $role \Application\Entity\Db\Role */ + $roles[] = new DbRole($role->getType(), $role->getStructure()); + } + + return $roles; } } \ No newline at end of file diff --git a/module/Application/src/Application/Provider/Identity/IdentityProviderFactory.php b/module/Application/src/Application/Provider/Identity/IdentityProviderFactory.php new file mode 100644 index 0000000000..12b1e9f1fa --- /dev/null +++ b/module/Application/src/Application/Provider/Identity/IdentityProviderFactory.php @@ -0,0 +1,27 @@ +<?php + +namespace Application\Provider\Identity; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class IdentityProviderFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return Acteur + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $em = $serviceLocator->get('doctrine.entitymanager.orm_default'); /* @var $em \Doctrine\ORM\EntityManager */ + + return new IdentityProvider($em); + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Provider/Role/RoleProvider.php b/module/Application/src/Application/Provider/Role/RoleProvider.php index 1aac3f33cb..01968063e4 100644 --- a/module/Application/src/Application/Provider/Role/RoleProvider.php +++ b/module/Application/src/Application/Provider/Role/RoleProvider.php @@ -4,21 +4,21 @@ namespace Application\Provider\Role; use BjyAuthorize\Provider\Role\ProviderInterface; use Doctrine\ORM\EntityManager; -use UnicaenAuth\Acl\NamedRole; +use UnicaenApp\Service\EntityManagerAwareInterface; +use UnicaenApp\Service\EntityManagerAwareTrait; +use Application\Acl\IntervenantRole; +use Application\Acl\DbRole; /** - * Fournisseur de tous les rôles utilisateurs existants dans l'application. + * Fournisseur des rôles utilisateurs de l'application : + * - ceux définis dans la table TYPE_ROLE ; + * - rôle "intervenant". * * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> */ -class RoleProvider implements ProviderInterface +class RoleProvider implements ProviderInterface, EntityManagerAwareInterface { - const ROLE_ID_INTERVENANT = 'Intervenant'; - - /** - * @var EntityManager - */ - protected $entityManager; + use EntityManagerAwareTrait; /** * @var array @@ -31,28 +31,59 @@ class RoleProvider implements ProviderInterface protected $roles; /** + * Constructeur. * * @param EntityManager $entityManager * @param array $config */ public function __construct(EntityManager $entityManager, $config = null) { - $this->entityManager = $entityManager; - $this->config = $config; + $this->setEntityManager($entityManager); + $this->getEntityManager()->getFilters()->enable('historique'); + + $this->config = $config; } /** * @return \Zend\Permissions\Acl\Role\RoleInterface[] + * @see \Application\Entity\Db\TypeRole */ public function getRoles() { - if (null === $this->roles) { - $roleIntervenant = new NamedRole(self::ROLE_ID_INTERVENANT, 'user'); + if (null === $this->roles) { + /** + * Rôle de base "intervenant" + */ + $roleIntervenant = new IntervenantRole(); + /** + * Rôles exercés sur une structure de niveau 2 porteuse d'éléments pédagogiques + */ + $qb = $this->getEntityManager()->getRepository('Application\Entity\Db\Role')->createQueryBuilder('r') + ->select('r, tr, s') + ->distinct() + ->innerJoin('r.type', 'tr') + ->innerJoin('r.structure', 's') + ->innerJoin('s.elementPedagogique', 'ep') + ->where('tr.code <> :code')->setParameter('code', 'IND') + ->andWhere('s.niveau = :niv')->setParameter('niv', 2); + $dbRoles = $qb->getQuery()->getResult(); + + /** + * Collecte des rôles + */ $this->roles = array(); -// $this->roles[] = $roleIntervenant; + $this->roles[$roleIntervenant->getRoleId()] = $roleIntervenant; + foreach ($dbRoles as $r) { /* @var $r \Application\Entity\Db\Role */ + $role = new DbRole($r->getType(), $r->getStructure(), null); + $this->roles[$role->getRoleId()] = $role; + } } +// foreach ($this->roles as $r) { /* @var $r \Zend\Permissions\Acl\Role\RoleInterface */ +// var_dump($r->getRoleId()); +// } + return $this->roles; } } \ No newline at end of file diff --git a/module/Application/src/Application/Service/AbstractService.php b/module/Application/src/Application/Service/AbstractService.php index 015be1e700..e433406b2e 100644 --- a/module/Application/src/Application/Service/AbstractService.php +++ b/module/Application/src/Application/Service/AbstractService.php @@ -3,9 +3,10 @@ namespace Application\Service; use Doctrine\ORM\EntityManager; -use Zend\ServiceManager\ServiceLocatorInterface; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; +use UnicaenApp\Service\EntityManagerAwareInterface; +use UnicaenApp\Service\EntityManagerAwareTrait; /** * Service abstrait @@ -14,28 +15,21 @@ use Zend\ServiceManager\ServiceLocatorAwareTrait; * * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> */ -class AbstractService implements ServiceLocatorAwareInterface { - +class AbstractService implements ServiceLocatorAwareInterface, EntityManagerAwareInterface +{ use ServiceLocatorAwareTrait; - - /** - * @var EntityManager - */ - protected $entityManager; - - - - + use EntityManagerAwareTrait; /** * Retourne le gestionnaire d'entités Doctrine * * @return EntityManager */ - protected function getEntityManager() + public function getEntityManager() { - if (empty($this->entityManager)) + if (empty($this->entityManager)) { $this->entityManager = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default'); + } return $this->entityManager; } } \ No newline at end of file diff --git a/module/Application/src/Application/Service/Context.php b/module/Application/src/Application/Service/Context.php deleted file mode 100644 index 134a68a94d..0000000000 --- a/module/Application/src/Application/Service/Context.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php - -namespace Application\Service; - -use Application\Entity\Db\Annee; -use Application\Entity\Db\Etablissement as EntityEtablissement; -use Application\Entity\Db\Intervenant as EntityIntervenant; -use Application\Entity\Db\Personnel; -use Application\Entity\Db\Utilisateur; -use Common\Exception\LogicException; -use Zend\Stdlib\Hydrator\HydratorAwareInterface; -use Zend\Stdlib\Hydrator\HydratorAwareTrait; -use Zend\Stdlib\Hydrator\ClassMethods; - -/** - * Service fournissant le contexte global de fonctionnement de l'application. - * - * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> - */ -class Context extends AbstractService implements HydratorAwareInterface -{ - use HydratorAwareTrait; - - /** - * @var Parametres - */ - protected $parametres; - - /** - * @var Utilisateur - */ - protected $utilisateur; - - /** - * @var EntityIntervenant - */ - protected $intervenant; - - /** - * @var Personnel - */ - protected $personnel; - - /** - * @var Annee - */ - protected $annee; - - /** - * @var EntityEtablissement - */ - protected $etablissement; - - /** - * Constructeur. - */ - public function __construct() - { - $this->setHydrator(new ClassMethods(false)); - } - -// public function toArray() -// { -// return array( -// 'utilisateur' => $this->getUtilisateur(), -// 'intervenant' => $this->getIntervenant(), -// 'personnel' => $this->getPersonnel(), -// 'annee' => $this->getAnnee(), -// 'etablissement' => $this->getEtablissement(), -// ); -// } - - public function set($name, $value) - { - if (!method_exists($this, $method = 'set' . ucfirst($name))) { - throw new LogicException("Méthode $method inexistante."); - } - - $this->$method($value); - } - - public function get($name) - { - if (method_exists($this, $method = 'get' . ucfirst($name))) { - return $this->$method(); - } - - return null; - } - - public function __set($name, $value) - { - $this->set($name, $value); - } - - public function __get($name) - { - return $this->get($name); - } - - protected function getParametres() - { - if (null === $this->parametres) { - $this->parametres = $this->getServiceLocator()->get('ApplicationParametres'); - } - return $this->parametres; - } - - public function getUtilisateur() - { - if (null === $this->utilisateur) { - $this->utilisateur = $this->getServiceLocator()->get('authUserContext')->getDbUser(); - } - return $this->utilisateur; - } - - public function getIntervenant() - { - if (null === $this->intervenant) { - $this->intervenant = $this->getUtilisateur()->getIntervenant(); - } - return $this->intervenant; - } - - public function getPersonnel() - { - if (null === $this->personnel) { - $this->personnel = $this->getUtilisateur()->getPersonnel(); - } - return $this->personnel; - } - - public function getAnnee() - { - if (null === $this->annee) { - $this->annee = $this->getEntityManager()->find( - 'Application\Entity\Db\Annee', - $this->getParametres()->annee); - } - return $this->annee; - } - - public function getEtablissement() - { - if (null === $this->etablissement) { - $this->etablissement = $this->getEntityManager()->find( - 'Application\Entity\Db\Etablissement', - $this->getParametres()->etablissement); - } - return $this->etablissement; - } - - public function setUtilisateur(Utilisateur $utilisateur) - { - $this->utilisateur = $utilisateur; - return $this; - } - - public function setIntervenant(EntityIntervenant $intervenant) - { - $this->intervenant = $intervenant; - return $this; - } - - public function setPersonnel(Personnel $personnel) - { - $this->personnel = $personnel; - return $this; - } - - public function setAnnee(Annee $annee) - { - $this->annee = $annee; - return $this; - } - - public function setEtablissement(EntityEtablissement $etablissement) - { - $this->etablissement = $etablissement; - return $this; - } -} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ContextAwareInterface.php b/module/Application/src/Application/Service/ContextAwareInterface.php deleted file mode 100644 index 55878647c1..0000000000 --- a/module/Application/src/Application/Service/ContextAwareInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -namespace Application\Service; - -use Application\Service\Context; - -/** - * - * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> - */ -interface ContextAwareInterface -{ - /** - * Retourne le service fournissant le context global de l'application. - * - * @return Context - */ - public function getContext(); -} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ContextAwareTrait.php b/module/Application/src/Application/Service/ContextAwareTrait.php deleted file mode 100644 index f0d80d97df..0000000000 --- a/module/Application/src/Application/Service/ContextAwareTrait.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -namespace Application\Service; - -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\AbstractPluginManager; -use Application\Service\Context; - -/** - * - * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> - */ -trait ContextAwareTrait -{ - /** - * @var Context - */ - protected $context; - - /** - * Retourne le service fournissant le context global de l'application. - * - * @return Context - */ - public function getContext() - { - if (null === $this->context && $this instanceof ServiceLocatorAwareInterface) { - $sl = $this->getServiceLocator(); - if ($sl instanceof AbstractPluginManager) { - $sl = $sl->getServiceLocator(); - } - $this->context = $sl->get('ApplicationContext'); - } - return $this->context; - } -} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ContextProvider.php b/module/Application/src/Application/Service/ContextProvider.php new file mode 100644 index 0000000000..6ef79f8f92 --- /dev/null +++ b/module/Application/src/Application/Service/ContextProvider.php @@ -0,0 +1,80 @@ +<?php + +namespace Application\Service; + +use Application\Service\Parametres; +use Application\Acl\IntervenantRole; +use Application\Acl\DbRole; + +/** + * Service fournissant les différents contextes de fonctionnement de l'application. + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class ContextProvider extends AbstractService +{ + /** + * @var Parametres + */ + protected $parametres; + + /** + * @var GlobalContext + */ + protected $globalContext; + + /** + * Retourne le contexte global. + * + * @return GlobalContext + */ + public function getGlobalContext() + { + if (null === $this->globalContext) { + $authUserContext = $this->getServiceLocator()->get('authUserContext'); + + $utilisateur = $authUserContext->getDbUser(); + $intervenant = $utilisateur->getIntervenant(); + $personnel = $utilisateur->getPersonnel(); + $annee = $this->getEntityManager()->find('Application\Entity\Db\Annee', $this->getParametres()->annee); + $etab = $this->getEntityManager()->find('Application\Entity\Db\Etablissement', $this->getParametres()->etablissement); + + if (null === $intervenant) { + $ldapUser = $authUserContext->getLdapUser(); + $intervenant = $this->getServiceLocator()->get('ApplicationIntervenant')->importer($ldapUser->getSupannEmpId()); + } + + $this->globalContext = new GlobalContext(); + $this->globalContext + ->setUtilisateur($utilisateur) + ->setIntervenant($intervenant) + ->setPersonnel($personnel) + ->setAnnee($annee) + ->setEtablissement($etab); + } + + return $this->globalContext; + } + + /** + * + * @return DbRole|IntervenantRole + */ + public function getSelectedIdentityRole() + { + return $this->getServiceLocator()->get('AuthUserContext')->getSelectedIdentityRole(); + } + + /** + * + * @return Parametres + */ + protected function getParametres() + { + if (null === $this->parametres) { + $this->parametres = $this->getServiceLocator()->get('ApplicationParametres'); + } + + return $this->parametres; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ContextProviderAwareInterface.php b/module/Application/src/Application/Service/ContextProviderAwareInterface.php new file mode 100644 index 0000000000..2ea880f642 --- /dev/null +++ b/module/Application/src/Application/Service/ContextProviderAwareInterface.php @@ -0,0 +1,27 @@ +<?php + +namespace Application\Service; + +use Application\Service\ContextProvider; + +/** + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +interface ContextProviderAwareInterface +{ + /** + * Spécifie le service fournissant le context global de l'application. + * + * @param ContextProvider $contextProvider + * @return self + */ + public function setContextProvider(ContextProvider $contextProvider); + + /** + * Retourne le service fournissant le context global de l'application. + * + * @return ContextProvider + */ + public function getContextProvider(); +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ContextProviderAwareTrait.php b/module/Application/src/Application/Service/ContextProviderAwareTrait.php new file mode 100644 index 0000000000..632fa88441 --- /dev/null +++ b/module/Application/src/Application/Service/ContextProviderAwareTrait.php @@ -0,0 +1,40 @@ +<?php + +namespace Application\Service; + +use Application\Service\ContextProvider; + +/** + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +trait ContextProviderAwareTrait +{ + /** + * @var ContextProvider + */ + protected $contextProvider; + + /** + * Spécifie le service fournissant le context global de l'application. + * + * @param ContextProvider $contextProvider + * @return self + */ + public function setContextProvider(ContextProvider $contextProvider = null) + { + $this->contextProvider = $contextProvider; + + return $this; + } + + /** + * Retourne le service fournissant le context global de l'application. + * + * @return ContextProvider + */ + public function getContextProvider() + { + return $this->contextProvider; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/GlobalContext.php b/module/Application/src/Application/Service/GlobalContext.php new file mode 100644 index 0000000000..2c9f7f6ed2 --- /dev/null +++ b/module/Application/src/Application/Service/GlobalContext.php @@ -0,0 +1,111 @@ +<?php + +namespace Application\Service; + +use Application\Entity\Db\Annee; +use Application\Entity\Db\Etablissement as EntityEtablissement; +use Application\Entity\Db\Intervenant as EntityIntervenant; +use Application\Entity\Db\Personnel; +use Application\Entity\Db\Utilisateur; + +/** + * Classe regroupant les données globales de fonctionnement de l'application. + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class GlobalContext +{ + /** + * @var Parametres + */ + protected $parametres; + + /** + * @var Utilisateur + */ + protected $utilisateur; + + /** + * @var EntityIntervenant + */ + protected $intervenant; + + /** + * @var Personnel + */ + protected $personnel; + + /** + * @var Annee + */ + protected $annee; + + /** + * @var EntityEtablissement + */ + protected $etablissement; + + public function get($name) + { + if (method_exists($this, $method = 'get' . ucfirst($name))) { + return $this->$method(); + } + + return null; + } + + public function getUtilisateur() + { + return $this->utilisateur; + } + + public function getIntervenant() + { + return $this->intervenant; + } + + public function getPersonnel() + { + return $this->personnel; + } + + public function getAnnee() + { + return $this->annee; + } + + public function getEtablissement() + { + return $this->etablissement; + } + + public function setUtilisateur(Utilisateur $utilisateur) + { + $this->utilisateur = $utilisateur; + return $this; + } + + public function setIntervenant(EntityIntervenant $intervenant) + { + $this->intervenant = $intervenant; + return $this; + } + + public function setPersonnel(Personnel $personnel) + { + $this->personnel = $personnel; + return $this; + } + + public function setAnnee(Annee $annee) + { + $this->annee = $annee; + return $this; + } + + public function setEtablissement(EntityEtablissement $etablissement) + { + $this->etablissement = $etablissement; + return $this; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/Intervenant.php b/module/Application/src/Application/Service/Intervenant.php index 5d04263e81..eee43031d7 100644 --- a/module/Application/src/Application/Service/Intervenant.php +++ b/module/Application/src/Application/Service/Intervenant.php @@ -3,6 +3,9 @@ namespace Application\Service; use Doctrine\ORM\QueryBuilder; +use Application\Entity\Db\Intervenant as IntervenantEntity; +use Application\Entity\Db\IntervenantPermanent; +use Application\Entity\Db\Finder\FinderIntervenantPermanentWithServiceReferentiel; /** * Description of Intervenant @@ -11,6 +14,50 @@ use Doctrine\ORM\QueryBuilder; */ class Intervenant extends AbstractEntityService { + use \Application\Service\ContextProviderAwareTrait; + + /** + * + * @return \Application\Entity\Db\Finder\FinderIntervenantPermanentWithServiceReferentiel + */ + public function getFinderIntervenantPermanentWithServiceReferentiel() + { + $qb = new FinderIntervenantPermanentWithServiceReferentiel($this->getEntityManager(), $this->getContextProvider()); + + return $qb; + } + + /** + * + * @param \Application\Entity\Db\Intervenant $intervenant + * @return \Application\Service\Intervenant + * @throws \Common\Exception\DomainException + */ + public function checkIntervenantForServiceReferentiel(IntervenantEntity $intervenant) + { + // verif type d'intervenant + if (!$intervenant instanceof IntervenantPermanent) { + throw new \Common\Exception\DomainException( + "La saisie de service référentiel n'est possible que pour les intervenants permanents."); + } + + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + + if ($role instanceof \Application\Acl\DbRole) { + if ($intervenant->getStructure() !== $role->getStructure() + && $intervenant->getStructure()->getParenteNiv2() !== $role->getStructure()->getParenteNiv2()) { + throw new \Common\Exception\DomainException( + sprintf("L'intervenant %s n'est pas affecté à votre structure de responsabilité (%s) ni à l'une de ses sous-structures.", + $intervenant, + $role->getStructure())); + } + } + + return $this; + } + + /** * retourne la classe des entités @@ -31,6 +78,31 @@ class Intervenant extends AbstractEntityService public function getAlias(){ return 'int'; } + + /** + * Importe un intervenant non encore importé. + * + * @param string $sourceCode Code source + * @return IntervenantEntity + * @throws RuntimeException Intervenant déjà importé ou introuvable après import + */ + public function importer($sourceCode) + { + $repo = $this->getEntityManager()->getRepository($this->getEntityClass()); + + if (($intervenant = $repo->findBySourceCode($sourceCode))) { + throw new RuntimeException("L'intervenant spécifié a déjà été importé : sourceCode = $sourceCode."); + } + + $import = $this->getServiceLocator()->get('importProcessusImport'); /* @var $import \Import\Processus\Import */ + $import->intervenant($sourceCode); + + if (!($intervenant = $repo->findOneBySourceCode($sourceCode))) { + throw new RuntimeException("L'intervenant suivant est introuvable après import : sourceCode = $sourceCode."); + } + + return $intervenant; + } /** * Retourne la liste des intervenants @@ -46,4 +118,4 @@ class Intervenant extends AbstractEntityService return parent::getList($qb, $alias); } -} \ No newline at end of file +} diff --git a/module/Application/src/Application/Service/IntervenantFactory.php b/module/Application/src/Application/Service/IntervenantFactory.php new file mode 100644 index 0000000000..130cc86bbb --- /dev/null +++ b/module/Application/src/Application/Service/IntervenantFactory.php @@ -0,0 +1,29 @@ +<?php + +namespace Application\Service; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of ServiceReferentielFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class IntervenantFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $service = new Intervenant(); + $service->setEntityManager($serviceLocator->get('doctrine.entitymanager.orm_default')); + $service->setContextProvider($serviceLocator->get('ApplicationContextProvider')); + + return $service; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ServiceReferentiel.php b/module/Application/src/Application/Service/ServiceReferentiel.php index 3974c20f4e..797034b03f 100644 --- a/module/Application/src/Application/Service/ServiceReferentiel.php +++ b/module/Application/src/Application/Service/ServiceReferentiel.php @@ -4,18 +4,93 @@ namespace Application\Service; use Doctrine\ORM\QueryBuilder; use Application\Entity\Db\ServiceReferentiel as ServiceEntity; - +use Application\Entity\Db\Finder\FinderServiceReferentiel; /** * Description of ServiceReferentiel * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class ServiceReferentiel extends AbstractEntityService +class ServiceReferentiel extends AbstractService implements ContextProviderAwareInterface { + use ContextProviderAwareTrait; + + /** + * Supprime (historise par défaut) le service spécifié. + * + * @param ServiceEntity $entity + * @param bool $softDelete + * @return self + */ + public function delete(ServiceEntity $entity, $softDelete = true) + { + if ($softDelete) { + $entity->setHistoDestruction(new \DateTime); + } + else { + $this->getEntityManager()->remove($entity); + } + + $this->getEntityManager()->flush($entity); + + return $this; + } + + /** + * Retourne le requêteur des services référentiels contraint par les critères spécifiés. + * + * @param array $criteria + * @return FinderServiceReferentiel + */ + public function getFinder(array $criteria = array()) + { + $qb = new FinderServiceReferentiel($this->getEntityManager(), $this->getContextProvider()); + + // application des critères locaux (filtrage par ex) + $this->applyLocalContext($qb, $criteria); + return $qb; + } + + /** + * Applique le contexte local (filtres). + * + * @param QueryBuilder $qb + * @param array $criteria + * @return self + */ + public function applyLocalContext(QueryBuilder $qb, array $criteria = array()) + { + if (isset($criteria['intervenant'])) { + $qb->andWhere("sr.intervenant = :intervenant")->setParameter('intervenant', $criteria['intervenant']); + } + if (isset($criteria['structure'])) { + $qb->andWhere("sr.structure = :structure")->setParameter('structure', $criteria['structure']); + } + + return $this; + } + + + + + + + + + + + + + + + + + + + /** - * retourne la classe des entités + * Retourne la classe des entités * * @return string * @throws RuntimeException @@ -24,7 +99,7 @@ class ServiceReferentiel extends AbstractEntityService { return 'Application\Entity\Db\ServiceReferentiel'; } - + /** * Retourne l'alias d'entité courante * @@ -41,9 +116,9 @@ class ServiceReferentiel extends AbstractEntityService * @param QueryBuilder|null $queryBuilder * @return QueryBuilder */ - public function finderByContext(Context $context, QueryBuilder $qb = null, $alias=null) + public function finderByContext(Context $context, QueryBuilder $qb = null, $alias = null) { - list($qb,$alias) = $this->initQuery($qb, $alias); + list($qb, $alias) = $this->initQuery($qb, $alias); if (($intervenant = $context->getIntervenant())) { $qb->andWhere("$alias.intervenant = :intervenant")->setParameter('intervenant', $intervenant); diff --git a/module/Application/src/Application/Service/ServiceReferentielFactory.php b/module/Application/src/Application/Service/ServiceReferentielFactory.php new file mode 100644 index 0000000000..523a3f8c90 --- /dev/null +++ b/module/Application/src/Application/Service/ServiceReferentielFactory.php @@ -0,0 +1,29 @@ +<?php + +namespace Application\Service; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of ServiceReferentielFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class ServiceReferentielFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $service = new ServiceReferentiel(); + $service->setEntityManager($serviceLocator->get('doctrine.entitymanager.orm_default')); + $service->setContextProvider($serviceLocator->get('ApplicationContextProvider')); + + return $service; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/Service/ValidationService.php b/module/Application/src/Application/Service/ValidationService.php new file mode 100644 index 0000000000..baaac23d1e --- /dev/null +++ b/module/Application/src/Application/Service/ValidationService.php @@ -0,0 +1,16 @@ +<?php + +namespace Application\Service; + +/** + * Description of ValidationService + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class ValidationService extends AbstractService +{ + public function getServicesAValider() + { + + } +} \ No newline at end of file diff --git a/module/Application/src/Application/View/Helper/Service/Ligne.php b/module/Application/src/Application/View/Helper/Service/Ligne.php index de5a4a94c4..d576a7251a 100644 --- a/module/Application/src/Application/View/Helper/Service/Ligne.php +++ b/module/Application/src/Application/View/Helper/Service/Ligne.php @@ -6,17 +6,19 @@ use Zend\View\Helper\AbstractHelper; use Application\Entity\Db\Service; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; +use Application\Service\ContextProviderAwareInterface; +use Application\Service\ContextProviderAwareTrait; /** * Aide de vue permettant d'afficher une ligne de service * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface +class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, ContextProviderAwareInterface { - use ServiceLocatorAwareTrait; - + use ContextProviderAwareTrait; + /** * @var Service */ @@ -29,10 +31,6 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface */ protected $context; - - - - /** * Helper entry point. * @@ -62,14 +60,19 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface * @param boolean $details * @return string */ - public function render( $details=false ){ + public function render( $details=false ) + { + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + $typesIntervention = $this->getServiceLocator()->getServiceLocator()->get('ApplicationTypeIntervention')->getTypesIntervention(); $heures = $this->getServiceLocator()->getServiceLocator()->get('ApplicationService')->getTotalHeures($this->service); $sid = $this->service->getId(); $out = ''; - if (empty($this->context['intervenant'])){ +// if (empty($this->context['intervenant'])){ + if (!$role instanceof \Application\Acl\IntervenantRole) { $out .= '<td>'.$this->renderIntervenant($this->service->getIntervenant()).'</td>'; if ($this->service->getIntervenant() instanceof Application\Entity\Db\IntervenantExterieur){ $out .= '<td>'.$this->renderStructure( $this->service->getStructureAff() )."</td>\n"; @@ -78,13 +81,15 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface } } - if ($this->service->getEtablissement() == $this->context['etablissement']){ +// if ($this->service->getEtablissement() == $this->context['etablissement']){ + if ($this->service->getEtablissement() === $context->getEtablissement()) { $out .= '<td>'.$this->renderStructure( $this->service->getStructureEns() )."</td>\n"; $out .= '<td>'.$this->renderElementPedagogique( $this->service->getElementPedagogique() )."</td>\n"; }else{ $out .= '<td colspan="2">'.$this->renderEtablissement( $this->service->getEtablissement() )."</td>\n"; } - if (empty($this->context['annee'])){ +// if (empty($this->context['annee'])){ + if (!$context->getAnnee()) { $out .= '<td>'.$this->renderAnnee( $this->service->getAnnee() )."</td>\n"; } foreach( $typesIntervention as $ti ){ diff --git a/module/Application/src/Application/View/Helper/Service/LigneFactory.php b/module/Application/src/Application/View/Helper/Service/LigneFactory.php new file mode 100644 index 0000000000..081067562c --- /dev/null +++ b/module/Application/src/Application/View/Helper/Service/LigneFactory.php @@ -0,0 +1,28 @@ +<?php + +namespace Application\View\Helper\Service; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of LigneFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class LigneFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $helper = new Ligne(); + $helper->setContextProvider($serviceLocator->getServiceLocator()->get('ApplicationContextProvider')); + + return $helper; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/View/Helper/Service/Liste.php b/module/Application/src/Application/View/Helper/Service/Liste.php index 4cf0bd1732..9905a3eacb 100644 --- a/module/Application/src/Application/View/Helper/Service/Liste.php +++ b/module/Application/src/Application/View/Helper/Service/Liste.php @@ -6,17 +6,18 @@ use Zend\View\Helper\AbstractHelper; use Application\Entity\Db\Service; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; +use Application\Service\ContextProviderAwareInterface; +use Application\Service\ContextProviderAwareTrait; /** * Aide de vue permettant d'afficher une liste de services * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class Liste extends AbstractHelper implements ServiceLocatorAwareInterface +class Liste extends AbstractHelper implements ServiceLocatorAwareInterface, ContextProviderAwareInterface { - use ServiceLocatorAwareTrait; - + use ContextProviderAwareTrait; /** * Helper entry point. @@ -47,21 +48,27 @@ class Liste extends AbstractHelper implements ServiceLocatorAwareInterface * * @return string */ - public function render( $details = false ){ + public function render( $details = false ) + { + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + $typesIntervention = $this->getServiceLocator()->getServiceLocator()->get('ApplicationTypeIntervention')->getTypesIntervention(); $colspan = 4; $out = $this->renderShowHide(); $out .= '<table id="services" class="table service">'; $out .= '<tr>'; - if (empty($this->context['intervenant'])){ +// if (empty($this->context['intervenant'])){ + if (!$role instanceof \Application\Acl\IntervenantRole) { $out .= "<th>Intervenant</th>\n"; $out .= "<th title=\"Structure d'appartenance de l'intervenant\">Structure d'affectation</th>\n"; $colspan += 2; } $out .= "<th title=\"Structure gestionnaire de l'enseignement\">Structure d'enseignement</th>\n"; $out .= "<th>Enseignement ou responsabilité</th>\n"; - if (empty($this->context['annee'])){ +// if (empty($this->context['annee'])){ + if (!$context->getAnnee()) { $out .= "<th>Année univ.</th>\n"; $colspan += 1; } diff --git a/module/Application/src/Application/View/Helper/Service/ListeFactory.php b/module/Application/src/Application/View/Helper/Service/ListeFactory.php new file mode 100644 index 0000000000..9f42fcc87e --- /dev/null +++ b/module/Application/src/Application/View/Helper/Service/ListeFactory.php @@ -0,0 +1,28 @@ +<?php + +namespace Application\View\Helper\Service; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of ListeFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class ListeFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $helper = new Liste(); + $helper->setContextProvider($serviceLocator->getServiceLocator()->get('ApplicationContextProvider')); + + return $helper; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/View/Helper/ServiceReferentiel/Dl.php b/module/Application/src/Application/View/Helper/ServiceReferentiel/Dl.php index 1066c5f7c4..4242f07e8c 100644 --- a/module/Application/src/Application/View/Helper/ServiceReferentiel/Dl.php +++ b/module/Application/src/Application/View/Helper/ServiceReferentiel/Dl.php @@ -37,10 +37,12 @@ class Dl extends AbstractDl $identite = array(); - $identite[] = sprintf($tplDtdd, - "Numéro :", - $this->entity->getId() - ); + if (!$this->short) { + $identite[] = sprintf($tplDtdd, + "Numéro :", + $this->entity->getId() + ); + } $identite[] = sprintf($tplDtdd, "Intervenant :", @@ -75,8 +77,10 @@ class Dl extends AbstractDl * Historique */ - $html .= $this->getView()->historiqueDl($this->entity, $this->horizontal); - + if (!$this->short) { + $html .= $this->getView()->historiqueDl($this->entity, $this->horizontal); + } + return $html; } } \ No newline at end of file diff --git a/module/Application/src/Application/View/Helper/ServiceReferentiel/Ligne.php b/module/Application/src/Application/View/Helper/ServiceReferentiel/Ligne.php index 74249824fa..a57a7638d2 100644 --- a/module/Application/src/Application/View/Helper/ServiceReferentiel/Ligne.php +++ b/module/Application/src/Application/View/Helper/ServiceReferentiel/Ligne.php @@ -6,19 +6,19 @@ use Zend\View\Helper\AbstractHelper; use Application\Entity\Db\ServiceReferentiel; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; -use Application\Service\Context; -use Application\Service\ContextAwareInterface; -use Application\Service\ContextAwareTrait; +use Application\Service\ContextProviderAwareInterface; +use Application\Service\ContextProviderAwareTrait; +use Application\Acl\IntervenantRole; /** * Aide de vue permettant d'afficher une ligne de service * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, ContextAwareInterface +class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, ContextProviderAwareInterface { use ServiceLocatorAwareTrait; - use ContextAwareTrait; + use ContextProviderAwareTrait; /** * @var ServiceReferentiel @@ -34,6 +34,7 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, Cont final public function __invoke(ServiceReferentiel $service) { $this->service = $service; + return $this; } @@ -55,27 +56,40 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, Cont */ public function render($details = false) { -// $typesIntervention = $this->getServiceLocator()->getServiceLocator()->get('ApplicationTypeIntervention')->getTypesIntervention(); -// $heures = $this->getServiceLocator()->getServiceLocator()->get('ApplicationService')->getTotalHeures($this->service); + $parts = array(); + + $parts['intervenant'] = '<td>' . $this->service->getIntervenant() . "</td>\n"; + $parts[] = '<td>' . $this->renderStructure($this->service->getStructure()) . "</td>\n"; + $parts['annee'] = '<td>' . $this->renderAnnee($this->service->getAnnee()) . "</td>\n"; + $parts[] = '<td>' . $this->renderFonction($this->service->getFonction()) . "</td>\n"; + $parts[] = '<td>' . $this->renderHeures($this->service->getHeures()) . "</td>\n"; + + $parts[] = $this->renderModifier(); + $parts[] = $this->renderSupprimer(); + + $this->applyGlobalContext($parts); + + return implode(PHP_EOL, $parts); + } - $out = ''; - if (!$this->getContext()->getIntervenant()) { - $out .= '<td>' . $this->service->getIntervenant() . "</td>\n"; - } - if (!$this->getContext()->getStructure()) { - $out .= '<td>' . $this->renderStructure($this->service->getStructure()) . "</td>\n"; + /** + * + * @param array $parts + * @return self + */ + public function applyGlobalContext(array &$parts) + { + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + + if ($role instanceof IntervenantRole) { + unset($parts['intervenant']); } - if (!$this->getContext()->getAnnee()) { - $out .= '<td>' . $this->renderAnnee($this->service->getAnnee()) . "</td>\n"; + if ($context->getAnnee()) { + unset($parts['annee']); } - $out .= '<td>' . $this->renderFonction($this->service->getFonction()) . "</td>\n"; - $out .= '<td>' . $this->renderHeures($this->service->getHeures()) . "</td>\n"; - -// $out .= $this->renderModifier(); -// $out .= $this->renderSupprimer(); -// $out .= $this->renderDetails($details); - return $out; + return $this; } protected function renderStructure($structure) @@ -118,24 +132,15 @@ class Ligne extends AbstractHelper implements ServiceLocatorAwareInterface, Cont protected function renderModifier() { - $url = $this->getView()->url('service-ref/default', array('action' => 'saisie', 'id' => $this->service->getId())); - return '<td><a class="ajax-modal" data-event="service-modify-message" href="' . $url . '" title="Modifier le service référentiel"><span class="glyphicon glyphicon-edit"></span></a></td>'; + $query = array('sourceCode' => $this->service->getIntervenant()->getSourceCode()); + $url = $this->getView()->url('service-ref/default', array('action' => 'saisir'), array('query' => $query)); + return '<td><a class="ajax-modal" data-event="service-modify-message" href="' . $url . '" title="Modifier le service référentiel de ' . $this->service->getIntervenant() . '"><span class="glyphicon glyphicon-edit"></span></a></td>'; } protected function renderSupprimer() { - $url = $this->getView()->url('service-ref/default', array('action' => 'suppression', 'id' => $this->service->getId())); //onclick="return ServiceReferentiel.get('.$this->service->getId().').delete(this)" - return '<td><a class="service-delete" data-id="' . $this->service->getId() . '" href="' . $url . '" title="Supprimer le service référentiel"><span class="glyphicon glyphicon-remove"></span></a></td>'; - } - - protected function renderDetails($details = false) - { - $out = '<td>' - . '<a class="service-details-button" title="Détails" onclick="ServiceReferentiel.get(' . $this->service->getId() . ').showHideDetails(this)">' - . '<span class="glyphicon glyphicon-chevron-' . ($details ? 'up' : 'down') . '"></span>' - . '</a>' - . "</td>\n"; - return $out; + $url = $this->getView()->url('service-ref/default', array('action' => 'supprimer', 'id' => $this->service->getId())); + return '<td><a class="ajax-modal" data-event="service-delete-message" data-id="' . $this->service->getId() . '" href="' . $url . '" title="Supprimer ce service référentiel"><span class="glyphicon glyphicon-remove"></span></a></td>'; } /** diff --git a/module/Application/src/Application/View/Helper/ServiceReferentiel/LigneFactory.php b/module/Application/src/Application/View/Helper/ServiceReferentiel/LigneFactory.php new file mode 100644 index 0000000000..6ba305cc01 --- /dev/null +++ b/module/Application/src/Application/View/Helper/ServiceReferentiel/LigneFactory.php @@ -0,0 +1,28 @@ +<?php + +namespace Application\View\Helper\ServiceReferentiel; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of LigneFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class LigneFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $helper = new Ligne(); + $helper->setContextProvider($serviceLocator->getServiceLocator()->get('ApplicationContextProvider')); + + return $helper; + } +} \ No newline at end of file diff --git a/module/Application/src/Application/View/Helper/ServiceReferentiel/Liste.php b/module/Application/src/Application/View/Helper/ServiceReferentiel/Liste.php index 51bbae23e8..e38dbf8bb1 100644 --- a/module/Application/src/Application/View/Helper/ServiceReferentiel/Liste.php +++ b/module/Application/src/Application/View/Helper/ServiceReferentiel/Liste.php @@ -6,18 +6,19 @@ use Zend\View\Helper\AbstractHelper; use Application\Entity\Db\ServiceReferentiel; use Zend\ServiceManager\ServiceLocatorAwareInterface; use Zend\ServiceManager\ServiceLocatorAwareTrait; -use Application\Service\ContextAwareInterface; -use Application\Service\ContextAwareTrait; +use Application\Service\ContextProviderAwareInterface; +use Application\Service\ContextProviderAwareTrait; +use Application\Acl\IntervenantRole; /** * Aide de vue permettant d'afficher une liste de services referentiels * * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr> */ -class Liste extends AbstractHelper implements ServiceLocatorAwareInterface, ContextAwareInterface +class Liste extends AbstractHelper implements ServiceLocatorAwareInterface, ContextProviderAwareInterface { use ServiceLocatorAwareTrait; - use ContextAwareTrait; + use ContextProviderAwareTrait; protected $services; @@ -31,6 +32,7 @@ class Liste extends AbstractHelper implements ServiceLocatorAwareInterface, Cont final public function __invoke(array $services) { $this->services = $services; + return $this; } @@ -51,56 +53,57 @@ class Liste extends AbstractHelper implements ServiceLocatorAwareInterface, Cont */ public function render($details = false) { -// $typesIntervention = $this->getServiceLocator()->getServiceLocator()->get('ApplicationTypeIntervention')->getTypesIntervention(); - - $colspan = 4; - - $out = ''; -// $out .= $this->renderShowHide(); - $out .= '<table id="services-ref" class="table service-ref-ref">'; - $out .= '<tr>'; - - if (!$this->getContext()->getIntervenant()) { - $out .= "<th colspan=\"2\">Intervenant</th>\n"; - $colspan += 2; - } - $out .= "<th>Structure</th>\n"; - $out .= "<th>Fonction référentielle</th>\n"; - if (!$this->getContext()->getAnnee()) { - $out .= "<th>Année univ.</th>\n"; - $colspan += 1; - } - $out .= "<th>Heures</th>\n"; - $out .= "</tr>\n"; + $urlSaisir = $this->getView()->url('service-ref/default', array('action' => 'saisir')); + $urlVoirListe = $this->getView()->url('service-ref/default', array('action' => 'voirListe')); + $parts = array(); + + $parts[] = '<table id="services-ref" class="table service-ref">'; + $parts[] = '<tr>'; + $parts['intervenant'] = "<th>Intervenant</th>"; + $parts[] = "<th>Structure</th>"; + $parts[] = "<th>Fonction référentielle</th>"; + $parts['annee'] = "<th>Année univ.</th>"; + $parts[] = "<th>Heures</th>"; + $parts[] = "<th class=\"action\" colspan=\"2\"> </th>"; + $parts[] = "</tr>"; foreach ($this->services as $service) { - $out .= '<tr id="service-ref-ref-' . $service->getId() . '-ligne">'; - $out .= $this->getView()->serviceReferentielLigne($service)->render($details); - $out .= '</tr>'; -// $out .= '<tr class="volume-horaire" id="service-ref-' . $service->getId() . '-volume-horaire-tr"' . ($details ? '' : ' style="display:none"') . '>' -// . '<td class="volume-horaire" id="service-ref-' . $service->getId() . '-volume-horaire-td" colspan="' . $colspan . '">' -// . $this->getView()->volumeHoraireListe($service->getVolumeHoraire(), array('service' => $service))->render() -// . '</td>' -// . '</tr>'; + $parts[] = '<tr id="service-ref-' . $service->getId() . '-ligne">'; + $parts[] = $this->getView()->serviceReferentielLigne($service)->render($details); + $parts[] = '</tr>'; } - $out .= '</table>' . "\n"; -// $out .= $this->renderShowHide(); + + $parts[] = '</table>'; - $url = $this->getView()->url('service-ref/default', array('action' => 'saisir')); - $out .= '<br /><a class="ajax-modal services-ref btn btn-default" data-event="service-ref-add-message" href="' . $url . '" title="Modifier le service référentiel"><span class="glyphicon glyphicon-edit"></span> Modifier le service référentiel</a>'; - $out .= '<script type="text/javascript">'; - $out .= '$(function() { ServiceReferentiel.init("' . $this->getView()->url('service-ref/default', array('action' => 'voirListe')) . '"); });'; - $out .= '</script>'; - return $out; + $parts[] = '<a class="ajax-modal services-ref btn btn-default" data-event="service-ref-add-message" href="' . $urlSaisir . '" title="Ajouter un service référentiel"><span class="glyphicon glyphicon-plus"></span> Saisir un nouveau service</a>'; + + $parts[] = '<script type="text/javascript">'; + $parts[] = '$(function() { ServiceReferentiel.init("' . $urlVoirListe . '"); });'; + $parts[] = '</script>'; + + $this->applyGlobalContext($parts); + + return implode(PHP_EOL, $parts); } - public function renderShowHide() + /** + * + * @param array $parts + * @return self + */ + public function applyGlobalContext(array &$parts) { - return - '<div class="service-ref-show-hide-buttons">' - . '<button type="button" class="btn btn-default btn-xs service-ref-show-all-details"><span class="glyphicon glyphicon-chevron-down"></span> Tout déplier</button> ' - . '<button type="button" class="btn btn-default btn-xs service-ref-hide-all-details"><span class="glyphicon glyphicon-chevron-up"></span> Tout replier</button>' - . '</div>'; + $context = $this->getContextProvider()->getGlobalContext(); + $role = $this->getContextProvider()->getSelectedIdentityRole(); + + if ($role instanceof IntervenantRole) { + unset($parts['intervenant']); + } + if ($context->getAnnee()) { + unset($parts['annee']); + } + + return $this; } /** diff --git a/module/Application/src/Application/View/Helper/ServiceReferentiel/ListeFactory.php b/module/Application/src/Application/View/Helper/ServiceReferentiel/ListeFactory.php new file mode 100644 index 0000000000..ba6b423fc3 --- /dev/null +++ b/module/Application/src/Application/View/Helper/ServiceReferentiel/ListeFactory.php @@ -0,0 +1,28 @@ +<?php + +namespace Application\View\Helper\ServiceReferentiel; + +use Zend\ServiceManager\FactoryInterface; +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Description of ListeFactory + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class ListeFactory implements FactoryInterface +{ + /** + * Create service + * + * @param ServiceLocatorInterface $serviceLocator + * @return mixed + */ + public function createService(ServiceLocatorInterface $serviceLocator) + { + $helper = new Liste(); + $helper->setContextProvider($serviceLocator->getServiceLocator()->get('ApplicationContextProvider')); + + return $helper; + } +} \ No newline at end of file diff --git a/module/Application/view/application/intervenant/choisir.phtml b/module/Application/view/application/intervenant/choisir.phtml index 2979bd8595..21b838075c 100644 --- a/module/Application/view/application/intervenant/choisir.phtml +++ b/module/Application/view/application/intervenant/choisir.phtml @@ -11,6 +11,7 @@ <script> $(function() { - $(":input").tooltip({ /*placement: 'left'*/ }); + $("form.intervenant-rech :input").tooltip({ /*placement: 'left'*/ }); + $("input[name='interv[label]']").focus(); }); </script> \ No newline at end of file diff --git a/module/Application/view/application/service-referentiel/index.phtml b/module/Application/view/application/service-referentiel/index.phtml index 76a61cb705..bf0f55f0bd 100644 --- a/module/Application/view/application/service-referentiel/index.phtml +++ b/module/Application/view/application/service-referentiel/index.phtml @@ -1,29 +1,4 @@ <h1>Services référentiels</h1> <h2>Année universitaire <?php echo $annee; ?></h2> -<?php echo $this->serviceListe; ?> - -<script> - $(function() { - $("body").tooltip({ - selector: '[rel=popover]', - placement: 'top', - title: "Cliquez pour ouvrir/fermer le formulaire de modification..." - }); - $("body").popover({ - selector: '[rel=popover]', - placement: 'bottom', - html: true, - title: "Modification d'heures ", - content: function() { - return $.ajax({ - url: "<?php echo $this->url('volume_horaire/default', array('action' => 'voir')) ?>/" + $(this).data('vhId'), -// data: { id: $(this).data('vhId') }, - async: false, - success: function(data) { } - }).responseText; - }, - container: "body", - }); - }); -</script> +<?php echo $this->serviceListe; ?> \ No newline at end of file diff --git a/module/Application/view/application/service-referentiel/saisir.phtml b/module/Application/view/application/service-referentiel/saisir.phtml index 126c7989f9..01979cbe9e 100644 --- a/module/Application/view/application/service-referentiel/saisir.phtml +++ b/module/Application/view/application/service-referentiel/saisir.phtml @@ -87,7 +87,7 @@ echo $this->form()->closeTag(); { var currentCount = getFonctionCurrentCount(); var template = $('> fieldset > span', form).data('template'); - var element = $(template.replace(/__index__/g, currentCount)); + var element = $(template.replace(/__index__/g, currentCount));console.log(template, element, currentCount); $('> fieldset', form).append(element.fadeIn()); $("select.fonction-referentiel-fonction").not($("select", element)).each(function() { applySelectUnicity($(this), $("select", element)); }); updateFonctionCounter(); diff --git a/module/Application/view/application/service-referentiel/suppression.phtml b/module/Application/view/application/service-referentiel/suppression.phtml deleted file mode 100644 index b347181c90..0000000000 --- a/module/Application/view/application/service-referentiel/suppression.phtml +++ /dev/null @@ -1,7 +0,0 @@ -<input type="hidden" id="service-deleted-id" value="<?php echo $entity->getId() ?>" /> -<?php - - if ($errors) - echo $this->messenger()->setMessages(array(UnicaenApp\View\Helper\Messenger::ERROR => array($errors))); - else - echo 'Le service a été supprimé.'; \ No newline at end of file diff --git a/module/Application/view/application/service-referentiel/supprimer.phtml b/module/Application/view/application/service-referentiel/supprimer.phtml new file mode 100644 index 0000000000..14a5bf46bb --- /dev/null +++ b/module/Application/view/application/service-referentiel/supprimer.phtml @@ -0,0 +1,14 @@ +<?php +if (isset($errors) && $errors) { + echo $this->messenger()->setMessages(array(UnicaenApp\View\Helper\Messenger::ERROR => array($errors))); +} +else { + echo '<p class="lead text-danger"><strong>Attention!</strong> Confirmez-vous la suppression de cet enregistrement ?</p>'; + echo $this->serviceReferentielDl($entity, true, true); + + echo $this->form()->openTag($form); + echo $this->formHidden($form->get('id')); + echo $this->formHidden($form->get('security')); + echo $this->formSubmit($form->get('submit')->setAttribute('class', 'btn btn-primary')); + echo $this->form()->closeTag(); +} \ No newline at end of file diff --git a/module/Common/src/Common/Exception/DomainException.php b/module/Common/src/Common/Exception/DomainException.php new file mode 100644 index 0000000000..e28a0f1591 --- /dev/null +++ b/module/Common/src/Common/Exception/DomainException.php @@ -0,0 +1,13 @@ +<?php + +namespace Common\Exception; + +/** + * Exception thrown if a value does not adhere to a defined valid data domain. + * + * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr> + */ +class DomainException extends LogicException +{ + +} \ No newline at end of file diff --git a/public/js/app.js b/public/js/app.js index e6fdb4b772..7a73337ec7 100755 --- a/public/js/app.js +++ b/public/js/app.js @@ -211,60 +211,14 @@ function ServiceReferentiel( id ) { this.id = id; -// this.delete = function( url ){ -// ok = window.confirm('Voulez-vous vraiment supprimer ce service ?'); -// if (ok){ -// $('#service-ref-div').modal({remote: url}); -// } -// return false; -// } -// -// this.showHideDetails = function( serviceA ){ -// -// var state = $.data(serviceA,'state'); -// var tr = $('#service-ref-' + this.id + '-volume-horaire-tr'); -// -// if (('show' == state || 'none' == tr.css('display')) && 'hide' != state ){ -// $(serviceA).html('<span class="glyphicon glyphicon-chevron-up"></span>'); -// tr.show(200); -// }else{ -// $(serviceA).html('<span class="glyphicon glyphicon-chevron-down"></span>'); -// tr.hide(200); -// } -// } -// -// this.showInterneExterne = function(){ -// if ('service-ref-interne' == this.id){ -// $('#element-interne').show(); -// $('#element-externe').hide(); -// $("input[name='etablissement\\[label\\]']").val(''); -// $("input[name='etablissement\\[id\\]']").val(''); -// }else{ -// $('#element-interne').hide(); -// $("input[name='elementPedagogique\\[label\\]']").val(''); -// $("input[name='elementPedagogique\\[id\\]']").val(''); -// $('#element-externe').show(); -// } -// } - - this.onAfterAdd = function(){ -// $.get( ServiceReferentiel.voirLigneUrl+"/"+this.id+'?only-content=0', function( data ) { -// $( "#service-ref-"+this.id+"-ligne" ).load( ServiceReferentiel.voirLigneUrl ); -// $('#services > tbody:last').append(data); -// }); + this.onAfterAdd = function() { $.get(ServiceReferentiel.voirLigneUrl, [], function(data) { $("#services-ref").replaceWith($(data).filter("table").fadeIn()); }); } -// this.onAfterModify = function(){ -// var details = $('#service-ref-'+this.id+'-volume-horaire-tr').css('display') == 'none' ? '0' : '1'; -// $( "#service-ref-"+this.id+"-ligne" ).load( ServiceReferentiel.voirLigneUrl + "/"+this.id+'?only-content=1&details='+details ); -// } -// -// this.onAfterDelete = function(){ -// $('#service-ref-'+this.id+'-volume-horaire-tr').remove(); -// $( "#service-ref-"+this.id+"-ligne" ).remove(); -// } - + this.onAfterDelete = function() { + console.log(this.id); + $( "#service-ref-" + this.id + "-ligne" ).fadeOut().remove(); + } } ServiceReferentiel.get = function( id ) @@ -278,40 +232,15 @@ ServiceReferentiel.init = function( voirLigneUrl ) { ServiceReferentiel.voirLigneUrl = voirLigneUrl; - $("body").on("service-ref-add-message", function(event, data) { + $("body").on("service-ref-add-message service-ref-modify-message", function(event, data) { var id = null; event.div.modal('hide'); // ferme la fenêtre modale ServiceReferentiel.get(id).onAfterAdd(); }); - -// $('#service-ref-div').on('loaded.bs.modal', function (e) { -// if (id = $('#service-ref-deleted-id').val()){ -// ServiceReferentiel.get(id).onAfterDelete(); -// } -// }); -// -// $("body").on('change', 'form#service input[name="interne-externe"]', function(){ -// ServiceReferentiel.get(this.value).showInterneExterne( $( this ).val() ); -// }); -// -// $(".service-ref-show-all-details").on('click', function(){ ServiceReferentiel.showAllDetails(); }); -// $(".service-ref-hide-all-details").on('click', function(){ ServiceReferentiel.hideAllDetails(); }); -// $('body').on('click', '.service-ref-delete', function(){ -// ServiceReferentiel.get( $(this).data('id') ).delete( $(this).attr('href') ); -// return false; -// }) -} - -//ServiceReferentiel.showAllDetails = function(){ -// $('.service-ref-details-button').data('state', 'show'); -// $('.service-ref-details-button').click(); -// $('.service-ref-details-button').data('state', ''); -//} -// -//ServiceReferentiel.hideAllDetails = function(){ -// $('.service-ref-details-button').data('state', 'hide'); -// $('.service-ref-details-button').click(); -// $('.service-ref-details-button').data('state', ''); -//} - - + + $("body").on("service-delete-message", function(event, data) { + event.div.modal('hide'); // ferme la fenêtre modale + console.log(event.a.data('id')); + ServiceReferentiel.get(event.a.data('id')).onAfterDelete(); + }); +} \ No newline at end of file -- GitLab