Ik ben bezig met het ontwikkelen van een eigen MVC. Via htaccess stuur ik alles door naar mijn index. Mijn index bepaalt vervolgens welke controller moet worden aangeroepen. Stel mijn url is /nieuws/nieuwsitem. In dit geval moet de NewsitemController worden aangeroepen om het nieuwsitem te tonen. Stel mijn URL is /over-ons. Dan moet de ContentController worden aangeroepen en een contentpagina getoond worden. Maar nu mijn vraag.. Hoe weet index welke controller moet worden aangeroepen?


// index.php
$route = explode("/", $_SERVER["REQUEST_URI"]);
Frank, het een sluit het ander niet uit.

Een view kán een controller aanroepen. Die doen dan plaatselijk in hun beperkte context hun eigen ding. Niets mis mee.

Voorbeeld: de view is een widget die een beoordeling in sterren toont. De view roept daarvoor een controller aan die de beoordeling "ergens" uit een model haalt. Maakt niet uit waar: het kan de eigen database zijn, maar ook een cURL-request naar KiyOh of iets dergelijks.

De complicatie is dat je dergelijke dingen moet samensmeden tot één fraaie webpagina. En dan komt het HMVC-model van pas, met meerdere hiërarchisch gestapelde MVC-componenten. Díé componenten moet je koppelen via hun controllers, niet via hun models.
Ward van der Put op 23/11/2014 16:45:31

Ja, prima oplossing.

Kun je daar een voorbeeldje van geven?
Misschien zoiets?


$controller = new NewsitemController();

$model = new NewsitemModel();
$controller->setModel($model);
Oké dus in een HMVC is het wel mogelijk om vanuit de view een andere controller in beweging te brengen. Dat je de controllers met elkaar koppelt dat klinkt wel logisch. Maar nu:

controller A wordt aangeroepen en die roept zijn eigen VIEW aan. Ik neem aan dat de VIEW niet direct output genereert maar eerder een response object vult en dit object dan weer teruggeeft aan de controller?
Daarna roept controller A controller B aan? Deze roept ook weer zijn VIEW aan en deze geeft ook een response object terug? Dan zitten we dus met twee response objecten??
>> Dan zitten we dus met twee response objecten??

Yep, goed gezien, vooral dat zit in de weg.
Daarvoor hebben we dan een registry met één request en één response.

Daarom hebben we ook de neiging om het request/response-systeem te modelleren als een besturingssysteem.

1. Er komt één request binnen. Helder: dít is ons HTTP-verzoek, hier moeten we een antwoord op vinden.
Van dat request is er maar één, dus we hebben een uniek instance die we centraal kunnen registreren.

2. Van die request moeten onderdelen worden gedelegeerd aan specifieke controllers.
Hier komt het op creativiteit aan. Alleen de webdeveloper weet wat het systeem met specifieke requests moet doen.

3. Er komt één response uit.
We kunnen HTTP-output genereren of een HTTP-statuscode, maar veel alternatieven biedt HTTP ons niet.
De request wordt beantwoord met een response óf een code voor een ongeldig request.

Roy B op 23/11/2014 17:51:54

[quote="Ward van der Put op 23/11/2014 16:45:31"]
Ja, prima oplossing.

Kun je daar een voorbeeldje van geven?
Misschien zoiets?


$controller = new NewsitemController();

$model = new NewsitemModel();
$controller->setModel($model);

[/quote]

Bedankt voor je heldere uitleg Ward. (Ben nog wel even aan piekeren hoe de developer dan zorgt dat dat ene response object dan bij de tweede en derde layer op de juiste manier uitgebreid wordt).

@Roy: In het systeem dat Ward beschrijft gaat het inderdaad om die manier. Ward geeft dat ook duidelijk aan:
<?php
$model = new NewsitemModel();
$controller = new NewsitemController($model);
?>

Het enige verschil tussen jouw voorbeeld en die van Ward is dat Ward het Model aan de constructor meegeeft en jij daar een aparte method voor aanroept.

In andere MVC's wordt het model in de controller bepaald. Je krijgt dan zoiets:

dispatcher:
<?php

$route = new Route('NewsItem', 'index');

$controllerName = $route->getController(); // geeft NewsItemController
$methodName = $route->getAction(); // geeft indexAction

$controller = new $controllerName();
$controller->$methodName($route->getVars());

?>

Controller:
<?php

class NewsItemController
{
public indexAction($newsitem_id)
{
$model = new NewsModel();
$newsitem = $model->getNewsItem($newsitem_id);

$data = array(
'newsitem' => $newsitem
);

return $this->loadView('newsItem', $data);
}
}
?>
Het Model in de Controller meegeven is doorgaans de beste optie dan?
Het is een keuze denk ik. Ik zou het doen maar dat is omdat ik het op die manier gewend ben. Ward mag zijn methode nog eens onderbouwen ;-).

Het probleem waar ik een beetje tegen aanloop is welke method moet ik nu aanroepen in het Model van Ward.
Je krijgt namelijk het hele object geïnjecteerd in je Controller maar in dat object kunnen twintig verschillende methods zitten...
Laten we ze dan eens vergelijken:


<?php
// Variant A
$user_model = new UserModel();
$user_controller = new UserController($user_model);

// Variant B
$user = new User();
?>


Bij variant A moet je overal steeds in de weer met twee objecten: model en controller. Bij variant B heb je maar één API: je spreekt de controller aan en die zoekt verder zelf maar uit of er een model nodig is, hoe dat model er uitziet en hoe met het model wordt gecommuniceerd.

Bij variant A kun je makkelijker verschillende combinaties van models en controllers maken, wat met name bij frameworks handig kan zijn. Je zou in het voorbeeld UserModel door AdminModel kunnen vervangen. Bij variant B is die logica verborgen, wat zowel een voordeel als een nadeel kan zijn.

Variant B leent zich ook wat beter voor het inzetten en veranderen van design patterns: een blanco new User() kun je op verschillende manieren bouwen, terwijl er bij een new User(\UserModel $model) al veel meer is voorgeschreven.

Het is dus inderdaad een keuze.
Heren, interessante discussie.

Ik zal ook even een spreekwoordelijke duit in het spreekwoordelijke zakje doen.

Wanneer geven we waardes of een object mee aan de constructor? Op het moment dat een class kan werken met dynamische data. Zo kan een database class via de constructor verschillende "verbindingsobjecten" binnenkrijgen om zodoende met verschillende databases contact te kunnen maken, en een e-mailer class kan bijvoorbeeld verschillende e-mailadressen ontvangen om naar verschillende personen te kunnen mailen.

Praten we over een model, dan ligt de situatie echter wat anders. Mijns insziens is een model niets meer dan een verlengstuk van een controller. De code die in het model staat, zouden we ook rechtstreeks in de controller kunnen plaatsen, maar dat doen we niet omdat we alles netjes gescheiden willen houden. En ... mochten we ooit een ander model gaan gebruiken, dan hoeven we niet alle code in de class zelf aan te passen.

Het klinkt natuurlijk leuk om het model via de constructor mee te geven, want dan hoeven we de class nooit aan te passen als we een ander model willen gebruiken. Maar ... is het logisch? Ik vind van niet. Een model is namelijk afgestemd op de controller. De controller en het model zijn onlosmakelijk met elkaar verbonden. Ze horen bij elkaar. Ze zijn als Bert en Ernie, of als Bassie en Adriaan ... maar net waar je zelf de voorkeur aan geeft. Het is dan ook vreemd om van buitenaf te gaan bepalen welk model er nodig is. Dat hoort niet. Als "buitenstaander" praat je enkel met de controller, en die controller bepaalt zelf welk model er nodig is. Het is de controller die dit bepaalt, en niet de "buitenstaander".

Op het moment dat je een AdminModel wilt gebruiken in een UserController zoals Ward hierboven aangeeft, zou het raar zijn om als "buitenstaander" zelf een model te kiezen en dat mee te geven aan de constructor van de UserController. Wie zegt dat de UserController wel overweg kan met dat door de "buitenstaander" gekozen model? Logischer zou het dan zijn om in de constructor van de UserController een parameter in te bouwen:

<?php

public function __construct($is_admin = false) {
if ($is_admin) {
$this->model = AdminModel;
} else {
$this->model = UserModel;
}
}

?>
Op deze manier houd je de beslissingsbevoegdheid bij de controller zelf.

Bottomline: als "buitenstaander" praat je enkel met de controller, en beslis je niet welk model de controller moet gebruiken. Deze bevoegdheid ligt bij de controller zelf.

Amen ... :)

Reageren