Graag zou ik willen weten of ik in de juiste richting zit te denken.
Vanuit mijn database maak ik opties aan voor in de select, zodat gebruikers alleen daar de keus uit hebben.
Natuurlijk wil je niet dat via de inspector de waardes alsnog kunnen worden aangepast.
Ik wil dus een controle of de waarde ook overeenkomt met de lijst uit de database.
Is het dan verstandig als het formulier geladen word eerst de waardes in een array te zetten en met een foreach loop de opties aan te maken en de controle te doen met array_key_exists?
dan hoef je in je controle enkel nog te kijken of het id bestaat binnen de context
select 1
from lijst
where id = {id} and {voorwaarden}
Dan hoef je dus niet je hele lijst op te halen (incl "name"). Andersom: als je die lijst toch al ergens voor nodig hebt, dan is een array_key_exists() natuurlijk het snelst.
Dit lijkt mij onderdeel van de validatie van de formulierinformatie na submit en voor wegschrijven naar de database.
Hoe je dit formulier opbouwt -dit is onderdeel van de weergave van het formulier, wat een andere actie is dan het verwerken van een formulier- staat hier in principe los van.
Wel zou je een validatieregel voor zo'n invoerveld kunnen hebben, of een formulier-object met hierin formulierveld-objecten kunnen hebben, waar je zowel bij weergave alsook validatie/verwerking op eenzelfde wijze informatie uit hengelt.
Ik denk dat je de verschillende onderdelen het beste in afzondering kunt behandelen:
Enerzijds de "flow" van het formuliergebruik: je hebt een aparte "actie" voor het weergeven van een formulier, eventueel met terugkoppeling van een eerdere submit + foutmeldingen en eerdere ingevulde waarden, en een aparte "actie" voor het verwerken van het formulier. Na validatie ga je dan terug naar het formulier op het moment dat er foutmeldingen zijn of schrijf je data permanent weg naar de database en verhuis je vervolgens weer terug naar een "succes"- of overzichtspagina.
Anderzijds heb je de formulierdata die je op een bepaalde manier inzet in beide acties voor initialsatie, validatie en weergave van het formulier. Deze formulierdata kan bijvoorbeeld in een soort van datastructuur zitten (configuratie-array) of ondergebracht zijn in een of meerdere klassen, of zelfs een combinatie van beide.
Als je veelvuldig gebruik maakt van formulieren loont het zelfs de moeite om een soort van formuliersysteem te bouwen die de formulieropbouw in HTML en de validatie grotendeels automatiseert. De bouwstenen (de formulierelementen) hoef je dan slechts één keer te schrijven.
Met een formuliersysteem zou je ook composiet- of volledige custom elementen kunnen bouwen.
Het "enige" wat je in wezen "schrijft" aan formulierprogrammering zijn dan de formuliervelden, en de programmering van de acties, zoals hier staat geïllustreerd. Nu staat hier "enige" tussen aanhalingstekens, want het is nog steeds redelijk wat code. Maar al die code bij elkaar (~163 regels) omvat de volledige afhandeling van een redelijk groot/complex formulier, exclusief de klassen voor het formulier en de -elementen, maar die verdien je vrij snel terug als je veel formulieren gebruikt.
Wanneer het formulier verstuurd is (vaak in de POST request method) dan is het altijd heel erg belangrijk om de data die ingestuurd is te valideren en wel SERVER-SIDE! Dus niet (alleen) met javascript maar met PHP. Valideren doe je op alle mogelijke manieren zodat de data in je database niet vervuild raakt.
Er is overigens nog een goede manier om te voorkomen dat je database inconsistent wordt namelijk door BEPERKINGEN (in het Engels constraints) toe te voegen op de vreemde sleutels.
Dat kan ook, maar dat werkt uiteraard alleen als je alles helemaal hebt uitgenormaliseerd (of je moet ENUMs gebruiken ofzo, maar dat is niet echt optimaal). De structuur van toegestane formulierwaarden kan dus zowel in de database alsook in code zijn vastgelegd. En op grond daarvan kun je toetsen of de aangeboden waarden geldig zijn. Deze zul je op zijn minst altijd aan de serverzijde moeten controleren zoals @Frank aangeeft.
@Thomas: Maar hoe controleer je dan in je "formuliersysteem" of een waarde (key) is toegestaan? In het voorbeeld dat je geeft hebben je "select" fields altijd een vaste "options" array. Maar ik kan me voorstellen dat die lijstjes meestal uit een DB komen. Haal je dan bij de initialisatie altijd de hele lijst uit de DB op*, om vervolgens dus met een array_key_exists vast te stellen dat de key bestaat en dus is toegestaan. Of zit er nog een slimmigheidje in waarbij je dus bij de controle niet weer de hele lijst op hoeft te halen, maar puur kijkt of die ene key bestaat (binnen de overige voorwaarden)?
* daarnaast kan ik me voorstellen dat er soms (asynchrone) "actions" zijn waarbij de inhoud van deze lijst er helemaal niet toe doet, en het dus helemaal niet nodig is om de lijst op te halen.
Voordat het formulier wordt gevalideerd in de verwerkstap worden de velden eerst geïnitialiseerd met waarden uit $_POST. Voor een select-veld houdt dit in dat wordt gecontroleerd of er een waarde is ingesteld, en zoja, of deze geldig is (met isset, ik sta geen null-waarden toe dus dat zou altijd goed moeten gaan), en zoja dan wordt de waarde toegekend. Indien er een niet-toegestane waarde is geselecteerd wordt de default-waarde gepakt. Maar voor hetzelfde geld zou het formulier(veld) een foutmelding kunnen retourneren, wat misschien beter is.
Aan de andere kant zou je ook van mening kunnen zijn dat op het moment dat iemand een formulier aan het manipuleren is, dat er andere dingen aan de hand zijn die wellicht ook op een andere plaats opgelost dienen te worden :p.
De opties kunnen zowel uit de database komen als je dat wilt, of gewoon in de definitie van het formulier-object zelf worden opgenomen.
In het validatie-gedeelte wat volgt op de initialisatie worden eventuele extra "regels" geïnspecteerd. Op het moment dat het select-veld een regel "verplicht" heeft en een ongeldige waarde was geselecteerd (waarbij dus de default waarde wordt gepakt die meestal als waarde "geen waarde" heeft) wordt op die wijze sowieso voorkomen dat de waarde wordt doorgelaten. Maar als je meer manipulatie verwacht zou je strengere controles kunnen doen. Volgens mij zat er in dit systeem ook iets dat je "default" regels kon definiëren die altijd worden gecontroleerd, daarbij maakt het dus niet uit of deze expliciet staan ingesteld of niet. Daar zou je eventueel dit soort extra controles kunnen opnemen, of in het initialisatie-gedeelte de boel al af kunnen blazen indien het lijkt alsof er sprake is van manipulatie.
Elk formulierveld heeft ook zijn eigen klasse, dus je zou deze ook kunnen extenden voor een paranoia-plus uitvoering.
Per page-access, zij het het tonen of verwerken van een formulier, wordt alles maar 1x ingeladen.
Ik ben het eens dat functionaliteit als deze er alles / zoveel mogelijk aan moet doen om ervoor te zorgen dat als data goed wordt bevonden en wordt doorgelaten, dat deze 100% moet kloppen en dus ook moet precies moet passen in de vakjes waar je de data vervolgens in wilt stoppen. Dat is immers het hele doel van de validatie.
?
Onbekende gebruiker
08-09-2020 09:05
gewijzigd op 08-09-2020 09:08
Wat ik sterk aanraad is om de database eigenaar te maken van de data, in plaats van PHP.
Want de database is daar speciaal voor gemaakt, en PHP niet.
Wat je op database niveau moet doen is een CONSTRAINT aanmaken van het type FOREIGN KEY (FK) op de kolom(men) waarin je de keuze opslaat van de gebruiker. De database zorgt er dan voor dat ze zullen wijzen naar de meestal PRIMARY KEY van de andere tabel waar de FK naar verwijst.
Geeft de database een fout bij een poging verkeerde invoer op te slaan? Dan weet je dat de data van de gebruiker niet klopt, en kan je dat aangeven bij de gebruiker.
Deze functionaliteit is standaard ingebouwd bij de meeste databases, behalve bij MySQL. Daar hangt het af van de storage engine, en als je InnoDB gebruikt, kan het wel.
Het waarborgen van de referentiële integriteit is natuurlijk altijd verstandig zodat op die manier gezorgd wordt dat de data IN de database consistent is en blijft. De validatie van formulierdata zorgt er voor (of maakt het op zijn minst meer aannemelijk) dat data alleen aan de database aangeboden wordt als deze ook echt "past".
Als je op voorhand al weet dat iets niet past dan is het niet nodig om hiervoor een query te laten mislukken om dat nog eens te bevestigen. Ik ben het met je eens dat de database middelen mag hebben om de data consistent te houden en verkeerde data mag weigeren, maar ook functionaliteit buiten de database kan hierbij helpen, dit is niet het exclusieve domein van de database zelf.
Een validatielaag in formulierfunctionaliteit heeft ook als extra doel om aan de gebruiker op een vriendelijke en begrijpelijke manier terug te koppelen wat deze zou moeten wijzigen aan de invoer om ervoor te zorgen dat deze alsnog weggeschreven kan worden naar de database. Dat werkt doorgaans wat beter dan "foreign key constraint X failed" oid.
Daarnaast: De tabel die voor deze <select> wordt gebruikt heeft misschien wel tig entries, maar de gebruiker mag er maar een paar selecteren (op basis van rechten, of van een andere keuze). Je kunt dus niet altijd alles afschuiven op de DB.
?
Onbekende gebruiker
08-09-2020 23:00
Wat zou de use case zijn die de overhead rechtvaardigt?
Het valideren van de data in PHP heeft een prijs, want dan moet je de gegevens laten controleren in de DB (wat die zelf al voor je doet middels een INSERT of UPDATE statement) om daarna alsnog binnen een transactie een INSERT of UPDATE te doen waarbij de DB het een tweede keer controleert. Daarbij is het niet nodig, omdat je als het goed is heldere foutcodes terug krijgt waardoor je alsnog de gebruiker normale terugkoppeling kunt geven.