update
This commit is contained in:
@@ -221,7 +221,37 @@ final class AgentModel extends BaseModel
|
||||
SQL;
|
||||
|
||||
/**
|
||||
* Tous les agents actifs.
|
||||
* Retire des listes D'AFFECTATION les agents dont le COMPTE D'ACCÈS est
|
||||
* désactivé (V7.29).
|
||||
*
|
||||
* Trois précisions, toutes portées par le `NOT EXISTS` :
|
||||
*
|
||||
* - un agent SANS compte reste proposé. Il n'a simplement pas encore reçu
|
||||
* son jeton, ce qui est l'état normal avant distribution : le filtrer
|
||||
* viderait les listes d'une installation neuve ;
|
||||
* - le filtre porte sur `compte_acces.actif`, PAS sur `agent.actif`, qui
|
||||
* est déjà exigé par ailleurs. Ce sont deux décisions distinctes :
|
||||
* fermer une fiche d'agent et couper un accès ;
|
||||
* - il ne s'applique QU'AUX listes où l'on affecte. Les écrans de
|
||||
* consultation (planning par agent, vue annuelle, PTA détaillé) et le
|
||||
* référentiel « Agents » continuent de montrer l'agent — sans quoi on ne
|
||||
* pourrait plus ni lire son année passée, ni lui rétablir son accès.
|
||||
*
|
||||
* La table compte_acces est garantie présente : SchemaModel::assertCurrent()
|
||||
* refuse de démarrer si les vues de comptes manquent.
|
||||
*/
|
||||
private const SANS_COMPTE_COUPE = <<<'SQL'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM compte_acces ca
|
||||
WHERE ca.id_agent = a.id_agent AND ca.actif = 0
|
||||
)
|
||||
SQL;
|
||||
|
||||
/**
|
||||
* Tous les agents actifs, y compris ceux dont l'accès est coupé.
|
||||
*
|
||||
* Liste de RÉFÉRENTIEL et de CONSULTATION. Pour une liste où l'on affecte,
|
||||
* voir allSelectable().
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
@@ -232,6 +262,19 @@ final class AgentModel extends BaseModel
|
||||
)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Agents proposables dans une liste d'affectation : actifs ET dont le compte
|
||||
* d'accès n'a pas été coupé.
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function allSelectable(): array
|
||||
{
|
||||
return $this->pdo->query(
|
||||
self::AGENT_SELECT . " WHERE a.actif = TRUE" . self::SANS_COMPTE_COUPE . " ORDER BY a.nom, a.prenom"
|
||||
)->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Agents visibles depuis un lieu : ceux qui y sont RATTACHÉS, plus ceux qui
|
||||
* y ont un planning, quel que soit leur rattachement.
|
||||
@@ -328,7 +371,7 @@ final class AgentModel extends BaseModel
|
||||
FROM agent a
|
||||
LEFT JOIN poste_agent po ON po.id_poste = a.id_poste
|
||||
LEFT JOIN structure s ON s.id_structure = a.id_structure
|
||||
WHERE a.actif = TRUE
|
||||
WHERE a.actif = TRUE" . self::SANS_COMPTE_COUPE . "
|
||||
ORDER BY lieu_principal_selectionne DESC, a.nom, a.prenom"
|
||||
);
|
||||
$stmt->execute(['selected_location' => $selectedLocation]);
|
||||
|
||||
@@ -125,9 +125,16 @@ final class CompteModel extends BaseModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste des comptes pour la page DSI.
|
||||
* Liste des comptes pour la page DSI et pour la page « Jetons d'accès » du
|
||||
* Service Enfance.
|
||||
*
|
||||
* @param array<string, mixed> $filtres role, actif (0|1), q (texte libre).
|
||||
* `roles` BORNE la liste à un ensemble de rôles. C'est ce qui permet à la
|
||||
* délégation V7.27 de ne jamais laisser voir un compte privilégié : le
|
||||
* contrôleur passe sa liste blanche, et aucun filtre d'interface ne peut
|
||||
* l'élargir — `role` ne fait que restreindre à l'intérieur de `roles`.
|
||||
*
|
||||
* @param array<string, mixed> $filtres role, actif (0|1), q (texte libre),
|
||||
* roles (array<int, string> facultatif).
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
@@ -136,10 +143,27 @@ final class CompteModel extends BaseModel
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
|
||||
$rolesAutorises = array_values(array_filter(array_map(
|
||||
static fn (mixed $role): string => strtoupper(trim((string) $role)),
|
||||
(array) ($filtres['roles'] ?? [])
|
||||
)));
|
||||
if ($rolesAutorises !== []) {
|
||||
$marqueurs = [];
|
||||
foreach ($rolesAutorises as $index => $roleAutorise) {
|
||||
$marqueurs[] = ':role_autorise_' . $index;
|
||||
$params['role_autorise_' . $index] = $roleAutorise;
|
||||
}
|
||||
$conditions[] = 'role IN (' . implode(', ', $marqueurs) . ')';
|
||||
}
|
||||
|
||||
$role = (string) ($filtres['role'] ?? '');
|
||||
if ($role !== '') {
|
||||
// Le filtre d'interface ne peut que restreindre : un rôle hors de la
|
||||
// liste blanche ne rend rien, il ne la contourne pas.
|
||||
if ($role !== '' && ($rolesAutorises === [] || in_array(strtoupper($role), $rolesAutorises, true))) {
|
||||
$conditions[] = 'role = :role';
|
||||
$params['role'] = $role;
|
||||
} elseif ($role !== '') {
|
||||
$conditions[] = '1 = 0';
|
||||
}
|
||||
|
||||
if (isset($filtres['actif']) && $filtres['actif'] !== '') {
|
||||
@@ -149,8 +173,18 @@ final class CompteModel extends BaseModel
|
||||
|
||||
$recherche = trim((string) ($filtres['q'] ?? ''));
|
||||
if ($recherche !== '') {
|
||||
$conditions[] = '(identite_libelle LIKE :q OR libelle LIKE :q OR matricule LIKE :q OR jeton_prefixe LIKE :q)';
|
||||
$params['q'] = '%' . $recherche . '%';
|
||||
// UN MARQUEUR PAR COLONNE, et non un seul répété quatre fois : PDO
|
||||
// tourne ici sans émulation de requêtes préparées (ATTR_EMULATE_
|
||||
// PREPARES = 0), et MariaDB refuse alors un même paramètre nommé
|
||||
// employé plusieurs fois — « Invalid parameter number ». Répéter
|
||||
// « :q » faisait échouer toute recherche en 500.
|
||||
$colonnes = ['identite_libelle', 'libelle', 'matricule', 'jeton_prefixe'];
|
||||
$comparaisons = [];
|
||||
foreach ($colonnes as $index => $colonne) {
|
||||
$comparaisons[] = $colonne . ' LIKE :q_' . $index;
|
||||
$params['q_' . $index] = '%' . $recherche . '%';
|
||||
}
|
||||
$conditions[] = '(' . implode(' OR ', $comparaisons) . ')';
|
||||
}
|
||||
|
||||
$where = $conditions === [] ? '' : ' WHERE ' . implode(' AND ', $conditions);
|
||||
|
||||
Reference in New Issue
Block a user