86 lines
3.6 KiB
PHP
86 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Core;
|
|
|
|
/**
|
|
* Contrôle de FORME des coordonnées d'un agent : adresse e-mail et numéro de
|
|
* téléphone. Source de vérité UNIQUE côté serveur — create() et update() de
|
|
* AgentController s'y réfèrent toutes les deux, et toute nouvelle voie
|
|
* d'écriture d'un contact doit faire de même plutôt que recopier une regex.
|
|
*
|
|
* Une copie de ces règles vit dans assets/js/field-format.js pour le retour
|
|
* immédiat à la saisie. C'est l'application habituelle du principe du projet :
|
|
* l'interface prévient, le serveur tranche. Modifier une règle ici impose donc
|
|
* de reporter la modification dans le module JS — l'inverse n'est jamais vrai.
|
|
*
|
|
* PORTÉE VOLONTAIREMENT LIMITÉE : ces deux champs sont FACULTATIFS et purement
|
|
* informatifs (ils n'ouvrent aucune session, n'envoient aucun message). Le
|
|
* contrôle attrape la faute de frappe, il ne prétend pas prouver qu'une boîte
|
|
* ou une ligne existe. Une valeur vide reste toujours acceptée.
|
|
*/
|
|
final class ContactFormat
|
|
{
|
|
/**
|
|
* Adresse e-mail. Regex délibérément plus stricte que la RFC 5322, qui
|
|
* autorise des formes que personne ne saisit dans un annuaire d'agents
|
|
* (commentaires, guillemets, adresses IP littérales). Elle est DOUBLÉE de
|
|
* FILTER_VALIDATE_EMAIL : la regex écarte ce que le filtre tolère (domaine
|
|
* sans point, par exemple « agent@mairie »), le filtre écarte ce que la
|
|
* regex laisserait passer.
|
|
*/
|
|
private const EMAIL_PATTERN = '/^[A-Za-z0-9._%+\-]+@[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9\-]*[A-Za-z0-9])?)*\.[A-Za-z]{2,}$/';
|
|
|
|
/**
|
|
* Numéro français, une fois les séparateurs retirés : 10 chiffres commençant
|
|
* par 0, ou la même chose en forme internationale (+33 / 0033). Couvre le
|
|
* fixe comme le mobile, métropole et outre-mer.
|
|
*/
|
|
private const PHONE_FR_PATTERN = '/^(?:\+33|0033|0)[1-9]\d{8}$/';
|
|
|
|
/**
|
|
* Repli international E.164 pour un agent joignable à l'étranger — refuser
|
|
* un numéro valide serait pire que d'en accepter un exotique, le champ
|
|
* n'étant qu'informatif.
|
|
*/
|
|
private const PHONE_INTERNATIONAL_PATTERN = '/^\+[1-9]\d{7,14}$/';
|
|
|
|
/** Séparateurs tolérés à la saisie : espaces (insécable compris), . - / ( ). */
|
|
private const PHONE_SEPARATORS = '/[\s.\-\/()\x{00A0}\x{202F}]/u';
|
|
|
|
/** Vrai si l'adresse e-mail est exploitable. La chaîne vide est refusée : c'est à l'appelant de traiter « non renseigné » avant. */
|
|
public static function isEmail(string $value): bool
|
|
{
|
|
$value = trim($value);
|
|
if ($value === '') {
|
|
return false;
|
|
}
|
|
|
|
return preg_match(self::EMAIL_PATTERN, $value) === 1
|
|
&& filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
|
}
|
|
|
|
/** Vrai si le numéro de téléphone est exploitable, séparateurs de saisie ignorés. */
|
|
public static function isPhone(string $value): bool
|
|
{
|
|
$compact = self::compactPhone($value);
|
|
if ($compact === '') {
|
|
return false;
|
|
}
|
|
|
|
return preg_match(self::PHONE_FR_PATTERN, $compact) === 1
|
|
|| preg_match(self::PHONE_INTERNATIONAL_PATTERN, $compact) === 1;
|
|
}
|
|
|
|
/**
|
|
* Numéro débarrassé de ses séparateurs, seule forme sur laquelle les regex
|
|
* travaillent. « 06 12 34 56 78 », « 06.12.34.56.78 » et « 0612345678 »
|
|
* décrivent la même ligne : les distinguer n'apporterait rien.
|
|
*/
|
|
public static function compactPhone(string $value): string
|
|
{
|
|
return (string) preg_replace(self::PHONE_SEPARATORS, '', trim($value));
|
|
}
|
|
}
|