Leggendo questa domanda SO sembra che non vengano considerate le eccezioni per la convalida dell'input dell'utente.
Ma chi dovrebbe validare questi dati? Nelle mie applicazioni, tutte le convalide vengono eseguite nel livello aziendale, poiché solo la classe stessa sa davvero quali valori sono validi per ciascuna delle sue proprietà. Se dovessi copiare le regole per la convalida di una proprietà sul controller, è possibile che le regole di convalida cambino e ora ci sono due punti in cui è necessario apportare la modifica.
La mia premessa è che la validazione dovrebbe essere fatta a livello aziendale sbagliata?
Quello che faccio
Quindi il mio codice di solito finisce così:
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
throw new ValidationException("Name cannot be empty");
}
$this->name = $n;
}
public function setAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
throw new ValidationException("Age $a is not valid");
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
throw new ValidationException("Age $a is out of bounds");
}
$this->age = $a;
}
// other getters, setters and methods
}
Nel controller, ho semplicemente passato i dati di input al modello e ho intercettato le eccezioni per mostrare all'utente gli errori:
<?php
$person = new Person();
$errors = array();
// global try for all exceptions other than ValidationException
try {
// validation and process (if everything ok)
try {
$person->setAge($_POST['age']);
} catch (ValidationException $e) {
$errors['age'] = $e->getMessage();
}
try {
$person->setName($_POST['name']);
} catch (ValidationException $e) {
$errors['name'] = $e->getMessage();
}
...
} catch (Exception $e) {
// log the error, send 500 internal server error to the client
// and finish the request
}
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
È una cattiva metodologia?
Metodo alternativo
Forse dovrei creare metodi per isValidAge($a)
restituire vero / falso e poi chiamarli dal controller?
<?php
class Person
{
private $name;
private $age;
public function setName($n) {
$n = trim($n);
if ($this->isValidName($n)) {
$this->name = $n;
} else {
throw new Exception("Invalid name");
}
}
public function setAge($a) {
if ($this->isValidAge($a)) {
$this->age = $a;
} else {
throw new Exception("Invalid age");
}
}
public function isValidName($n) {
$n = trim($n);
if (mb_strlen($n) == 0) {
return false;
}
return true;
}
public function isValidAge($a) {
if (!is_int($a)) {
if (!ctype_digit(trim($a))) {
return false;
}
$a = (int)$a;
}
if ($a < 0 || $a > 150) {
return false;
}
return true;
}
// other getters, setters and methods
}
E il controller sarà sostanzialmente lo stesso, solo invece di provare / catturare ci sono ora se / else:
<?php
$person = new Person();
$errors = array();
if ($person->isValidAge($age)) {
$person->setAge($age);
} catch (Exception $e) {
$errors['age'] = "Invalid age";
}
if ($person->isValidName($name)) {
$person->setName($name);
} catch (Exception $e) {
$errors['name'] = "Invalid name";
}
...
if (count($errors) == 0) {
// process
} else {
showErrorsToUser($errors);
}
Quindi cosa dovrei fare?
Sono abbastanza contento del mio metodo originale, e ai miei colleghi a cui l'ho mostrato in generale è piaciuto. Nonostante ciò, dovrei passare al metodo alternativo? O sto facendo questo terribilmente sbagliato e dovrei cercare un altro modo?
IValidateResults
.
ValidationException
e altre eccezioni