1076 lines
40 KiB
PHP
1076 lines
40 KiB
PHP
<?php
|
|
|
|
namespace libraries;
|
|
|
|
/**
|
|
* Classe de validation pour les formulaires de crédit
|
|
*/
|
|
class FormValidator
|
|
{
|
|
private $errors = [];
|
|
private $data = [];
|
|
private $creditModel = null;
|
|
|
|
/**
|
|
* Constructeur
|
|
* @param array $data Les données à valider
|
|
* @param object $creditModel Instance du modèle de crédit (optionnel)
|
|
*/
|
|
public function __construct($data = [], $creditModel = null)
|
|
{
|
|
$this->data = $data;
|
|
$this->creditModel = $creditModel;
|
|
}
|
|
|
|
/**
|
|
* Valide un champ requis
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function required($field, $message = null)
|
|
{
|
|
if (empty($this->data[$field]) || trim($this->data[$field]) === '') {
|
|
$this->addError($field, $message ?: "Le champ {$field} est requis.");
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un email
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function email($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field]) && !filter_var($this->data[$field], FILTER_VALIDATE_EMAIL)) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être un email valide.");
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un numéro de téléphone belge
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function phone($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$phone = preg_replace('/[^0-9+]/', '', $this->data[$field]);
|
|
if (!preg_match('/^(\+32|0)[0-9]{8,9}$/', $phone)) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être un numéro de téléphone belge valide.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un code postal belge
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function zipCode($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
if (!preg_match('/^[0-9]{4}$/', $this->data[$field])) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être un code postal belge valide (4 chiffres).");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un numéro de registre national belge
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function nationalNumber($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$number = preg_replace('/[^0-9]/', '', $this->data[$field]);
|
|
if (strlen($number) !== 11) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit contenir 11 chiffres.");
|
|
return $this;
|
|
}
|
|
|
|
// Validation de la clé de contrôle du registre national
|
|
if (!$this->validateNationalNumberChecksum($number)) {
|
|
$this->addError($field, $message ?: "Le champ {$field} n'est pas un numéro de registre national valide.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un numéro de compte bancaire belge (IBAN)
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function bankAccount($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$account = preg_replace('/[^0-9]/', '', $this->data[$field]);
|
|
if (strlen($account) < 10 || strlen($account) > 16) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit contenir entre 10 et 16 chiffres.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide une date au format JJ/MM/AAAA
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function date($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$date = \DateTime::createFromFormat('d/m/Y', $this->data[$field]);
|
|
if (!$date || $date->format('d/m/Y') !== $this->data[$field]) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être une date valide au format JJ/MM/AAAA.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide qu'une date est dans le passé
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function datePast($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$date = \DateTime::createFromFormat('d/m/Y', $this->data[$field]);
|
|
if ($date && $date > new \DateTime()) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être une date dans le passé.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide qu'une date est dans le futur
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function dateFuture($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$date = \DateTime::createFromFormat('d/m/Y', $this->data[$field]);
|
|
if ($date && $date < new \DateTime()) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être une date dans le futur.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un montant (nombre positif)
|
|
* @param string $field Le nom du champ
|
|
* @param float $min Montant minimum
|
|
* @param float $max Montant maximum
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function amount($field, $min = 0, $max = null, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$amount = floatval($this->data[$field]);
|
|
if ($amount < $min) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être supérieur ou égal à {$min}.");
|
|
}
|
|
if ($max !== null && $amount > $max) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être inférieur ou égal à {$max}.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un nombre d'enfants
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function childrenCount($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$count = intval($this->data[$field]);
|
|
if ($count < 0 || $count > 24) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être entre 0 et 24.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide qu'un champ est dans une liste de valeurs
|
|
* @param string $field Le nom du champ
|
|
* @param array $allowedValues Valeurs autorisées
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function in($field, $allowedValues, $message = null)
|
|
{
|
|
if (!empty($this->data[$field]) && !in_array($this->data[$field], $allowedValues)) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être une des valeurs autorisées.");
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide la longueur d'une chaîne
|
|
* @param string $field Le nom du champ
|
|
* @param int $min Longueur minimum
|
|
* @param int $max Longueur maximum
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function length($field, $min, $max, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$length = strlen($this->data[$field]);
|
|
if ($length < $min || $length > $max) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit contenir entre {$min} et {$max} caractères.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un numéro de carte d'identité belge
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function identityCard($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$card = preg_replace('/[^0-9]/', '', $this->data[$field]);
|
|
if (strlen($card) < 8 || strlen($card) > 12) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit contenir entre 8 et 12 chiffres.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide un taux (pourcentage) au format "int%" ou juste un entier positif
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function rate($field, $message = null)
|
|
{
|
|
if (!empty($this->data[$field])) {
|
|
$value = trim($this->data[$field]);
|
|
|
|
// Vérifier si c'est au format "X%" ou juste "X"
|
|
if (preg_match('/^(\d+)%?$/', $value, $matches)) {
|
|
$rate = intval($matches[1]);
|
|
if ($rate < 0 || $rate > 100) {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être un taux entre 0 et 100.");
|
|
}
|
|
} else {
|
|
$this->addError($field, $message ?: "Le champ {$field} doit être un taux au format 'X%' ou juste 'X'.");
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Valide qu'un montant est dans les limites définies pour le type de crédit
|
|
* @param string $amountField Le nom du champ montant
|
|
* @param string $creditTypeField Le nom du champ type de crédit
|
|
* @param string $message Message d'erreur personnalisé
|
|
* @return FormValidator
|
|
*/
|
|
public function creditAmountWithinLimits($amountField, $creditTypeField, $message = null)
|
|
{
|
|
if (!empty($this->data[$amountField]) && !empty($this->data[$creditTypeField])) {
|
|
$amount = floatval($this->data[$amountField]);
|
|
$creditType = $this->data[$creditTypeField];
|
|
|
|
// Récupérer les limites depuis le modèle
|
|
if (isset($this->creditModel) && method_exists($this->creditModel, 'get_credit_limits')) {
|
|
$limits = $this->creditModel->get_credit_limits($creditType);
|
|
|
|
if ($amount < $limits['limite_basse']) {
|
|
$this->addError($amountField, $message ?: "Le montant demandé ({$amount}€) est inférieur à la limite minimale de {$limits['limite_basse']}€ pour ce type de crédit.");
|
|
} elseif ($amount > $limits['limite_haute']) {
|
|
$this->addError($amountField, $message ?: "Le montant demandé ({$amount}€) dépasse la limite maximale de {$limits['limite_haute']}€ pour ce type de crédit.");
|
|
}
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Détermine automatiquement le type de champ et applique les bonnes validations
|
|
* @param string $field Le nom du champ
|
|
* @param mixed $value La valeur du champ
|
|
* @param bool $required Si le champ est requis
|
|
* @return FormValidator
|
|
*/
|
|
public function autoValidate($field, $value, $required = false)
|
|
{
|
|
$this->data[$field] = $value;
|
|
|
|
// Validation des champs requis
|
|
if ($required) {
|
|
$this->required($field);
|
|
}
|
|
|
|
// Détermination automatique du type de champ
|
|
$fieldType = $this->detectFieldType($field, $value);
|
|
|
|
// Application des validations selon le type détecté
|
|
switch ($fieldType) {
|
|
case 'email':
|
|
$this->email($field);
|
|
break;
|
|
case 'phone':
|
|
$this->phone($field);
|
|
break;
|
|
case 'date':
|
|
$this->date($field);
|
|
break;
|
|
case 'date_past':
|
|
$this->date($field)->datePast($field);
|
|
break;
|
|
case 'date_future':
|
|
$this->date($field)->dateFuture($field);
|
|
break;
|
|
case 'zip_code':
|
|
$this->zipCode($field);
|
|
break;
|
|
case 'national_number':
|
|
$this->nationalNumber($field);
|
|
break;
|
|
case 'bank_account':
|
|
$this->bankAccount($field);
|
|
break;
|
|
case 'identity_card':
|
|
$this->identityCard($field);
|
|
break;
|
|
case 'amount':
|
|
$this->amount($field);
|
|
break;
|
|
case 'rate':
|
|
$this->rate($field);
|
|
break;
|
|
case 'children_count':
|
|
$this->childrenCount($field);
|
|
break;
|
|
case 'text':
|
|
$this->length($field, 1, 255);
|
|
break;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Détecte automatiquement le type de champ basé sur son nom et sa valeur
|
|
* @param string $field Le nom du champ
|
|
* @param mixed $value La valeur du champ
|
|
* @return string Le type de champ détecté
|
|
*/
|
|
private function detectFieldType($field, $value)
|
|
{
|
|
$field = strtolower($field);
|
|
|
|
// Détection par nom de champ
|
|
if (strpos($field, 'email') !== false) {
|
|
return 'email';
|
|
}
|
|
|
|
if (strpos($field, 'phone') !== false || strpos($field, 'telephone') !== false) {
|
|
return 'phone';
|
|
}
|
|
|
|
if (strpos($field, 'zip') !== false || strpos($field, 'code_postal') !== false) {
|
|
return 'zip_code';
|
|
}
|
|
|
|
if (strpos($field, 'nationalregistrationnumber') !== false || strpos($field, 'num_registre_national') !== false) {
|
|
return 'national_number';
|
|
}
|
|
|
|
if (strpos($field, 'bankaccountnumber') !== false || strpos($field, 'num_compte_bancaire') !== false) {
|
|
return 'bank_account';
|
|
}
|
|
|
|
if (strpos($field, 'cardnumber') !== false || strpos($field, 'num_carte_identite') !== false) {
|
|
return 'identity_card';
|
|
}
|
|
|
|
if (strpos($field, 'salary') !== false || strpos($field, 'salaire') !== false ||
|
|
strpos($field, 'loyer') !== false || strpos($field, 'montant') !== false ||
|
|
strpos($field, 'capital') !== false || strpos($field, 'mensualite') !== false ||
|
|
strpos($field, 'cout_total') !== false) {
|
|
return 'amount';
|
|
}
|
|
|
|
if (strpos($field, 'taux') !== false || strpos($field, 'rate') !== false) {
|
|
return 'rate';
|
|
}
|
|
|
|
if (strpos($field, 'children') !== false || strpos($field, 'enfant') !== false) {
|
|
return 'children_count';
|
|
}
|
|
|
|
// Détection par nom de champ contenant "date"
|
|
if (strpos($field, 'date') !== false) {
|
|
if (strpos($field, 'validity') !== false || strpos($field, 'validite') !== false) {
|
|
return 'date_future';
|
|
}
|
|
if (strpos($field, 'birth') !== false || strpos($field, 'naissance') !== false) {
|
|
return 'date_past';
|
|
}
|
|
return 'date';
|
|
}
|
|
|
|
// Détection par valeur si c'est une date
|
|
if (!empty($value) && $this->isDateFormat($value)) {
|
|
return 'date';
|
|
}
|
|
|
|
// Détection par valeur si c'est un email
|
|
if (!empty($value) && filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
return 'email';
|
|
}
|
|
|
|
// Détection par valeur si c'est un montant
|
|
if (!empty($value) && is_numeric($value) && floatval($value) > 0) {
|
|
return 'amount';
|
|
}
|
|
|
|
return 'text';
|
|
}
|
|
|
|
/**
|
|
* Vérifie si une valeur est au format date JJ/MM/AAAA
|
|
* @param string $value La valeur à vérifier
|
|
* @return bool
|
|
*/
|
|
private function isDateFormat($value)
|
|
{
|
|
if (empty($value)) return false;
|
|
|
|
// Vérifier le format JJ/MM/AAAA
|
|
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $value)) {
|
|
$date = \DateTime::createFromFormat('d/m/Y', $value);
|
|
return $date && $date->format('d/m/Y') === $value;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Valide les données de l'emprunteur principal
|
|
* @param array $data Les données du formulaire
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function validateBorrower($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
// Informations de base
|
|
$this->required('firstname', 'Le prénom est requis.')
|
|
->required('lastname', 'Le nom est requis.')
|
|
->required('email', 'L\'email est requis.')
|
|
->email('email', 'L\'email doit être valide.')
|
|
->required('phone', 'Le téléphone est requis.')
|
|
->phone('phone', 'Le téléphone doit être un numéro belge valide.')
|
|
->required('zip', 'Le code postal est requis.')
|
|
->zipCode('zip', 'Le code postal doit être valide.')
|
|
->required('country', 'Le pays est requis.');
|
|
|
|
// Données personnelles (étape 3)
|
|
if (isset($data['birthdate'])) {
|
|
$this->required('birthdate', 'La date de naissance est requise.')
|
|
->date('birthdate', 'La date de naissance doit être au format JJ/MM/AAAA.')
|
|
->datePast('birthdate', 'La date de naissance doit être dans le passé.');
|
|
}
|
|
|
|
if (isset($data['birthplace'])) {
|
|
$this->required('birthplace', 'Le lieu de naissance est requis.');
|
|
}
|
|
|
|
if (isset($data['nationality'])) {
|
|
$this->required('nationality', 'La nationalité est requise.');
|
|
}
|
|
|
|
if (isset($data['cardnumber'])) {
|
|
$this->required('cardnumber', 'Le numéro de carte d\'identité est requis.')
|
|
->identityCard('cardnumber', 'Le numéro de carte d\'identité doit être valide.');
|
|
}
|
|
|
|
if (isset($data['cnvaliditydate'])) {
|
|
$this->required('cnvaliditydate', 'La date de validité de la carte est requise.')
|
|
->date('cnvaliditydate', 'La date de validité doit être au format JJ/MM/AAAA.')
|
|
->dateFuture('cnvaliditydate', 'La date de validité doit être dans le futur.');
|
|
}
|
|
|
|
if (isset($data['nationalregistrationnumber'])) {
|
|
$this->required('nationalregistrationnumber', 'Le numéro de registre national est requis.')
|
|
->nationalNumber('nationalregistrationnumber', 'Le numéro de registre national doit être valide.');
|
|
}
|
|
|
|
if (isset($data['bankaccountnumber'])) {
|
|
$this->required('bankaccountnumber', 'Le numéro de compte bancaire est requis.')
|
|
->bankAccount('bankaccountnumber', 'Le numéro de compte bancaire doit être valide.');
|
|
}
|
|
|
|
if (isset($data['dependentchildren'])) {
|
|
$this->childrenCount('dependentchildren', 'Le nombre d\'enfants doit être entre 0 et 24.');
|
|
}
|
|
|
|
// Informations professionnelles
|
|
if (isset($data['civilstatus'])) {
|
|
$this->required('civilstatus', 'L\'état civil est requis.');
|
|
}
|
|
|
|
if (isset($data['job'])) {
|
|
$this->required('job', 'La profession est requise.');
|
|
}
|
|
|
|
if (isset($data['salary'])) {
|
|
$this->required('salary', 'Le salaire est requis.')
|
|
->amount('salary', 0, null, 'Le salaire doit être un montant positif.');
|
|
}
|
|
|
|
if (isset($data['annual_taxable_income'])) {
|
|
$this->amount('annual_taxable_income', 0, null, 'Le revenu imposable doit être un montant positif.');
|
|
}
|
|
|
|
// Autres revenus
|
|
if (isset($data['oiamouthmealvoucher'])) {
|
|
$this->amount('oiamouthmealvoucher', 0, null, 'Le montant des chèques repas doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthrentalincome'])) {
|
|
$this->amount('oiamouthrentalincome', 0, null, 'Le montant des revenus locatifs doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthunemployment'])) {
|
|
$this->amount('oiamouthunemployment', 0, null, 'Le montant du chômage doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthother'])) {
|
|
$this->amount('oiamouthother', 0, null, 'Le montant des autres revenus doit être positif.');
|
|
}
|
|
|
|
// Logement
|
|
if (isset($data['habitation_type'])) {
|
|
$allowedTypes = ['proprietaire', 'proprietaire_sans_pret', 'locataire', 'cohabitant'];
|
|
$this->in('habitation_type', $allowedTypes, 'Le type d\'habitation doit être valide.');
|
|
}
|
|
|
|
if (isset($data['habitation_loyer'])) {
|
|
$this->amount('habitation_loyer', 0, null, 'Le montant du loyer doit être positif.');
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide les données du co-emprunteur
|
|
* @param array $data Les données du formulaire
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function validateCoBorrower($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
// Préfixe 'co' pour les champs du co-emprunteur
|
|
$coFields = [
|
|
'cobirthdate' => 'birthdate',
|
|
'cobirthplace' => 'birthplace',
|
|
'conationality' => 'nationality',
|
|
'cocardnumber' => 'cardnumber',
|
|
'cocnvaliditydate' => 'cnvaliditydate',
|
|
'conationalregistrationnumber' => 'nationalregistrationnumber',
|
|
'cobankaccountnumber' => 'bankaccountnumber',
|
|
'codependentchildren' => 'dependentchildren'
|
|
];
|
|
|
|
foreach ($coFields as $coField => $baseField) {
|
|
if (isset($data[$coField]) && !empty($data[$coField])) {
|
|
$this->data[$baseField] = $data[$coField];
|
|
|
|
switch ($baseField) {
|
|
case 'birthdate':
|
|
$this->date($baseField, 'La date de naissance du co-emprunteur doit être au format JJ/MM/AAAA.')
|
|
->datePast($baseField, 'La date de naissance du co-emprunteur doit être dans le passé.');
|
|
break;
|
|
case 'birthplace':
|
|
$this->required($baseField, 'Le lieu de naissance du co-emprunteur est requis.');
|
|
break;
|
|
case 'nationality':
|
|
$this->required($baseField, 'La nationalité du co-emprunteur est requise.');
|
|
break;
|
|
case 'cardnumber':
|
|
$this->identityCard($baseField, 'Le numéro de carte d\'identité du co-emprunteur doit être valide.');
|
|
break;
|
|
case 'cnvaliditydate':
|
|
$this->date($baseField, 'La date de validité de la carte du co-emprunteur doit être au format JJ/MM/AAAA.')
|
|
->dateFuture($baseField, 'La date de validité de la carte du co-emprunteur doit être dans le futur.');
|
|
break;
|
|
case 'nationalregistrationnumber':
|
|
$this->nationalNumber($baseField, 'Le numéro de registre national du co-emprunteur doit être valide.');
|
|
break;
|
|
case 'bankaccountnumber':
|
|
$this->bankAccount($baseField, 'Le numéro de compte bancaire du co-emprunteur doit être valide.');
|
|
break;
|
|
case 'dependentchildren':
|
|
$this->childrenCount($baseField, 'Le nombre d\'enfants du co-emprunteur doit être entre 0 et 24.');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide les crédits en cours
|
|
* @param array $data Les données du formulaire
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function validateCurrentLoans($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
if (isset($data['currentloans']) && is_array($data['currentloans'])) {
|
|
foreach ($data['currentloans'] as $index => $loan) {
|
|
$prefix = "currentloans[{$index}]";
|
|
|
|
if (isset($loan['loantype'])) {
|
|
$this->required($prefix . '[loantype]', "Le type de créance du crédit {$index} est requis.");
|
|
}
|
|
|
|
if (isset($loan['bankname'])) {
|
|
$this->required($prefix . '[bankname]', "Le nom de la banque du crédit {$index} est requis.")
|
|
->length($prefix . '[bankname]', 2, 100, "Le nom de la banque du crédit {$index} doit contenir entre 2 et 100 caractères.");
|
|
}
|
|
|
|
if (isset($loan['borrowedcapital'])) {
|
|
$this->required($prefix . '[borrowedcapital]', "Le capital emprunté du crédit {$index} est requis.")
|
|
->amount($prefix . '[borrowedcapital]', 0, null, "Le capital emprunté du crédit {$index} doit être positif.");
|
|
}
|
|
|
|
if (isset($loan['durationmonth'])) {
|
|
$this->required($prefix . '[durationmonth]', "La durée du crédit {$index} est requise.")
|
|
->amount($prefix . '[durationmonth]', 1, 600, "La durée du crédit {$index} doit être entre 1 et 600 mois.");
|
|
}
|
|
|
|
if (isset($loan['monthlypayment'])) {
|
|
$this->required($prefix . '[monthlypayment]', "La mensualité du crédit {$index} est requise.")
|
|
->amount($prefix . '[monthlypayment]', 0, null, "La mensualité du crédit {$index} doit être positive.");
|
|
}
|
|
|
|
if (isset($loan['firstduedate'])) {
|
|
$this->required($prefix . '[firstduedate]', "La date de première échéance du crédit {$index} est requise.")
|
|
->date($prefix . '[firstduedate]', "La date de première échéance du crédit {$index} doit être au format JJ/MM/AAAA.");
|
|
}
|
|
|
|
if (isset($loan['remainingbalance'])) {
|
|
$this->required($prefix . '[remainingbalance]', "Le solde restant du crédit {$index} est requis.")
|
|
->amount($prefix . '[remainingbalance]', 0, null, "Le solde restant du crédit {$index} doit être positif.");
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide automatiquement tous les champs d'un formulaire
|
|
* @param array $data Les données du formulaire
|
|
* @param array $requiredFields Liste des champs requis
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function autoValidateAll($data, $requiredFields = [])
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
foreach ($data as $field => $value) {
|
|
// Ignorer les champs spéciaux
|
|
if (in_array($field, ['credit-direct-token', 'type_credit_selected', 'sub_loan_type'])) {
|
|
continue;
|
|
}
|
|
|
|
// Déterminer si le champ est requis
|
|
$isRequired = in_array($field, $requiredFields);
|
|
|
|
// Validation automatique
|
|
$this->autoValidate($field, $value, $isRequired);
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide les données de l'étape 2 (revenus et charges)
|
|
* @param array $data Les données du formulaire
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function validateStep2($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
// Champs requis pour l'étape 2 UNIQUEMENT
|
|
$step2RequiredFields = [
|
|
'firstname', 'lastname', 'email', 'phone',
|
|
'civilstatus', 'job', 'salary', 'habitation_type'
|
|
];
|
|
|
|
// Validation explicite des champs requis de l'étape 2
|
|
foreach ($step2RequiredFields as $field) {
|
|
if (isset($data[$field])) {
|
|
$this->required($field);
|
|
}
|
|
}
|
|
|
|
// Validation des champs spécifiques de l'étape 2
|
|
if (isset($data['email'])) {
|
|
$this->email('email', 'L\'email doit être valide.');
|
|
}
|
|
|
|
if (isset($data['phone'])) {
|
|
$this->phone('phone', 'Le téléphone doit être un numéro belge valide.');
|
|
}
|
|
|
|
// Type de contrat et revenus
|
|
if (isset($data['contract_type']) && !empty($data['contract_type'])) {
|
|
$allowedContracts = ['cdi', 'cdd', 'fon', 'int', 'oth', 'ssc'];
|
|
$this->in('contract_type', $allowedContracts, 'Le type de contrat doit être valide.');
|
|
}
|
|
|
|
if (isset($data['independent_since'])) {
|
|
$this->date('independent_since', 'La date de début d\'activité indépendante doit être au format JJ/MM/AAAA.');
|
|
}
|
|
|
|
if (isset($data['salary'])) {
|
|
$this->amount('salary', 0, null, 'Le salaire doit être un montant positif.');
|
|
}
|
|
|
|
if (isset($data['annual_taxable_income'])) {
|
|
$this->amount('annual_taxable_income', 0, null, 'Le revenu imposable doit être un montant positif.');
|
|
}
|
|
|
|
// Autres revenus
|
|
if (isset($data['hasotherincome']) && $data['hasotherincome'] === '1') {
|
|
if (isset($data['oiamouthmealvoucher'])) {
|
|
$this->amount('oiamouthmealvoucher', 0, null, 'Le montant des chèques repas doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthrentalincome'])) {
|
|
$this->amount('oiamouthrentalincome', 0, null, 'Le montant des revenus locatifs doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthunemployment'])) {
|
|
$this->amount('oiamouthunemployment', 0, null, 'Le montant du chômage doit être positif.');
|
|
}
|
|
|
|
if (isset($data['oiamouthother'])) {
|
|
$this->amount('oiamouthother', 0, null, 'Le montant des autres revenus doit être positif.');
|
|
}
|
|
}
|
|
|
|
// Fichage
|
|
if (isset($data['isFiched']) && $data['isFiched'] === '1') {
|
|
$this->required('fichage_status', 'Le statut du fichage est requis.');
|
|
}
|
|
|
|
// Logement
|
|
if (isset($data['habitation_type'])) {
|
|
$allowedTypes = ['proprietaire', 'proprietaire_sans_pret', 'locataire', 'cohabitant'];
|
|
$this->in('habitation_type', $allowedTypes, 'Le type d\'habitation doit être valide.');
|
|
}
|
|
|
|
if (isset($data['habitation_loyer'])) {
|
|
$this->amount('habitation_loyer', 0, null, 'Le montant du loyer doit être positif.');
|
|
}
|
|
|
|
// Crédits en cours
|
|
if (isset($data['hascurrentloan']) && $data['hascurrentloan'] === '1') {
|
|
$this->validateCurrentLoans($data);
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide les données de l'étape 3 (informations personnelles)
|
|
* @param array $data Les données du formulaire
|
|
* @return array Erreurs de validation
|
|
*/
|
|
public function validateStep3($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->errors = [];
|
|
|
|
// Champs requis pour l'étape 3 UNIQUEMENT - Emprunteur principal
|
|
$step3RequiredFields = [
|
|
'birthdate', 'birthplace', 'nationality',
|
|
'cardnumber', 'cnvaliditydate',
|
|
'nationalregistrationnumber', 'bankaccountnumber',
|
|
'dependentchildren'
|
|
];
|
|
|
|
// Validation explicite des champs requis de l'étape 3 pour l'emprunteur principal
|
|
foreach ($step3RequiredFields as $field) {
|
|
if (isset($data[$field])) {
|
|
$this->required($field);
|
|
}
|
|
}
|
|
|
|
// Validation spécifique des champs de l'étape 3 - Emprunteur principal
|
|
if (isset($data['birthdate'])) {
|
|
$this->date('birthdate', 'La date de naissance doit être au format JJ/MM/AAAA.')
|
|
->datePast('birthdate', 'La date de naissance doit être dans le passé.');
|
|
}
|
|
|
|
if (isset($data['cnvaliditydate'])) {
|
|
$this->date('cnvaliditydate', 'La date de validité de la carte doit être au format JJ/MM/AAAA.')
|
|
->dateFuture('cnvaliditydate', 'La date de validité de la carte doit être dans le futur.');
|
|
}
|
|
|
|
if (isset($data['nationalregistrationnumber'])) {
|
|
$this->nationalNumber('nationalregistrationnumber', 'Le numéro de registre national doit être valide.');
|
|
}
|
|
|
|
if (isset($data['bankaccountnumber'])) {
|
|
$this->bankAccount('bankaccountnumber', 'Le numéro de compte bancaire doit être valide.');
|
|
}
|
|
|
|
if (isset($data['cardnumber'])) {
|
|
$this->identityCard('cardnumber', 'Le numéro de carte d\'identité doit être valide.');
|
|
}
|
|
|
|
if (isset($data['dependentchildren'])) {
|
|
$this->childrenCount('dependentchildren', 'Le nombre d\'enfants doit être entre 0 et 24.');
|
|
}
|
|
|
|
if (isset($data['montant_allocation_familiale'])) {
|
|
$this->amount('montant_allocation_familiale', 0, null, 'Le montant des allocations familiales doit être positif.');
|
|
}
|
|
|
|
// Validation du co-emprunteur UNIQUEMENT si hascoborrower est défini et égal à '1'
|
|
if (isset($data['hascoborrower']) && $data['hascoborrower'] === '1') {
|
|
// Validation des champs du co-emprunteur (tous optionnels mais si présents, doivent être valides)
|
|
if (isset($data['cobirthdate'])) {
|
|
$this->date('cobirthdate', 'La date de naissance du co-emprunteur doit être au format JJ/MM/AAAA.')
|
|
->datePast('cobirthdate', 'La date de naissance du co-emprunteur doit être dans le passé.');
|
|
}
|
|
|
|
if (isset($data['cocnvaliditydate'])) {
|
|
$this->date('cocnvaliditydate', 'La date de validité de la carte du co-emprunteur doit être au format JJ/MM/AAAA.')
|
|
->dateFuture('cocnvaliditydate', 'La date de validité de la carte du co-emprunteur doit être dans le futur.');
|
|
}
|
|
|
|
if (isset($data['conationalregistrationnumber'])) {
|
|
$this->nationalNumber('conationalregistrationnumber', 'Le numéro de registre national du co-emprunteur doit être valide.');
|
|
}
|
|
|
|
if (isset($data['cobankaccountnumber'])) {
|
|
$this->bankAccount('cobankaccountnumber', 'Le numéro de compte bancaire du co-emprunteur doit être valide.');
|
|
}
|
|
|
|
if (isset($data['cocardnumber'])) {
|
|
$this->identityCard('cocardnumber', 'Le numéro de carte d\'identité du co-emprunteur doit être valide.');
|
|
}
|
|
|
|
if (isset($data['codependentchildren'])) {
|
|
$this->childrenCount('codependentchildren', 'Le nombre d\'enfants du co-emprunteur doit être entre 0 et 24.');
|
|
}
|
|
|
|
if (isset($data['comontant_allocation_familiale'])) {
|
|
$this->amount('comontant_allocation_familiale', 0, null, 'Le montant des allocations familiales du co-emprunteur doit être positif.');
|
|
}
|
|
}
|
|
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Valide la clé de contrôle du numéro de registre national belge
|
|
* @param string $number Le numéro à valider
|
|
* @return bool
|
|
*/
|
|
private function validateNationalNumberChecksum($number)
|
|
{
|
|
if (strlen($number) !== 11) {
|
|
return false;
|
|
}
|
|
|
|
$base = substr($number, 0, 9);
|
|
$check = substr($number, 9, 2);
|
|
|
|
$remainder = intval($base) % 97;
|
|
$expectedCheck = 97 - $remainder;
|
|
|
|
return intval($check) === $expectedCheck;
|
|
}
|
|
|
|
/**
|
|
* Ajoute une erreur
|
|
* @param string $field Le nom du champ
|
|
* @param string $message Le message d'erreur
|
|
*/
|
|
private function addError($field, $message)
|
|
{
|
|
$this->errors[$field] = $message;
|
|
}
|
|
|
|
/**
|
|
* Retourne les erreurs
|
|
* @return array
|
|
*/
|
|
public function getErrors()
|
|
{
|
|
return $this->errors;
|
|
}
|
|
|
|
/**
|
|
* Vérifie s'il y a des erreurs
|
|
* @return bool
|
|
*/
|
|
public function hasErrors()
|
|
{
|
|
return !empty($this->errors);
|
|
}
|
|
|
|
/**
|
|
* Retourne les erreurs formatées pour l'affichage
|
|
* @return string
|
|
*/
|
|
public function getFormattedErrors()
|
|
{
|
|
if (empty($this->errors)) {
|
|
return '';
|
|
}
|
|
|
|
$html = '<div class="alert alert-danger"><h4>Erreurs de validation :</h4><ul>';
|
|
foreach ($this->errors as $field => $message) {
|
|
$html .= '<li>' . htmlspecialchars($message) . '</li>';
|
|
}
|
|
$html .= '</ul></div>';
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Analyse les champs d'un formulaire et retourne leurs types détectés
|
|
* @param array $data Les données du formulaire
|
|
* @return array Types de champs détectés
|
|
*/
|
|
public function analyzeFields($data)
|
|
{
|
|
$fieldTypes = [];
|
|
|
|
foreach ($data as $field => $value) {
|
|
if (in_array($field, ['credit-direct-token', 'type_credit_selected', 'sub_loan_type'])) {
|
|
continue;
|
|
}
|
|
|
|
$fieldType = $this->detectFieldType($field, $value);
|
|
$fieldTypes[$field] = [
|
|
'type' => $fieldType,
|
|
'value' => $value,
|
|
'detection_method' => $this->getDetectionMethod($field, $value, $fieldType)
|
|
];
|
|
}
|
|
|
|
return $fieldTypes;
|
|
}
|
|
|
|
/**
|
|
* Retourne la méthode de détection utilisée pour un champ
|
|
* @param string $field Le nom du champ
|
|
* @param mixed $value La valeur du champ
|
|
* @param string $detectedType Le type détecté
|
|
* @return string
|
|
*/
|
|
private function getDetectionMethod($field, $value, $detectedType)
|
|
{
|
|
$field = strtolower($field);
|
|
|
|
// Vérifier si c'est par nom de champ
|
|
if (strpos($field, 'email') !== false && $detectedType === 'email') {
|
|
return 'nom_champ';
|
|
}
|
|
|
|
if (strpos($field, 'phone') !== false && $detectedType === 'phone') {
|
|
return 'nom_champ';
|
|
}
|
|
|
|
if (strpos($field, 'date') !== false && in_array($detectedType, ['date', 'date_past', 'date_future'])) {
|
|
return 'nom_champ';
|
|
}
|
|
|
|
// Vérifier si c'est par valeur
|
|
if ($detectedType === 'email' && filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
return 'valeur';
|
|
}
|
|
|
|
if ($detectedType === 'date' && $this->isDateFormat($value)) {
|
|
return 'valeur';
|
|
}
|
|
|
|
if ($detectedType === 'amount' && is_numeric($value)) {
|
|
return 'valeur';
|
|
}
|
|
|
|
return 'nom_champ';
|
|
}
|
|
|
|
/**
|
|
* Génère un rapport d'analyse des champs
|
|
* @param array $data Les données du formulaire
|
|
* @return string Rapport HTML
|
|
*/
|
|
public function generateFieldAnalysisReport($data)
|
|
{
|
|
$fieldTypes = $this->analyzeFields($data);
|
|
|
|
$html = '<div class="field-analysis-report">';
|
|
$html .= '<h3>Analyse des types de champs</h3>';
|
|
$html .= '<table class="table table-striped">';
|
|
$html .= '<thead><tr><th>Champ</th><th>Valeur</th><th>Type détecté</th><th>Méthode de détection</th></tr></thead>';
|
|
$html .= '<tbody>';
|
|
|
|
foreach ($fieldTypes as $field => $info) {
|
|
$html .= '<tr>';
|
|
$html .= '<td><code>' . htmlspecialchars($field) . '</code></td>';
|
|
$html .= '<td>' . htmlspecialchars($info['value']) . '</td>';
|
|
$html .= '<td><span class="badge badge-info">' . htmlspecialchars($info['type']) . '</span></td>';
|
|
$html .= '<td>' . htmlspecialchars($info['detection_method']) . '</td>';
|
|
$html .= '</tr>';
|
|
}
|
|
|
|
$html .= '</tbody></table>';
|
|
$html .= '</div>';
|
|
|
|
return $html;
|
|
}
|
|
}
|