Johnny Hogenbirk: Artikelen, code-snippets, etc.


Home

MVC in PHP: een simpele code structuur 07-02-2020


Inleiding

MVC staat voor Model View Controller. MVC staat los van de programmeertaal, maar op deze plaats beschouwen we MVC vanuit PHP.
MVC is een veel gebruikte code structuur, m.n. binnen Frameworks, bijvoorbeeld Laravel.
Echter, voor beginnende PHP ontwikkelaars is een Framework m.i. niet aan te bevelen. Je kunt beter eerst 'vanilla' PHP leren. Dus, puur PHP.
Op deze pagina wordt derhalve een toepassing van MVC behandeld met alleen de taal PHP.

Model: hierbij gaat het om de data. Data die de gebruiker heeft opgevraagd of heeft opgestuurd. Of data die de applicatie zelf nodig heeft om goed te werken. Concreet gaat het om de database, maar het kunnen ook bestanden met gegevens zijn of json berichten die van een andere applicatie worden opgevraagd.

View: hierbij gaat het om de HTML code die teruggestuurd wordt naar de browser. Inclusief de style (CSS) en Javascript.

Controller: hierbij gaat het om de code die de vraag van de browser opvraagd en de regie heeft over de model- en view code. Het is zeg maar de verkeerspolitie.

Genoeg tekst, tijd voor een plaatje:


Er zijn veel MVC plaatjes. De meest voorkomende heeft een lijntje van de browser naar Controller, naar Model, naar View en weer terug naar de browser. Echter, dit sluit in mijn opzet niet aan op hoe door de code heen wordt gelopen.


Mappenstructuur

En dan nu, tijd voor concretisering. Zo kan de mappenstructuur zijn opgezet:

En in de map view hebben we submappen voor de stylesheets, images en Javascript


Er zijn volop keuzes qua opzet van de code. PHP kan op de OO- (Object Oriented) of procedurele manier worden gebruikt. Je kunt met includes van code werken of functies aanroepen.
Omdat ik me richt op beginnende ontwikkelaars, kies ik ervoor niet met classes te werken.
Daarnaast hanteer ik zowel functies als includes. Alles zou via functies kunnen, maar het werken met includes is iets makkelijker. Zeker voor de beginnende ontwikkelaar.
In de voorbeeld code zitten slechts twee functies en voor de rest includes.

Wel een waarschuwing v.w.b. includes: de variabelen die je in de code die je include gebruikt, zijn dus globaal. Je kunt makkelijk conflicten krijgen tussen variabelen die je in de hoofdpagina gebruikt en de pagina die je include. En dat is nou net het voordeel van functies (maar ook classes): de variabelen die je daarin gebruikt zijn in principe lokaal (alleen binnen die functie). Ok, je kan 'global' bovenaan zetten, maar dat raad ik zeker af. Netjes via return waarden terug geven, evt. in een array als je meerdere hebt.


index.php

Het bestand index.php kan er zo uit zien:
Tip: geheel onderaan is alle code in één keer via een zip te downloaden
// voorbereiding *************************************************
// include de functies voor de controller en algemene settings
include("controller/functions.php");
include("controller/settings.php");

// Model aanroep *************************************************
// check of er een pagina is gepost ($ post_pag is leeg of bevat de id van dat formulier)
$post_pag = f_post_pag();
if($post_pag != ""){
  include("model/$post_pag.php");
}

// View aanroep **************************************************
// in drie trappen de output genereren, wordt toegevoegd aan $output
$output = "";

// altijd kopje van de html pagina includen
include("view/1_head.php");

// check of er een pagina is opgevraagd ($get_pag bevat startpagina of id van opgevraagde pagina
$get_pag = f_get_pag();

// altijd de html die in de body moet komen opvragen
include("view/2_$get_pag.php");

// en afsluiten met slot
include("view/3_end.php");

// en dan nu alles terugsturen naar de browser
echo $output;

Toelichting:
- Bovenaan worden functies geinclude. Hierin zitten ook de functies die in de index.php worden aangeroepen: f_post_pag en f_get_pag
- Vervolgens worden algemene settings geinclude. Hierin wordt de sessie gestart en kunnen naar believen zaken worden toegevoegd.
- Na de voorbereidingen is het tijd voor actie: er wordt gecheckt of er een pagina gepost is. Zo ja, dan wordt de model aangeroepen. Althans, de relevante PHP uit de map model. Let op: in elk formulier moet dus een hidden variabele p zitten met een value, die gelijk is aan de naam van het model PHP bestand. Zie ook hierna de view-code van het login formulier.
- In het laatste blok is het tijd voor de output, dus het aanroepen van de view-code. In dit voorbeeld van MVC maakt de view-code een variabele $output aan. De controller (index.php dus) stuurt die terug naar de browser. Het voordeel is dat, als er ergens iets mis gaat, dit afgevangen kan worden en de output compleet anders kan zijn. Daarom stuurt de view-code dus niet direct via echo de output naar de browser.
Zoals is te zien, is index.php een lekker korte overzichtelijke pagina.


Model bestanden

Er is in de voorbeeld code maar één model bestand:
login.php Hierin wordt de login afgehandeld. Normaal wordt de database geopend en gecheckt of de inlognaam en het wachtwoord goed is. Zo nee, moet het inlogformulier weer worden getoond met foutmelding. Zo ja, dan kan de pagina worden getoond die de gebruiker na het inloggen mag zien. In de voorbeeld code is dit niet verder uitgewerkt.


View bestanden

Er zijn in de voorbeeld code vier view bestanden:
1_head.php Hierin wordt $output gevuld met de HTML code. In de body is één simpel menukeuze toegevoegd: de login. Via <a href="index.php?p=login">Login</a>
Let op de 'p=login': er moet dus ook een bestand 2_login.php zijn, die het login formulier op het scherm zet.
2_start.php Hierin wordt $output gevuld met de tekst die de gebruiker ziet als hij de pagina voor de eerste keer opent.
2_login.php Zoals twee regels hierboven aangegeven, moet dit bestand er zijn. Deze zet het formulier op het scherm. Belangrijk is de hidden variabele p, die moet de value 'login' hebben.
3_end.php Een klein bestand, alleen einde body en html. Je zou hier nog script kunnen toevoegen, evt. dynamisch, afhankelijk van de pagina.


Controller bestanden

Er zijn in de voorbeeld code twee controller bestanden:
functions.php Hierin zitten nu nog maar twee functies, voor ophalen van de mogelijke &dollar_GET en &dollar_POST
settings.php In het voorbeeld zitten maar een paar, bijvoorbeeld session_start();, maar er kunnen meer worden toegevoegd. Waarschuwing; het is aantrekkelijk om hier ook variabelen aan te maken. Deze zijn dan globaal. Dit levert gevaren op. Ook ben ik geen voorstander van constanten. Als er over de code heen iets nodig is, sla de waarden dan op in sessies.


Beheer

Normaal gesproken hoef je als ontwikkelaar nooit weer aan index.php iets te veranderen
Als je een menu keuze wilt toevoegen of veranderen, pak je view/1_head.php erbij. Bedenk een heldere/relevante id, dus zoals in het voorbeeld 'login'. Die moet voor jezelf later aangeven waar het om gaat. En die id gebruik je hierna.
Als je een menu keuze hebt toegevoegd, moet je een overzicht of formulier toevoegen in view: altijd met '2_' starten, met '.php' eindigen. Ertussen in plaats je de id, die je ook in het menu hebt geplaatst.
Als je een formulier hebt toegevoegd, plaats dan de id als value in een hidden variabele (genaamd p) in het formulier. En, maak een nieuw bestand aan in de map model, waarbij de naam van dat bestand gelijk is aan de id, met natuurlijk .php erachter.


Slot

Zelf de code uitproberen? Klik dan hier

De code downloaden? Klik dan hier


Opmerkingen? Ze zijn van harte welkom: email@johnnyhogenbirk.nl!