Door
Marlies Maalderink
op 06-01-2017 14:51
gewijzigd op 06-01-2017 15:01
3.207 views
Ik ben bezig met een wordpress plugin voor een simpel contactformulier. Aangezien ik graag wat meer ervaring op wil doen met OOP probeer ik deze helemaal in classes in te delen.
Voor het afhandelen van het formulier moet de input worden opgehaald, gevalideerd en daarna moet een mail gestuurd worden. Het leek mij logisch om aparte classes to maken voor de validatie en de afhandeling, maar voor beide heb ik de post variabelen nodig.
Zodoende heb ik een parent class gemaakt die alle post variabelen ophaalt en dan twee child classes voor de validatie en de afhandeling, die dus beide toegang hebben tot alle variabelen.
Is dat een logische methode? Of had ik beter alles in 1 class kunnen zetten? Of het misschien nog op een heel andere manier moeten doen.
Dit voert misschien wat ver voor een "simpel" contactformulier?
Indien je dit enkel wilt opbouwen uit herbruikbare componenten (en wanneer dit enige meerwaarde heeft, bijvoorbeeld omdat je dit vaak doet, zodat deze handeling zich na een eenmalige investering snel terugverdient) zou je eens kunnen kijken naar wat er nu eigenlijk gebeurt:
- het tonen van een formulier
- het verwerken van een formulier
- eventueel met terugkoppeling tijdens invullen (terugkoppeling over fouten) of na verzenden (bedankpagina)
Je bent voornamelijk met formulieren bezig, dus als je herbruikbare code hebt waarmee je formulieren snel kunt opbouwen en formulierinvoer kunt valideren dan kun je daar veel tijdswinst mee pakken. Maar dit wordt pas interessant zodra je dit soort functionaliteit (formulieren + afhandeling) vaker bouwt.
Mogelijke indeling voor classes:
Form
FormField (abstract)
concrete FormField typen (text, checkbox, select, of zelfs custom, samengestelde formulierelementen)
FormFields hang je op aan het formulier. Wanneer je het formulier valideert doorloop je de velden en roep je validatieregels van de specifieke velden aan.
Door alle bouwstenen voor te bakken kun je formulieren snel in elkaar zetten. Daarna zou je eens na kunnen gaan denken over een gebruiksvriendelijke interface zodat je formulieren (letterlijk) in elkaar kunt klikken (en dus zelfs geen code meer hoeft te schrijven, of een minimale hoeveelheid). En dit is volgens mij precies wat sommige plugins (al) doen.
Ik besef nu dat mijn formulier classes echt compleet niet reusable zijn en ik dus eigenlijk de hele middag bezig ben geweest en nu een contactformuliertje heb (wat ik al had maar dan niet OOP) en wat ik niet opnieuw kan gebruiken. Nou ja, van je fouten leer je zeggen ze.
Wauw Ward, die is mooi! Dank je wel voor deze uitleg, en bovendien kende ik die magic method nog niet, is ook wel handig om die te gebruiken!!
Ik ga er mee aan de slag, als ik er niet uit kom mag ik dan hier weer komen vragen? :)
[size=xsmall]Toevoeging op 07/01/2017 14:23:36:[/size]
Als aanvulling op hierboven, hiermee kan alleen geen textarea gemaakt worden omdat die anders in elkaar zit.
Als ik een class Textarea extends AbstractInput maak waar ook weer de method __toString in gebruikt wordt met variabele $str, en ik maak die zo dat hij geschikt is voor een textarea, gebruikt hij deze dan als ik een instance van Textarea aanmaak, terwijl hij de method uit de abstract class blijft gebruiken bij alle andere classes?
En (uit nieuwsgierigheid) waarom heb je hier gekozen voor een abstract class en niet een parent class? Wat ik ervan begrijp is dat een abstract class altijd minstens één abstract method moet bevatten, wat hier niet het geval is.
Hm. In mijn opzet heb je een abstracte class "Formfield", wat eigenlijk van alles kan zijn. Elke class afgeleid van een FormField vormt een logische eenheid in het formulier. Zo'n eenheid kan best opgebouwd zijn uit meerdere elementaire formulier elementen (selects, inputs en buttons) die samen een nieuw formulier element vormt (met functionaliteit die verder voert dan de delen waar ze uit opgebouwd zijn), bijvoorbeeld zoiets:
Dat veld toevoegen aan het formulier verloopt via iets als:
Thomas, ik had de class zoals jij voorstelde inmiddels al deels uitgewerkt (alleen de formfields zelf, nog geen validatie erbij) en dat werkt ook prachtig.
Ik merk iig dat mijn vraag 'wat is de beste manier om classes in te delen' misschien niet zo makkelijk is als ik dacht, omdat het van veel dingen af hangt en dan nog er meerdere manier zijn.
We kunnen in ieder geval stellen dat mijn aanvankelijke class helemaal fout was, en dat ik bij deze twee betere manier heb om mee aan het werk te kunnen!
Voor de grap dan hier nog even mijn originele 2 classes. Behalve dus dat ze niet reusable zijn en helemaal verkeerd ingedeeld, heb ik hier nog meer dingen gedaan die niet goed zijn/niet zouden moeten of iets dergelijks? (voor de duidelijkheid helemaal onderaan nog de partial met de html
<?php
class Topsecreet_Contactformulier_Verwerk {
private $naam;
private $email;
private $telefoon;
private $bericht;
private $verzonden;
public function __construct() {
$this->naam = $_POST['naam'];
$this->email = $_POST['email'];
$this->telefoon = $_POST['telefoon'];
$this->bericht = $_POST['bericht'];
$this->verzonden = $_GET['verzonden'];
}
//de method om de variabele waar de naam in is gepost op te vragen
public function get_naam() {
return $this->naam;
}
//de method om de variabele waar het emailadres in is gepost op te vragen
public function get_email() {
return $this->email;
}
//de method om de variabele waar het telefoonnummer in is gepost op te vragen
public function get_telefoon() {
return $this->telefoon;
}
//de method om de variabele waar het bericht in is gepost op te vragen
public function get_bericht() {
return $this->bericht;
}
//de method om te contoleren of het formulier verzonden is of niet
public function get_verzonden() {
return $this->verzonden;
}
}
class Topsecreet_Contactformulier_Validate extends Topsecreet_Contactformulier_Verwerk {
//hier slaan we de foutmeldingen in op
private $errors;
public function __construct() {
parent::__construct();
$this->errors = $errors;
}
//valideer invoerveld naam en sanitize uitvoer
public function validate_naam() {
if( $this->get_naam() == "" ){
return $this->errors = 1;
} else {
return $this->naam = filter_var( $this->get_naam(), FILTER_SANITIZE_STRING );
}
}
//valideer invoerveld email en sanitize uitvoer
public function validate_email() {
if( $this->get_email() == "" || filter_var( $this->get_email(), FILTER_VALIDATE_EMAIL ) === false ) {
return $this->errors = 1;
} else {
return $this->email = filter_var( $this->get_email(), FILTER_SANITIZE_EMAIL );
}
}
//sanitize telefoon uitvoer
public function sanitize_telefoon() {
return $this->telefoon = filter_var( $this->get_telefoon(), FILTER_SANITIZE_STRING );
}
//valideer invoerveld bericht en sanitze uitvoer
public function validate_bericht() {
if( $this->get_bericht() == "" ){
return $this->errors = 1;
} else {
return $this->bericht = filter_var($this->get_bericht(), FILTER_SANITIZE_STRING);
}
}
//controleer of er fouten zijn en zo ja, geef de 1 terug. Dit is nodig om te bepalen of het formulier getoond moet worden of
//dat we verder gaan met het aanmaken en verzenden van de email
public function check_errors() {
$this->validate_bericht();
$this->validate_email();
$this->validate_naam();
return $this->errors;
}
}
?>
[size=xsmall]Toevoeging op 07/01/2017 18:05:00:[/size]
oh, ik zie net de de html niet klopt, omdat ik dit uit 2 bestanden heb samengevoegd voordat ik het hier plakte. Als er fouten zijn moet het formulier natuurlijk ook getoond worden! ;)