2. Een ontwikkelingsaanpak voor web/PHP volgens de MVC-architectuur
Hier stellen we een aanpak voor voor de ontwikkeling van web-/PHP-applicaties die voldoen aan de MVC-architectuur. Deze aanpak is louter bedoeld om ideeën aan te reiken. De lezer kan deze aanpassen aan zijn eigen voorkeuren en behoeften.
- We beginnen met het definiëren van alle weergaven van de applicatie. Dit zijn de webpagina’s die aan de gebruiker worden getoond. We plaatsen ons in het perspectief van de gebruiker om de weergaven te ontwerpen. Er worden drie soorten weergaven onderscheiden:
- het invoerformulier, dat bedoeld is om informatie van de gebruiker te verkrijgen. Dit formulier beschikt doorgaans over een knop om de ingevoerde informatie naar de server te verzenden.
- de responspagina, die uitsluitend dient om informatie aan de gebruiker te verstrekken. Deze bevat vaak een of meer links waarmee de gebruiker de applicatie kan voortzetten op een andere pagina.
- de gemengde pagina: de controller heeft de client een pagina gestuurd met informatie die hij zelf heeft gegenereerd. Diezelfde pagina zal door de client worden gebruikt om nieuwe informatie van de gebruiker aan de controller door te geven.
- Elke weergave zal resulteren in een pagina met de naam PHP. Voor elk van deze pagina’s:
- bepalen we hoe de pagina eruit komt te zien
- bepalen we welke delen dynamisch zijn:
- de informatie voor de gebruiker die door de controller als parameters aan de weergave PHP moet worden doorgegeven. Een eenvoudige oplossing is de volgende:
- de controller plaatst in een woordenboek $dReponse de informatie die hij aan een weergave V wil verstrekken
- de controller laat de weergave V weergeven. Als deze overeenkomt met het bronbestand V.php, wordt deze weergave eenvoudig verkregen door de instructie include V.php.
- De voorgaande include is een code-include in de controller. Het door de controller gevulde woordenboek $dReponse is rechtstreeks toegankelijk via de code van V.php.
- De invoergegevens die ter verwerking naar het hoofdprogramma moeten worden verzonden. Deze moeten deel uitmaken van een formulier HTML (tag <form>).
- de informatie voor de gebruiker die door de controller als parameters aan de weergave PHP moet worden doorgegeven. Een eenvoudige oplossing is de volgende:
- De in- en uitgangen van elke weergave kunnen als volgt worden weergegeven
![]() |
- de invoer bestaat uit de gegevens die de controller aan de pagina PHP moet leveren
- de uitgangen zijn de gegevens die de pagina PHP aan de controller van de applicatie moet leveren. Ze maken deel uit van een formulier HTML en de controller haalt ze op via een bewerking van het type $_GET["param"] (methode GET) of $_POST["param"] (methode POST).
- Vaak is de uiteindelijke pagina die naar de klant wordt verzonden geen weergave, maar een samenstelling van weergaven. De pagina die naar een gebruiker wordt verzonden, kan bijvoorbeeld de volgende vorm hebben:
![]() |
Zone 1 kan een titelbalk zijn, zone 2 een menubalk en zone 3 een inhoudsgebied. In PHP kan deze samenstelling worden verkregen met de volgende code HTML/PHP:
<table>
<tr>
<td><?php include zone1.php ?></td>
</tr>
<tr>
<td><?php include zone2.php ?></td>
<td><?php include zone3.php ?></td>
</tr>
</table>
Je kunt deze code dynamisch maken door het volgende te schrijven:
<table>
<tr>
<td><?php include $dReponse['urlZone1'] ?></td>
</tr>
<tr>
<td><?php include $dReponse['urlZone2'] ?></td>
<td><?php include $dReponse['urlZone3'] ?></td>
</tr>
</table>
Deze samenstelling van weergaven kan het enige formaat zijn van het antwoord aan de gebruiker. In dat geval moet elk antwoord aan de klant de drie URL vastleggen die in de drie zones moeten worden geladen voordat de antwoordpagina wordt weergegeven. Dit voorbeeld kan worden veralgemeend door te veronderstellen dat er meerdere mogelijke sjablonen voor de antwoordpagina zijn. Het antwoord aan de klant moet dus:
- het te gebruiken sjabloon vastleggen
- de elementen vastleggen die daarin moeten worden opgenomen
- de weergave van het sjabloon aanvragen
- We schrijven de code PHP/HTML voor elk antwoordmodel. De code is doorgaans eenvoudig. Die van het bovenstaande voorbeeld zou kunnen zijn:
<?php
// initialisaties voor tests zonder controller
...
?>
<html>
<head>
<title><?php echo $dReponse['titre'] ?></title>
<link type="text/css" href="<?php echo $dReponse['style']['url'] ?>" rel="stylesheet" />
</head>
<body>
<table>
<tr>
<td><?php include $dReponse['urlZone1'] ?></td>
</tr>
<tr>
<td><?php include $dReponse['urlZone2'] ?></td>
<td><?php include $dReponse['urlZone3'] ?></td>
</tr>
</table>
<body>
</html>
Waar mogelijk wordt een stylesheet gebruikt om de "look" van het antwoord te kunnen aanpassen zonder de code PHP/HTML te hoeven wijzigen.
- We schrijven de code PHP/HTML voor elke elementaire weergave. Deze heeft meestal de volgende vorm:
<?php
// eventueel enkele initialisaties, met name tijdens de debugfase
...
?>
<balise>
...
// hier zullen we proberen de PHP-code te minimaliseren
</balise>
Merk op dat een elementaire weergave in een model wordt geïntegreerd. De code HTML wordt in de code van het model opgenomen. Meestal bevat deze code al de tags <html>, <head> en <body>. Het komt dan ook zelden voor dat deze tags in een elementaire weergave voorkomen.
- De verschillende responsmodellen en elementaire weergaven kunnen worden getest
- Elk responsmodel wordt getest. Als een model modele1.php heet, roepen we met een browser URL op: http://localhost/chemin/modele1.php Het model verwacht waarden van de controller. Hier wordt het model rechtstreeks aangeroepen en niet via de controller. Het model ontvangt de verwachte parameters niet. Om de tests toch mogelijk te maken, initialiseren we zelf, met behulp van constanten, de verwachte parameters op de pagina PHP van het model.
- Elk model wordt getest, evenals alle elementaire weergaven. Dit is ook het moment om de eerste elementen van de gebruikte stylesheets uit te werken.
- Vervolgens schrijven we de applicatielogica van de applicatie:
- De controller of het hoofdprogramma beheert doorgaans meerdere acties. In de verzoeken die het ontvangt, moet de uit te voeren actie zijn gedefinieerd. Dit kan gebeuren door middel van een parameter in het verzoek, die we hier ‘actie’ zullen noemen:
- als het verzoek afkomstig is van een formulier (<form>), kan deze parameter een verborgen parameter van het formulier zijn:
<form ... action="/C/main.php" method="post" ...>
<input type="hidden" name="action" value="uneAction">
...
</form>
- (vervolg)
- als het verzoek afkomstig is van een link, kan deze als volgt worden ingesteld:
De controller kan beginnen met het uitlezen van de waarde van deze parameter en vervolgens de verwerking van het verzoek delegeren aan een module die verantwoordelijk is voor het verwerken van dit type verzoek. We zijn hier uitgegaan van het scenario waarin alles werd aangestuurd door één enkel script met de naam main.php. Als de applicatie acties action1, action2, ..., actiex moet verwerken, kan binnen de controller voor elke actie een functie worden aangemaakt. Als er veel acties zijn, kan dit leiden tot een ‘dinosaurus’-controller. Men kan ook scripts aanmaken, zoals action1.php, action2.php, …,actionx.php die elk een van de acties verwerken. De controller die actie actionx moet verwerken, hoeft alleen maar de code van het bijbehorende script te laden met een instructie zoals include "actionx.php". Het voordeel van deze methode is dat men buiten de code van de controller werkt. Elk lid van het ontwikkelingsteam kan zo relatief onafhankelijk werken aan het script voor de verwerking van een actie actionx. Het opnemen van de scriptcode actionx.php in de code van de controller op het moment van uitvoering heeft bovendien het voordeel dat de code die in het geheugen wordt geladen, lichter wordt. Alleen de verwerkingscode van de huidige actie wordt geladen. Door deze opname van code kunnen variabelen van de controller in conflict komen met die van het actiescript. We zullen zien dat we ervoor kunnen zorgen dat de variabelen van de controller worden beperkt tot enkele welomschreven variabelen, die vervolgens niet in de scripts mogen worden gebruikt.
- We zullen er systematisch naar streven om de bedrijfslogica of de code voor toegang tot persistente gegevens in afzonderlijke modules te isoleren. De controller is een soort teamleider die verzoeken van zijn klanten (webklanten) ontvangt en deze laat uitvoeren door de meest geschikte personen (de bedrijfsmodules). Bij het schrijven van de controller wordt de interface van de te schrijven bedrijfsmodules bepaald. Dit geldt als deze bedrijfsmodules nog moeten worden gebouwd. Als ze al bestaan, past de controller zich aan aan de interface van deze bestaande modules.
- We schrijven het raamwerk van de bedrijfsmodules die de controller nodig heeft. Als de controller bijvoorbeeld gebruikmaakt van een module getCodes die een tabel met tekenreeksen retourneert, volstaat het in eerste instantie om het volgende te schrijven:
- Vervolgens kunnen we overgaan tot het testen van de controller en de bijbehorende PHP-scripts:
- de controller, de actiescripts, de modellen, de weergaven en de benodigde bronnen voor de applicatie (afbeeldingen,...) worden in de map DC geplaatst, die gekoppeld is aan de context C van de applicatie.
- Zodra dit is gebeurd, wordt de applicatie getest en worden de eerste fouten verholpen. Als main.php de controller is en C de context van de applicatie, wordt de URL-http://localhost/C/main.php opgevraagd. Aan het einde van deze fase is de architectuur van de applicatie operationeel. Deze testfase kan lastig zijn, aangezien er weinig debuggingtools beschikbaar zijn als men geen geavanceerde – en doorgaans betaalde – ontwikkelomgevingen gebruikt. We kunnen gebruikmaken van echo "message"-instructies die in de naar de client verzonden HTML-stream schrijven en dus verschijnen op de webpagina die door de browser wordt weergegeven.
- Ten slotte schrijven we de businessklassen die de controller nodig heeft. Hier gaat het doorgaans om de klassieke ontwikkeling van een PHP-klasse, die meestal onafhankelijk is van welke webapplicatie dan ook. Deze wordt eerst buiten deze omgeving getest, bijvoorbeeld met een console-applicatie. Zodra een businessklasse is geschreven, wordt deze geïntegreerd in de implementatiearchitectuur van de webapplicatie en wordt getest of de integratie correct verloopt. Dit proces wordt voor elke businessklasse herhaald.

