[oop] validatie
Ik wil graag duidelijkheid. Een tijdje terug zei iemand op het forum dat een User class niet zelf mag valideren of de gegevens van een User geldig zijn. Functies moeten gescheiden blijven en het controleren van persoonsgegevens is niet de taak van de User class.
Oké, prima. Stel we hebben een User class waarin ik iemands voornaam wil setten:
We hadden dus besloten dat de User class niet mag valideren of Ozzie een geldige naam is. Maar hoe moet die naam dan gevalideerd worden?
Ik ben een beetje de weg kwijt...
Gewijzigd op 15/04/2014 21:49:01 door Ozzie PHP
http://www.phphulp.nl/php/forum/topic/verificatie-veiligheid/94423/
En hela, daar worden wel 3365 tekens "verspilt" (zo lijkt het wel) aan dit onderwerp. Dat is van 10 dagen geleden, ik zou het jammer vinden als je dat al niet meer weet/niet meer kan terug vinden...
Gelukkig kun je altijd terug kijken op je recente topics en dan zie je na 10 topics ofzo dit topic staan: En hela, daar worden wel 3365 tekens "verspilt" (zo lijkt het wel) aan dit onderwerp. Dat is van 10 dagen geleden, ik zou het jammer vinden als je dat al niet meer weet/niet meer kan terug vinden...
Wie doet wat, en hoe. Moet ik met 2 classes werken? Een UserValidator en een User? Of stop ik toch alles in de User class? Waar hoort die validatie thuis?
Ik ben gewend om alle validatie in de class zelf te stoppen. Een tijdje terug zei iemand hier dat dat niet de bedoeling is. En ergens snap ik dat ook, want als ik gegevens uit de database haal en in de User class stop, worden ze telkens opnieuw gevalideerd. Maar waar voer ik die validatie dan wel uit?
Gebruik ik bijv. de setters van de User class en stop ik de User class vervolgens in een validator?
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$user = new User();
$user->setName('Ozzie');
$validator = new UserValidator($user);
$validator->validateUser();
?>
$user = new User();
$user->setName('Ozzie');
$validator = new UserValidator($user);
$validator->validateUser();
?>
Moet ik me zoiets voorstellen? Of is dat helemaal de verkeerde gedachte? Ik hoop dat iemand een duwtje in de juiste richting kan geven.
Deze vraag geldt overigens niet alleen voor een User class, maar voor alle classes waarbij data gecontroleerd moet worden. Waar hoort die controle van de data thuis? In de setters, of in een Validator class?
Gewijzigd op 15/04/2014 22:14:17 door Ozzie PHP
Code (php)
Heb je er wel is over nagedacht met een bestaand groot framework te werken? dan zou je zulke vragen direct kunnen opzoeken in de framework als je ziet hoe ze het daar doen.
Dus even heel simpel gezegd. Ik wil een User object maken met jouw voornaam daarin. Normaal gesproken deed ik dan dit:
Hoe zou dit simpele voorbeeld er dan uitzien als je gebruik maakt van een Validator?
Je doet toch ook geen vuile was in je droogtrommel?
voordat je een variabele gaat opslaan (ook in een entity zoals User) ga je zorgen dat deze 'clean' is.
Ik snap wat je bedoelt, en ik ben blij met je tekening :)
Als ik je dus goed begrijp "ontsmet" je de data vantevoren en geef je 'm dan door aan de User class.
Oké... maar wat doet de setter van de User class dan? Doet die enkel dit?
Code (php)
1
2
3
4
5
2
3
4
5
<?php
public function setFirstName($first_name) {
$this->first_name = $first_name;
}
?>
public function setFirstName($first_name) {
$this->first_name = $first_name;
}
?>
Is dat alles?
Je mag nog kleine modificaties toepassen maar nog een error teruggeven is er niet meer bij en de data is schoon.
Gewijzigd op 16/04/2014 00:31:12 door Frank Nietbelangrijk
Hoe je het precies invult ligt aan de klemtoon. Je kan, zoals frank, eerst de data valideren en dan pas in het object stoppen. Ik ben meer voor de JSR Bean methode: Het valideren van een object state. In plaats van het valideren van elke aparte waarde valideer je de "state" (weet het nederlandse woord even niet) van het object op een bepaald moment.
Als je valideert dan ga je ervanuit dat de data erin al "schoon" is zoals Frank het noemt. Je Validator kan als dit niet van toepassing is een error teruggeven.
@Wouter Toestand?
Gewijzigd op 16/04/2014 00:24:40 door Reshad F
Je accepteert dus het feit dat een (hele domme) programmeur dit zou kunnen doen:
Code (php)
1
2
3
4
5
2
3
4
5
<?php
$user->setFirstName(false);
$user->setFirstName(12);
$user->setFirstName('<script>I\'m evil!</script>');
?>
$user->setFirstName(false);
$user->setFirstName(12);
$user->setFirstName('<script>I\'m evil!</script>');
?>
Anders gezegd, je gaat er dus vanuit dat een programmeur weet wat er verwacht wordt en gaat zijn code dus niet controleren?
Nu hebben jullie het dus over validatie. Nu wil ik dat een voornaam een string is, en minstens 1 letter. Oké, de code hiervoor hoef ik niet te weten, maar ik ben wel benieuwd op welke plek je dit bepaalt, en waar je die variabele controleert.
Ik heb van Wouter al eens een voorbeeldje gezien, dus ik ben vooral benieuwd naar hoe Reshad en Frank dat aanpakken. Dus stel je hebt ergens een formulier waar iemand z'n naam invult, waar wordt dan die naam gecontroleerd? Heeft een User class bijvoorbeeld z'n eigen UserValidator class?
Gewijzigd op 16/04/2014 00:31:43 door Ozzie PHP
- emailValidator
- dutchPostcodeValidator
- integerValidator
- decimalValidator
- isAlphanumericValidator
- passwordValidator
Ze zijn allemaal extended van de Validator class en Validator interface en ze hebben allemaal de public method validate(). Ze kunnen al dan niet een constructor hebben voor initialisatie. (bijvoorbeeld voor minimale lengte van de string)
Maar als ik het dus goed begrijp vang je ergens je POST data op, en dan doe je zoiets?
Code (php)
1
2
3
4
2
3
4
<?php
$email_validator = new emailValidator();
$email_validator->validate($_POST['mail']);
?>
$email_validator = new emailValidator();
$email_validator->validate($_POST['mail']);
?>
En geeft die validate method dan een boolean terug? Of gooi je een exception vanuit de validate method?
En welke van deze validators gebruik je om iemands voor- of achternaam te controleren?
Op deze manier:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
$form = new FormHandler;
if ($form -> isMethod('post')) {
$fields = $form -> getFields(array('firstname', 'lastname', 'email'));
$validator = new FormValidator($fields);
$validator -> rule('required', array('firstname', 'lastname', 'email'));
$validator -> rule('email', 'email');
if (!$validator -> validate()) {
print_r($validator -> getErrors());
} else {
$user = new User;
$user -> setFirstname($fields['firstname']);
$user -> setLastname($fields['lastname']);
$user -> setEmail($fields['email']);
//....
}
}
?>
$form = new FormHandler;
if ($form -> isMethod('post')) {
$fields = $form -> getFields(array('firstname', 'lastname', 'email'));
$validator = new FormValidator($fields);
$validator -> rule('required', array('firstname', 'lastname', 'email'));
$validator -> rule('email', 'email');
if (!$validator -> validate()) {
print_r($validator -> getErrors());
} else {
$user = new User;
$user -> setFirstname($fields['firstname']);
$user -> setLastname($fields['lastname']);
$user -> setEmail($fields['email']);
//....
}
}
?>
Gewijzigd op 16/04/2014 02:38:21 door Jordi Kroon
Die getErrors() method, wat geeft die dan terug? Geeft die foutmeldingen voor de bezoeker terug, dus bijv.
"U heeft geen voornaam ingevuld."
Of geeft ie enkel de de namen van de velden terug die niet goed zijn ingevuld?
Oh ja, ik zie dus dat je aangeeft dat die 3 velden verplicht zijn, maar controleer je ook of de voor- en achternaam een x aantal tekens bevatten en uitsluitend letters?
Is het een uitzondering dat de validate method een invalide waarde krijgt? Nee, want dat is juist wat hij moet doen. Dus geen exceptions gebruiken.
Wil je meer weten dan alleen valide/invalide (true/false)? Ik vind van wel, bijv. de error message, wat er precies fout is en welke rule/constraint er fout is gegaan. Ik zou je eigen error system gaan maken en een ErrorCollection teruggeven. Deze is empty als de waarde valide is en bevat Error objects wanneer de waarde invalide is.
Helder.
>> Ik vind van wel, bijv. de error message, wat er precies fout is en welke rule/constraint er fout is gegaan.
Oké. En dat "wat er precies fout is" heb je het dan over foutcodes, of heb je het dan over de foutmeldingen richting de gebruiker "uw e-mailadres is niet geldig"?
Verder valt het me nog op dat Frank gebruik maakt van verschillende validator classes. Eén class om één ding te valideren, bijv. een emailValidator. In het voorbeeld hierboven van Jordi, zie ik dat hij juist slechts één validator gebruikt met verschillende rules. Heeft een van beide aanpakken de voorkeur?