diff --git a/SQL/001_tables.sql b/SQL/001_tables.sql
deleted file mode 100644
index 66d474ca069a5e3516e1ca694456e788016b658b..0000000000000000000000000000000000000000
--- a/SQL/001_tables.sql
+++ /dev/null
@@ -1,44 +0,0 @@
--- categories de privilege
-create table unicaen_privilege_categorie
-(
-    id        serial       not null
-        constraint categorie_privilege_pkey primary key,
-    code      varchar(150) not null,
-    libelle   varchar(200) not null,
-    ordre     integer default 0,
-    namespace varchar(255)
-);
-
-create unique index categorie_privilege_code_uindex on unicaen_privilege_categorie (code);
-create unique index categorie_privilege_id_uindex on unicaen_privilege_categorie (id);
-
---privileges
-create table unicaen_privilege_privilege
-(
-    id           serial       not null
-        constraint privilege_pkey primary key,
-    categorie_id integer      not null
-        constraint privilege_categorie_privilege_id_fk references unicaen_privilege_categorie,
-    code         varchar(150) not null,
-    libelle      varchar(200) not null,
-    ordre        integer default 0
-);
-
-create index privilege_categorie_id_index on unicaen_privilege_privilege (categorie_id);
-create unique index privilege_id_uindex on unicaen_privilege_privilege (id);
-create unique index unicaen_privilege_privilege_code_uindex on unicaen_privilege_privilege (categorie_id, code);
-
--- linker
-create table unicaen_privilege_privilege_role_linker
-(
-    role_id      integer not null
-        constraint unicaen_privilege_privilege_role_linker_role_id_fk
-            references unicaen_utilisateur_role
-            on delete cascade,
-    privilege_id integer not null
-        constraint unicaen_privilege_privilege_role_linker_privilege_id_fk
-            references unicaen_privilege_privilege
-            on delete cascade,
-    constraint unicaen_privilege_privilege_role_linker_pk
-        primary key (role_id, privilege_id)
-);
\ No newline at end of file
diff --git a/SQL/002_privileges.sql b/SQL/002_privileges.sql
deleted file mode 100644
index 7f5e9b22b803e58802b363e5eb9007272aa7dc4f..0000000000000000000000000000000000000000
--- a/SQL/002_privileges.sql
+++ /dev/null
@@ -1,9 +0,0 @@
--- Insertion de la catégorie associée à la gestion des utilisateurs
-INSERT INTO unicaen_privilege_categorie (id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_categorie_id_seq), 'privilege', 'Gestion des  privilèges', 2000);
-
--- Insertion des privilèges de base
-INSERT INTO unicaen_privilege_privilege (id, categorie_id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_privilege_id_seq), current_val(unicaen_privilege_categorie_id_seq), 'privilege_voir', 'Afficher les privilèges', 10);
-INSERT INTO unicaen_privilege_privilege (id, categorie_id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_privilege_id_seq), current_val(unicaen_privilege_categorie_id_seq), 'privilege_ajouter', 'Ajouter un privilège', 20);
-INSERT INTO unicaen_privilege_privilege (id, categorie_id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_privilege_id_seq), current_val(unicaen_privilege_categorie_id_seq), 'privilege_modifier', 'Modifier un privilège', 30);
-INSERT INTO unicaen_privilege_privilege (id, categorie_id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_privilege_id_seq), current_val(unicaen_privilege_categorie_id_seq), 'privilege_supprimer', 'Supprimer un privilège', 40);
-INSERT INTO unicaen_privilege_privilege (id, categorie_id, code, libelle, ordre) VALUES (next_val(unicaen_privilege_privilege_id_seq), current_val(unicaen_privilege_categorie_id_seq), 'privilege_affecter', 'Affecter un privilège', 50);
diff --git a/config/merged/affectation.config.php b/config/merged/affectation.config.php
deleted file mode 100644
index fd3321ca8f912c19dd6ebc40e34ac01297839486..0000000000000000000000000000000000000000
--- a/config/merged/affectation.config.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-use UnicaenPrivilege\Controller\AffectationController;
-use UnicaenPrivilege\Controller\AffectationControllerFactory;
-use UnicaenPrivilege\Guard\PrivilegeController;
-use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
-use UnicaenPrivilege\Service\Affectation\AffectationService;
-use UnicaenPrivilege\Service\Affectation\AffectationServiceFactory;
-use Zend\Router\Http\Literal;
-use Zend\Router\Http\Segment;
-
-return [
-    'bjyauthorize' => [
-        'guards' => [
-            UnicaenPrivilege\Guard\PrivilegeController::class => [
-                [
-                    'controller' => AffectationController::class,
-                    'action' => [
-                        'index',
-                        'modifier'
-                    ],
-                    'privileges' => [
-                        PrivilegePrivileges::PRIVILEGE_VOIR,
-                    ],
-                ],
-            ],
-        ],
-    ],
-
-    'navigation' => [
-        'default' => [
-            'home' => [
-                'pages' => [
-                    'administration' => [
-                        'pages' => [
-                            'privilege' => [
-                                'label' => 'Privilège',
-                                'route' => 'unicaen-privilege/affectation',
-                                'resource' => PrivilegeController::getResourceId(AffectationController::class, 'index'),
-                                'order'    => 5000,
-                            ],
-                        ],
-                    ],
-                ],
-            ],
-        ],
-    ],
-
-    'router' => [
-        'routes' => [
-            'unicaen-privilege' => [
-                'type' => Literal::class,
-                'options' => [
-                    'route'    => '/unicaen-privilege',
-                ],
-                'may_terminate' => false,
-                'child_routes' => [
-                    'affectation' => [
-                        'type' => Literal::class,
-                        'options' => [
-                            'route'    => '/affectation',
-                            'defaults' => [
-                                'controller' => AffectationController::class,
-                                'action' => 'index',
-                            ],
-                        ],
-                    ],
-                    'modifier-affectation' => [
-                        'type' => Segment::class,
-                        'options' => [
-                            'route'    => '/modifier-affectation/:role/:privilege',
-                            'defaults' => [
-                                'controller' => AffectationController::class,
-                                'action' => 'modifier',
-                            ],
-                        ],
-                    ],
-                ],
-            ],
-        ],
-    ],
-
-    'service_manager' => [
-        'factories' => [
-            AffectationService::class => AffectationServiceFactory::class,
-        ],
-    ],
-    'controllers'     => [
-        'factories' => [
-            AffectationController::class => AffectationControllerFactory::class,
-
-        ],
-    ],
-    'form_elements' => [
-        'factories' => [],
-    ],
-    'hydrators' => [
-        'factories' => [],
-    ]
-];
\ No newline at end of file
diff --git a/config/merged/categorie.config.php b/config/merged/categorie.config.php
index 85177a5e984938d058332e03099ffbfdeee7ad34..54ed7708a07c2c7962a79971af4cc77711925a11 100644
--- a/config/merged/categorie.config.php
+++ b/config/merged/categorie.config.php
@@ -2,10 +2,10 @@
 
 use UnicaenPrivilege\Controller\CategorieController;
 use UnicaenPrivilege\Controller\CategorieControllerFactory;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreForm;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreFormFactory;
 use UnicaenPrivilege\Form\Categorie\CategorieForm;
 use UnicaenPrivilege\Form\Categorie\CategorieFormFactory;
-use UnicaenPrivilege\Form\Categorie\CategorieHydrator;
-use UnicaenPrivilege\Form\Categorie\CategorieHydratorFactory;
 use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
 use UnicaenPrivilege\Service\Categorie\CategorieService;
 use UnicaenPrivilege\Service\Categorie\CategorieServiceFactory;
@@ -38,11 +38,6 @@ return [
     'router' => [
         'routes' => [
             'unicaen-privilege' => [
-                'type' => Literal::class,
-                'options' => [
-                    'route'    => '/unicaen-privilege',
-                ],
-                'may_terminate' => false,
                 'child_routes' => [
                     'categorie' => [
                         'type' => Literal::class,
@@ -126,19 +121,17 @@ return [
             CategorieController::class => CategorieControllerFactory::class,
         ],
     ],
+
     'service_manager' => [
         'factories' => [
             CategorieService::class => CategorieServiceFactory::class,
         ],
     ],
+
     'form_elements' => [
         'factories' => [
             CategorieForm::class => CategorieFormFactory::class,
-        ],
-    ],
-    'hydrators' => [
-        'factories' => [
-            CategorieHydrator::class => CategorieHydratorFactory::class,
+            CategorieFiltreForm::class => CategorieFiltreFormFactory::class,
         ],
     ],
 ];
\ No newline at end of file
diff --git a/config/merged/pivilege.config.php b/config/merged/pivilege.config.php
deleted file mode 100644
index 694602609e66b684977aaa9b6462505ba7a80706..0000000000000000000000000000000000000000
--- a/config/merged/pivilege.config.php
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-
-use UnicaenPrivilege\Controller\PrivilegeController;
-use UnicaenPrivilege\Controller\PrivilegeControllerFactory;
-use UnicaenPrivilege\Form\Privilege\PrivilegeForm;
-use UnicaenPrivilege\Form\Privilege\PrivilegeFormFactory;
-use UnicaenPrivilege\Form\Privilege\PrivilegeHydrator;
-use UnicaenPrivilege\Form\Privilege\PrivilegeHydratorFactory;
-use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
-use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProvider;
-use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProviderFactory;
-use UnicaenPrivilege\Service\Privilege\PrivilegeService;
-use UnicaenPrivilege\Service\Privilege\PrivilegeServiceFactory;
-use Zend\Router\Http\Literal;
-use Zend\Router\Http\Segment;
-
-return [
-
-    'bjyauthorize' => [
-        'guards' => [
-            UnicaenPrivilege\Guard\PrivilegeController::class => [
-                [
-                    'controller' => PrivilegeController::class,
-                    'action' => [
-                        'ajouter',
-                        'modifier',
-                        'supprimer',
-                    ],
-                    'privileges' => [
-                        PrivilegePrivileges::PRIVILEGE_AJOUTER,
-                    ],
-                ],
-            ],
-        ],
-    ],
-
-    'router' => [
-        'routes' => [
-            'unicaen-privilege' => [
-                'type' => Literal::class,
-                'options' => [
-                    'route'    => '/unicaen-privilege',
-                ],
-                'may_terminate' => false,
-                'child_routes' => [
-                    'privilege' => [
-                        'type' => Literal::class,
-                        'options' => [
-                            'route'    => '/privilege',
-                            'defaults' => [
-                                'controller' => PrivilegeController::class,
-                            ],
-                        ],
-                        'may_terminate' => false,
-                        'child_routes' => [
-                            'ajouter' => [
-                                'type' => Segment::class,
-                                'options' => [
-                                    'route'    => '/ajouter/:categorie',
-                                    'defaults' => [
-                                        'controller' => PrivilegeController::class,
-                                        'action'     => 'ajouter',
-                                    ],
-                                ],
-                            ],
-                            'modifier' => [
-                                'type' => Segment::class,
-                                'options' => [
-                                    'route'    => '/modifier/:privilege',
-                                    'defaults' => [
-                                        'controller' => PrivilegeController::class,
-                                        'action'     => 'modifier',
-                                    ],
-                                ],
-                            ],
-                            'supprimer' => [
-                                'type' => Segment::class,
-                                'options' => [
-                                    'route'    => '/supprimer/:privilege',
-                                    'defaults' => [
-                                        'controller' => PrivilegeController::class,
-                                        'action'     => 'supprimer',
-                                    ],
-                                ],
-                            ],
-                        ],
-                    ],
-                ],
-            ],
-        ],
-    ],
-
-    'controllers' => [
-        'factories' => [
-            PrivilegeController::class  => PrivilegeControllerFactory::class,
-        ],
-    ],
-
-    'service_manager' => [
-        'factories' => [
-            PrivilegeService::class => PrivilegeServiceFactory::class,
-            PrivilegeRuleProvider::class => PrivilegeRuleProviderFactory::class,
-        ],
-    ],
-
-    'form_elements' => [
-        'factories' => [
-            PrivilegeForm::class => PrivilegeFormFactory::class,
-        ],
-    ],
-    'hydrators' => [
-        'factories' => [
-            PrivilegeHydrator::class => PrivilegeHydratorFactory::class,
-        ],
-    ],
-
-];
\ No newline at end of file
diff --git a/config/merged/privilege.config.php b/config/merged/privilege.config.php
new file mode 100644
index 0000000000000000000000000000000000000000..051c963a369d2c813dc415dbd9e880127b845a26
--- /dev/null
+++ b/config/merged/privilege.config.php
@@ -0,0 +1,152 @@
+<?php
+
+use UnicaenPrivilege\Controller\PrivilegeController;
+use UnicaenPrivilege\Controller\PrivilegeControllerFactory;
+use UnicaenPrivilege\Form\Privilege\PrivilegeForm;
+use UnicaenPrivilege\Form\Privilege\PrivilegeFormFactory;
+use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
+use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProvider;
+use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProviderFactory;
+use UnicaenPrivilege\Service\Privilege\PrivilegeService;
+use UnicaenPrivilege\Service\Privilege\PrivilegeServiceFactory;
+use UnicaenPrivilege\View\Privilege\PrivilegeViewHelper;
+use Zend\Router\Http\Literal;
+use Zend\Router\Http\Segment;
+
+return [
+
+    'bjyauthorize' => [
+        'guards' => [
+            UnicaenPrivilege\Guard\PrivilegeController::class => [
+                [
+                    'controller' => PrivilegeController::class,
+                    'action' => [
+                        'index',
+                    ],
+                    'privileges' => [
+                        PrivilegePrivileges::PRIVILEGE_VOIR,
+                    ],
+                ],
+                [
+                    'controller' => PrivilegeController::class,
+                    'action' => [
+                        'attribuer',
+                    ],
+                    'privileges' => [
+                        PrivilegePrivileges::PRIVILEGE_ATTRIBUER,
+                    ],
+                ],
+                [
+                    'controller' => PrivilegeController::class,
+                    'action' => [
+                        'ajouter',
+                    ],
+                    'privileges' => [
+                        PrivilegePrivileges::PRIVILEGE_AJOUTER,
+                    ],
+                ],
+                [
+                    'controller' => PrivilegeController::class,
+                    'action' => [
+                        'modifier',
+                    ],
+                    'privileges' => [
+                        PrivilegePrivileges::PRIVILEGE_MODIFIER,
+                    ],
+                ],
+                [
+                    'controller' => PrivilegeController::class,
+                    'action' => [
+                        'supprimer',
+                    ],
+                    'privileges' => [
+                        PrivilegePrivileges::PRIVILEGE_SUPPRIMER,
+                    ],
+                ],
+            ],
+        ],
+    ],
+
+    'router' => [
+        'routes' => [
+            'unicaen-privilege' => [
+                'type' => Literal::class,
+                'options' => [
+                    'route' => '/privilege',
+                    'defaults' => [
+                        'controller' => PrivilegeController::class,
+                        'action' => 'index',
+                    ],
+                ],
+                'may_terminate' => true,
+                'child_routes' => [
+                    'attribuer' => [
+                        'type' => Segment::class,
+                        'options' => [
+                            'route'    => '/attribuer/:role/:privilege',
+                            'defaults' => [
+                                'controller' => PrivilegeController::class,
+                                'action' => 'attribuer',
+                            ],
+                        ],
+                    ],
+                    'ajouter' => [
+                        'type' => Segment::class,
+                        'options' => [
+                            'route' => '/ajouter/:categorie',
+                            'defaults' => [
+                                'controller' => PrivilegeController::class,
+                                'action' => 'ajouter',
+                            ],
+                        ],
+                    ],
+                    'modifier' => [
+                        'type' => Segment::class,
+                        'options' => [
+                            'route' => '/modifier/:privilege',
+                            'defaults' => [
+                                'controller' => PrivilegeController::class,
+                                'action' => 'modifier',
+                            ],
+                        ],
+                    ],
+                    'supprimer' => [
+                        'type' => Segment::class,
+                        'options' => [
+                            'route' => '/supprimer/:privilege',
+                            'defaults' => [
+                                'controller' => PrivilegeController::class,
+                                'action' => 'supprimer',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ],
+    ],
+
+    'controllers' => [
+        'factories' => [
+            PrivilegeController::class  => PrivilegeControllerFactory::class,
+        ],
+    ],
+
+    'service_manager' => [
+        'factories' => [
+            PrivilegeService::class => PrivilegeServiceFactory::class,
+            PrivilegeRuleProvider::class => PrivilegeRuleProviderFactory::class,
+        ],
+    ],
+
+    'form_elements' => [
+        'factories' => [
+            PrivilegeForm::class => PrivilegeFormFactory::class,
+        ],
+    ],
+
+    'view_helpers' => [
+        'invokables' => [
+            'privilege' => PrivilegeViewHelper::class,
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/config/module.config.php b/config/module.config.php
index 05ac34e3952db4a06121bc0c189b275a3e67c14b..ae40b5cb06937bcd0cf3959d7469dbf0a28e611d 100644
--- a/config/module.config.php
+++ b/config/module.config.php
@@ -30,7 +30,7 @@ return [
     'service_manager' => [
         'factories' => [
             'BjyAuthorize\Service\Authorize'           => \UnicaenPrivilege\Service\AuthorizeServiceFactory::class,
-//            'BjyAuthorize\Service\Authorize'           => 'UnicaenAuthentification\Service\AuthorizeServiceFactory', // substituion
+//            'BjyAuthorize\Service\Authorize'           => 'UnicaenAuthentification\Service\AuthorizeServiceFactory', // TODO déplacer le service dans UnicaenAuthentification
         ],
     ],
     'view_manager'    => [
diff --git a/config/unicaen-privilege.global.php.dist b/config/unicaen-privilege.global.php.dist
new file mode 100644
index 0000000000000000000000000000000000000000..d364d0b81d9ce010e9bf87685c41f6259a0b1512
--- /dev/null
+++ b/config/unicaen-privilege.global.php.dist
@@ -0,0 +1,65 @@
+<?php
+
+use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
+use UnicaenPrivilege\Provider\Rule\PrivilegeRuleProvider;
+use UnicaenPrivilege\Service\Privilege\PrivilegeService;
+use UnicaenPrivilege\Entity\Db\Privilege;
+use UnicaenUtilisateur\Provider\Privilege\RolePrivileges;
+
+
+$settings = [
+    'unicaen-auth' => [
+        'enable_privileges' => true,
+    ],
+];
+
+if ($settings['unicaen-auth']['enable_privileges']) {
+    $privileges = [
+        'unicaen-auth' => [
+            /**
+             * L'entité associée aux privilèges peut être spécifiée via la clef de configuration ['unicaen_auth']['privilege_entity_class']
+             * Si elle est manquante alors la classe @see \UnicaenPrivilege\Entity\Db\Privilege est utilisée
+             * NB: la classe spécifiée doit hériter de @see \UnicaenPrivilege\Entity\Db\AbstractPrivilege
+             */
+            'privilege_entity_class' => Privilege::class,
+        ],
+
+        'bjyauthorize' => [
+
+            'resource_providers' => [
+                /**
+                 * Le service Privilege peut aussi être une source de ressources,
+                 * si on souhaite tester directement l'accès à un privilège
+                 */
+                PrivilegeService::class => [],
+            ],
+
+            'rule_providers'     => [
+                PrivilegeRuleProvider::class => [],
+            ],
+        ],
+
+        'navigation' => [
+            'default' => [
+                'home' => [
+                    'pages' => [
+                        'droits' => [
+                            'pages' => [
+                                [
+                                    'label' => "Gérer les privilèges",
+                                    'title' => "Gérer les privilèges",
+                                    'route' => 'unicaen-privilege',
+                                    'resource' => RolePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR),
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ],
+    ];
+} else {
+    $privileges = [];
+}
+
+return array_merge_recursive($settings, $privileges);
\ No newline at end of file
diff --git a/data/sql/schema_oracle.sql b/data/sql/schema_oracle.sql
new file mode 100644
index 0000000000000000000000000000000000000000..daf39566ec2e8d039f526fa3774663ae6b473049
--- /dev/null
+++ b/data/sql/schema_oracle.sql
@@ -0,0 +1,156 @@
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_CATEGORIE
+-- -----------------------------------------------------
+CREATE SEQUENCE UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ NOCYCLE START WITH 1 INCREMENT BY 1 MINVALUE 0;
+
+CREATE TABLE UNICAEN_PRIVILEGE_CATEGORIE (
+  ID        NUMBER(*,0)         NOT NULL,
+  CODE      VARCHAR2(150 CHAR)  NOT NULL,
+  LIBELLE   VARCHAR2(200 CHAR)  NOT NULL,
+  NAMESPACE VARCHAR(255),
+  ORDRE     INT                 DEFAULT 0,
+  CONSTRAINT PK_UNICAEN_PRIVILEGE_CATEGORIE PRIMARY KEY (ID),
+  CONSTRAINT UN_UNICAEN_PRIVILEGE_CATEGORIE_CODE UNIQUE (CODE)
+);
+
+
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_PRIVILEGE
+-- -----------------------------------------------------
+CREATE SEQUENCE UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ NOCYCLE START WITH 1 INCREMENT BY 1 MINVALUE 0;
+
+CREATE TABLE UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID           NUMBER(*, 0)       NOT NULL,
+  CATEGORIE_ID NUMBER(*, 0)       NOT NULL,
+  CODE         VARCHAR2(150 CHAR) NOT NULL,
+  LIBELLE      VARCHAR2(200 CHAR) NOT NULL,
+  ORDRE        INT                DEFAULT 0,
+  CONSTRAINT PK_UNICAEN_PRIVILEGE_PRIVILEGE PRIMARY KEY (ID),
+  CONSTRAINT UN_UNICAEN_PRIVILEGE_CODE UNIQUE (CODE),
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_CATEGORIE FOREIGN KEY (CATEGORIE_ID) REFERENCES UNICAEN_PRIVILEGE_CATEGORIE (ID) DEFERRABLE INITIALLY IMMEDIATE
+);
+
+CREATE INDEX IX_UNICAEN_PRIVILEGE_CATEGORIE ON UNICAEN_PRIVILEGE_PRIVILEGE(CATEGORIE_ID);
+
+
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER
+-- -----------------------------------------------------
+CREATE TABLE UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (
+  ROLE_ID      NUMBER(*, 0) NOT NULL,
+  PRIVILEGE_ID NUMBER(*, 0) NOT NULL,
+  CONSTRAINT PK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER PRIMARY KEY (ROLE_ID, PRIVILEGE_ID),
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_ROLE FOREIGN KEY (ROLE_ID) REFERENCES UNICAEN_UTILISATEUR_ROLE (ID) DEFERRABLE INITIALLY IMMEDIATE,
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_PRIVILEGE FOREIGN KEY (PRIVILEGE_ID) REFERENCES UNICAEN_PRIVILEGE_PRIVILEGE (ID) DEFERRABLE INITIALLY IMMEDIATE
+);
+
+CREATE INDEX IX_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_ROLE ON UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (ROLE_ID);
+CREATE INDEX IX_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_PRIVILEGE ON UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (PRIVILEGE_ID);
+
+
+-- DATA
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'utilisateur'  c, 'Gestion des utilisateurs' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'utilisateur_afficher'      c, 'Consulter un utilisateur'                       l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'utilisateur_ajouter'       c, 'Ajouter un utilisateur'                         l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'utilisateur_changerstatus' c, 'Changer le statut d''un utilisateur'            l, 3  o FROM dual UNION
+  SELECT 4, 1 ca, 'utilisateur_modifierrole'  c, 'Modifier les rôles attribués à un utilisateur'  l, 4  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'role'  c, 'Gestion des rôles' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'role_afficher' c, 'Consulter les rôles'  l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'role_modifier' c, 'Modifier un rôle'     l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'role_effacer'  c, 'Supprimer un rôle'    l, 3  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'privilege'  c, 'Gestion des privilèges' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'privilege_voir'      c, 'Afficher les privilèges'  l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'privilege_ajouter'   c, 'Ajouter un privilège'     l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'privilege_modifier'  c, 'Modifier un privilège'    l, 3  o FROM dual UNION
+  SELECT 4, 1 ca, 'privilege_supprimer' c, 'Supprimer un privilège'   l, 4  o FROM dual UNION
+  SELECT 5, 1 ca, 'privilege_affecter'  c, 'Attribuer un privilège'   l, 5  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
\ No newline at end of file
diff --git a/data/sql/schema_postgresql.sql b/data/sql/schema_postgresql.sql
new file mode 100644
index 0000000000000000000000000000000000000000..acba07dfaa687da9103e2f69e732f4e3ad732677
--- /dev/null
+++ b/data/sql/schema_postgresql.sql
@@ -0,0 +1,150 @@
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_CATEGORIE
+-- -----------------------------------------------------
+CREATE TABLE UNICAEN_PRIVILEGE_CATEGORIE (
+  ID        SERIAL        PRIMARY KEY,
+  CODE      VARCHAR(150)  NOT NULL,
+  LIBELLE   VARCHAR(200)  NOT NULL,
+  NAMESPACE VARCHAR(255),
+  ORDRE     INTEGER       DEFAULT 0
+);
+
+CREATE UNIQUE INDEX UN_UNICAEN_PRIVILEGE_CATEGORIE_CODE ON UNICAEN_PRIVILEGE_CATEGORIE (CODE);
+
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_PRIVILEGE
+-- -----------------------------------------------------
+CREATE TABLE UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID           SERIAL       PRIMARY KEY,
+  CATEGORIE_ID INTEGER      NOT NULL,
+  CODE         VARCHAR(150) NOT NULL,
+  LIBELLE      VARCHAR(200) NOT NULL,
+  ORDRE        INTEGER      NOT NULL,
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_CATEGORIE FOREIGN KEY (CATEGORIE_ID) REFERENCES UNICAEN_PRIVILEGE_CATEGORIE (ID) DEFERRABLE INITIALLY IMMEDIATE
+);
+
+CREATE UNIQUE INDEX UN_UNICAEN_PRIVILEGE_CODE ON UNICAEN_PRIVILEGE_PRIVILEGE(CODE);
+CREATE INDEX IX_UNICAEN_PRIVILEGE_CATEGORIE ON UNICAEN_PRIVILEGE_PRIVILEGE(CATEGORIE_ID);
+
+
+-- -----------------------------------------------------
+-- TABLE UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER
+-- -----------------------------------------------------
+CREATE TABLE UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (
+  ROLE_ID      INTEGER  NOT NULL,
+  PRIVILEGE_ID INTEGER  NOT NULL,
+  CONSTRAINT PK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER PRIMARY KEY (ROLE_ID, PRIVILEGE_ID),
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_ROLE FOREIGN KEY (ROLE_ID) REFERENCES UNICAEN_UTILISATEUR_ROLE (ID) DEFERRABLE INITIALLY IMMEDIATE,
+  CONSTRAINT FK_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_PRIVILEGE FOREIGN KEY (PRIVILEGE_ID) REFERENCES UNICAEN_PRIVILEGE_PRIVILEGE (ID) DEFERRABLE INITIALLY IMMEDIATE
+);
+
+CREATE INDEX IX_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_ROLE ON UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (ROLE_ID);
+CREATE INDEX IX_UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER_PRIVILEGE ON UNICAEN_PRIVILEGE_PRIVILEGE_ROLE_LINKER (PRIVILEGE_ID);
+
+
+-- DATA
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'utilisateur'  c, 'Gestion des utilisateurs' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'utilisateur_afficher'      c, 'Consulter un utilisateur'                       l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'utilisateur_ajouter'       c, 'Ajouter un utilisateur'                         l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'utilisateur_changerstatus' c, 'Changer le statut d''un utilisateur'            l, 3  o FROM dual UNION
+  SELECT 4, 1 ca, 'utilisateur_modifierrole'  c, 'Modifier les rôles attribués à un utilisateur'  l, 4  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'role'  c, 'Gestion des rôles' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'role_afficher' c, 'Consulter les rôles'  l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'role_modifier' c, 'Modifier un rôle'     l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'role_effacer'  c, 'Supprimer un rôle'    l, 3  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_CATEGORIE (
+  ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT  1, 'privilege'  c, 'Gestion des privilèges' l, 1  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.nextval,
+  tmp.c,
+  tmp.l,
+  tmp.o
+FROM tmp;
+
+INSERT INTO UNICAEN_PRIVILEGE_PRIVILEGE (
+  ID,
+  CATEGORIE_ID,
+  CODE,
+  LIBELLE,
+  ORDRE)
+WITH tmp AS (
+  SELECT 1, 1 ca, 'privilege_voir'      c, 'Afficher les privilèges'  l, 1  o FROM dual UNION
+  SELECT 2, 1 ca, 'privilege_ajouter'   c, 'Ajouter un privilège'     l, 2  o FROM dual UNION
+  SELECT 3, 1 ca, 'privilege_modifier'  c, 'Modifier un privilège'    l, 3  o FROM dual UNION
+  SELECT 4, 1 ca, 'privilege_supprimer' c, 'Supprimer un privilège'   l, 4  o FROM dual UNION
+  SELECT 5, 1 ca, 'privilege_affecter'  c, 'Attribuer un privilège'   l, 5  o FROM dual
+)
+SELECT
+  UNICAEN_PRIVILEGE_PRIVILEGE_ID_SEQ.nextval,
+  tmp.ca,
+  UNICAEN_PRIVILEGE_CATEGORIE_ID_SEQ.currval,
+  tmp.l,
+  tmp.o
+FROM tmp;
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Assertion/AbstractAssertion.php b/src/UnicaenPrivilege/Assertion/AbstractAssertion.php
index 7351510314023054f612de3f34a5077137957ed1..1ef48b313964dd300967195a5db0246f9fb89ca5 100644
--- a/src/UnicaenPrivilege/Assertion/AbstractAssertion.php
+++ b/src/UnicaenPrivilege/Assertion/AbstractAssertion.php
@@ -3,8 +3,6 @@
 namespace UnicaenPrivilege\Assertion;
 
 use BjyAuthorize\Service\Authorize;
-use UnicaenAuth\Service\AuthorizeService;
-use UnicaenAuth\Service\UserContext;
 use UnicaenAuthentification\Service\Traits\AuthorizeServiceAwareTrait;
 use UnicaenAuthentification\Service\Traits\UserContextServiceAwareTrait;
 use Zend\Mvc\MvcEvent;
diff --git a/src/UnicaenPrivilege/Controller/AffectationController.php b/src/UnicaenPrivilege/Controller/AffectationController.php
deleted file mode 100644
index 535ffdc4429254a6b3ef2966b4b31d5d3606ddb8..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Controller/AffectationController.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Controller;
-
-use UnicaenPrivilege\Service\Affectation\AffectationServiceAwareTrait;
-use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
-use UnicaenPrivilege\Service\Privilege\PrivilegeServiceAwareTrait;
-use UnicaenUtilisateur\Service\Role\RoleServiceAwareTrait;
-use Zend\Mvc\Controller\AbstractActionController;
-use Zend\View\Model\JsonModel;
-use Zend\View\Model\ViewModel;
-
-class AffectationController extends AbstractActionController {
-    use AffectationServiceAwareTrait;
-    use CategorieServiceAwareTrait;
-    use RoleServiceAwareTrait;
-    use PrivilegeServiceAwareTrait;
-
-    public function indexAction() : ViewModel
-    {
-        $namespaces = $this->getCategorieService()->listerNamespaces();
-        $namespace = $this->params()->fromQuery('namespace');
-
-        $roles = $this->getRoleService()->getRoles();
-        $privileges = $this->getPrivilegeService()->getPrivilegesWithCategories($namespace);
-
-        return new ViewModel([
-            'roles' => $roles,
-            'privileges' => $privileges,
-            'namespaces' => $namespaces,
-        ]);
-    }
-
-    public function modifierAction() : JsonModel
-    {
-        $privilege = $this->getPrivilegeService()->getRequestedPrivilege($this);
-        $role = $this->getRoleService()->getRequestedRole($this);
-
-        $value = $this->getAffectationService()->toggle($role,$privilege);
-
-        return new JsonModel([
-            'value' => $value,
-        ]);
-    }
-
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Controller/AffectationControllerFactory.php b/src/UnicaenPrivilege/Controller/AffectationControllerFactory.php
deleted file mode 100644
index 005d1dfc23a3dc4bf464c0fae31c2ad00a0cb0bb..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Controller/AffectationControllerFactory.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Controller;
-
-use Interop\Container\ContainerInterface;
-use UnicaenPrivilege\Service\Affectation\AffectationService;
-use UnicaenPrivilege\Service\Categorie\CategorieService;
-use UnicaenPrivilege\Service\Privilege\PrivilegeService;
-use UnicaenUtilisateur\Service\Role\RoleService;
-
-class AffectationControllerFactory {
-
-    public function __invoke(ContainerInterface $container) : AffectationController
-    {
-        /**
-         * @var AffectationService $affectationService
-         * @var CategorieService $categorieService
-         * @var PrivilegeService $privilegeService
-         * @var RoleService $roleService
-         */
-        $affectationService = $container->get(AffectationService::class);
-        $categorieService = $container->get(CategorieService::class);
-        $privilegeService = $container->get(PrivilegeService::class);
-        $roleService = $container->get(RoleService::class);
-
-        /** @var AffectationController $controller*/
-        $controller = new AffectationController();
-        $controller->setAffectationService($affectationService);
-        $controller->setCategorieService($categorieService);
-        $controller->setPrivilegeService($privilegeService);
-        $controller->setRoleService($roleService);
-        return $controller;
-    }
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Controller/CategorieController.php b/src/UnicaenPrivilege/Controller/CategorieController.php
index 0cdfc476f8e51cc72a0ff3e309444211d877f08b..a5df2e39d1af9809c7cf1cbb8679444202329731 100644
--- a/src/UnicaenPrivilege/Controller/CategorieController.php
+++ b/src/UnicaenPrivilege/Controller/CategorieController.php
@@ -2,9 +2,11 @@
 
 namespace UnicaenPrivilege\Controller;
 
-use UnicaenPrivilege\Entity\Db\Categorie;
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreFormAwareTrait;
 use UnicaenPrivilege\Form\Categorie\CategorieFormAwareTrait;
 use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
+use UnicaenPrivilege\Service\Privilege\PrivilegeServiceAwareTrait;
 use Zend\Http\Request;
 use Zend\Mvc\Controller\AbstractActionController;
 use Zend\View\Model\ViewModel;
@@ -12,122 +14,112 @@ use Zend\View\Model\ViewModel;
 class CategorieController extends AbstractActionController
 {
     use CategorieServiceAwareTrait;
+    use PrivilegeServiceAwareTrait;
     use CategorieFormAwareTrait;
+    use CategorieFiltreFormAwareTrait;
 
-    public function indexAction() : ViewModel
+    public function indexAction() : array
     {
-        /**
-         * @var string[] $namespaces
-         * @var string $namespaces
-         */
-        $namespaces = $this->getCategorieService()->listerNamespaces();
+        $form = $this->categorieFiltreForm;
         $namespace = $this->params()->fromQuery('namespace');
+        if($namespace) {
+            $form->get('namespace')->setValue($namespace);
+            $categories = $this->categorieService->findByNamespace($namespace);
+        }
+        else {
+            $categories = $this->categorieService->findAll();
+        }
 
-        /** @var Categorie[] $categories */
-        $categories = $this->getCategorieService()->getCategories('ordre');
-        $namespaceC = ($namespace === "Laissé vide !")?"":$namespace;
-        if ($namespace !== null AND $namespace !== "") $categories = array_filter($categories, function (Categorie $a) use ($namespaceC) { return $a->getNamespace() == $namespaceC; });
-
-        return new ViewModel([
-            'namespaces' => $namespaces,
-            'namespace' => $namespace,
-            'categories' => $categories,
-        ]);
+        $title = "Gestion des catégories";
+        return compact('title', 'form', 'categories');
     }
 
     public function ajouterAction() : ViewModel
     {
-        $categorie = new Categorie();
-        $form = $this->getCategorieForm();
+        $categorie = $this->categorieService->getEntityInstance();
+        $categorie->setOrdre($this->categorieService->getMaxOrdre()+1);
+        $form = $this->categorieForm;
         $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/categorie/ajouter', [], [], true));
         $form->bind($categorie);
 
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
+        if ($data = $this->params()->fromPost()) {
             $form->setData($data);
             if ($form->isValid()) {
-                $this->getCategorieService()->create($categorie);
+                try {
+                    $this->categorieService->create($categorie);
+                    $this->flashMessenger()->addSuccessMessage(sprintf("Catégorie <strong>%s</strong> créée avec succès.", $categorie->getLibelle()));
+                } catch (Exception $e) {
+                    $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la création de la catégorie <strong>%s</strong>.", $categorie->getLibelle()));
+                }
             }
         }
 
-        $vm = new ViewModel();
-        $vm->setTemplate('unicaen-privilege/default/default-form');
-        $vm->setVariables([
-            'title' => "Ajout d'une nouvelle catégorie de privilège",
+        $view = new ViewModel();
+        $view->setTemplate('unicaen-privilege/categorie/template/form-categorie');
+        $view->setVariables([
+            'title' => "Ajout d'une nouvelle catégorie",
             'form' => $form,
         ]);
-        return $vm;
+
+        return $view;
     }
 
-    public function gererAction() : ViewModel
+    public function gererAction() : array
     {
-        $categorie = $this->getCategorieService()->getRequestedCategorie($this);
+        $categorie = $this->categorieService->getRequestedCategorie($this);
+        $privileges = $this->privilegeService->findByCategorie($categorie);
+        $title = "Gestion de la catégorie";
 
-        return new ViewModel([
-            'categorie' => $categorie,
-        ]);
+        return compact('title', 'categorie', 'privileges');
     }
 
-    public function providerAction() : ViewModel
+    public function providerAction() : array
     {
-        $categorie = $this->getCategorieService()->getRequestedCategorie($this);
+        $categorie = $this->categorieService->getRequestedCategorie($this);
 
-        return new ViewModel([
-            'title' => "Affichage du fichier fournissant la déclaration des privilèges",
-            'categorie' => $categorie,
-        ]);
+        return compact('categorie');
     }
 
     public function modifierAction() : ViewModel
     {
-        $categorie = $this->getCategorieService()->getRequestedCategorie($this);
-        $form = $this->getCategorieForm();
+        $categorie = $this->categorieService->getRequestedCategorie($this);
+        $form = $this->categorieForm;
         $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/categorie/modifier', ['categorie' => $categorie->getId()], [], true));
         $form->bind($categorie);
-        $form->setOldLibelle($categorie->getLibelle());
-        $form->setOldCode($categorie->getCode());
 
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
+        if ($data = $this->params()->fromPost()) {
             $form->setData($data);
             if ($form->isValid()) {
-                $this->getCategorieService()->update($categorie);
+                try {
+                    $this->categorieService->update($categorie);
+                    $this->flashMessenger()->addSuccessMessage(sprintf("Catégorie <strong>%s</strong> modifiée avec succès.", $categorie->getLibelle()));
+                } catch (Exception $e) {
+                    $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la modification de la catégorie <strong>%s</strong>.", $categorie->getLibelle()));
+                }
             }
         }
 
-        $vm = new ViewModel();
-        $vm->setTemplate('unicaen-privilege/default/default-form');
-        $vm->setVariables([
-            'title' => "Modification d'une catégorie de privilège",
+        $view = new ViewModel();
+        $view->setTemplate('unicaen-privilege/categorie/template/form-categorie');
+        $view->setVariables([
+            'title' => "Modification de la catégorie",
             'form' => $form,
         ]);
-        return $vm;
+
+        return $view;
     }
 
-    public function supprimerAction() : ViewModel {
-        $categorie = $this->getCategorieService()->getRequestedCategorie($this);
 
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
-            if ($data["reponse"] === "oui") $this->getCategorieService()->delete($categorie);
-            exit();
+    public function supprimerAction() : array
+    {
+        try {
+            $categorie = $this->categorieService->getRequestedCategorie($this);
+            $this->categorieService->delete($categorie);
+            $this->flashMessenger()->addSuccessMessage(sprintf("Catégorie <strong>%s</strong> supprimée avec succès.", $categorie->getLibelle()));
+        } catch (Exception $e) {
+            $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la suppression de la catégorie <strong>%s</strong>.", $categorie->getLibelle()));
         }
 
-        $vm = new ViewModel();
-        if ($categorie !== null) {
-            $vm->setTemplate('unicaen-privilege/default/confirmation');
-            $vm->setVariables([
-                'title' => "Suppression de la Catégorie de privilège  de " . $categorie->getLibelle(),
-                'text' => "La suppression est définitive êtes-vous sûr&middot;e de vouloir continuer ?",
-                'action' => $this->url()->fromRoute('unicaen-privilege/categorie/supprimer', ["categorie" => $categorie->getId()], [], true),
-            ]);
-        }
-        return $vm;
+        return compact('categorie');
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Controller/CategorieControllerFactory.php b/src/UnicaenPrivilege/Controller/CategorieControllerFactory.php
index 49cf867550a2524f69624c9e23e7b92a625e1744..da8dcce90840bddac9419a641e97a3c14c61752d 100644
--- a/src/UnicaenPrivilege/Controller/CategorieControllerFactory.php
+++ b/src/UnicaenPrivilege/Controller/CategorieControllerFactory.php
@@ -3,26 +3,38 @@
 namespace UnicaenPrivilege\Controller;
 
 use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreForm;
 use UnicaenPrivilege\Form\Categorie\CategorieForm;
 use UnicaenPrivilege\Service\Categorie\CategorieService;
+use UnicaenPrivilege\Service\Privilege\PrivilegeService;
 
-class CategorieControllerFactory {
-
-    public function __invoke(ContainerInterface $container) : CategorieController
+class CategorieControllerFactory
+{
+    /**
+     * Create controller
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return CategorieController|object
+     */
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
     {
         /**
          * @var CategorieService $categorieService
+         * @var PrivilegeService $privilegeService
          */
         $categorieService = $container->get(CategorieService::class);
-
-        /**
-         * @var CategorieForm $categorieForm
-         */
+        $privilegeService = $container->get(PrivilegeService::class);
         $categorieForm = $container->get('FormElementManager')->get(CategorieForm::class);
+        $categorieFiltreForm = $container->get('FormElementManager')->get(CategorieFiltreForm::class);
 
         $controller = new CategorieController();
         $controller->setCategorieService($categorieService);
+        $controller->setPrivilegeService($privilegeService);
         $controller->setCategorieForm($categorieForm);
+        $controller->setCategorieFiltreForm($categorieFiltreForm);
+
         return $controller;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Controller/PrivilegeController.php b/src/UnicaenPrivilege/Controller/PrivilegeController.php
index 14ebee57dcd9b8f7e55e5be02470167bc301cc61..899c901b5cc3ecf16f658622023aa79a7b0addce 100644
--- a/src/UnicaenPrivilege/Controller/PrivilegeController.php
+++ b/src/UnicaenPrivilege/Controller/PrivilegeController.php
@@ -2,98 +2,126 @@
 
 namespace UnicaenPrivilege\Controller;
 
-use UnicaenPrivilege\Entity\Db\Privilege;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreFormAwareTrait;
 use UnicaenPrivilege\Form\Privilege\PrivilegeFormAwareTrait;
 use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
 use UnicaenPrivilege\Service\Privilege\PrivilegeServiceAwareTrait;
+use UnicaenUtilisateur\Service\Role\RoleServiceAwareTrait;
 use Zend\Http\Request;
 use Zend\Mvc\Controller\AbstractActionController;
+use Zend\View\Model\JsonModel;
 use Zend\View\Model\ViewModel;
 
-class PrivilegeController extends AbstractActionController {
+class PrivilegeController extends AbstractActionController
+{
     use CategorieServiceAwareTrait;
     use PrivilegeServiceAwareTrait;
+    use RoleServiceAwareTrait;
     use PrivilegeFormAwareTrait;
+    use CategorieFiltreFormAwareTrait;
+
+    public function indexAction() : array
+    {
+        $form = $this->categorieFiltreForm;
+        $namespace = $this->params()->fromQuery('namespace');
+        if($namespace) {
+            $form->get('namespace')->setValue($namespace);
+        }
+
+        $roles = $this->roleService->findAll();
+        $privilegesByCategorie = $this->privilegeService->listByCategorie($namespace);
+
+        $title = "Attribution des privilèges";
+        return compact('title', 'form', 'roles', 'privilegesByCategorie');
+    }
 
     public function ajouterAction() : ViewModel
     {
-        $categorie = $this->getCategorieService()->getRequestedCategorie($this);
-        $privilege = new Privilege();
-        $form = $this->getPrivilegeForm();
-        $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/privilege/ajouter', ['categorie' => $categorie->getId()], [], true));
+        $categorie = $this->categorieService->getRequestedCategorie($this);
+        $privilege = $this->privilegeService->getEntityInstance();
+        $privilege->setOrdre($this->privilegeService->getMaxOrdreByCategorie($categorie)+1);
+        $privilege->setCategorie($categorie);
+        $form = $this->privilegeForm;
+        $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/ajouter', ['categorie' => $categorie->getId()], [], true));
+        $form->get('categorieId')->setValue($categorie->getId());
         $form->bind($privilege);
-        $form->setCategorie($categorie);
 
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
+        if ($data = $this->params()->fromPost()) {
             $form->setData($data);
             if ($form->isValid()) {
-                $privilege->setCategorie($categorie);
-                $this->getPrivilegeService()->create($privilege);
+                try {
+                    $this->privilegeService->create($privilege);
+                    $this->flashMessenger()->addSuccessMessage(sprintf("Privilège <strong>%s</strong> créé avec succès.", $privilege->getLibelle()));
+                } catch (Exception $e) {
+                    $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la création du privilège <strong>%s</strong>.", $privilege->getLibelle()));
+                }
             }
         }
 
-        $vm = new ViewModel();
-        $vm->setTemplate('unicaen-privilege/default/default-form');
-        $vm->setVariables([
+        $view = new ViewModel();
+        $view->setTemplate('unicaen-privilege/privilege/template/form-privilege');
+        $view->setVariables([
             'title' => "Ajout d'un nouveau privilège",
             'form' => $form,
         ]);
-        return $vm;
+
+        return $view;
     }
 
     public function modifierAction() : ViewModel
     {
-        $privilege = $this->getPrivilegeService()->getRequestedPrivilege($this);
-        $form = $this->getPrivilegeForm();
-        $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/privilege/modifier', ['privilege' => $privilege->getId()], [], true));
+        $privilege = $this->privilegeService->getRequestedPrivilege($this);
+        $form = $this->privilegeForm;
+        $form->setAttribute('action', $this->url()->fromRoute('unicaen-privilege/modifier', ['privilege' => $privilege->getId()], [], true));
+        $form->get('categorieId')->setValue($privilege->getCategorie()->getId());
         $form->bind($privilege);
-        $form->setCategorie($privilege->getCategorie());
-        $form->setOldLibelle($privilege->getLibelle());
-        $form->setOldCode($privilege->getCode());
-
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
+
+        if ($data = $this->params()->fromPost()) {
             $form->setData($data);
             if ($form->isValid()) {
-                $this->getPrivilegeService()->update($privilege);
+                try {
+                    $this->privilegeService->update($privilege);
+                    $this->flashMessenger()->addSuccessMessage(sprintf("Privilège <strong>%s</strong> modifié avec succès.", $privilege->getLibelle()));
+                } catch (Exception $e) {
+                    $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la modification du privilège <strong>%s</strong>.", $privilege->getLibelle()));
+                }
             }
         }
 
-        $vm = new ViewModel();
-        $vm->setTemplate('unicaen-privilege/default/default-form');
-        $vm->setVariables([
-            'title' => "Modification d'un privilège",
+        $view = new ViewModel();
+        $view->setTemplate('unicaen-privilege/privilege/template/form-privilege');
+        $view->setVariables([
+            'title' => "Modification privilège",
             'form' => $form,
         ]);
-        return $vm;
+
+        return $view;
     }
 
-    public function supprimerAction() : ViewModel
+    public function attribuerAction(): ViewModel
     {
-        $privilege = $this->getPrivilegeService()->getRequestedPrivilege($this);
-
-        /** @var Request $request */
-        $request = $this->getRequest();
-        if ($request->isPost()) {
-            $data = $request->getPost();
-            if ($data["reponse"] === "oui") $this->getPrivilegeService()->delete($privilege);
-            exit();
-        }
+        $privilege = $this->privilegeService->getRequestedPrivilege($this);
+        $role = $this->roleService->getRequestedRole($this);
+        $this->privilegeService->toggle($role,$privilege);
 
-        $vm = new ViewModel();
-        if ($privilege !== null) {
-            $vm->setTemplate('unicaen-privilege/default/confirmation');
-            $vm->setVariables([
-                'title' => "Suppression du privilège " . $privilege->getLibelle(),
-                'text' => "La suppression est définitive êtes-vous sûr&middot;e de vouloir continuer ?",
-                'action' => $this->url()->fromRoute('unicaen-privilege/privilege/supprimer', ["privilege" => $privilege->getId()], [], true),
-            ]);
+        $viewModel = new ViewModel();
+        $viewModel
+            ->setVariables(compact('privilege', 'role'))
+            ->setTerminal(true);
+
+        return $viewModel;
+    }
+
+    public function supprimerAction() : array
+    {
+        try {
+            $privilege = $this->privilegeService->getRequestedPrivilege($this);
+            $this->privilegeService->delete($privilege);
+            $this->flashMessenger()->addSuccessMessage(sprintf("Privilège <strong>%s</strong> supprimé avec succès.", $privilege->getLibelle()));
+        } catch (Exception $e) {
+            $this->flashMessenger()->addErrorMessage(sprintf("Une erreur est survenu lors de la suppression du privilège <strong>%s</strong>.", $privilege->getLibelle()));
         }
-        return $vm;
+
+        return compact('privilege');
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Controller/PrivilegeControllerFactory.php b/src/UnicaenPrivilege/Controller/PrivilegeControllerFactory.php
index 903691d0ceec03f768a66baf43cdf4883626a19d..83eb0d3a40df13f0511d95f063baecbaf33da431 100644
--- a/src/UnicaenPrivilege/Controller/PrivilegeControllerFactory.php
+++ b/src/UnicaenPrivilege/Controller/PrivilegeControllerFactory.php
@@ -3,34 +3,42 @@
 namespace UnicaenPrivilege\Controller;
 
 use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Form\Categorie\CategorieFiltreForm;
 use UnicaenPrivilege\Form\Privilege\PrivilegeForm;
 use UnicaenPrivilege\Service\Categorie\CategorieService;
 use UnicaenPrivilege\Service\Privilege\PrivilegeService;
+use UnicaenUtilisateur\Service\Role\RoleService;
 
-class PrivilegeControllerFactory {
-
+class PrivilegeControllerFactory
+{
     /**
+     * Create controller
+     *
      * @param ContainerInterface $container
-     * @return PrivilegeController
+     * @param string $requestedName
+     * @param array|null $options
+     * @return PrivilegeController|object
      */
-    public function __invoke(ContainerInterface $container) : PrivilegeController
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
     {
         /**
          * @var CategorieService $categorieService
          * @var PrivilegeService $privilegeService
+         * @var RoleService $roleService
          */
         $categorieService = $container->get(CategorieService::class);
         $privilegeService = $container->get(PrivilegeService::class);
-
-        /**
-         * @var PrivilegeForm $privilegeForm
-         */
+        $roleService = $container->get(RoleService::class);
         $privilegeForm = $container->get('FormElementManager')->get(PrivilegeForm::class);
+        $categorieFiltreForm = $container->get('FormElementManager')->get(CategorieFiltreForm::class);
 
         $controller = new PrivilegeController();
         $controller->setCategorieService($categorieService);
         $controller->setPrivilegeService($privilegeService);
+        $controller->setRoleService($roleService);
         $controller->setPrivilegeForm($privilegeForm);
+        $controller->setCategorieFiltreForm($categorieFiltreForm);
+
         return $controller;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Entity/Db/AbstractPrivilege.php b/src/UnicaenPrivilege/Entity/Db/AbstractPrivilege.php
index 70c009255840fcb32673b5a288827dc9f959601d..c6968dbcc9b51c50a41537b417b1c5d91b50640e 100644
--- a/src/UnicaenPrivilege/Entity/Db/AbstractPrivilege.php
+++ b/src/UnicaenPrivilege/Entity/Db/AbstractPrivilege.php
@@ -8,142 +8,175 @@ use UnicaenPrivilege\Provider\Privilege\Privileges;
 use UnicaenUtilisateur\Entity\Db\RoleInterface;
 use Zend\Permissions\Acl\Resource\ResourceInterface;
 
-
-/**
- * Privilege entity abstract mother class.
- *
- * @ORM\MappedSuperclass
- */
 abstract class AbstractPrivilege implements PrivilegeInterface, ResourceInterface
 {
     /**
      * @var int
-     * @ORM\Id
-     * @ORM\Column(type="integer")
-     * @ORM\GeneratedValue(strategy="AUTO")
      */
     protected $id;
 
     /**
      * @var string
-     * @ORM\Column(name="code", type="string", length=150, unique=false, nullable=false)
      */
     protected $code;
 
     /**
      * @var string
-     * @ORM\Column(name="libelle", type="string", length=200, unique=false, nullable=false)
      */
     protected $libelle;
 
     /**
      * @var int
-     * @ORM\Column(name="ordre", type="integer", unique=false, nullable=true)
      */
     protected $ordre;
 
     /**
-     * @var Categorie
-     * @ORM\ManyToOne(targetEntity="Categorie", inversedBy="privilege")
-     * @ORM\JoinColumn(name="categorie_id", referencedColumnName="id")
+     * @var CategorieInterface
      */
     protected $categorie;
 
     /**
-     * @ORM\ManyToMany(targetEntity="UnicaenAuth\Entity\Db\Role",cascade={"all"})
-     * @ORM\JoinTable(
-     *     name="role_privilege",
-     *     joinColumns={@ORM\JoinColumn(name="privilege_id", referencedColumnName="id", onDelete="cascade")},
-     *     inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id", onDelete="cascade")}
-     *
-     * )
+     * @var Collection
      */
-    protected $role;
+    protected $roles;
+
 
     /**
      * Constructor
      */
     public function __construct()
     {
-        $this->role = new ArrayCollection();
+        $this->roles = new ArrayCollection();
     }
 
     /**
-     * @param string $code
-     * @return Privilege
+     * @return string
      */
-    public function setCode(string $code) : PrivilegeInterface
+    public function __toString()
     {
-        $this->code = $code;
+        return $this->getLibelle();
+    }
+
+    /**
+     * Get id.
+     *
+     * @return int
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * Set id.
+     *
+     * @param int $id
+     * @return PrivilegeInterface
+     */
+    public function setId($id)
+    {
+        $this->id = (int)$id;
 
         return $this;
     }
 
     /**
+     * Get code.
+     *
      * @return string
      */
-    public function getCode() : ?string
+    public function getCode()
     {
         return $this->code;
     }
 
-    public function getFullCode() : string
+    /**
+     * Set code.
+     *
+     * @param string $code
+     * @return PrivilegeInterface
+     */
+    public function setCode($code)
     {
-        return $this->getCategorie()->getCode() . '-' . $this->getCode();
+        $this->code = $code;
+
+        return $this;
     }
 
     /**
-     * @param string $libelle
-     * @return Privilege
+     * Get code with category.
+     *
+     * @return string
      */
-    public function setLibelle(string $libelle) : PrivilegeInterface
+    public function getFullCode()
     {
-        $this->libelle = $libelle;
-
-        return $this;
+        return sprintf('%s-%s', $this->categorie->getCode(), $this->getCode());
     }
 
     /**
-     * Get libelle
+     * Get libelle.
+     *
      * @return string
      */
-    public function getLibelle() : ?string
+    public function getLibelle()
     {
         return $this->libelle;
     }
 
     /**
+     * Set libelle.
+     *
+     * @param string $libelle
+     * @return PrivilegeInterface
+     */
+    public function setLibelle($libelle)
+    {
+        $this->libelle = $libelle;
+
+        return $this;
+    }
+
+    /**
+     * Get ordre.
+     *
      * @return integer
      */
-    function getOrdre() : ?int
+    function getOrdre()
     {
         return $this->ordre;
     }
 
     /**
+     * Set ordre.
+     *
      * @param integer $ordre
-     * @return self
+     * @return PrivilegeInterface
      */
-    function setOrdre(int $ordre) : PrivilegeInterface
+    function setOrdre($ordre)
     {
-        $this->ordre = $ordre;
+        $this->ordre = (int)$ordre;
 
         return $this;
     }
 
+
     /**
-     * @return integer
+     * Get categorie.
+     *
+     * @return CategorieInterface
      */
-    public function getId() : int
+    public function getCategorie()
     {
-        return $this->id;
+        return $this->categorie;
     }
 
     /**
-     * @param Categorie|null $categorie
-     * @return self
+     * Set categorie.
+     *
+     * @param CategorieInterface $categorie
+     * @return PrivilegeInterface
      */
-    public function setCategorie(?Categorie $categorie = null) : PrivilegeInterface
+    public function setCategorie(CategorieInterface $categorie)
     {
         $this->categorie = $categorie;
 
@@ -151,53 +184,59 @@ abstract class AbstractPrivilege implements PrivilegeInterface, ResourceInterfac
     }
 
     /**
-     * @return Categorie
+     * @return Collection
      */
-    public function getCategorie() : ?Categorie
+    public function getRoles()
     {
-        return $this->categorie;
+        return $this->roles;
     }
 
     /**
+     * Add role.
+     *
      * @param RoleInterface $role
-     * @return self
+     * @return PrivilegeInterface
      */
-    public function addRole(RoleInterface $role) : PrivilegeInterface
+    public function addRole(RoleInterface $role)
     {
-        $this->role->add($role);
+        $this->roles->add($role);
+        $role->addPrivilege($this);
+
         return $this;
     }
 
     /**
+     * Remove role.
+     *
      * @param RoleInterface $role
-     * @return self
+     * @return PrivilegeInterface
      */
-    public function removeRole(RoleInterface $role) : PrivilegeInterface
+    public function removeRole(RoleInterface $role)
     {
-        $this->role->removeElement($role);
+        $this->roles->removeElement($role);
+        $role->removePrivilege($this);
         return $this;
     }
 
     /**
-     * @return Collection
+     * Check privilege role
+     *
+     * @param RoleInterface $role
+     * @return bool
      */
-    public function getRole() : Collection
+    function hasRole(RoleInterface $role)
     {
-        return $this->role;
-    }
+        foreach ($this->roles as $r) {
+            if ($r === $role) return true;
+        }
 
-    /**
-     * @return string
-     */
-    public function __toString() : string
-    {
-        return $this->getLibelle();
+        return false;
     }
 
     /**
      * @return string
      */
-    public function getResourceId() : string
+    public function getResourceId()
     {
         return Privileges::getResourceId($this);
     }
diff --git a/src/UnicaenPrivilege/Entity/Db/Categorie.php b/src/UnicaenPrivilege/Entity/Db/Categorie.php
index b9dddc787e2e0ac1f794bdebfa31e5c2ce9acc87..30c73e305ef58afcabbfd6b431d3c86f6b088aaf 100644
--- a/src/UnicaenPrivilege/Entity/Db/Categorie.php
+++ b/src/UnicaenPrivilege/Entity/Db/Categorie.php
@@ -3,144 +3,214 @@
 namespace UnicaenPrivilege\Entity\Db;
 
 use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
 
-class Categorie
+class Categorie implements CategorieInterface
 {
-    /**@var int */
+    /**
+     * @var int
+     */
     private $id;
-    /**@var string */
+
+    /**
+     * @var string
+     */
     private $code;
-    /** @var string */
+
+    /**
+     * @var string
+     */
     private $libelle;
-    /** @var string */
+
+    /**
+     * @var string
+     */
     private $namespace;
-    /** @var int */
+
+    /**
+     * @var int
+     */
     private $ordre;
-    /** @var ArrayCollection */
+
+    /**
+     * @var ArrayCollection
+     */
     private $privileges;
 
+
+    /**
+     * Categorie constructor
+     */
     public function __construct()
     {
         $this->privileges = new ArrayCollection();
     }
 
     /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getLibelle();
+    }
+
+    /**
+     * Get id.
+     *
      * @return integer
      */
-    public function getId() : ?int
+    public function getId()
     {
         return $this->id;
     }
 
     /**
+     * Set id.
+     *
+     * @param int $id
+     * @return CategorieInterface
+     */
+    public function setId($id)
+    {
+        $this->id = (int)$id;
+
+        return $this;
+    }
+
+    /**
+     * Get code.
+     *
      * @return string
      */
-    public function getCode() : ?string
+    public function getCode()
     {
         return $this->code;
     }
 
     /**
+     * Set code.
+     *
      * @param string $code
-     * @return Categorie
+     * @return CategorieInterface
      */
-    public function setCode(string $code) : Categorie
+    public function setCode($code)
     {
         $this->code = $code;
+
         return $this;
     }
 
     /**
+     * Get libelle.
+     *
      * @return string
      */
-    public function getLibelle() : ?string
+    public function getLibelle()
     {
         return $this->libelle;
     }
 
     /**
+     * Set libelle.
+     *
      * @param string $libelle
-     * @return Categorie
+     * @return CategorieInterface
      */
-    public function setLibelle(string $libelle) : Categorie
+    public function setLibelle($libelle)
     {
         $this->libelle = $libelle;
+
         return $this;
     }
 
     /**
+     * Get namespace.
+     *
      * @return string
      */
-    public function getNamespace() : ?string
+    public function getNamespace()
     {
         return $this->namespace;
     }
 
     /**
+     * Set namespace.
+     *
      * @param string $namespace
-     * @return Categorie
+     * @return CategorieInterface
      */
-    public function setNamespace(string $namespace) : Categorie
+    public function setNamespace($namespace)
     {
         $this->namespace = $namespace;
+
         return $this;
     }
 
     /**
+     * Get ordre.
+     *
      * @return int
      */
-    public function getOrdre() : ?int
+    public function getOrdre()
     {
         return $this->ordre;
     }
 
     /**
+     * Set ordre.
+     *
      * @param int $ordre
-     * @return Categorie
+     * @return CategorieInterface
      */
-    public function setOrdre(int $ordre) : Categorie
+    public function setOrdre($ordre)
     {
-        $this->ordre = $ordre;
+        $this->ordre = (int)$ordre;
+
         return $this;
     }
 
     /**
-     * @param Privilege $privilege
-     * @return Categorie
+     * Get privileges.
+     *
+     * @return Collection
      */
-    public function addPrivilege(Privilege $privilege) : Categorie
+    public function getPrivileges()
     {
-        $this->privileges->add($privilege);
-        return $this;
+        return $this->privileges;
     }
 
     /**
-     * @param Privilege $privilege
-     * @return Categorie
+     * Add privilege.
+     *
+     * @param PrivilegeInterface $privilege
+     * @return CategorieInterface
      */
-    public function removePrivilege(Privilege $privilege) : Categorie
+    public function addPrivilege(PrivilegeInterface $privilege)
     {
-        $this->privileges->removeElement($privilege);
+        $this->privileges->add($privilege);
+
         return $this;
     }
 
     /**
-     * @return Privilege[]
+     * Remove privilege.
+     *
+     * @param PrivilegeInterface $privilege
+     * @return CategorieInterface
      */
-    public function getPrivilege() : array
+    public function removePrivilege(PrivilegeInterface $privilege)
     {
-        return $this->privileges->toArray();
+        $this->privileges->removeElement($privilege);
+
+        return $this;
     }
 
     /**
+     * Get privileges class name
+     *
      * @return string
      */
-    public function __toString() : string
-    {
-        return $this->getLibelle();
-    }
-
-    public function getClassname() : string
+    public function getClassname()
     {
         return ucfirst(strtolower($this->getCode())) . "Privileges";
     }
diff --git a/src/UnicaenPrivilege/Entity/Db/CategorieInterface.php b/src/UnicaenPrivilege/Entity/Db/CategorieInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b6c18382e42332de9700442f1c5d03940de17375
--- /dev/null
+++ b/src/UnicaenPrivilege/Entity/Db/CategorieInterface.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace UnicaenPrivilege\Entity\Db;
+
+use Doctrine\Common\Collections\Collection;
+
+interface CategorieInterface
+{
+    /**
+     * @return string
+     */
+    public function __toString();
+
+    /**
+     * Get id.
+     *
+     * @return integer
+     */
+    public function getId();
+
+    /**
+     * Set id.
+     *
+     * @param int $id
+     * @return CategorieInterface
+     */
+    public function setId($id);
+
+    /**
+     * Get code.
+     *
+     * @return string
+     */
+    public function getCode();
+
+    /**
+     * Set code.
+     *
+     * @param string $code
+     * @return CategorieInterface
+     */
+    public function setCode($code);
+
+    /**
+     * Get libelle.
+     *
+     * @return string
+     */
+    public function getLibelle();
+
+    /**
+     * Set libelle.
+     *
+     * @param string $libelle
+     * @return CategorieInterface
+     */
+    public function setLibelle($libelle);
+
+    /**
+     * Get namespace.
+     *
+     * @return string
+     */
+    public function getNamespace();
+
+    /**
+     * Set namespace.
+     *
+     * @param string $namespace
+     * @return CategorieInterface
+     */
+    public function setNamespace($namespace);
+
+    /**
+     * Get ordre.
+     *
+     * @return int
+     */
+    public function getOrdre();
+
+    /**
+     * Set ordre.
+     *
+     * @param int $ordre
+     * @return CategorieInterface
+     */
+    public function setOrdre($ordre);
+
+    /**
+     * Get privileges.
+     *
+     * @return Collection
+     */
+    public function getPrivileges();
+
+    /**
+     * Add privilege.
+     *
+     * @param PrivilegeInterface $privilege
+     * @return CategorieInterface
+     */
+    public function addPrivilege(PrivilegeInterface $privilege);
+
+    /**
+     * Remove privilege.
+     *
+     * @param PrivilegeInterface $privilege
+     * @return CategorieInterface
+     */
+    public function removePrivilege(PrivilegeInterface $privilege);
+
+    /**
+     * Get privileges class name
+     *
+     * @return string
+     */
+    public function getClassname();
+}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Categorie.dcm.xml b/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Categorie.dcm.xml
index f036fbc606f2dca6765ba012b2480572a4179e6f..767bc548be6cdcfecbee340c975a38e7cde5a62a 100644
--- a/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Categorie.dcm.xml
+++ b/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Categorie.dcm.xml
@@ -1,16 +1,19 @@
 <?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="UnicaenPrivilege\Entity\Db\Categorie" table="unicaen_privilege_categorie">
+<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="UnicaenPrivilege\Entity\Db\Categorie" table="UNICAEN_PRIVILEGE_CATEGORIE">
 
-        <id name="id" type="integer" column="id">
+        <id name="id" type="integer" column="ID">
             <generator strategy="IDENTITY"/>
         </id>
 
-        <field name="code" type="string" column="code" length="150" nullable="false"/>
-        <field name="libelle" type="string" column="libelle" length="200" nullable="false"/>
-        <field name="ordre" type="integer" column="ordre" nullable="false"/>
-        <field name="namespace" type="string" column="namespace" length="256" nullable="true"/>
+        <field name="code" type="string" column="CODE" length="150" nullable="false"/>
+        <field name="libelle" type="string" column="LIBELLE" length="200" nullable="false"/>
+        <field name="namespace" type="string" column="NAMESPACE" length="256" nullable="true"/>
+        <field name="ordre" type="integer" column="ORDRE" nullable="false"/>
+
+        <one-to-many field="privileges" target-entity="UnicaenPrivilege\Entity\Db\Privilege" mapped-by="categorie"/>
 
-        <one-to-many target-entity="UnicaenPrivilege\Entity\Db\Privilege" mapped-by="categorie" field="privileges"/>
     </entity>
 </doctrine-mapping>
diff --git a/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Privilege.dcm.xml b/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Privilege.dcm.xml
index 77f78430ced2619b73520678368fdf04ecb07888..b894bb0f0fd20f4c26645c2c19047f65e929aea8 100644
--- a/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Privilege.dcm.xml
+++ b/src/UnicaenPrivilege/Entity/Db/Mapping/UnicaenPrivilege.Entity.Db.Privilege.dcm.xml
@@ -1,28 +1,32 @@
 <?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="UnicaenPrivilege\Entity\Db\Privilege" table="unicaen_privilege_privilege">
+<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="UnicaenPrivilege\Entity\Db\Privilege" table="UNICAEN_PRIVILEGE_PRIVILEGE">
 
-    <id name="id" type="integer" column="id">
-      <generator strategy="IDENTITY"/>
-    </id>
+        <indexes>
+            <index name="ix_privilege_categorie" columns="CATEGORIE_ID"/>
+        </indexes>
 
-    <field name="code" type="string" column="code" length="150" nullable="false"/>
-    <field name="libelle" type="string" column="libelle" length="200" nullable="false"/>
-    <field name="ordre" type="integer" column="ordre" nullable="false"/>
+        <unique-constraints>
+            <unique-constraint name="un_privilege_code" columns="CODE"/>
+        </unique-constraints>
 
-    <many-to-one target-entity="UnicaenPrivilege\Entity\Db\Categorie"  field="categorie">
-      <join-column name="categorie_id" referenced-column-name="id"/>
-    </many-to-one>
+        <id name="id" type="integer" column="ID">
+            <generator strategy="IDENTITY"/>
+        </id>
 
-    <many-to-many field="role" target-entity="UnicaenUtilisateur\Entity\Db\Role" inversed-by="privilege" fetch="LAZY">
-      <join-table name="unicaen_privilege_privilege_role_linker">
-        <join-columns>
-          <join-column name="privilege_id" referenced-column-name="id"/>
-        </join-columns>
-        <inverse-join-columns>
-          <join-column name="role_id" referenced-column-name="id"/>
-        </inverse-join-columns>
-      </join-table>
-    </many-to-many>
-  </entity>
+        <field name="code" type="string" column="CODE" length="150" nullable="false"/>
+        <field name="libelle" type="string" column="LIBELLE" length="200" nullable="false"/>
+        <field name="ordre" type="integer" column="ORDRE" nullable="false"/>
+
+        <many-to-one field="categorie" target-entity="UnicaenPrivilege\Entity\Db\Categorie" fetch="LAZY">
+            <join-columns>
+                <join-column name="CATEGORIE_ID" referenced-column-name="ID"/>
+            </join-columns>
+        </many-to-one>
+
+        <many-to-many field="roles" target-entity="UnicaenUtilisateur\Entity\Db\Role" mapped-by="privileges" fetch="LAZY"/>
+
+    </entity>
 </doctrine-mapping>
diff --git a/src/UnicaenPrivilege/Entity/Db/Privilege.php b/src/UnicaenPrivilege/Entity/Db/Privilege.php
index a23fe8b52e30a3db07dcb3c97d78dd0eb3904ae8..7547e80c4dbd0d53a21068f57e5cc1b40c637429 100644
--- a/src/UnicaenPrivilege/Entity/Db/Privilege.php
+++ b/src/UnicaenPrivilege/Entity/Db/Privilege.php
@@ -2,177 +2,8 @@
 
 namespace UnicaenPrivilege\Entity\Db;
 
-use Doctrine\Common\Collections\ArrayCollection;
-use Doctrine\Common\Collections\Collection;
-use UnicaenUtilisateur\Entity\Db\RoleInterface;
-
-
 /**
  * Privilege
  */
-class Privilege implements  PrivilegeInterface //extends AbstractPrivilege
-{
-    const DROIT_ROLE_VISUALISATION          = 'droit-role-visualisation';
-    const DROIT_ROLE_EDITION                = 'droit-role-edition';
-    const DROIT_PRIVILEGE_VISUALISATION     = 'droit-privilege-visualisation';
-    const DROIT_PRIVILEGE_EDITION           = 'droit-privilege-edition';
-
-    /** @var integer */
-    protected $id;
-    /** @var string */
-    protected $code;
-    /** @var string */
-    protected $libelle;
-    /** @var integer */
-    protected $ordre;
-    /** @var Categorie */
-    protected $categorie;
-    /** @var ArrayCollection */
-    protected $role;
-
-    public function __construct()
-    {
-        //parent::__construct();
-        $this->role = new ArrayCollection();
-    }
-
-    /**
-     * @return int
-     */
-    public function getId() : int
-    {
-        return $this->id;
-    }
-
-    /**
-     * @return string
-     */
-    public function getCode() : ?string
-    {
-        return $this->code;
-    }
-
-    /**
-     * @param string $code
-     * @return Privilege
-     */
-    public function setCode(string $code) : PrivilegeInterface
-    {
-        $this->code = $code;
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function getLibelle() : ?string
-    {
-        return $this->libelle;
-    }
-
-    /**
-     * @param string $libelle
-     * @return Privilege
-     */
-    public function setLibelle(string $libelle) : PrivilegeInterface
-    {
-        $this->libelle = $libelle;
-        return $this;
-    }
-
-    /**
-     * @return int
-     */
-    public function getOrdre() : ?int
-    {
-        return $this->ordre;
-    }
-
-    /**
-     * @param int $ordre
-     * @return Privilege
-     */
-    public function setOrdre(int $ordre) : PrivilegeInterface
-    {
-        $this->ordre = $ordre;
-        return $this;
-    }
-
-    /**
-     * @return Categorie
-     */
-    public function getCategorie() : ?Categorie
-    {
-        return $this->categorie;
-    }
-
-    /**
-     * @param Categorie|null $categorie
-     * @return Privilege
-     */
-    public function setCategorie(?Categorie $categorie = null) : PrivilegeInterface
-    {
-        $this->categorie = $categorie;
-        return $this;
-    }
-
-    /**
-     * @return Collection
-     */
-    public function getRole() : Collection
-    {
-        return $this->role;
-    }
-
-    /**
-     * @param RoleInterface $role
-     * @return Privilege
-     */
-    public function addRole(RoleInterface $role) : PrivilegeInterface
-    {
-        $this->role->add($role);
-        return $this;
-    }
-    /**
-     * @param RoleInterface $role
-     * @return Privilege
-     */
-    public function removeRole(RoleInterface $role) : PrivilegeInterface
-    {
-        $this->role->removeElement($role);
-        return $this;
-    }
-
-    /**
-     * @param RoleInterface $role
-     * @return bool
-     */
-    public function hasRole(RoleInterface $role) : bool
-    {
-        $roles = $this->getRole()->toArray();
-        /** @var RoleInterface $roleLF */
-        foreach ($roles as $roleLF) {
-            $a = $role->getId();
-            $b = $roleLF->getId();
-            if ($a == $b) return true;
-        }
-        return false;
-    }
-
-    /**
-     * @return string
-     */
-    public function getFullCode() : string
-    {
-        return $this->getCategorie()->getCode() . '-' . $this->getCode();
-    }
-
-    /**
-     * @return string
-     */
-    public function __toString() : string
-    {
-        return $this->getCode() . " : " . $this->getLibelle();
-    }
-}
+class Privilege extends AbstractPrivilege {}
 
diff --git a/src/UnicaenPrivilege/Entity/Db/PrivilegeInterface.php b/src/UnicaenPrivilege/Entity/Db/PrivilegeInterface.php
index 74fda81d28ed8d6ca44ad66857491656b5834495..b5e45cc30bfe3686613bb7fa960a7ef26f63869e 100644
--- a/src/UnicaenPrivilege/Entity/Db/PrivilegeInterface.php
+++ b/src/UnicaenPrivilege/Entity/Db/PrivilegeInterface.php
@@ -3,84 +3,130 @@
 namespace UnicaenPrivilege\Entity\Db;
 
 use Doctrine\Common\Collections\Collection;
+use UnicaenPrivilege\Provider\Privilege\Privileges;
 use UnicaenUtilisateur\Entity\Db\RoleInterface;
-//use UnicaenAuthentification\Entity\Db\Categorie;
 
 interface PrivilegeInterface
 {
     /**
-     * @return integer
+     * @return string
      */
-    public function getId() : int;
+    public function __toString();
 
     /**
-     * @param string $code
-     * @return self
+     * Get id.
+     *
+     * @return int
      */
-    public function setCode(string $code) : PrivilegeInterface;
+    public function getId();
 
     /**
-     * @return string
+     * Set id.
+     *
+     * @param int $id
+     * @return PrivilegeInterface
      */
-    public function getCode() : ?string;
+    public function setId($id);
 
     /**
+     * Get code.
+     *
      * @return string
      */
-    public function getFullCode() : string;
+    public function getCode();
 
     /**
-     * @param string $libelle
-     * @return self
+     * Set code.
+     *
+     * @param string $code
+     * @return PrivilegeInterface
+     */
+    public function setCode($code);
+
+    /**
+     * Get code with category.
+     *
+     * @return string
      */
-    public function setLibelle(string $libelle) : PrivilegeInterface;
+    public function getFullCode();
 
     /**
+     * Get libelle.
+     *
      * @return string
      */
-    public function getLibelle() : ?string;
+    public function getLibelle();
 
     /**
+     * Set libelle.
+     *
+     * @param string $libelle
+     * @return PrivilegeInterface
+     */
+    public function setLibelle($libelle);
+
+    /**
+     * Get ordre.
+     *
      * @return integer
      */
-    function getOrdre() : ?int;
+    function getOrdre();
 
     /**
+     * Set ordre.
+     *
      * @param integer $ordre
-     * @return self
+     * @return PrivilegeInterface
      */
-    function setOrdre(int $ordre) : PrivilegeInterface;
+    function setOrdre($ordre);
+
 
+    /**
+     * Get categorie.
+     *
+     * @return CategorieInterface
+     */
+    public function getCategorie();
 
     /**
-     * @param Categorie|null $categorie
-     * @return self
+     * Set categorie.
+     *
+     * @param CategorieInterface $categorie
+     * @return PrivilegeInterface
      */
-    public function setCategorie(?Categorie $categorie = null) : PrivilegeInterface;
+    public function setCategorie(CategorieInterface $categorie);
 
     /**
-     * @return Categorie
+     * @return Collection
      */
-    public function getCategorie() : ?Categorie;
+    public function getRoles();
 
     /**
+     * Add role.
+     *
      * @param RoleInterface $role
-     * @return self
+     * @return PrivilegeInterface
      */
-    public function addRole(RoleInterface $role) : PrivilegeInterface;
+    public function addRole(RoleInterface $role);
 
     /**
+     * Remove role.
+     *
      * @param RoleInterface $role
+     * @return PrivilegeInterface
      */
-    public function removeRole(RoleInterface $role) : PrivilegeInterface;
+    public function removeRole(RoleInterface $role);
 
     /**
-     * @return Collection
+     * Check privilege role
+     *
+     * @param RoleInterface $role
+     * @return bool
      */
-    public function getRole() : Collection;
+    function hasRole(RoleInterface $role);
 
     /**
      * @return string
      */
-    public function __toString() : string;
+    public function getResourceId();
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreForm.php b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreForm.php
new file mode 100644
index 0000000000000000000000000000000000000000..eb474e02f5025289f22e43f08b9d8dc9ffae5538
--- /dev/null
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreForm.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace UnicaenPrivilege\Form\Categorie;
+
+use DoctrineModule\Form\Element\ObjectSelect;
+use UnicaenApp\Service\EntityManagerAwareTrait;
+use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
+use Zend\Form\Element\Button;
+use Zend\Form\Element\Select;
+use Zend\Form\Element\Submit;
+use Zend\Form\Form;
+use Zend\InputFilter\Factory;
+
+class CategorieFiltreForm extends Form
+{
+    use EntityManagerAwareTrait;
+    use CategorieServiceAwareTrait;
+
+    public function init()
+    {
+        $this->setAttribute('method', 'get');
+
+        $this->add([
+            'type' => Select::class,
+            'name' => 'namespace',
+            'options' => [
+                'empty_option' => "Tous les namespaces",
+                'value_options' => $this->categorieService->getListForSelect(
+                    $this->categorieService->findAllWithNamespace(), 'namespace', 'namespace'
+                ),
+            ],
+            'attributes' => [
+                'id' => 'namespace',
+                'class' => "selectpicker show-tick",
+                'data-live-search' => "true",
+            ],
+        ]);
+
+        $this->add([
+            'type' => Button::class,
+            'name' => 'filtrer',
+            'options' => [
+                'label' => '<i class="fas fa-filter"></i> filtrer',
+                'label_options' => [
+                    'disable_html_escape' => true,
+                ],
+            ],
+            'attributes' => [
+                'type' => 'submit',
+                'class' => 'btn btn-primary',
+                'id' => 'filtrer'
+            ],
+        ]);
+
+        $this->add([
+            'type' => Button::class,
+            'name' => 'effacer',
+            'options' => [
+                'label' => '<i class="fas fa-backspace"></i> effacer',
+                'label_options' => [
+                    'disable_html_escape' => true,
+                ],
+            ],
+            'attributes' => [
+                'type' => 'button',
+                'class' => 'btn btn-primary',
+                'id' => 'effacer'
+            ],
+        ]);
+
+        $this->setInputFilter((new Factory())->createInputFilter([
+            'namespace' => [
+                'required' => false,
+            ],
+        ]));
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormAwareTrait.php b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f574477addbf3608727c70d33e724cd5dd25251
--- /dev/null
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormAwareTrait.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace UnicaenPrivilege\Form\Categorie;
+
+trait CategorieFiltreFormAwareTrait
+{
+    /**
+     * @var CategorieFiltreForm $categorieFiltreForm
+     */
+    protected $categorieFiltreForm;
+
+    /**
+     * @param CategorieFiltreForm $categorieFiltreForm
+     * @return CategorieFiltreForm
+     */
+    public function setCategorieFiltreForm(CategorieFiltreForm $categorieFiltreForm) : CategorieFiltreForm
+    {
+        $this->categorieFiltreForm = $categorieFiltreForm;
+
+        return $this->categorieFiltreForm;
+    }
+
+    /**
+     * @return CategorieFiltreForm
+     */
+    public function getCategorieFiltreForm() : CategorieFiltreForm
+    {
+        return $this->categorieFiltreForm;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormFactory.php b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3c6ee4edbda183f936a030fcc3fdffb923100ee
--- /dev/null
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieFiltreFormFactory.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace  UnicaenPrivilege\Form\Categorie;
+
+use Doctrine\ORM\EntityManager;
+use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
+use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Service\Categorie\CategorieService;
+use UnicaenUtilisateur\Service\Role\RoleService;
+
+class CategorieFiltreFormFactory
+{
+    /**
+     * Create form
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return CategorieFiltreForm|object
+     */
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+    {
+        /**
+         * @var EntityManager $entityManager
+         * @var RoleService $categorieService
+         */
+        $entityManager = $container->get('Doctrine\ORM\EntityManager');
+        $categorieService = $container->get(CategorieService::class);
+
+        $form = new CategorieFiltreForm();
+        $form->setEntityManager($entityManager);
+        $form->setCategorieService($categorieService);
+
+        return $form;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieForm.php b/src/UnicaenPrivilege/Form/Categorie/CategorieForm.php
index 1717314ff7ed4fd49ec2240c5fef014a5e29103f..521b93128fe2a114d8dee6261fe89de58072c342 100644
--- a/src/UnicaenPrivilege/Form/Categorie/CategorieForm.php
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieForm.php
@@ -1,60 +1,57 @@
 <?php
 
-//TODO prévoir le cas de l'édition ou le nom et le code peuvent rester identiques
-
 namespace UnicaenPrivilege\Form\Categorie;
 
+use DoctrineModule\Validator\UniqueObject;
 use UnicaenApp\Service\EntityManagerAwareTrait;
-use UnicaenPrivilege\Entity\Db\Categorie;
+use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
 use Zend\Form\Element\Button;
 use Zend\Form\Element\Hidden;
+use Zend\Form\Element\Number;
 use Zend\Form\Element\Text;
 use Zend\Form\Form;
 use Zend\InputFilter\Factory;
 use Zend\Validator\Callback;
+use Zend\Validator\NotEmpty;
+use Zend\Validator\Regex;
 
-class CategorieForm extends Form {
+class CategorieForm extends Form
+{
     use EntityManagerAwareTrait;
+    use CategorieServiceAwareTrait;
 
     public function init()
     {
-        //libelle
+        $this->setAttribute('id', 'form-categorie');
+
         $this->add([
             'type' => Text::class,
             'name' => 'libelle',
             'options' => [
-                'label' => "Libelle* :",
+                'label' => "Libellé :",
+                'label_attributes' => [
+                    'class' => 'required',
+                ],
             ],
             'attributes' => [
                 'id' => 'libelle',
             ],
         ]);
-        $this->add([
-            'name' => 'old-libelle',
-            'type' => Hidden::class,
-            'attributes' => [
-                'value' => "",
-            ],
-        ]);
-        //code
+
         $this->add([
             'type' => Text::class,
             'name' => 'code',
             'options' => [
-                'label' => "Code* :",
+                'label' => "Code :",
+                'label_attributes' => [
+                    'class' => 'required',
+                ],
             ],
             'attributes' => [
                 'id' => 'code',
             ],
         ]);
-        $this->add([
-            'name' => 'old-code',
-            'type' => Hidden::class,
-            'attributes' => [
-                'value' => "",
-            ],
-        ]);
-        //namespace
+
         $this->add([
             'type' => Text::class,
             'name' => 'namespace',
@@ -65,9 +62,9 @@ class CategorieForm extends Form {
                 'id' => 'namespace',
             ],
         ]);
-        //ordre
+
         $this->add([
-            'type' => Text::class,
+            'type' => Number::class,
             'name' => 'ordre',
             'options' => [
                 'label' => "Ordre dans la liste :",
@@ -76,10 +73,10 @@ class CategorieForm extends Form {
                 'id' => 'ordre',
             ],
         ]);
-        //submit
+
         $this->add([
             'type' => Button::class,
-            'name' => 'bouton',
+            'name' => 'enregistrer',
             'options' => [
                 'label' => '<i class="fas fa-save"></i> Enregistrer',
                 'label_options' => [
@@ -95,48 +92,89 @@ class CategorieForm extends Form {
         $this->setInputFilter((new Factory())->createInputFilter([
             'libelle' => [
                 'required' => true,
-                'validators' => [[
-                    'name' => Callback::class,
-                    'options' => [
-                        'messages' => [
-                            Callback::INVALID_VALUE => "Ce libellé existe déjà",
+                'validators' => [
+                    [
+                        'name' => NotEmpty::class,
+                        'options' => [
+                            'messages' => [
+                                NotEmpty::IS_EMPTY => "Veuillez renseigner un libellé."
+                            ],
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                    [
+                        'name' => Callback::class,
+                        'options' => [
+                            'messages' => [
+                                Callback::INVALID_VALUE => "Ce libellé est déjà utilisé pour une autre catégorie.",
+                            ],
+                            'callback' => function ($value, $context = []) {
+                                $categorie = $this->categorieService->findByLibelle($value);
+                                if(!$categorie) {
+                                    return true;
+                                }
+                                elseif($this->getObject()->getId() != null) { // modification
+                                    return strtoupper($this->getObject()->getLibelle()) === strtoupper($value);
+                                }
+                                return false;
+                            },
+                            'break_chain_on_failure' => true,
                         ],
-                        'callback' => function ($value, $context = []) {
-                            if($value == $context['old-libelle']) return true;
-                            return ($this->getEntityManager()->getRepository(Categorie::class)->findOneBy(['libelle'=>$value],[]) == null);
-                        },
-                        //'break_chain_on_failure' => true,
                     ],
-                ]],
+                ],
             ],
+
             'code' => [
                 'required' => true,
-                'validators' => [[
-                    'name' => Callback::class,
-                    'options' => [
-                        'messages' => [
-                            Callback::INVALID_VALUE => "Ce code existe déjà",
+                'validators' => [
+                    [
+                        'name' => NotEmpty::class,
+                        'options' => [
+                            'messages' => [
+                                NotEmpty::IS_EMPTY => "Veuillez renseigner un code."
+                            ],
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                    [
+                        'name' => Regex::class,
+                        'options' => [
+                            'pattern' => '/^[a-z0-9_-]+$/',
+                            'messages' => [
+                                Regex::NOT_MATCH => "Seuls les caractères suivants sont autorisés : [a-z, 0-9, _, -].",
+                            ],
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                    [
+                        'name' => Callback::class,
+                        'options' => [
+                            'messages' => [
+                                Callback::INVALID_VALUE => "Ce code est déjà utilisé pour une autre catégorie.",
+                            ],
+                            'callback' => function ($value, $context = []) {
+                                $categorie = $this->categorieService->findByCode($value);
+                                if(!$categorie) {
+                                    return true;
+                                }
+                                elseif($this->getObject()->getId() != null) { // modification
+                                    return strtoupper($this->getObject()->getCode()) === strtoupper($value);
+                                }
+                                return false;
+                            },
+                            'break_chain_on_failure' => true,
                         ],
-                        'callback' => function ($value, $context = []) {
-                            if($value == $context['old-code']) return true;
-                            return ($this->getEntityManager()->getRepository(Categorie::class)->findOneBy(['code'=>$value],[]) == null);
-                        },
-                        //'break_chain_on_failure' => true,
                     ],
-                ]],
+                ],
             ],
-            'old-libelle' => ['required' => false, ],
-            'old-code' => ['required' => false, ],
-            'namespace' => ['required' => false, ],
-            'ordre' => ['required' => false, ],
-        ]));
-    }
 
-    public function setOldLibelle($value){
-        $this->get('old-libelle')->setValue($value);
-    }
+            'namespace' => [
+                'required' => false,
+            ],
 
-    public function setOldCode($value){
-        $this->get('old-code')->setValue($value);
+            'ordre' => [
+                'required' => false,
+            ],
+        ]));
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieFormAwareTrait.php b/src/UnicaenPrivilege/Form/Categorie/CategorieFormAwareTrait.php
index 04c13a7522610260bf1f4d0beb521ad1a2408dbe..608ad9b9adf71c3cb6aed05bb2958dccbf0ac3f9 100644
--- a/src/UnicaenPrivilege/Form/Categorie/CategorieFormAwareTrait.php
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieFormAwareTrait.php
@@ -2,28 +2,30 @@
 
 namespace UnicaenPrivilege\Form\Categorie;
 
-trait CategorieFormAwareTrait {
+trait CategorieFormAwareTrait
+{
+    /**
+     * @var CategorieForm
+     */
+    protected $categorieForm;
 
-    /** @var CategorieForm  */
-    private $categoriePrivilegeForm;
 
     /**
+     * @param CategorieForm $categorieForm
      * @return CategorieForm
      */
-    public function getCategorieForm() : CategorieForm
+    public function setCategorieForm(CategorieForm $categorieForm) : CategorieForm
     {
-        return $this->categoriePrivilegeForm;
+        $this->categorieForm = $categorieForm;
+
+        return $this->categorieForm;
     }
 
     /**
-     * @param CategorieForm $categoriePrivilegeForm
      * @return CategorieForm
      */
-    public function setCategorieForm(CategorieForm $categoriePrivilegeForm) : CategorieForm
+    public function getCategorieForm() : CategorieForm
     {
-        $this->categoriePrivilegeForm = $categoriePrivilegeForm;
-        return $this->categoriePrivilegeForm;
+        return $this->categorieForm;
     }
-
-
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieFormFactory.php b/src/UnicaenPrivilege/Form/Categorie/CategorieFormFactory.php
index 1f943a44df215eb8c7b07cbc4b43a4ed3cb9c41e..ebef1a0eb5979292cc164ef3dcf05f6be185e896 100644
--- a/src/UnicaenPrivilege/Form/Categorie/CategorieFormFactory.php
+++ b/src/UnicaenPrivilege/Form/Categorie/CategorieFormFactory.php
@@ -3,24 +3,35 @@
 namespace UnicaenPrivilege\Form\Categorie;
 
 use Doctrine\ORM\EntityManager;
+use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
 use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Service\Categorie\CategorieService;
 
-class CategorieFormFactory {
-
-    public function __invoke(ContainerInterface $container) : CategorieForm
+class CategorieFormFactory
+{
+    /**
+     * Create form
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return CategorieForm|object
+     */
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
     {
         /**
-         * @var EntityManager $entitymanager
+         * @var EntityManager $entityManager
+         * @var CategorieService $categorieService
          */
-        $entitymanager = $container->get('doctrine.entitymanager.orm_default');
-
-        /** @var CategorieHydrator $hydrator */
-        $hydrator = $container->get('HydratorManager')->get(CategorieHydrator::class);
+        $entityManager = $container->get('Doctrine\ORM\EntityManager');
+        $categorieService = $container->get(CategorieService::class);
+        $hydrator = $container->get('HydratorManager')->get(DoctrineObject::class);
 
-        /** @var CategorieForm $form */
         $form = new CategorieForm();
-        $form->setEntityManager($entitymanager);
+        $form->setEntityManager($entityManager);
+        $form->setCategorieService($categorieService);
         $form->setHydrator($hydrator);
+
         return $form;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieHydrator.php b/src/UnicaenPrivilege/Form/Categorie/CategorieHydrator.php
deleted file mode 100644
index 1b7a05efd8cccf56feee84205e4c3dff3b63d217..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Form/Categorie/CategorieHydrator.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Form\Categorie;
-
-use UnicaenPrivilege\Entity\Db\Categorie;
-use Zend\Hydrator\HydratorInterface;
-
-class CategorieHydrator implements HydratorInterface {
-
-    /**
-     * @param Categorie $object
-     * @return array
-     */
-    public function extract($object) : array
-    {
-        $data = [
-            'libelle'     => $object->getLibelle(),
-            'code'        => $object->getCode(),
-            'ordre'       => $object->getOrdre() ?? null,
-            'namespace'   => $object->getNamespace() ?? null,
-        ];
-        return $data;
-    }
-
-    /**
-     * @param array $data
-     * @param Categorie $object
-     * @return Categorie
-     */
-    public function hydrate(array $data, $object)
-    {
-        $object->setLibelle($data['libelle']);
-        $object->setCode($data['code']);
-        if (isset($data['ordre']) AND $data['ordre'] !== '')
-            $object->setOrdre((int) $data['ordre']);
-        else
-            $object->setOrdre(9999);
-        $object->setNamespace($data['namespace']);
-    }
-
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Categorie/CategorieHydratorFactory.php b/src/UnicaenPrivilege/Form/Categorie/CategorieHydratorFactory.php
deleted file mode 100644
index f588b6a63971f91c0f67b3323993fc252e4e8c57..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Form/Categorie/CategorieHydratorFactory.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Form\Categorie;
-
-use Interop\Container\ContainerInterface;
-
-class CategorieHydratorFactory {
-
-    public function __invoke(ContainerInterface $container) : CategorieHydrator
-    {
-        /** @var CategorieHydrator $hydrator */
-        $hydrator = new CategorieHydrator();
-        return $hydrator;
-    }
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Privilege/PrivilegeForm.php b/src/UnicaenPrivilege/Form/Privilege/PrivilegeForm.php
index a4720ddfb9c9498744ff83f32c2ac0473819d508..9650ec48c6ed2beee6e7f5701df959dfe0160091 100644
--- a/src/UnicaenPrivilege/Form/Privilege/PrivilegeForm.php
+++ b/src/UnicaenPrivilege/Form/Privilege/PrivilegeForm.php
@@ -1,84 +1,106 @@
 <?php
-//TODO utiliser la classe privilege de la config privilege_entity_class
 //TODO prévoir le cas de l'édition ou le nom et le code peuvent rester identiques
 
 namespace UnicaenPrivilege\Form\Privilege;
 
+use DoctrineModule\Form\Element\ObjectSelect;
 use DoctrineModule\Validator\NoObjectExists;
+use DoctrineModule\Validator\UniqueObject;
 use UnicaenApp\Service\EntityManagerAwareTrait;
-use UnicaenPrivilege\Entity\Db\Categorie;
-use UnicaenPrivilege\Entity\Db\Privilege;
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
+use UnicaenPrivilege\Service\Privilege\PrivilegeServiceAwareTrait;
 use Zend\Form\Element\Button;
 use Zend\Form\Element\Hidden;
+use Zend\Form\Element\Number;
 use Zend\Form\Element\Text;
 use Zend\Form\Form;
 use Zend\InputFilter\Factory;
 use Zend\Validator\Callback;
+use Zend\Validator\NotEmpty;
+use Zend\Validator\Regex;
 
-class PrivilegeForm extends Form {
+class PrivilegeForm extends Form
+{
     use EntityManagerAwareTrait;
+    use CategorieServiceAwareTrait;
+    use PrivilegeServiceAwareTrait;
 
     public function init()
     {
-        //libelle
+        $this->setAttribute('id', 'form-privilege');
+
         $this->add([
-            'type' => Text::class,
-            'name' => 'libelle',
+            'type' => Hidden::class,
+            'name' => 'categorieId',
+        ]);
+
+        $this->add([
+            'type' => ObjectSelect::class,
+            'name' => 'categorie',
             'options' => [
-                'label' => "Libelle* :",
+                'label' => "Catégorie :",
+                'object_manager' => $this->getEntityManager(),
+                'target_class' => $this->categorieService->getEntityClass(),
+                'property' => 'libelle',
+                'find_method' => [
+                    'name' => 'findBy',
+                    'params' => [
+                        'criteria' => [],
+                        'orderBy' => ['libelle' => 'ASC'],
+                    ],
+                ],
+                'disable_inarray_validator' => true,
             ],
             'attributes' => [
-                'id' => 'libelle',
+                'id' => 'categorie',
+                'readonly' => true
             ],
         ]);
+
         $this->add([
-            'name' => 'old-libelle',
-            'type' => Hidden::class,
+            'type' => Text::class,
+            'name' => 'libelle',
+            'options' => [
+                'label' => "Libelle :",
+                'label_attributes' => [
+                    'class' => 'required',
+                ],
+            ],
             'attributes' => [
-                'value' => "",
+                'id' => 'libelle',
             ],
         ]);
-        //code
+
         $this->add([
             'type' => Text::class,
             'name' => 'code',
             'options' => [
-                'label' => "Code* :",
+                'label' => "Code :",
+                'label_attributes' => [
+                    'class' => 'required',
+                ],
             ],
             'attributes' => [
                 'id' => 'code',
             ],
         ]);
+
         $this->add([
-            'name' => 'old-code',
-            'type' => Hidden::class,
-            'attributes' => [
-                'value' => "",
-            ],
-        ]);
-        //categorie
-        $this->add([
-            'name' => 'categorie',
-            'type' => Hidden::class,
-            'attributes' => [
-                'value' => "",
-            ],
-        ]);
-        //ordre
-        $this->add([
-            'type' => Text::class,
+            'type' => Number::class,
             'name' => 'ordre',
             'options' => [
                 'label' => "Ordre dans la liste :",
             ],
             'attributes' => [
                 'id' => 'ordre',
+                'min' => 1
             ],
         ]);
-        //submit
+
         $this->add([
             'type' => Button::class,
-            'name' => 'bouton',
+            'name' => 'enregistrer',
             'options' => [
                 'label' => '<i class="fas fa-save"></i> Enregistrer',
                 'label_options' => [
@@ -94,53 +116,91 @@ class PrivilegeForm extends Form {
         $this->setInputFilter((new Factory())->createInputFilter([
             'libelle' => [
                 'required' => true,
-                'validators' => [[
-                    'name' => Callback::class,
-                    'options' => [
-                        'messages' => [
-                            Callback::INVALID_VALUE => "Ce libellé existe déjà dans cette catégorie de privilège",
-                            Callback::INVALID_CALLBACK => "Ce libellé existe déjà dans cette catégorie de privilège",
+                'validators' => [
+                    [
+                        'name' => NotEmpty::class,
+                        'options' => [
+                            'messages' => [
+                                NotEmpty::IS_EMPTY => "Veuillez renseigner un libellé."
+                            ],
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                    [
+                        'name' => Callback::class,
+                        'options' => [
+                            'messages' => [
+                                Callback::INVALID_VALUE => "Ce libellé est déjà utilisé pour un autre privilège de cette catégorie.",
+                            ],
+                            'callback' => function ($value, $context = []) {
+                                $categorie = $this->categorieService->find($context['categorieId']);
+                                $privilege = $this->privilegeService->findByLibelle($value, $categorie);
+                                if(!$privilege) {
+                                    return true;
+                                }
+                                elseif($this->getObject()->getId() != null) { // modification
+                                    return strtoupper($this->getObject()->getLibelle()) === strtoupper($value);
+                                }
+                                return false;
+                            },
+                            'break_chain_on_failure' => true,
                         ],
-                        'callback' => function ($value, $context = []) {
-                            if($value == $context['old-libelle']) return true;
-                            return ($this->getEntityManager()->getRepository(Privilege::class)->findOneBy(['libelle'=>$value, 'categorie' => $context['categorie']],[]) == null);
-                        },
-                        //'break_chain_on_failure' => true,
                     ],
-                ]],
+                ],
             ],
+
             'code' => [
                 'required' => true,
-                'validators' => [[
-                    'name' => Callback::class,
-                    'options' => [
-                        'messages' => [
-                            Callback::INVALID_VALUE => "Ce code existe déjà dans cette catégorie de privilège",
-                            Callback::INVALID_CALLBACK => "Ce code existe déjà dans cette catégorie de privilège",
+                'validators' => [
+                    [
+                        'name' => NotEmpty::class,
+                        'options' => [
+                            'messages' => [
+                                NotEmpty::IS_EMPTY => "Veuillez renseigner un code."
+                            ],
+                            'break_chain_on_failure' => true,
                         ],
-                        'callback' => function ($value, $context = []) {
-                            if($value == $context['old-code']) return true;
-                            return ($this->getEntityManager()->getRepository(Privilege::class)->findOneBy(['code'=>$value, 'categorie' => $context['categorie']],[]) == null);
-                        },
-                        //'break_chain_on_failure' => true,
                     ],
-                ]],
+                    [
+                        'name' => Regex::class,
+                        'options' => [
+                            'pattern' => '/^[a-z0-9_-]+$/',
+                            'messages' => [
+                                Regex::NOT_MATCH => "Seuls les caractères suivants sont autorisés : [a-z, 0-9, _, -].",
+                            ],
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                    [
+                        'name' => Callback::class,
+                        'options' => [
+                            'messages' => [
+                                Callback::INVALID_VALUE => "Ce code est déjà utilisé pour un autre privilège de cette catégorie.",
+                            ],
+                            'callback' => function ($value, $context = []) {
+                                $categorie = $this->categorieService->find($context['categorieId']);
+                                $privilege = $this->privilegeService->findByCode($value, $categorie);
+                                if(!$privilege) {
+                                    return true;
+                                }
+                                elseif($this->getObject()->getId() != null) { // modification
+                                    return strtoupper($this->getObject()->getCode()) === strtoupper($value);
+                                }
+                                return false;
+                            },
+                            'break_chain_on_failure' => true,
+                        ],
+                    ],
+                ],
             ],
-            'old-libelle' => ['required' => false, ],
-            'old-code' => ['required' => false, ],
-            'ordre' => ['required' => false, ],
-        ]));
-    }
 
-    public function setCategorie(Categorie $categorie){
-        $this->get('categorie')->setValue($categorie->getId());
-    }
-
-    public function setOldLibelle($value){
-        $this->get('old-libelle')->setValue($value);
-    }
+            'categorie' => [
+                'required' => false,
+            ],
 
-    public function setOldCode($value){
-        $this->get('old-code')->setValue($value);
+            'ordre' => [
+                'required' => false,
+            ],
+        ]));
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormAwareTrait.php b/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormAwareTrait.php
index b3eef86794aa03a50bb4a7d9f9cd57d8b0808f2c..4c35ec8bd65e2462f56d46c5c5a2178543ee52ac 100644
--- a/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormAwareTrait.php
+++ b/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormAwareTrait.php
@@ -2,28 +2,29 @@
 
 namespace UnicaenPrivilege\Form\Privilege;
 
-trait  PrivilegeFormAwareTrait {
-
-    /** @var PrivilegeForm $privilegeForm */
-    private $privilegeForm;
+trait PrivilegeFormAwareTrait
+{
+    /**
+     * @var PrivilegeForm $privilegeForm
+     */
+    protected $privilegeForm;
 
     /**
+     * @param PrivilegeForm $privilegeForm
      * @return PrivilegeForm
      */
-    public function getPrivilegeForm() : PrivilegeForm
+    public function setPrivilegeForm(PrivilegeForm $privilegeForm): PrivilegeForm
     {
+        $this->privilegeForm = $privilegeForm;
+
         return $this->privilegeForm;
     }
 
     /**
-     * @param PrivilegeForm $privilegeForm
      * @return PrivilegeForm
      */
-    public function setPrivilegeForm(PrivilegeForm $privilegeForm) : PrivilegeForm
+    public function getPrivilegeForm(): PrivilegeForm
     {
-        $this->privilegeForm = $privilegeForm;
         return $this->privilegeForm;
     }
-
-
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormFactory.php b/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormFactory.php
index dcd7dce30d3ce539b0f5dae64a4e01a475861b2a..b8640df724f3146632c4b1506c288c427a998562 100644
--- a/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormFactory.php
+++ b/src/UnicaenPrivilege/Form/Privilege/PrivilegeFormFactory.php
@@ -3,24 +3,39 @@
 namespace UnicaenPrivilege\Form\Privilege;
 
 use Doctrine\ORM\EntityManager;
+use DoctrineModule\Stdlib\Hydrator\DoctrineObject;
 use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Service\Categorie\CategorieService;
+use UnicaenPrivilege\Service\Privilege\PrivilegeService;
 
-class PrivilegeFormFactory {
-
-    public function __invoke(ContainerInterface $container) : PrivilegeForm
+class PrivilegeFormFactory
+{
+    /**
+     * Create form
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return PrivilegeForm|object
+     */
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
     {
         /**
-         * @var EntityManager $entitymanager
+         * @var EntityManager $entityManager
+         * @var CategorieService $categorieService
+         * @var PrivilegeService $privilegeService
          */
-        $entitymanager = $container->get('doctrine.entitymanager.orm_default');
-
-        /** @var PrivilegeHydrator $hydrator */
-        $hydrator = $container->get('HydratorManager')->get(PrivilegeHydrator::class);
+        $entityManager = $container->get('Doctrine\ORM\EntityManager');
+        $categorieService = $container->get(CategorieService::class);
+        $privilegeService = $container->get(PrivilegeService::class);
+        $hydrator = $container->get('HydratorManager')->get(DoctrineObject::class);
 
-        /** @var PrivilegeForm $form */
         $form = new PrivilegeForm();
-        $form->setEntityManager($entitymanager);
+        $form->setEntityManager($entityManager);
+        $form->setCategorieService($categorieService);
+        $form->setPrivilegeService($privilegeService);
         $form->setHydrator($hydrator);
+
         return $form;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydrator.php b/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydrator.php
deleted file mode 100644
index f7bca2c71cb87e6eaa8a18406c92a3852e6ac8f9..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydrator.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Form\Privilege;
-
-use UnicaenPrivilege\Entity\Db\Privilege;
-use Zend\Hydrator\HydratorInterface;
-
-class PrivilegeHydrator implements HydratorInterface {
-
-    /**
-     * @param Privilege $object
-     * @return array
-     */
-    public function extract($object) : array
-    {
-        $data = [
-            'libelle'     => $object->getLibelle(),
-            'code'        => $object->getCode(),
-            'ordre'       => $object->getOrdre() ?? null,
-        ];
-        return $data;
-    }
-
-    /**
-     * @param array $data
-     * @param Privilege $object
-     * @return Privilege
-     */
-    public function hydrate(array $data, $object)
-    {
-        $object->setLibelle($data['libelle']);
-        $object->setCode($data['code']);
-        if (isset($data['ordre']) AND $data['ordre'] !== '')
-            $object->setOrdre((int) $data['ordre']);
-        else
-            $object->setOrdre(9999);
-    }
-
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydratorFactory.php b/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydratorFactory.php
deleted file mode 100644
index ef14e4de0605a02ed6853233fc2a708b0d542971..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Form/Privilege/PrivilegeHydratorFactory.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Form\Privilege;
-
-use Interop\Container\ContainerInterface;
-
-class PrivilegeHydratorFactory {
-
-    public function __invoke(ContainerInterface $container) : PrivilegeHydrator
-    {
-        /** @var PrivilegeHydrator $hydrator */
-        $hydrator = new PrivilegeHydrator();
-        return $hydrator;
-    }
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Provider/Privilege/PrivilegePrivileges.php b/src/UnicaenPrivilege/Provider/Privilege/PrivilegePrivileges.php
index 0fabf6677d7780897dcbd19e1a16d615eac5eae9..51ca177a0597beb1daf2183f0141e990d072a2e8 100644
--- a/src/UnicaenPrivilege/Provider/Privilege/PrivilegePrivileges.php
+++ b/src/UnicaenPrivilege/Provider/Privilege/PrivilegePrivileges.php
@@ -8,5 +8,5 @@ class PrivilegePrivileges extends Privileges
     const PRIVILEGE_AJOUTER = 'privilege-privilege_ajouter';
     const PRIVILEGE_MODIFIER = 'privilege-privilege_modifier';
     const PRIVILEGE_SUPPRIMER = 'privilege-privilege_supprimer';
-    const PRIVILEGE_AFFECTER = 'privilege-privilege_affecter';
+    const PRIVILEGE_ATTRIBUER = 'privilege-privilege_affecter';
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Provider/Privilege/Privileges.php b/src/UnicaenPrivilege/Provider/Privilege/Privileges.php
index b7791e1dd4efdc25d1ae18a2814d540de6c2596b..877cb9111167ce0c620ee51a51966b5de07d185c 100644
--- a/src/UnicaenPrivilege/Provider/Privilege/Privileges.php
+++ b/src/UnicaenPrivilege/Provider/Privilege/Privileges.php
@@ -2,21 +2,23 @@
 
 namespace UnicaenPrivilege\Provider\Privilege;
 
-use UnicaenPrivilege\Entity\Db\Privilege;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
 
 class Privileges {
 
     /**
      * Retourne le nom de la ressource associée au privilège donné
-     * @param $privilege
+     *
+     * @param PrivilegeInterface|string $privilege
      * @return string
      */
-    public static function getResourceId( $privilege )
+    public static function getResourceId($privilege)
     {
-        if ($privilege instanceof Privilege){
+        if ($privilege instanceof PrivilegeInterface) {
             $privilege = $privilege->getFullCode();
         }
-        return 'privilege/'.$privilege;
+
+        return 'privilege/' . $privilege;
     }
 
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Affectation/AffectationService.php b/src/UnicaenPrivilege/Service/Affectation/AffectationService.php
deleted file mode 100644
index ddc7594f3f8913cb7ff5d55432a8edc42f4b95ed..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Service/Affectation/AffectationService.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Service\Affectation;
-
-use Doctrine\ORM\ORMException;
-use UnicaenApp\Service\EntityManagerAwareTrait;
-use UnicaenPrivilege\Entity\Db\Privilege;
-use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
-use UnicaenPrivilege\Exception\RuntimeException;
-use UnicaenPrivilege\Provider\Privilege\PrivilegeProviderInterface;
-use UnicaenUtilisateur\Entity\Db\RoleInterface;
-
-class AffectationService implements PrivilegeProviderInterface {
-    use EntityManagerAwareTrait;
-
-    protected $privilegesRoles;
-
-    /**
-     * @param RoleInterface $role
-     * @param Privilege $privilege
-     * @return bool
-     */
-    public function toggle(RoleInterface $role, Privilege $privilege) : bool
-    {
-        if ($privilege->hasRole($role)) {
-            $privilege->removeRole($role);
-            $value = false;
-        } else {
-            $privilege->addRole($role);
-            $value = true;
-        }
-        try {
-            $this->getEntityManager()->flush($privilege);
-        } catch (ORMException $e) {
-            throw new RuntimeException("Un problème est survenu lors du changement du privilège.", $e);
-        }
-        return $value;
-    }
-
-    /**
-     * Retourne un tableau à deux dimentions composé de chaînes de caractère UNIQUEMENT
-     * Format du tableau :
-     * [
-     *   'privilege_a' => ['role_1', ...],
-     *   'privilege_b' => ['role_1', 'role_2', ...],
-     * ]
-     *
-     * @return string[][]
-     */
-    public function getPrivilegesRoles() : array
-    {
-        if (null === $this->privilegesRoles) {
-            $this->privilegesRoles = [];
-
-            $qb = $this->getEntityManager()->getRepository(Privilege::class)->createQueryBuilder('p')
-                ->addSelect('c, r')
-                ->join('p.categorie', 'c')
-                ->join('p.role', 'r');
-            $result = $qb->getQuery()->getResult();
-
-            foreach ($result as $privilege) {
-                /* @var $privilege PrivilegeInterface */
-                $pr = [];
-                foreach ($privilege->getRole() as $role) {
-                    /* @var $role RoleInterface */
-                    $pr[] = $role->getRoleId();
-                }
-                $this->privilegesRoles[$privilege->getFullCode()] = $pr;
-            }
-        }
-
-        return $this->privilegesRoles;
-    }
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Affectation/AffectationServiceAwareTrait.php b/src/UnicaenPrivilege/Service/Affectation/AffectationServiceAwareTrait.php
deleted file mode 100644
index d9753eaf644e7aec067c56cd39c102c07ffedc2a..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Service/Affectation/AffectationServiceAwareTrait.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Service\Affectation;
-
-trait AffectationServiceAwareTrait {
-
-    /** @var AffectationService */
-    private $affectationService;
-
-    /**
-     * @return AffectationService
-     */
-    public function getAffectationService(): AffectationService
-    {
-        return $this->affectationService;
-    }
-
-    /**
-     * @param AffectationService $affectationService
-     * @return AffectationService
-     */
-    public function setAffectationService(AffectationService $affectationService): AffectationService
-    {
-        $this->affectationService = $affectationService;
-        return $this->affectationService;
-    }
-
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Affectation/AffectationServiceFactory.php b/src/UnicaenPrivilege/Service/Affectation/AffectationServiceFactory.php
deleted file mode 100644
index 556f0a0f949e3b44bd1ebc1b481da8b62cb15e5b..0000000000000000000000000000000000000000
--- a/src/UnicaenPrivilege/Service/Affectation/AffectationServiceFactory.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-namespace UnicaenPrivilege\Service\Affectation;
-
-use Doctrine\ORM\EntityManager;
-use Interop\Container\ContainerInterface;
-
-class AffectationServiceFactory {
-
-    public function __invoke(ContainerInterface $container)
-    {
-        /**
-         * @var EntityManager $entityManager
-         */
-        $entityManager = $container->get('doctrine.entitymanager.orm_default');
-
-        $service = new AffectationService();
-        $service->setEntityManager($entityManager);
-        return $service;
-    }
-}
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Categorie/CategorieService.php b/src/UnicaenPrivilege/Service/Categorie/CategorieService.php
index cfd5f4ac1089486b2bc7ff2ba19b8b588819cec7..c05f52c717c27fba34c68f4c61acb0c7a17fad9b 100644
--- a/src/UnicaenPrivilege/Service/Categorie/CategorieService.php
+++ b/src/UnicaenPrivilege/Service/Categorie/CategorieService.php
@@ -2,162 +2,219 @@
 
 namespace UnicaenPrivilege\Service\Categorie;
 
+use Doctrine\ORM\EntityRepository;
 use Doctrine\ORM\NonUniqueResultException;
 use Doctrine\ORM\ORMException;
 use Doctrine\ORM\QueryBuilder;
 use UnicaenApp\Exception\RuntimeException;
 use UnicaenApp\Service\EntityManagerAwareTrait;
-use UnicaenPrivilege\Entity\Db\Categorie;
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
 use Zend\Mvc\Controller\AbstractActionController;
 
-class CategorieService {
+class CategorieService 
+{
     use EntityManagerAwareTrait;
 
+    /**
+     * @var string
+     */
     private $categorieEntityClass;
 
+    /**
+     * @param string $categorieEntityClass
+     */
     public function setCategorieEntityClass($categorieEntityClass)
     {
+        if (! class_exists($categorieEntityClass) || ! in_array(CategorieInterface::class, class_implements($categorieEntityClass))) {
+            throw new InvalidArgumentException("L'entité associée aux catégories de privilège doit implémenter " . CategorieInterface::class);
+        }
+
         $this->categorieEntityClass = $categorieEntityClass;
     }
 
     /**
-     * @var array
+     * @return string
      */
-    protected $privilegesRoles;
+    public function getEntityClass()
+    {
+        return $this->categorieEntityClass;
+    }
 
-    /** GESTION DES ENTITES *******************************************************************************************/
+    /**
+     * Retourne une nouvelle instance de l'entité courante
+     *
+     * @return CategorieInterface
+     */
+    public function getEntityInstance()
+    {
+        return new $this->categorieEntityClass;
+    }
 
     /**
-     * @param Categorie $categorie
-     * @return Categorie
+     * @return EntityRepository
      */
-    public function create(Categorie $categorie) : Categorie
+    public function getRepo()
     {
-        try {
-            $this->getEntityManager()->persist($categorie);
-            $this->getEntityManager()->flush($categorie);
-        } catch (ORMException $e) {
-            throw new RuntimeException("Un problème est survenu lors de l'enregistrement en base.",0, $e);
-        }
-        return $categorie;
+        return $this->getEntityManager()->getRepository($this->categorieEntityClass);
     }
 
     /**
-     * @param Categorie $categorie
-     * @return Categorie
+     * @param $id
+     *
+     * @return null|CategorieInterface
      */
-    public function update(Categorie $categorie) : Categorie
+    public function find($id)
     {
-        try {
-            $this->getEntityManager()->flush($categorie);
-        } catch (ORMException $e) {
-            throw new RuntimeException("Un problème est survenu lors de l'enregistrement en base.",0, $e);
-        }
-        return $categorie;
+        return $this->getRepo()->find($id);
     }
 
     /**
-     * @param Categorie $categorie
-     * @return Categorie
+     * @param array $orderBy
+     * @return CategorieInterface[]
      */
-    public function delete(Categorie $categorie) : Categorie
+    public function findAll(array $orderBy = ['ordre' => 'ASC'])
     {
-        try {
-            $this->getEntityManager()->remove($categorie);
-            $this->getEntityManager()->flush($categorie);
-        } catch (ORMException $e) {
-            throw new RuntimeException("Un problème est survenu lors de l'enregistrement en base.",0, $e);
-        }
-        return $categorie;
+        return $this->getRepo()->findBy([], $orderBy);
     }
 
-    /** REQUETAGE *****************************************************************************************************/
+    /**
+     * @param array $orderBy
+     * @return float|int|mixed|string
+     */
+    public function findAllWithNamespace(array $orderBy = ['ordre' => 'ASC'])
+    {
+        $qb = $this->getRepo()->createQueryBuilder('c');
+        $qb ->distinct()
+            ->andWhere($qb->expr()->isNotNull('c.namespace'));
+
+        return $qb->getQuery()->getResult();
+    }
 
     /**
-     * @return QueryBuilder
+     * @param string $code
+     * @return CategorieInterface
      */
-    public function createQueryBuilder() : QueryBuilder
+    public function findByCode(string $code)
     {
-        $qb = $this->getEntityManager()->getRepository(Categorie::class)->createQueryBuilder('categorie')
-            ->leftJoin('categorie.privileges', 'privileges')->addSelect('privileges')
-        ;
-        return $qb;
+        return $this->getRepo()->findOneBy(['code' => $code]);
     }
 
     /**
-     * @param string $champ
-     * @param string $ordre
-     * @return Categorie[]
+     * @param string $libelle
+     * @return CategorieInterface
      */
-    public function getCategories(string $champ = 'ordre', string $ordre = 'ASC') : array
+    public function findByLibelle(string $libelle)
     {
-        $qb = $this->createQueryBuilder()
-            ->orderBy('categorie.' . $champ, $ordre);
-        $result = $qb->getQuery()->getResult();
-        return $result;
+        return $this->getRepo()->findOneBy(['libelle' => $libelle]);
+    }
+
+    /**
+     * @param string $namespace
+     * @param array $orderBy
+     * @return array
+     */
+    public function findByNamespace(string $namespace, array $orderBy = ['ordre' => 'ASC'])
+    {
+        return $this->getRepo()->findBy(['namespace' => $namespace]);
     }
 
     /**
-     * @param int|null $id
-     * @return Categorie|null
+     * @param CategorieInterface $categorie
+     * @return CategorieInterface
      */
-    public function getCategorie(?int $id) : ?Categorie
+    public function create(CategorieInterface $categorie)
     {
-        $qb = $this->createQueryBuilder()
-            ->andWhere('categorie.id = :id')
-            ->setParameter('id', $id)
-        ;
         try {
-            $result = $qb->getQuery()->getOneOrNullResult();
-        } catch (NonUniqueResultException $e) {
-            throw new RuntimeException('Plusieurs Categorie portent le même identifiant ['.$id.']', $e);
+            $this->getEntityManager()->persist($categorie);
+            $this->getEntityManager()->flush($categorie);
+        } catch (ORMException $e) {
+            throw new RuntimeException("Un problème est survenu lors de la création de la catégorie de privilège.", null, $e);
         }
-        return $result;
+
+        return $categorie;
     }
 
     /**
-     * @param string $code
-     * @return Categorie|null
+     * @param CategorieInterface $categorie
+     * @return CategorieInterface
      */
-    public function getCategorieByCode(string $code) : ?Categorie
+    public function update(CategorieInterface $categorie)
     {
-        $qb = $this->createQueryBuilder()
-            ->andWhere('categorie.code = :code')
-            ->setParameter('code', $code)
-        ;
         try {
-            $result = $qb->getQuery()->getOneOrNullResult();
-        } catch (NonUniqueResultException $e) {
-            throw new RuntimeException('Plusieurs Categorie portent le même code ['.$code.']', $e);
+            $this->getEntityManager()->flush($categorie);
+        } catch (ORMException $e) {
+            throw new RuntimeException("Un problème est survenu lors de la mise à jour de la catégorie de privilège \"" . $categorie->getLibelle() . "\"", null, $e);
         }
-        return $result;
+
+        return $categorie;
+    }
+
+    /**
+     * @param CategorieInterface $categorie
+     * @return CategorieInterface
+     */
+    public function delete(CategorieInterface $categorie) : CategorieInterface
+    {
+        try {
+            $this->getEntityManager()->remove($categorie);
+            $this->getEntityManager()->flush($categorie);
+        } catch (ORMException $e) {
+            throw new RuntimeException("Un problème est survenu lors de la suppression de la catégorie de privilège \"" . $categorie->getLibelle() . "\"", null, $e);
+        }
+
+        return $categorie;
     }
 
+
     /**
      * @param AbstractActionController $controller
      * @param string $param
-     * @return Categorie|null
+     * @return CategorieInterface|null
      */
-    public function getRequestedCategorie(AbstractActionController $controller, string $param='categorie') : ?Categorie
+    public function getRequestedCategorie(AbstractActionController $controller, string $param = 'categorie')
     {
         $id = $controller->params()->fromRoute($param);
-        $result = $this->getCategorie($id);
+        $result = $this->find($id);
+
         return $result;
     }
 
-    /** FACADE ********************************************************************************************************/
-
     /**
-     * @return string[]
+     * Retourne une liste d'entités sous forme d'un tableau associatif dont les clés
+     * sont les id des entités et les valeurs correspondent au champ choisi
+     *
+     * @param array $entities liste des entités
+     * @param string $key attribut utilisé comme clé
+     * @param string $value attribut utilisé pour les valeurs
+     * @param string $entityClass classe de l'entité
+     * @return array
      */
-    public function listerNamespaces() : array
+    public function getListForSelect($entities, $key = 'id', $value = 'libelle', $entityClass = null)
     {
-        $categories = $this->getCategories();
-        $result = [];
-        foreach ($categories as $categorie) {
-            $result[$categorie->getNamespace()] = $categorie->getNamespace();
+        $entityClass = $entityClass ?: $this->getEntityClass();
+
+        foreach ($entities as $entity) {
+            if ($entity instanceof $entityClass
+                && method_exists($entity, $kgetter = 'get' . ucfirst($key))
+                && method_exists($entity, $vgetter = 'get' . ucfirst($value))) {
+                $result[$entity->$kgetter()] = $entity->$vgetter();
+            }
         }
-        ksort($result);
-        return $result;
+
+        return (array)$result;
+    }
+
+    /**
+     * @return float|int|mixed|string
+     * @throws NonUniqueResultException
+     * @throws \Doctrine\ORM\NoResultException
+     */
+    public function getMaxOrdre()
+    {
+        $qb = $this->getRepo()->createQueryBuilder('c');
+        $qb->select($qb->expr()->max('c.ordre'));
+
+        return $qb->getQuery()->getSingleScalarResult();
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Categorie/CategorieServiceAwareTrait.php b/src/UnicaenPrivilege/Service/Categorie/CategorieServiceAwareTrait.php
index ae83c27599648737b32b676ac4ee16aecf08bccd..62bcd7f76918cf9e04b2a8099a1edf4a02388624 100644
--- a/src/UnicaenPrivilege/Service/Categorie/CategorieServiceAwareTrait.php
+++ b/src/UnicaenPrivilege/Service/Categorie/CategorieServiceAwareTrait.php
@@ -2,27 +2,29 @@
 
 namespace UnicaenPrivilege\Service\Categorie;
 
-trait CategorieServiceAwareTrait {
-
-    /** @var CategorieService */
+trait CategorieServiceAwareTrait
+{
+    /**
+     * @var CategorieService
+     */
     private $categorieService;
 
     /**
+     * @param CategorieService $categorieService
      * @return CategorieService
      */
-    public function getCategorieService(): CategorieService
+    public function setCategorieService(CategorieService $categorieService): CategorieService
     {
+        $this->categorieService = $categorieService;
+
         return $this->categorieService;
     }
 
     /**
-     * @param CategorieService $categorieService
      * @return CategorieService
      */
-    public function setCategorieService(CategorieService $categorieService): CategorieService
+    public function getCategorieService(): CategorieService
     {
-        $this->categorieService = $categorieService;
         return $this->categorieService;
     }
-
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Categorie/CategorieServiceFactory.php b/src/UnicaenPrivilege/Service/Categorie/CategorieServiceFactory.php
index 18d6051a0b6b5a09b296d5f20e091617af4190b2..aca68b2b6fcc00854084726c5f7432c3e35e6066 100644
--- a/src/UnicaenPrivilege/Service/Categorie/CategorieServiceFactory.php
+++ b/src/UnicaenPrivilege/Service/Categorie/CategorieServiceFactory.php
@@ -4,18 +4,33 @@ namespace UnicaenPrivilege\Service\Categorie;
 
 use Doctrine\ORM\EntityManager;
 use Interop\Container\ContainerInterface;
+use UnicaenPrivilege\Entity\Db\Privilege;
 
-class CategorieServiceFactory {
-
-    public function __invoke(ContainerInterface $container) : CategorieService
+class CategorieServiceFactory
+{
+    /**
+     * Create service
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return CategorieService
+     */
+    public function  __invoke(ContainerInterface $container, $requestedName, array $options = null)
     {
         /**
          * @var EntityManager $entityManager
          */
-        $entityManager = $container->get('doctrine.entitymanager.orm_default');
+        $entityManager = $container->get('Doctrine\ORM\EntityManager');
+        $config = $container->get('Config');
+
+        $privilegeEntityClass = $config['unicaen-auth']['privilege_entity_class'] ?? Privilege::class;
+        $mapping = $entityManager->getClassMetadata($privilegeEntityClass)->getAssociationMapping('categorie');
 
         $service = new CategorieService();
         $service->setEntityManager($entityManager);
+        $service->setCategorieEntityClass($mapping['targetEntity']);
+
         return $service;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Privilege/PrivilegeService.php b/src/UnicaenPrivilege/Service/Privilege/PrivilegeService.php
index 61930dcb51e9748e522ce538fe85217bf3209f79..7f8a4fb740e9a4cb78c2ca764824591699eeb4d2 100644
--- a/src/UnicaenPrivilege/Service/Privilege/PrivilegeService.php
+++ b/src/UnicaenPrivilege/Service/Privilege/PrivilegeService.php
@@ -3,192 +3,266 @@
 namespace UnicaenPrivilege\Service\Privilege;
 
 use BjyAuthorize\Provider\Resource\ProviderInterface as ResourceProviderInterface;
+use Doctrine\ORM\EntityRepository;
 use Doctrine\ORM\NonUniqueResultException;
 use Doctrine\ORM\ORMException;
 use Doctrine\ORM\QueryBuilder;
 use UnicaenApp\Service\EntityManagerAwareTrait;
-use UnicaenPrivilege\Entity\Db\Categorie;
-use UnicaenPrivilege\Entity\Db\Privilege;
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
 use UnicaenPrivilege\Exception\RuntimeException;
 use UnicaenPrivilege\Provider\Privilege\PrivilegeProviderInterface;
 use UnicaenPrivilege\Provider\Privilege\Privileges;
-use UnicaenPrivilege\Service\Affectation\AffectationServiceAwareTrait;
 use UnicaenPrivilege\Service\Categorie\CategorieServiceAwareTrait;
+use UnicaenUtilisateur\Entity\Db\RoleInterface;
 use Zend\Mvc\Controller\AbstractActionController;
 
-class PrivilegeService implements PrivilegeProviderInterface, ResourceProviderInterface {
+class PrivilegeService implements PrivilegeProviderInterface, ResourceProviderInterface
+{
     use EntityManagerAwareTrait;
-    use AffectationServiceAwareTrait;
     use CategorieServiceAwareTrait;
 
-    private $privilegeEntityClass;
+    /**
+     * @var string
+     */
+    protected $privilegeEntityClass;
+
+    /**
+     * @var array
+     */
+    protected $privilegesRoles;
 
+
+    /**
+     * @param string $privilegeEntityClass
+     * @return void
+     */
     public function setPrivilegeEntityClass($privilegeEntityClass)
     {
+        if (! class_exists($privilegeEntityClass) || ! in_array(PrivilegeInterface::class, class_implements($privilegeEntityClass))) {
+            throw new InvalidArgumentException("L'entité associée aux privilèges doit implémenter " . PrivilegeInterface::class);
+        }
+
         $this->privilegeEntityClass = $privilegeEntityClass;
     }
 
-    protected $privilegesRoles;
+    /**
+     * @return string
+     */
+    public function getEntityClass()
+    {
+        return $this->privilegeEntityClass;
+    }
+
+    /**
+     * Retourne une nouvelle instance de l'entité lié au service
+     *
+     * @return PrivilegeInterface
+     */
+    public function getEntityInstance()
+    {
+        return new $this->privilegeEntityClass;
+    }
+
+    /**
+     * @return EntityRepository
+     */
+    public function getRepo()
+    {
+        return $this->getEntityManager()->getRepository($this->privilegeEntityClass);
+    }
+
+    /**
+     * @param $id
+     *
+     * @return null|PrivilegeInterface
+     */
+    public function find($id)
+    {
+        return $this->getRepo()->find($id);
+    }
+
+    /**
+     * @param string $code
+     * @param int|CategorieInterface $categorie
+     * @return CategorieInterface
+     */
+    public function findByCode(string $code, $categorie)
+    {
+        return $this->getRepo()->findOneBy(['code' => $code, 'categorie' => $categorie]);
+    }
 
     /**
+     * @param string $libelle
+     * @param int|CategorieInterface $categorie
+     * @return CategorieInterface
+     */
+    public function findByLibelle(string $libelle, $categorie)
+    {
+        return $this->getRepo()->findOneBy(['libelle' => $libelle, 'categorie' => $categorie]);
+    }
+
+    /**
+     * @param string $categorie
+     * @param array $orderBy
      * @return array
      */
-    public function getResources() : array
+    public function findByCategorie(CategorieInterface $categorie, array $orderBy = ['ordre' => 'ASC'])
     {
-        $resources = [];
-        $privileges = array_keys($this->getAffectationService()->getPrivilegesRoles());
-        foreach ($privileges as $privilege) {
-            $resources[] = Privileges::getResourceId($privilege);
+        return $this->getRepo()->findBy(['categorie' => $categorie], $orderBy);
+    }
+
+    /**
+     * @param string $namespace
+     * @return array
+     */
+    public function listByCategorie(?string $namespace)
+    {
+        $categories = $namespace
+            ? $this->categorieService->findByNamespace($namespace)
+            : $this->categorieService->findAll();
+
+        $privilegesByCategorie = [];
+        foreach ($categories as $c) {
+            $privileges = $this->findByCategorie($c);
+            if(count($privileges) > 0) {
+                $privilegesByCategorie[$c->getLibelle()] = $privileges;
+            }
         }
 
-        return $resources;
+        return $privilegesByCategorie;
     }
 
-    /** GESTION DES ENTITES *******************************************************************************************/
-
     /**
-     * @param Privilege $privilege
-     * @return Privilege
+     * @param PrivilegeInterface $privilege
+     * @return PrivilegeInterface
      */
-    public function create(Privilege $privilege) : Privilege
+    public function create(PrivilegeInterface $privilege)
     {
         try {
             $this->getEntityManager()->persist($privilege);
             $this->getEntityManager()->flush($privilege);
         } catch(ORMException $e) {
-            throw new RuntimeException("Un problème est survenue lors de l'enregistrement en BD.");
+            throw new RuntimeException("Un problème est survenu lors de la création du privilège.", null, $e);
         }
+
         return $privilege;
     }
 
     /**
-     * @param Privilege $privilege
-     * @return Privilege
+     * @param PrivilegeInterface $privilege
+     * @return PrivilegeInterface
      */
-    public function update(Privilege $privilege) : Privilege
+    public function update(PrivilegeInterface $privilege)
     {
         try {
             $this->getEntityManager()->flush($privilege);
         } catch(ORMException $e) {
-            throw new RuntimeException("Un problème est survenue lors de l'enregistrement en BD.");
+            throw new RuntimeException("Un problème est survenu lors de la mise à jour du privilège \"" . $privilege->getLibelle() . "\"", null, $e);
         }
+
         return $privilege;
     }
 
     /**
-     * @param Privilege $privilege
-     * @return Privilege
+     * @param PrivilegeInterface $privilege
+     * @return PrivilegeInterface
      */
-    public function delete(Privilege $privilege) : Privilege
+    public function delete(PrivilegeInterface $privilege)
     {
         try {
             $this->getEntityManager()->remove($privilege);
             $this->getEntityManager()->flush($privilege);
         } catch(ORMException $e) {
-            throw new RuntimeException("Un problème est survenue lors de l'enregistrement en BD.");
+            throw new RuntimeException("Un problème est survenu lors de la suppression du privilège \"" . $privilege->getLibelle() . "\"", null, $e);
         }
-        return $privilege;
-    }
-
-    /** REQUETAGE *****************************************************************************************************/
 
-
-    /**
-     * @return QueryBuilder
-     */
-    public function createQueryBuilder() : QueryBuilder
-    {
-        $qb = $this->getEntityManager()->getRepository($this->privilegeEntityClass)->createQueryBuilder('privilege')
-            ->addSelect('categorie')->leftJoin('privilege.categorie', 'categorie')
-        ;
-        return $qb;
-    }
-
-    /**
-     * @return Privilege[]
-     */
-    public function getPrivileges() : array
-    {
-        $qb = $this->createQueryBuilder()
-            ->orderBy('privilege.categorie', 'ASC')
-            ->addOrderBy('privilege.ordre', 'ASC')
-        ;
-
-        $result = $qb->getQuery()->getResult();
-        return $result;
+        return $privilege;
     }
 
     /**
-     * @param int|null $id
-     * @return Privilege|null
+     * @param RoleInterface $role
+     * @param PrivilegeInterface $privilege
+     * @return void
      */
-    public function getPrivilege(?int $id) : ?Privilege
+    public function toggle(RoleInterface $role, PrivilegeInterface $privilege)
     {
-        $qb = $this->createQueryBuilder()
-            ->andWhere('privilege.id = :id')
-            ->setParameter('id', $id)
-        ;
+        if ($privilege->hasRole($role)) {
+            $privilege->removeRole($role);
+        } else {
+            $privilege->addRole($role);
+        }
 
         try {
-            $result = $qb->getQuery()->getOneOrNullResult();
-        } catch (NonUniqueResultException $e) {
-            throw new RuntimeException('Plusieurs Privilege partagent le même identifiant ['.$id.']', $e);
+            $this->getEntityManager()->flush();
+        } catch (ORMException $e) {
+            throw new RuntimeException("Un problème est survenu lors du changement de privilège \"" . $privilege->getLibelle() . "\" pour le rôle \"" . $role->getLibelle() . "\".", $e);
         }
-        return $result;
     }
 
     /**
      * @param AbstractActionController $controller
      * @param string $paramName
-     * @return Privilege|null
+     * @return PrivilegeInterface|null
      */
-    public function getRequestedPrivilege(AbstractActionController $controller, string $paramName='privilege') : ?Privilege
+    public function getRequestedPrivilege(AbstractActionController $controller, string $paramName='privilege')
     {
         $id = $controller->params()->fromRoute($paramName);
-        $result = $this->getPrivilege($id);
+        $result = $this->find($id);
+
         return $result;
     }
 
-    /** FACADE ********************************************************************************************************/
-
     /**
-     * @var string|null $namespace
      * @return array
      */
-    public function getPrivilegesWithCategories(?string $namespace) : array
+    public function getPrivilegesRoles() : array
     {
-        $categories = $this->getCategorieService()->getCategories();
-
-        $privileges = [];
+        if (null === $this->privilegesRoles) {
+            $this->privilegesRoles = [];
 
-        /** @var Categorie $categorie */
-        foreach ($categories as $categorie) {
-            $qb = $this->createQueryBuilder()
-                ->andWhere('privilege.categorie = :id')
-                ->setParameter('id', $categorie->getId())
-                ->orderBy('privilege.ordre', 'ASC')
-            ;
-            if ($namespace !== null AND $namespace !== "") {
-                $qb = $qb->andWhere('categorie.namespace = :namespace')
-                    ->setParameter('namespace', $namespace);
-            }
-
-            $result = $qb->getQuery()->getResult();
-            if ($result && count($result) > 0) {
-                $privileges[$categorie->getLibelle()] = $result;
+            foreach ($this->getRepo()->findAll() as $privilege) {
+                /* @var $privilege PrivilegeInterface */
+                $pr = [];
+                foreach ($privilege->getRoles() as $role) {
+                    /* @var $role RoleInterface */
+                    $pr[] = $role->getRoleId();
+                }
+                $this->privilegesRoles[$privilege->getFullCode()] = $pr;
             }
         }
 
-        return $privileges;
+        return $this->privilegesRoles;
     }
 
-   /**
-     * @return string[][]
+    /**
+     * @return array
      */
-    public function getPrivilegesRoles() : array
+    public function getResources() : array
     {
-        return $this->getAffectationService()->getPrivilegesRoles();
+        $resources = [];
+        $privileges = array_keys($this->getPrivilegesRoles());
+        foreach ($privileges as $privilege) {
+            $resources[] = Privileges::getResourceId($privilege);
+        }
+
+        return $resources;
     }
 
+    /**
+     * @param CategorieInterface $categorie
+     * @return float|int|mixed|string
+     * @throws NonUniqueResultException
+     * @throws \Doctrine\ORM\NoResultException
+     */
+    public function getMaxOrdreByCategorie(CategorieInterface $categorie)
+    {
+        $qb = $this->getRepo()->createQueryBuilder('p');
+        $qb ->select($qb->expr()->max('p.ordre'))
+            ->andWhere($qb->expr()->eq('p.categorie', ':categorie'))
+                ->setParameter('categorie', $categorie);
+
+        return $qb->getQuery()->getSingleScalarResult();
+    }
 }
 
diff --git a/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceAwareTrait.php b/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceAwareTrait.php
index 7c9a42db85474751806bcefb89dcd307f5c69aa6..a5e9c35cb0b7ae8b2602258160e6039a5f1273ed 100644
--- a/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceAwareTrait.php
+++ b/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceAwareTrait.php
@@ -2,26 +2,29 @@
 
 namespace UnicaenPrivilege\Service\Privilege;
 
-trait PrivilegeServiceAwareTrait {
-
-    /** @var PrivilegeService $privilegeService */
-    private $privilegeService;
+trait PrivilegeServiceAwareTrait
+{
+    /**
+     * @var PrivilegeService $privilegeService
+     */
+    protected $privilegeService;
 
     /**
+     * @param PrivilegeService $privilegeService
      * @return PrivilegeService
      */
-    public function getPrivilegeService()
+    public function setPrivilegeService(PrivilegeService $privilegeService): PrivilegeService
     {
+        $this->privilegeService = $privilegeService;
+
         return $this->privilegeService;
     }
 
     /**
-     * @param PrivilegeService $privilegeService
      * @return PrivilegeService
      */
-    public function setPrivilegeService($privilegeService)
+    public function getPrivilegeService(): PrivilegeService
     {
-        $this->privilegeService = $privilegeService;
         return $this->privilegeService;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceFactory.php b/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceFactory.php
index 2a80d5c2ff0e8cc4bd654d49f0198aa76f3815cc..6839b4bbf6fe476a4fb3a42d1231c8c35781ba21 100644
--- a/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceFactory.php
+++ b/src/UnicaenPrivilege/Service/Privilege/PrivilegeServiceFactory.php
@@ -2,33 +2,37 @@
 
 namespace UnicaenPrivilege\Service\Privilege;
 
-
 use Doctrine\ORM\EntityManager;
 use Interop\Container\ContainerInterface;
 use UnicaenPrivilege\Entity\Db\Privilege;
 use UnicaenPrivilege\Service\Affectation\AffectationService;
 use UnicaenPrivilege\Service\Categorie\CategorieService;
 
-class PrivilegeServiceFactory {
-
-    public function __invoke(ContainerInterface $container) {
-
+class PrivilegeServiceFactory
+{
+    /**
+     * Create service
+     *
+     * @param ContainerInterface $container
+     * @param string $requestedName
+     * @param array|null $options
+     * @return PrivilegeService
+     */
+    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
+    {
         /**
          * @var EntityManager $entityManager
-         * @var AffectationService $affectationService
          * @var CategorieService $categorieService
          */
-        $entityManager = $container->get('doctrine.entitymanager.orm_default');
-        $affectationService = $container->get(AffectationService::class);
+        $entityManager = $container->get('Doctrine\ORM\EntityManager');
+        $config = $container->get('Config');
         $categorieService = $container->get(CategorieService::class);
-        $allConfig = $container->get('Config');
 
-        /** @var PrivilegeService $service */
         $service = new PrivilegeService();
         $service->setEntityManager($entityManager);
-        $service->setAffectationService($affectationService);
         $service->setCategorieService($categorieService);
-        $service->setPrivilegeEntityClass($allConfig['unicaen-auth']['privilege_entity_class'] ?? Privilege::class);
+        $service->setPrivilegeEntityClass($config['unicaen-auth']['privilege_entity_class'] ?? Privilege::class);
+
         return $service;
     }
 }
\ No newline at end of file
diff --git a/src/UnicaenPrivilege/View/Privilege/PrivilegeViewHelper.php b/src/UnicaenPrivilege/View/Privilege/PrivilegeViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ba461e13810e9f0412b4e8aaf2d9939048a0445
--- /dev/null
+++ b/src/UnicaenPrivilege/View/Privilege/PrivilegeViewHelper.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace UnicaenPrivilege\View\Privilege;
+
+use Application\Entity\Db\Profil;
+use Application\Entity\Db\Service;
+use Application\Provider\Privilege\ProfilPrivileges;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
+use UnicaenUtilisateur\Entity\Db\RoleInterface;
+use Zend\View\Helper\AbstractHelper;
+
+class PrivilegeViewHelper extends AbstractHelper
+{
+    /**
+     * @var PrivilegeInterface
+     */
+    private $privilege;
+
+
+    /**
+     * @param PrivilegeInterface $privilege
+     * @return self
+     */
+    public function __invoke($privilege = null)
+    {
+        $this->privilege = $privilege;
+
+        return $this;
+    }
+
+    /**
+     * @param RoleInterface $role
+     * @return string
+     */
+    public function renderLienAjouter($role)
+    {
+        return $this->view->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_ATTRIBUER))
+            ? sprintf(
+                '<a href="%s" class="modifier-privilege"
+                    data-toggle="tooltip" 
+                    data-original-title="<span class=\'text-highlight\'><small>Activer le privilège <br/> <strong><em>%s</em></strong> <br/> pour le rôle <br/> <strong><em>%s</em></strong></small></span>">
+                    <i class="fas fa-times-circle text-danger"></i>
+                </a>',
+                $this->view->url('unicaen-privilege/attribuer', ['role' => $role->getId(), 'privilege' => $this->privilege->getId()], [], true),
+                $this->privilege,
+                $role
+            )
+            : sprintf(
+                '<a data-toggle="tooltip" 
+                    data-original-title="<span class=\'text-highlight\'><small>Privilège <br/> <strong><em>%s</em></strong> <br/> Rôle <br/> <strong><em>%s</em></strong></small></span>">
+                    <i class="fas fa-times-circle text-danger"></i>
+                </a>',
+                $this->privilege,
+                $role
+            );
+    }
+
+    /**
+     * @param RoleInterface $role
+     * @return string
+     */
+    public function renderLienSupprimer($role)
+    {
+        return $this->view->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_ATTRIBUER))
+            ? sprintf(
+                '<a href="%s" class="modifier-privilege"
+                    data-toggle="tooltip" 
+                    data-original-title="<span class=\'text-highlight\'><small>Désactiver le privilège <br/> <strong><em>%s</em></strong> <br/> pour le rôle <br/> <strong><em>%s</em></strong></small></span>">
+                    <i class="fas fa-check-circle text-success"></i>
+                </a>',
+                $this->view->url('unicaen-privilege/attribuer', ['role' => $role->getId(), 'privilege' => $this->privilege->getId()], [], true),
+                $this->privilege,
+                $role
+            )
+            : sprintf(
+                '<a data-toggle="tooltip" 
+                    data-original-title="<span class=\'text-highlight\'><small>Privilège <br/> <strong><em>%s</em></strong> <br/> Rôle <br/> <strong><em>%s</em></strong></small></span>">
+                    <i class="fas fa-check-circle text-success"></i>
+                </a>',
+                $this->privilege,
+                $role
+            );
+    }
+
+    /**
+     * @param RoleInterface $role
+     * @return string
+     */
+    public function renderStatut($role)
+    {
+        $check = $this->privilege->hasRole($role);
+        $html = '<td class="role-privilege-statut text-center %s" style="border-right: 1px solid #ddd;">%s</td>';
+        return sprintf($html,
+            $check ? 'success' : 'danger',
+            $check ? $this->renderLienSupprimer($role) : $this->renderLienAjouter($role)
+        );
+    }
+}
\ No newline at end of file
diff --git a/view/unicaen-privilege/affectation/index.phtml b/view/unicaen-privilege/affectation/index.phtml
deleted file mode 100644
index bf12f7d5495cc9fe21617a886593428af0541df1..0000000000000000000000000000000000000000
--- a/view/unicaen-privilege/affectation/index.phtml
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-
-/**
- * @see \UnicaenPrivilege\Controller\AffectationController::indexAction()
- * @var RoleInterface[] $roles
- * @var array $privileges
- * @var string[] $namespaces
- * @var string $namespace
- */
-
-use UnicaenAuth\Entity\Db\RoleInterface;
-use UnicaenPrivilege\Entity\Db\Privilege;
-use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
-
-//var_dump($privileges);
-
-$this->headTitle("Gestion des affectations de privilège");
-
-$nbRoles = count($roles);
-
-$canAffecter = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_AFFECTER))
-?>
-
-<h1 class="page-header">
-    Gestion des affectations de privilège
-</h1>
-
-
-<div class="row">
-    <?php /** @see \UnicaenPrivilege\Controller\CategorieController::indexAction() */ ?>
-    <a href="<?php echo $this->url('unicaen-privilege/categorie', [], []); ?>"
-       class="btn btn-primary action"
-    >
-        <span class="icon listing"></span>
-        Gestion des catégories
-    </a>
-</div>
-
-<?php echo $this->partial('partial/filtre-categorie.phtml', ['namespaces' => $namespaces, 'namespace' => $namespace]); ?>
-
-<div class="row">
-<table class="privilege">
-    <thead>
-        <tr>
-            <th class="action">
-                <span id="show"><span class="glyphicon glyphicon-eye-open"></span> Afficher les privilèges</span>
-                <br/>
-                <span id="hide"><span class="glyphicon glyphicon-eye-close"></span> Masquer les privilèges</span>
-            </th>
-            <?php foreach ($roles as $role) : ?>
-                <th class="role">
-                    <span class="vertical">
-                        <?php echo $role->getRoleId(); ?>
-                    </span>
-                </th>
-            <?php endforeach; ?>
-        </tr>
-    </thead>
-    <tbody>
-        <?php $categorieId = 1; ?>
-        <?php foreach ($privileges as $libelleCategorie => $privilegesCategorie) : ?>
-            <tr>
-                <th id="<?php echo current($privilegesCategorie)->getCategorie()->getId(); ?>" class="categorie" colspan="<?php echo (1+$nbRoles);?>"> <?php echo $libelleCategorie; ?></th>
-            </tr>
-                <?php /** @var Privilege $privilegeCategorie */ ?>
-                <?php foreach ($privilegesCategorie as $privilegeCategorie) : ?>
-                    <tr class="privilege <?php echo $privilegeCategorie->getCategorie()->getId(); ?>">
-                        <th class="privilege">
-                            <?php echo $privilegeCategorie->getLibelle(); ?>
-                        </th>
-                        <?php foreach ($roles as $role) : ?>
-                            <td id="<?php echo $role->getId();?>_<?php echo $privilegeCategorie->getId();?>"
-                                class="affectation <?php echo ($canAffecter)?"can":"none"; ?>"
-                                title="<?php echo $role->getRoleId(); ?> > <?php echo $privilegeCategorie->getLibelle(); ?>"
-                            >
-                                <?php if( $privilegeCategorie->hasRole($role)) : ?>
-                                    <span class="glyphicon glyphicon-ok text-success"></span>
-                                <?php else: ?>
-                                    <span class="glyphicon glyphicon-remove text-danger"></span>
-                                <?php endif; ?>
-                            </td>
-                        <?php endforeach; ?>
-                    </tr>
-                <?php endforeach; ?>
-        <?php $categorieId++; ?>
-        <?php endforeach; ?>
-    </tbody>
-</table>
-</div>
-
-<style>
-    th.categorie {
-        background-color: lightsteelblue;
-        border: 1px solid black;
-        height: 3rem;
-    }
-
-    th.privilege {
-        background-color: lightgoldenrodyellow;
-        border: 1px solid gray;
-        height: 2rem;
-        width: 30rem;
-    }
-
-    th.action {
-        width: 30rem;
-    }
-
-    th.role {
-        border: 1px solid gray;
-        width:4.5rem;
-        text-align: center;
-    }
-
-    .vertical {
-        writing-mode: vertical-rl;
-        text-orientation: sideways;
-    }
-
-    td.affectation {
-        border: 1px solid gray;
-        text-align: center;
-        height: 4.5rem;
-        width: 4.5rem;
-    }
-
-    td.can:hover {
-        cursor: pointer;
-    }
-
-    th.categorie:hover {
-        cursor: row-resize;
-    }
-</style>
-
-<script>
-    $('a.toggle').click(function() {
-        $("tr.privilege").hide();
-        let namespace = $(this).attr("id");
-    });
-
-    $("th.categorie").click(function(){
-        let categorieId = $(this).attr("id");
-        $("tr."+ categorieId).toggle();
-    });
-
-    $("span#show").click(function(){
-        $("tr.privilege").show();
-    });
-
-    $("span#hide").click(function(){
-        $("tr.privilege").hide();
-    });
-
-    $("td.can").click(function(){
-        let id = $(this).attr("id");
-        var splits = id.split("_");
-        let role = splits[0];
-        let privilege = splits[1];
-
-
-        var url = "modifier-affectation/" + role + "/" + privilege;
-        console.log('click : ' + url);
-        $.ajax({
-            type: "POST",
-            url : url,
-            beforeSend:
-                function () {
-                    document.getElementById(id).innerHTML = "<span class='glyphicon glyphicon-hourglass text-info'></span>";
-                },
-            success:
-                function(retour){
-                    console.log(retour);
-                    var texte = "";
-                    if (retour["value"] == 1) texte = "<span class='glyphicon glyphicon-ok text-success'></span>";
-                    else var texte = "<span class='glyphicon glyphicon-remove text-danger'></span>";
-                    document.getElementById(id).innerHTML = texte;
-                }
-        });
-    });
-</script>
\ No newline at end of file
diff --git a/view/unicaen-privilege/affectation/partial/filtre-categorie.phtml b/view/unicaen-privilege/affectation/partial/filtre-categorie.phtml
deleted file mode 100644
index d8fa89493935775a301019da21c79676e6978ca7..0000000000000000000000000000000000000000
--- a/view/unicaen-privilege/affectation/partial/filtre-categorie.phtml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/**
- * @var string[] $namespaces
- * @var string $namespace
- */
-
-?>
-
-<div class="panel panel-default">
-    <div class="panel panel-heading">
-        <span class="icon filtrer"></span>
-        Filtrage des catégories de privilège
-    </div>
-    <div class="panel panel-body">
-        <form id="filter" method="get" action="<?php echo $this->url(); /**$this->url('unicaen-privilege/categorie',[],[], true);**/ ?>">
-        <div class="row">
-            <div class="col-md-4">
-                <select id="namespace" name="namespace" class="selectpicker show-tick" data-live-search="true">
-                    <option value=""> Tous les namespaces </option>
-                    <?php foreach ($namespaces as $namespaceCurrent) : ?>
-                        <?php $string = (trim($namespaceCurrent) === "")?"Laissé vide !":$namespaceCurrent; ?>
-                        <option value="<?php echo $string; ?>" <?php if ($string === $namespace) echo " selected"; ?> >
-                            <?php echo $string ?>
-                        </option>
-                    <?php endforeach; ?>
-                </select>
-            </div>
-        </div>
-
-        <div class="row">
-            <div class="pull-right">
-                <button type="button" id="filter" class="btn btn-primary filter-action">
-                    <span class="icon filtrer" aria-hidden="true"></span> Filtrer
-                </button>
-                <button type="button" id="reset" class="btn btn-primary filter-action">
-                    <span class="icon remise-a-zero" aria-hidden="true"></span> R.A.Z.
-                </button>
-            </div>
-        </div>
-        </form>
-
-    </div>
-</div>
-
-<style>
-    .filter-action {
-        width: 25rem;
-        margin: 0 1rem;
-    }
-
-    form#filter label {
-        width: 10rem;
-    }
-</style>
-
-<script>
-    $('button#reset').click(function (e) {
-        e.preventDefault();
-        window.location = '?';
-    });
-    $('button#filter').click(function () {
-        console.log('pouet');
-        $('form#filter').submit();
-    });
-</script>
diff --git a/view/unicaen-privilege/categorie/gerer.phtml b/view/unicaen-privilege/categorie/gerer.phtml
index 3a1cc8eec9820cdbdcd7126893650fb923fe1a7b..1f4bb5a27518bade9bba3f5dcc1841f7bd0b0ba9 100644
--- a/view/unicaen-privilege/categorie/gerer.phtml
+++ b/view/unicaen-privilege/categorie/gerer.phtml
@@ -1,163 +1,231 @@
 <?php
 
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
+
 /**
  * @see \UnicaenPrivilege\Controller\CategorieController::gererAction()
- * @var Categorie $categorie
+ * @var CategorieInterface $categorie
+ * @var PrivilegeInterface[] $privileges
  */
 
-use UnicaenPrivilege\Entity\Db\Categorie;
-use UnicaenPrivilege\Entity\Db\Privilege;
-use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
-
-$this->headTitle('Gestion de la catégorie : ' . $categorie->getLibelle());
-
-$canRetour              = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
+$canVoir                = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
 $canEditerCategorie     = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_MODIFIER));
+$canDetruireCategorie   = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_SUPPRIMER));
 $canAjouterPrivilege    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_AJOUTER));
 $canEditerPrivilege     = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_MODIFIER));
 $canDetruirePrivilege   = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_SUPPRIMER));
 $canProvider            = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
-
 ?>
 
+<?php $this->headTitle($this->translate($title)) ?>
+
 <h1 class="page-header">
-    Gestion la catégorie <br/>
-    <strong><?php echo $categorie; ?></strong>
+    <?php echo sprintf("%s : <strong>%s</strong>", $title, $categorie->getLibelle()); ?>
 </h1>
 
-    <div class="row">
-        <div class="col-md-6">
-            <?php if ($canRetour) : ?>
-            <?php /** @see \UnicaenPrivilege\Controller\CategorieController::indexAction()*/ ?>
-            <a href="<?php echo $this->url('unicaen-privilege/categorie', [], [], true); ?>" class="btn btn-primary action">
-                <span class="icon retour"></span>
-                Retour à l'index des catégories
+<?php echo $this->messenger()->addMessagesFromFlashMessenger(); ?>
+
+<?php if ($canVoir) : ?>
+    <?php /** @see CategorieController::indexAction() */ ?>
+    <a href="<?php echo $this->url('unicaen-privilege/categorie', [], [], true); ?>" class="btn btn-primary">
+        <i class="fas fa-tag"></i>
+        Gérer les catégories
+    </a>
+<?php endif; ?>
+
+<?php if ($canAjouterPrivilege) : ?>
+    <?php /** @see PrivilegeController::ajouterAction() */ ?>
+    <a href="<?php echo $this->url('unicaen-privilege/ajouter', ['categorie' => $categorie->getId()], [], true); ?>"
+       class="btn btn-primary ajax-modal" data-event="event-unicaen-privilege-editer">
+        <i class="fas fa-plus-square"></i>
+        Ajouter un privilège
+    </a>
+<?php endif; ?>
+
+<p></p>
+
+<div class="panel panel-info">
+    <div class="panel-heading">
+        Information sur la catégorie #<?php echo $categorie->getId()?>
+    </div>
+    <table class="table">
+        <tbody>
+        <tr>
+            <th class="col-md-4">Libellé</th>
+            <td><?php echo $categorie->getLibelle(); ?></td>
+        </tr>
+        <tr>
+            <th>Code</th>
+            <td><?php echo $categorie->getCode(); ?></td>
+        </tr>
+        <tr>
+            <th>Namespace</th>
+            <td>
+                <code><?php echo $categorie->getNamespace(); ?></code>
+            </td>
+        </tr>
+        <tr>
+            <th>Ordre</th>
+            <td><?php echo $categorie->getOrdre(); ?></td>
+        </tr>
+        </tbody>
+    </table>
+    <div class="panel-footer">
+        <?php if ($canEditerCategorie) : ?>
+            <?php /** @see CategorieController::modifierAction()() */ ?>
+            <a href="<?php echo $this->url('unicaen-privilege/categorie/modifier', ['categorie' => $categorie->getId()], [], true); ?>"
+               class="btn btn-primary ajax-modal" data-event="event-unicaen-privilege-editer">
+                <i class="fas fa-edit"></i> Modifier la catégorie
             </a>
-            <?php endif;?>
+        <?php endif; ?>
 
-            <?php if ($canEditerCategorie) : ?>
-            <?php /** @see \UnicaenPrivilege\Controller\CategorieController::modifierAction()() */ ?>
-            <a href="<?php echo $this->url('unicaen-privilege/categorie/modifier', ['categorie' => $categorie->getId()], [], true); ?>" class="btn btn-primary action ajax-modal" data-event="modification">
-                <span class="icon editer"></span>
-                Modifier la catégorie
+        <?php if ($canProvider) : ?>
+            <?php /** @see ConfigurationController::providerAction() */ ?>
+            <a href="<?php echo $this->url('unicaen-privilege/categorie/provider', ['categorie' => $categorie->getId()], [], true); ?>"
+               class="btn btn-default ajax-modal">
+                <i class="fas fa-code"></i> Générer le "Provider"
             </a>
-            <?php endif;?>
-
-            <?php if ($canAjouterPrivilege) : ?>
-            <?php /** @see \UnicaenPrivilege\Controller\PrivilegeController::ajouterAction() */ ?>
-            <a href="<?php echo $this->url('unicaen-privilege/privilege/ajouter', ['categorie' => $categorie->getId()], [], true); ?>" class="btn btn-primary action ajax-modal" data-event="modification">
-                <span class="icon ajouter"></span>
-                Ajouter un privilège
+        <?php endif; ?>
+
+        <?php if ($canDetruireCategorie) : ?>
+            <?php /** @see CategorieController::supprimerAction() */ ?>
+            <a href="<?php echo $this->url('unicaen-privilege/categorie/supprimer', ['categorie' => $categorie->getId()], [], true); ?>"
+               class="btn btn-danger pop-ajax"
+               data-confirm="true"
+               data-submit-close="true"
+               data-submit-event="event-unicaen-privilege-categorie-supprimer"
+               title="Supprimer la catégorie"
+               data-title="Suppression de la catégorie"
+               data-confirm-button=""
+               data-cancel-button=""
+               data-content="<p>Voulez-vous supprimer la catégorie ?</p>
+                        <div class='text-center'>
+                            <div class='btn-group'>
+                                <button type='submit' class='btn btn-success'><i class='fas fa-check'></i> Oui</button>
+                                <button type='button' class='btn btn-danger pop-ajax-hide'><i class='fas fa-times'></i> Non</button>
+                            </div>
+                        </div>">
+                <i class="fas fa-trash-alt"></i> Supprimer la catégorie
             </a>
-            <?php endif;?>
-
-            <?php if ($canProvider) : ?>
-                <?php /** @see ConfigurationController::providerAction() */ ?>
-                <a href="<?php echo $this->url('unicaen-privilege/categorie/provider', ['categorie' => $categorie->getId()], [], true); ?>" class="btn btn-primary  action ajax-modal">
-                    <span class="icon csv"></span>
-                    Générer le provider
-                </a>
-            <?php endif; ?>
-        </div>
-
-        <div class="col-md-6">
-
-        <div class="panel panel-info">
-            <div class=" panel-heading">
-                <h2>Informations générales</h2>
-            </div>
-            <div class=" panel-body">
-                <dl class="dl-horizontal">
-                    <dt> Libellé</dt>
-                    <dd> <?php echo $categorie->getLibelle(); ?></dd>
-                    <dt> Code </dt>
-                    <dd> <?php echo $categorie->getCode(); ?></dd>
-                    <dt> Namespace </dt>
-                    <dd> <?php echo $categorie->getNamespace(); ?></dd>
-                    <dt> Ordre </dt>
-                    <dd> <?php echo $categorie->getOrdre(); ?></dd>
-                    <dt> #Privilège </dt>
-                    <dd> <?php echo count($categorie->getPrivilege()); ?></dd>
-                </dl>
-            </div>
-        </div>
-        </div>
+        <?php endif; ?>
     </div>
-
-    <h2>
-        Privilèges
-        <span class="badge">
-            <?php echo count($categorie->getPrivilege()); ?>
-        </span>
-    </h2>
-
-    <table class="table table-condensed">
-        <thead>
+</div>
+
+<h2>
+    Liste des privilèges
+    <span class="badge">
+        <?php echo $categorie->getPrivileges()->count(); ?>
+    </span>
+</h2>
+
+<table id="privilege-liste" class="table table-condensed">
+    <thead>
+        <tr>
+            <th>Libellé</th>
+            <th>Code</th>
+            <th class="col-md-1">
+                Constante <i class="fa fa-info-circle" title="Vérification de l'existence de la constante associée au privilège"></i>
+            </th>
+            <th class="col-md-1">
+                Valeur <i class="fa fa-info-circle" title="Vérification de la valeur de la constante associée au privilège"></i>
+            </th>
+            <th class="col-md-1">Ordre</th>
+            <th class="col-md-1">Action</th>
+        </tr>
+    </thead>
+    <tbody>
+        <?php foreach ($privileges as $privilege) : ?>
             <tr>
-                <th> Libellé </th>
-                <th> Code </th>
-                <th> Ordre </th>
-                <th> set? </th>
-                <th> ok? </th>
-                <th> Action </th>
+                <td><?php echo $privilege->getLibelle(); ?></td>
+                <td><?php echo $privilege->getCode(); ?></td>
+                <?php
+                $template = '\\%s\\%s::%s';
+                $categorie = $privilege->getCategorie();
+                $constant = sprintf($template,
+                    $categorie->getNamespace(),
+                    $categorie->getClassname(),
+                    strtoupper(str_replace('-', '_', $privilege->getCode()))
+                );
+                $check = defined($constant);
+                $value = $check ? constant($constant) : '';
+                ?>
+                <td>
+                    <?php if ($value) : ?>
+                        <i class="fas fa-check-circle text-success" title="La constante associée au privilège existe : <?php echo $constant ?>"></i>
+                    <?php else : ?>
+                        <i class="fas fa-exclamation-triangle text-warning" title="La constante associée au privilège n'existe pas : <?php echo $constant ?>"></i>
+                    <?php endif; ?>
+                </td>
+                <td>
+                    <?php if ($value === $privilege->getFullCode()) : ?>
+                        <i class="fas fa-check-circle text-success" title="La valeur de la constante associée au privilège correspond au code du privilège : '<?php echo $privilege->getFullCode() ?>'"></i>
+                    <?php else : ?>
+                        <i class="fas fa-exclamation-triangle text-warning" title="La valeur de la constante associée au privilège ne correspond pas au code du privilège : '<?php echo $privilege->getFullCode() ?>'"></i>
+                    <?php endif; ?>
+                </td>
+                <td><?php echo $privilege->getOrdre(); ?></td>
+                <td>
+                    <?php if($canEditerPrivilege) : ?>
+                        <?php /** @see PrivilegeController::modifierAction() **/ ?>
+                        <a href="<?php echo $this->url('unicaen-privilege/modifier', ['privilege' => $privilege->getId()], [], true); ?>"
+                           class="ajax-modal" data-event="event-unicaen-privilege-editer">
+                            <i class="fas fa-edit" title="Modifier le privilège"></i>
+                        </a>
+                    <?php endif; ?>
+                    <?php if($canDetruirePrivilege) : ?>
+                        <?php /** @see PrivilegeController::supprimerAction() **/ ?>
+                        <a href="<?php echo $this->url('unicaen-privilege/supprimer', ['privilege' => $privilege->getId()], [], true); ?>"
+                           class="pop-ajax"
+                           data-confirm="true"
+                           data-submit-close="true"
+                           data-submit-event="event-unicaen-privilege-supprimer"
+                           title="Supprimer la privilège"
+                           data-title="Suppression du privilège"
+                           data-confirm-button=""
+                           data-cancel-button=""
+                           data-content="<p>Voulez-vous supprimer le privilège ?</p>
+                            <div class='text-center'>
+                                <div class='btn-group'>
+                                    <button type='submit' class='btn btn-success'><i class='fas fa-check'></i> Oui</button>
+                                    <button type='button' class='btn btn-danger pop-ajax-hide'><i class='fas fa-times'></i> Non</button>
+                                </div>
+                            </div>">
+                            <i class="fas fa-trash-alt text-danger" title="Supprimer le privilège"></i>
+                        </a>
+                    <?php endif; ?>
+                </td>
             </tr>
-        </thead>
-        <tbody>
-            <?php
-                $privileges = $categorie->getPrivilege();
-                usort($privileges, function(Privilege $a, Privilege $b) { return $a->getOrdre() > $b->getOrdre();} );
-            ?>
-            <?php foreach ($privileges as $privilege) : ?>
-                <tr>
-                    <td> <?php echo $privilege->getLibelle(); ?> </td>
-                    <td> <?php echo $privilege->getCode(); ?> </td>
-                    <td> <?php echo $privilege->getOrdre(); ?> </td>
-                    <?php
-                    $constant = '\\'.$privilege->getCategorie()->getNamespace().'\\'. $privilege->getCategorie()->getClassname() . '::' . strtoupper($privilege->getCode());
-                    $value = defined($constant);
-                    $content = ($value === true) ? eval("return ".$constant.";") : null;
-                    ?>
-                    <td>
-                        <?php if ($value === true) : ?>
-                            <span class="icon ok" style="color:darkgreen;" title="<?php echo " = '".$constant. "'"; ?>"></span>
-                        <?php else : ?>
-                            <span class="icon ko" style="color:darkred;" title="<?php echo " != '".$constant. "'"; ?>"></span>
-                        <?php endif; ?>
-                    </td>
-                    <td>
-                        <?php if ($content === $privilege->getFullCode()) : ?>
-                            <span class="icon ok" style="color:darkgreen;" title="<?php echo  " =  '" .$privilege->getFullCode(). "'" ?>"></span>
-                        <?php else : ?>
-                            <span class="icon ko" style="color:darkred;" title="<?php echo " != '" . $privilege->getFullCode(). "'"; ?>"></span>
-                        <?php endif; ?>
-                    </td>
-                    <td>
-                        <?php if($canEditerPrivilege) : ?>
-                            <?php /** @see ConfigurationController::modifierPrivilegeAction() **/ ?>
-                            <a href="<?php echo $this->url('unicaen-privilege/privilege/modifier', ['privilege' => $privilege->getId()], [], true); ?>"
-                               class="ajax-modal" data-event="modification">
-                            <span class="icon editer" title="Éditer le privilège [<?php echo htmlentities($privilege->getLibelle()); ?>]"></span></a>
-                        <?php else: ?>
-                            <span class="icon editer" style="color:lightgrey;"></span>
-                        <?php endif; ?>
-                        <?php if($canDetruirePrivilege) : ?>
-                            <?php /** @see ConfigurationController::detruirePrivilegeAction() **/ ?>
-                            <a href="<?php echo $this->url('unicaen-privilege/privilege/supprimer', ['privilege' => $privilege->getId()], [], true); ?>"
-                               class="ajax-modal" data-event="modification">
-                                <span class="icon detruire" title="Détruire le privilège [<?php echo htmlentities($privilege->getLibelle()); ?>]"></span></a>
-                        <?php else: ?>
-                            <span class="icon detruire" style="color:lightgrey;"></span>
-                        <?php endif; ?>
-                    </td>
-                </tr>
-            <?php endforeach; ?>
-        </tbody>
-    </table>
-
+        <?php endforeach; ?>
+    </tbody>
+</table>
 
 <script>
     $(function() {
-        $("body").on("modification", function (event) {
+        $('#privilege-liste').DataTable( {
+            "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "Tous"]],
+            "order": [[4, 'asc']],
+            "language": {
+                'lengthMenu': "Afficher _MENU_ &eacute;l&eacute;ments",
+                "search": "Filtre de recherche : _INPUT_",
+                "loadingRecords": "Chargement en cours...",
+                'info': "<small class=\"text-highlight\">Affichage : <strong><i class=\"far fa-list-alt\"></i> _START_ - _END_ sur _TOTAL_</strong></small>",
+                'infoEmpty': "",
+                'infoFiltered': "<small class=\"text-highlight\">(_MAX_ &eacute;l&eacute;ments au total)</small>",
+                'emptyTable': "Aucune donnée disponible.",
+                'zeroRecords': "Aucun enregistrement trouvé.",
+                "paginate": {
+                    "previous": "<i class=\"fas fa-chevron-left\"></i>",
+                    "next": "<i class=\"fas fa-chevron-right\"></i>"
+                }
+            },
+            "createdRow": function (row, data, index) {
+                $('.pop-ajax', row).popAjax();
+            },
+        });
+
+        $("body").on("event-unicaen-privilege-editer", function (event) {
             event.div.modal('hide');
             window.location.reload();
         });
diff --git a/view/unicaen-privilege/categorie/index.phtml b/view/unicaen-privilege/categorie/index.phtml
index aeb86d34013dc65c8d990ec8d6dabdbb6b79eca9..e3f06ee895aaadd230cf24ccba1cffae57494e25 100644
--- a/view/unicaen-privilege/categorie/index.phtml
+++ b/view/unicaen-privilege/categorie/index.phtml
@@ -1,119 +1,188 @@
 <?php
 
-/**
- * @see \UnicaenPrivilege\Controller\ConfigurationController::indexConfigurationCategorieAction()
- * @var string[] $namespaces
- * @var string $namespace
- * @var Categorie[] $categories
- */
-
-use UnicaenPrivilege\Entity\Db\Categorie;
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
 use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
 
-$this->headTitle("Configuration des catégories de privilèges");
+/**
+ * @var string $title
+ * @var CategorieInterface[] $categories
+ *
+ * @see CategorieController::indexAction()
+ */
 
-$canAffecter    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_AFFECTER));
-$canGerer       = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
+$canAffecter    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_ATTRIBUER));
+$canVoir        = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
 $canAjouter     = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_AJOUTER));
 $canModifier    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_MODIFIER));
 $canDetruire    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_SUPPRIMER));
 $canProvider    = $this->isAllowed(PrivilegePrivileges::getResourceId(PrivilegePrivileges::PRIVILEGE_VOIR));
 ?>
 
+<?php $this->headTitle($this->translate($title)) ?>
+
 <h1 class="page-header">
-    Configuration des catégories de privilèges
+    <?php echo $title; ?>
+    <span class="badge">
+        <?php echo count($categories); ?>
+    </span>
 </h1>
 
-<div class="row">
-    <?php if ($canAffecter): ?>
-        <?php /** @see \UnicaenPrivilege\Controller\PrivilegeController::indexAction() */ ?>
-        <a href="<?php echo $this->url('unicaen-privilege/affectation', [], [], true); ?>"
-           class="btn btn-primary action"
-        >
-            <span class="icon listing"></span>
-            Affecter les privilèges
-        </a>
-    <?php endif; ?>
-</div>
+<?php echo $this->messenger()->addMessagesFromFlashMessenger(); ?>
+
+<?php if ($canVoir): ?>
+    <?php /** @see PrivilegeController::indexAction() */ ?>
+    <a href="<?php echo $this->url('unicaen-privilege', [], [], true); ?>"
+       class="btn btn-primary">
+        <i class="fas fa-check-square"></i>
+        Attribuer les privilèges
+    </a>
+<?php endif; ?>
+
+<?php if ($canAjouter): ?>
+    <?php /** @see CategorieController::ajouterAction() */ ?>
+    <a href="<?php echo $this->url('unicaen-privilege/categorie/ajouter', [], [], true); ?>"
+       class="btn btn-primary ajax-modal"
+       data-event="event-unicaen-privilege-categorie-editer">
+        <span class="fas fa-plus-square"></span>
+        Ajouter une catégorie
+    </a>
+<?php endif; ?>
 
-<?php echo $this->partial('partial/filtre-categorie', ['namespaces' => $namespaces, 'namespace' => $namespace]); ?>
+<p></p>
+
+<?php echo $this->form()->openTag($form->prepare()); ?>
+
+<p>
+    À partir de ce formulaire, vous pouvez filtrer les privilèges.
+</p>
 
 <div class="row">
-    <?php if ($canAjouter): ?>
-        <?php /** @see CategorieController::ajouterAction() */ ?>
-        <a href="<?php echo $this->url('unicaen-privilege/categorie/ajouter', [], [], true); ?>"
-           class="btn btn-primary action ajax-modal"
-           data-event="modification"
-       >
-            <span class="icon ajouter"></span>
-            Ajouter une catégorie
-        </a>
-    <?php endif; ?>
+    <div class="col-md-5">
+        <?php echo $this->formControlGroup($form->get('namespace')); ?>
+    </div>
+    <div class="col-md-7">
+        <div class="form-group">
+            <?php echo $this->formButton($form->get('filtrer')); ?>
+            <?php echo $this->formButton($form->get('effacer')); ?>
+        </div>
+    </div>
 </div>
 
-    <table class="table table-condensed">
-        <thead>
-            <tr>
-                <th> Libellé </th>
-                <th> Code </th>
-                <th> Ordre </th>
-                <th> Namespace </th>
-                <th> #Privilège </th>
-                <th style="min-width:10rem;"> Action </th>
-            </tr>
-        </thead>
-        <tbody>
-        <?php foreach ($categories as $categorie) : ?>
-            <tr>
-                <td> <?php echo $categorie->getLibelle(); ?> </td>
-                <td> <?php echo $categorie->getCode(); ?> </td>
-                <td> <?php echo $categorie->getOrdre(); ?> </td>
-                <td> <?php echo $categorie->getNamespace(); ?> </td>
-                <td> <?php echo count($categorie->getPrivilege()); ?> </td>
-                <td>
-                    <?php if ($canGerer) : ?>
-                        <?php /** @see \UnicaenPrivilege\Controller\CategorieController::gererAction() */ ?>
-                        <a href="<?php echo $this->url('unicaen-privilege/categorie/gerer', ['categorie' => $categorie->getId()], [], true); ?>">
-                        <span class="icon gerer" title="Gérer la catégorie [<?php echo htmlentities($categorie->getLibelle()); ?>]" ></span></a>
-                    <?php else : ?>
-                        <span class="icon gerer" style="color:lightgrey;"></span>
-                    <?php endif; ?>
-                    <?php if ($canProvider) : ?>
-                        <?php /** @see \UnicaenPrivilege\Controller\CategorieController::providerAction() */ ?>
-                        <a href="<?php echo $this->url('unicaen-privilege/categorie/provider', ['categorie' => $categorie->getId()], [], true); ?>" class="ajax-modal">
-                            <span class="icon code" title="Afficher le fichier provider de  [<?php echo htmlentities($categorie->getLibelle()); ?>]" ></span></a>
-                    <?php else : ?>
-                        <span class="icon code" style="color:lightgrey;"></span>
-                    <?php endif; ?>
-                    <?php if ($canModifier) : ?>
-                        <?php /** @see \UnicaenPrivilege\Controller\CategorieController::modifierAction() */ ?>
-                        <a href="<?php echo $this->url('unicaen-privilege/categorie/modifier', ['categorie' => $categorie->getId()], [], true); ?>"
-                           class="ajax-modal" data-event="modification" style="/**display:none;**/">
-                        <span class="icon editer" title="Éditer la catégorie [<?php echo htmlentities($categorie->getLibelle()); ?>]"></span></a>
-                    <?php else : ?>
-                        <span class="icon editer" style="color:lightgrey;"></span>
-                    <?php endif; ?>
-                    <?php if ($canDetruire /** AND empty($categorie->getPrivilege()) */) : ?>
-                        <?php /** @see \UnicaenPrivilege\Controller\CategorieController::supprimerAction() */ ?>
-                        <a href="<?php echo $this->url('unicaen-privilege/categorie/supprimer', ['categorie' => $categorie->getId()], [], true); ?>"
-                           class="ajax-modal" data-event="modification">
-                        <span class="icon detruire" title="Détruire la catégorie [<?php echo htmlentities($categorie->getLibelle()); ?>]"></span></a>
-                    <?php else : ?>
-                        <span class="icon detruire" style="color:lightgrey;"></span>
-                    <?php endif; ?>
-                </td>
-            </tr>
-
-        <?php endforeach; ?>
-        </tbody>
-    </table>
-</div>
+<?php echo $this->form()->closeTag(); ?>
+
+<p></p>
+
+<table id="privilege-categorie-liste" class="table table-condensed">
+    <thead>
+        <tr>
+            <th>Libellé</th>
+            <th>Code</th>
+            <th>Privilèges</th>
+            <th>Namespace</th>
+            <th class="col-md-1">Ordre</th>
+            <th class="col-md-1">Action</th>
+        </tr>
+    </thead>
+    <tbody>
+    <?php foreach ($categories as $categorie) : ?>
+        <?php
+        $listing = [];
+        /** @var PrivilegeInterface $privilege */
+        foreach ($categorie->getPrivileges() as $privilege) {
+            $listing[] = $privilege->getLibelle();
+        }
+        sort($listing);
+        ?>
+
+        <tr>
+            <td>
+                <?php if ($canVoir) : ?>
+                    <?php /** @see CategorieController::gererAction() */ ?>
+                    <a title="Gérer la catégorie et ses privilèges" href="<?php echo $this->url('unicaen-privilege/categorie/gerer', ['categorie' => $categorie->getId()], [], true); ?>">
+                <?php endif; ?>
+                <?php echo $categorie->getLibelle(); ?>
+                <?php if ($canVoir) : ?>
+                    </a>
+                <?php endif; ?>
+            </td>
+            <td><?php echo $categorie->getCode(); ?></td>
+            <td>
+                <a href="#" data-toggle="popover" data-placement="left" data-html="true" data-content="<?php echo implode("<br />", $listing); ?>">
+                    <i class="fas fa-crown"></i> <?php echo $categorie->getPrivileges()->count(); ?>
+                </a>
+            </td>
+            <td>
+                <?php echo $categorie->getNamespace() ? sprintf('<code>%s</code>', $categorie->getNamespace()) : ''; ?>
+            </td>
+            <td><?php echo $categorie->getOrdre(); ?></td>
+            <td>
+                <?php if ($canModifier) : ?>
+                    <?php /** @see CategorieController::modifierAction() */ ?>
+                    <a href="<?php echo $this->url('unicaen-privilege/categorie/modifier', ['categorie' => $categorie->getId()], [], true); ?>"
+                       class="ajax-modal" data-event="event-unicaen-privilege-categorie-editer">
+                        <i class="fas fa-edit" title="Modifier la catégorie"></i></a>
+                <?php endif; ?>
+                <?php if ($canProvider) : ?>
+                    <?php /** @see CategorieController::providerAction() */ ?>
+                    <a href="<?php echo $this->url('unicaen-privilege/categorie/provider', ['categorie' => $categorie->getId()], [], true); ?>" class="ajax-modal">
+                        <i class="fas fa-code" title='Afficher le fichier "Provider"'></i></a>
+                <?php endif; ?>
+                <?php if ($canDetruire) : ?>
+                    <?php /** @see CategorieController::supprimerAction() */ ?>
+                    <a href="<?php echo $this->url('unicaen-privilege/categorie/supprimer', ['categorie' => $categorie->getId()], [], true); ?>"
+                       class="pop-ajax"
+                       data-confirm="true"
+                       data-submit-close="true"
+                       data-submit-event="event-unicaen-privilege-categorie-supprimer"
+                       title="Supprimer la catégorie"
+                       data-title="Suppression de la catégorie"
+                       data-confirm-button=""
+                       data-cancel-button=""
+                       data-content="<p>Voulez-vous supprimer la catégorie ?</p>
+                        <div class='text-center'>
+                            <div class='btn-group'>
+                                <button type='submit' class='btn btn-success'><i class='fas fa-check'></i> Oui</button>
+                                <button type='button' class='btn btn-danger pop-ajax-hide'><i class='fas fa-times'></i> Non</button>
+                            </div>
+                        </div>">
+                        <i class="fas fa-trash-alt text-danger" title="Supprimer la catégorie"></i>
+                    </a>
+                <?php endif; ?>
+            </td>
+        </tr>
+
+    <?php endforeach; ?>
+    </tbody>
+</table>
 
 <script>
     $(function() {
-        // $('a.ajax-modal').css('display', 'inline');
+        $('[data-toggle="popover"]').popover();
+
+        $('#privilege-categorie-liste').DataTable( {
+            "lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "Tous"]],
+            "order": [[4, 'asc']],
+            "language": {
+                'lengthMenu': "Afficher _MENU_ &eacute;l&eacute;ments",
+                "search": "Filtre de recherche : _INPUT_",
+                "loadingRecords": "Chargement en cours...",
+                'info': "<small class=\"text-highlight\">Affichage : <strong><i class=\"far fa-list-alt\"></i> _START_ - _END_ sur _TOTAL_</strong></small>",
+                'infoEmpty': "",
+                'infoFiltered': "<small class=\"text-highlight\">(_MAX_ &eacute;l&eacute;ments au total)</small>",
+                'emptyTable': "Aucune donnée disponible.",
+                'zeroRecords': "Aucun enregistrement trouvé.",
+                "paginate": {
+                    "previous": "<i class=\"fas fa-chevron-left\"></i>",
+                    "next": "<i class=\"fas fa-chevron-right\"></i>"
+                }
+            },
+            "createdRow": function (row, data, index) {
+                $('.pop-ajax', row).popAjax();
+            },
+        });
 
-        $("body").on("modification", function (event) {
+        $("body").on("event-unicaen-privilege-categorie-editer", function (event) {
             event.div.modal('hide');
             window.location.reload();
         });
diff --git a/view/unicaen-privilege/categorie/partial/filtre-categorie.phtml b/view/unicaen-privilege/categorie/partial/filtre-categorie.phtml
deleted file mode 100644
index d8fa89493935775a301019da21c79676e6978ca7..0000000000000000000000000000000000000000
--- a/view/unicaen-privilege/categorie/partial/filtre-categorie.phtml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-/**
- * @var string[] $namespaces
- * @var string $namespace
- */
-
-?>
-
-<div class="panel panel-default">
-    <div class="panel panel-heading">
-        <span class="icon filtrer"></span>
-        Filtrage des catégories de privilège
-    </div>
-    <div class="panel panel-body">
-        <form id="filter" method="get" action="<?php echo $this->url(); /**$this->url('unicaen-privilege/categorie',[],[], true);**/ ?>">
-        <div class="row">
-            <div class="col-md-4">
-                <select id="namespace" name="namespace" class="selectpicker show-tick" data-live-search="true">
-                    <option value=""> Tous les namespaces </option>
-                    <?php foreach ($namespaces as $namespaceCurrent) : ?>
-                        <?php $string = (trim($namespaceCurrent) === "")?"Laissé vide !":$namespaceCurrent; ?>
-                        <option value="<?php echo $string; ?>" <?php if ($string === $namespace) echo " selected"; ?> >
-                            <?php echo $string ?>
-                        </option>
-                    <?php endforeach; ?>
-                </select>
-            </div>
-        </div>
-
-        <div class="row">
-            <div class="pull-right">
-                <button type="button" id="filter" class="btn btn-primary filter-action">
-                    <span class="icon filtrer" aria-hidden="true"></span> Filtrer
-                </button>
-                <button type="button" id="reset" class="btn btn-primary filter-action">
-                    <span class="icon remise-a-zero" aria-hidden="true"></span> R.A.Z.
-                </button>
-            </div>
-        </div>
-        </form>
-
-    </div>
-</div>
-
-<style>
-    .filter-action {
-        width: 25rem;
-        margin: 0 1rem;
-    }
-
-    form#filter label {
-        width: 10rem;
-    }
-</style>
-
-<script>
-    $('button#reset').click(function (e) {
-        e.preventDefault();
-        window.location = '?';
-    });
-    $('button#filter').click(function () {
-        console.log('pouet');
-        $('form#filter').submit();
-    });
-</script>
diff --git a/view/unicaen-privilege/categorie/provider.phtml b/view/unicaen-privilege/categorie/provider.phtml
index 99c1364273bdde1f9478e93ce427abee2ca01ddd..21364047b6db77dd7b2f8ffa6a6700f6989f70f8 100644
--- a/view/unicaen-privilege/categorie/provider.phtml
+++ b/view/unicaen-privilege/categorie/provider.phtml
@@ -1,17 +1,17 @@
 <?php
 
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+
 /**
- * @var Categorie $categorie
+ * @var CategorieInterface $categorie
  */
 
-use UnicaenPrivilege\Entity\Db\Categorie;
-use UnicaenPrivilege\Entity\Db\Privilege;
-
 $namespace = ($categorie->getNamespace() ? $categorie->getNamespace() : "<span class='missing-data'>NONE_GIVEN</span>");
 $classname = ucfirst(strtolower($categorie->getCode())) . "Privileges";
 
-$privileges = $categorie->getPrivilege();
-usort($privileges, function(Privilege $a, Privilege $b) { return $a->getOrdre() > $b->getOrdre(); });
+$privileges = $categorie->getPrivileges()->toArray();
+usort($privileges, function(PrivilegeInterface $a, PrivilegeInterface $b) { return $a->getOrdre() > $b->getOrdre(); });
 ?>
 
 <h2> Chemin du fichier </h2>
diff --git a/view/unicaen-privilege/categorie/supprimer.phtml b/view/unicaen-privilege/categorie/supprimer.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..c91f9bbe1efeef06a9cfff2591f77340b5585fb8
--- /dev/null
+++ b/view/unicaen-privilege/categorie/supprimer.phtml
@@ -0,0 +1,18 @@
+<?php
+
+use UnicaenPrivilege\Entity\Db\CategorieInterface;
+
+/**
+ * @var CategorieInterface $role
+ *
+ * @see CategorieController::supprimerAction()
+ */
+?>
+
+<script>
+    $(function () {
+        $("body").one("event-unicaen-privilege-categorie-supprimer", function (event, data) {
+            window.location.href = '/privilege/categorie';
+        });
+    });
+</script>
diff --git a/view/unicaen-privilege/categorie/template/form-categorie.phtml b/view/unicaen-privilege/categorie/template/form-categorie.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..20cd4c7fe886fac4a277e2954f9bdec6f70089cd
--- /dev/null
+++ b/view/unicaen-privilege/categorie/template/form-categorie.phtml
@@ -0,0 +1,14 @@
+<?php
+
+use UnicaenPrivilege\Form\Categorie\CategorieForm;
+
+/**
+ * @var CategorieForm $form
+ */
+?>
+
+<?php echo $this->form($form); ?>
+
+<script>
+    installFormRequirement($('#form-categorie'));
+</script>
diff --git a/view/unicaen-privilege/default/confirmation.phtml b/view/unicaen-privilege/default/confirmation.phtml
deleted file mode 100644
index f76498563da71720fdb2bf97cab40d68dffb876a..0000000000000000000000000000000000000000
--- a/view/unicaen-privilege/default/confirmation.phtml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-/**
- * @var string $title
- * @var string $text
- * @var string $action
- */
-
-?>
-
-<style>
-    input.action{
-        margin:1em;
-        width: 18.25em;
-        color:white;
-    }
-</style>
-
-<p class="lead">
-<?php echo $text; ?>
-</p>
-
-<table>
-    <tr><td>
-<form method="post" action="<?php echo $action; ?>">
-    <input type="hidden" name="reponse" value="oui">
-    <input type="submit" name="reponse" class="btn btn-success action" value="Oui, je suis sûr&middot;e">
-</form>
-        </td><td>
-<form method="post" action="<?php echo $action; ?>">
-    <input type="hidden" name="reponse" value="non">
-    <input type="submit" id="non" name="reponse" class="btn btn-danger action"  value="Non, je ne veux pas">
-</form>
-        </td></tr>
-</table>
-
-<script>
-    $(function() {
-        $("input#non").click(function(e){
-            $('div.modal').modal('hide');
-            e.preventDefault(e);
-        });
-    });
-</script>
-
-
-
diff --git a/view/unicaen-privilege/default/default-form.phtml b/view/unicaen-privilege/default/default-form.phtml
deleted file mode 100644
index 32e163c76d4f7c1057046bd95c3c2c1d4245d768..0000000000000000000000000000000000000000
--- a/view/unicaen-privilege/default/default-form.phtml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-/**
- * @var Form $form
- */
-
-use Zend\Form\Form;
-
-?>
-
-<?php echo $this->form($form); ?>
-
-<script>
-    $('select').selectpicker();
-</script>
diff --git a/view/unicaen-privilege/privilege/attribuer.phtml b/view/unicaen-privilege/privilege/attribuer.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..275b8e74e6c888e7a3457f9b8ba9745d533d162c
--- /dev/null
+++ b/view/unicaen-privilege/privilege/attribuer.phtml
@@ -0,0 +1,13 @@
+<?php
+
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+use UnicaenUtilisateur\Entity\Db\RoleInterface;
+
+/**
+ * @var PrivilegeInterface  $privilege
+ * @var RoleInterface       $role
+ *
+ * @see PrivilegeController::attribuerAction()
+ */
+
+echo $this->privilege($this->privilege)->renderStatut($this->role); ?>
\ No newline at end of file
diff --git a/view/unicaen-privilege/privilege/index.phtml b/view/unicaen-privilege/privilege/index.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..44c9701abb1db18226801d087fe723ec5bc8a7f6
--- /dev/null
+++ b/view/unicaen-privilege/privilege/index.phtml
@@ -0,0 +1,193 @@
+<?php
+
+use UnicaenAuth\Entity\Db\RoleInterface;
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+use UnicaenPrivilege\Provider\Privilege\PrivilegePrivileges;
+
+/**
+ * @var string $title
+ * @var RoleInterface[] $roles
+ * @var array $privilegesByCategorie
+ *
+ * @see PrivilegeController::indexAction()
+ */
+?>
+
+<?php $this->headTitle($this->translate($title)) ?>
+
+<h1 class="page-header">
+    <?php echo $title; ?>
+</h1>
+
+<?php echo $this->messenger()->addMessagesFromFlashMessenger(); ?>
+
+<?php /** @see CategorieController::indexAction() */ ?>
+<a href="<?php echo $this->url('unicaen-privilege/categorie', [], []); ?>"
+   class="btn btn-primary">
+    <i class="fas fa-crown"></i>
+    Gestion des privilèges
+</a>
+
+<p></p>
+
+<?php echo $this->form()->openTag($form->prepare()); ?>
+
+<p>
+    À partir de ce formulaire, vous pouvez filtrer les privilèges.
+</p>
+
+<div class="row">
+    <div class="col-md-5">
+        <?php echo $this->formControlGroup($form->get('namespace')); ?>
+    </div>
+    <div class="col-md-7">
+        <div class="form-group">
+            <?php echo $this->formButton($form->get('filtrer')); ?>
+            <?php echo $this->formButton($form->get('effacer')); ?>
+        </div>
+    </div>
+</div>
+
+<?php echo $this->form()->closeTag(); ?>
+
+<p></p>
+
+<table id="privilege-liste" class="table table-hover table-condensed table-header-rotated">
+    <thead>
+        <tr>
+            <th></th>
+            <?php $first = true; foreach( $roles as $role ):?>
+                <th class="rotate-45" title="<?php echo $role; ?>"><div<?php if ($first) echo ' class="first"'; ?>><span><?php echo $role; ?></span></div></th>
+            <?php $first = false; endforeach; ?>
+            <th></th>
+        </tr>
+        <tr>
+            <th>Privilèges <i title="Afficher / Masquer tous les privilèges" class="hide-privileges fas fa-caret-square-down"></i></th>
+            <th colspan="<?php echo count($roles); ?>">Rôles</th>
+            <th style="min-width:166px"></th>
+        </tr>
+    </thead>
+    <tbody>
+    <?php foreach ($privilegesByCategorie as $libelleCategorie => $privileges) : ?>
+        <tr>
+            <th id="<?php echo current($privileges)->getCategorie()->getId(); ?>" class="categorie"
+                colspan="<?php echo 1 + count($roles); ?>"><?php echo $libelleCategorie; ?> <i class="fas fa-caret-square-down text-muted"></i></th>
+        </tr>
+        <?php /** @var PrivilegeInterface $privilege */ ?>
+        <?php foreach ($privileges as $privilege) : ?>
+            <tr class="privilege categorie-id-<?php echo $privilege->getCategorie()->getId(); ?>">
+                <td class="privilege">
+                    <?php echo $privilege; ?>
+                </td>
+                <?php foreach($roles as $role): ?>
+                    <?php echo $this->privilege($privilege)->renderStatut($role); ?>
+                <?php endforeach; ?>
+            </tr>
+        <?php endforeach; ?>
+    <?php endforeach; ?>
+    </tbody>
+</table>
+
+<style>
+    .table-header-rotated th.rotate-45 {
+        border: none;
+        width: 50px;
+        padding: 0;
+        white-space: nowrap;
+    }
+    .table-header-rotated th.rotate-45 > div {
+        position: relative;
+        top: 0;
+        height: 200px;
+        left: 84px;
+        transform: skew(-40deg, 0deg);
+        overflow: hidden;
+        border-right: 1px solid #ddd;
+        z-index: 99;
+    }
+    .table-header-rotated th.rotate-45 > div.first {
+        border-left: 1px solid #ddd;
+    }
+    .table-header-rotated th.rotate-45 span {
+        transform: skew(40deg, 0deg) rotate(310deg);
+        position: absolute;
+        bottom: 40px;
+        left: -30px;
+        display: inline-block;
+        width: 100px;
+        text-align: left;
+    }
+
+    th.categorie {
+        background-color: #f5f5f5;
+    }
+
+    th.categorie > i:hover {
+        cursor: pointer;
+    }
+</style>
+
+<script type="text/javascript">
+    $(function () {
+        var body = $('body');
+
+        body.tooltip({
+            selector: '[data-toggle="tooltip"]',
+            placement: "bottom",
+            html: true
+        });
+
+        body.on('click', 'a.modifier-privilege', function (e) {
+            e.preventDefault();
+            that = $(this);
+            $.ajax({
+                type: "GET",
+                url: $(this).attr('href'),
+                dataType: "html",
+                beforeSend: function () {
+                    that.find('i').attr('class', 'fas fa-pulse fa-spinner');
+                },
+                success: function (data) {
+                    that.parent('td.role-privilege-statut').replaceWith(data);
+                },
+            });
+        });
+
+        $("i.hide-privileges").click(function ()
+        {
+            if ($(this).hasClass('fa-caret-square-down')) {
+                $("tr.privilege").hide();
+                $(this)
+                    .removeClass('fa-caret-square-down')
+                    .addClass('fa-caret-square-up')
+            }
+            else {
+                $("tr.privilege").show();
+                $(this)
+                    .removeClass('fa-caret-square-up')
+                    .addClass('fa-caret-square-down')
+            }
+        });
+
+        $("th.categorie > i").click(function ()
+        {
+            let categorieId = $(this).parent().attr("id");
+            $("tr.categorie-id-" + categorieId).toggle();
+            if ($(this).hasClass('fa-caret-square-down')) {
+                $(this)
+                    .removeClass('fa-caret-square-down')
+                    .addClass('fa-caret-square-up')
+            }
+            else {
+                $(this)
+                    .removeClass('fa-caret-square-up')
+                    .addClass('fa-caret-square-down')
+            }
+        });
+
+        $('button#effacer').click(function (e) {
+            $('#namespace').prop('selected', false);
+            $('.selectpicker').val('').selectpicker('refresh');
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/view/unicaen-privilege/privilege/supprimer.phtml b/view/unicaen-privilege/privilege/supprimer.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..33b1ecc56d095379cb838f493aec2b25d95e27a0
--- /dev/null
+++ b/view/unicaen-privilege/privilege/supprimer.phtml
@@ -0,0 +1,18 @@
+<?php
+
+use UnicaenPrivilege\Entity\Db\PrivilegeInterface;
+
+/**
+ * @var PrivilegeInterface $privilege
+ *
+ * @see PrivilegeController::supprimerAction()
+ */
+?>
+
+<script>
+    $(function () {
+        $("body").one("event-unicaen-privilege-supprimer", function (event, data) {
+            window.location.href = '/privilege/categorie/gerer/' + <?php echo $privilege->getCategorie()->getId(); ?>
+        });
+    });
+</script>
diff --git a/view/unicaen-privilege/privilege/template/form-privilege.phtml b/view/unicaen-privilege/privilege/template/form-privilege.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..efe119d8337b45d0d57f2605f16c617aef7cf680
--- /dev/null
+++ b/view/unicaen-privilege/privilege/template/form-privilege.phtml
@@ -0,0 +1,18 @@
+<?php
+
+use UnicaenPrivilege\Form\Privilege\PrivilegeForm;
+
+/**
+ * @var PrivilegeForm $form
+ */
+?>
+
+<?php
+$form->get('categorie')->setAttribute('disabled', 'disabled');
+echo $this->form($form);
+?>
+
+<script>
+    installFormRequirement($('#form-privilege'));
+    $('#categorie').selectpicker();
+</script>