Template en Controller
In mijn ander topic heb ik het gehad over een registry, er werd mij verteld geen registry te gaan gebruiken.
Moet ik vanuit mijn Controllers elke keer alle object opnieuw maken? Er zijn bijvoorbeeld een aantal objecten die ik in alle controllers nodig heb, denk aan het Template object.
Verder kom ik er niet helemaal uit hoe ik dan de data naar de template stuur e.t.c.
Ik zie dat er een aantal mensen een array aanmaken, maar hoe gaat het dan met de objecten?
Een voorbeeld hoe ik het nu doe:
ArticleController
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Template
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
class Template
{
private $_vars;
function __construct()
{
$this->_vars = array();
}
public function setVars( $name, $value )
{
$this->_vars[$name] = $value;
}
function show( $name )
{
$path = dirname(__FILE__) . '/../../../test.112pers.nl/public_html/view/' . $name . '.view.tpl';
if ( file_exists( $path ) == false )
{
throw new Exception( 'Template not found in '. $path );
return false;
}
// Load variables
if( $this->_vars )
{
foreach ( $this->_vars as $key => $value )
{
$$key = $value;
}
}
include ( $path );
}
}
?>
class Template
{
private $_vars;
function __construct()
{
$this->_vars = array();
}
public function setVars( $name, $value )
{
$this->_vars[$name] = $value;
}
function show( $name )
{
$path = dirname(__FILE__) . '/../../../test.112pers.nl/public_html/view/' . $name . '.view.tpl';
if ( file_exists( $path ) == false )
{
throw new Exception( 'Template not found in '. $path );
return false;
}
// Load variables
if( $this->_vars )
{
foreach ( $this->_vars as $key => $value )
{
$$key = $value;
}
}
include ( $path );
}
}
?>
Tom Swinkels op 20/09/2013 00:21:52:
Er zijn bijvoorbeeld een aantal objecten die ik in alle controllers nodig heb, denk aan het Template object.
Waarom kies je hiervoor? Elke controller een eigen template geven lijkt mij namelijk een tamelijk inflexibele keuze. En elke controller hetzelfde template meegeven is nog vele malen erger.
Kijk bijvoorbeeld eens naar het onderstaande MVC-pattern. Jij bent nu in de weer met relatie 3, maar je vergeet de relaties 1 en 2. Je hebt nu een ArticleController waar niets inkomt uit 1 (input van buiten) en niets inkomt uit 2 (het model). De controller heeft daardoor nu niets via 3 door te geven aan de view; dáárom zit je nu met deze vraag.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+------------------------------------+
| |
| +------------+ +-------+ |
--(1)->| Controller |<-(2)->| Model | |
| +------------+ +-------+ |
| | |
| (3) |
| | |
| ? |
| +------+ |
| | View | |
| +------+ |
| | |
+--------(4)-------------------------+
|
?
| |
| +------------+ +-------+ |
--(1)->| Controller |<-(2)->| Model | |
| +------------+ +-------+ |
| | |
| (3) |
| | |
| ? |
| +------+ |
| | View | |
| +------+ |
| | |
+--------(4)-------------------------+
|
?
Gewijzigd op 20/09/2013 08:56:03 door Ward van der Put
Even iets anders is die include in je template class niet een beetje dirty manier van programmeren?
Ik snap de bedoeling nog niet helemaal.
De Controller krijgt een Model terug en het Model wordt naar de view gestuurd?
Ik dacht dat ik voor simpele tekst teksten dit direct in de controller kon doen, maar dat is natuurlijk tegen het principe in.
Uiteindelijk heb ik toch nog een Model object dat ik uiteindelijk wil ophalen in mijn view?
Hoe denken jullie verder over het registry, zijn jullie ook van mening om het niet te gebruiken, en waarom?
@Reshad: Dit komt af van een voorbeeld waar ik heb gekeken, dit kan later ook anders meer eerst het ander probleem.
Gewijzigd op 20/09/2013 12:59:05 door Tom Swinkels
1. De controller ontvangt van de client (via 1) een HTTP-verzoek om een artikel.
2. De controller controleert de geldigheid van het verzoek. De ArticleController zal veelal de unieke ID van een artikel nodig hebben om iets te kunnen doen.
3. De ArticleController vraagt het gevraagde artikel (via 2) op uit het (data)model. Dat kan een databasetabel met alle artikelen zijn.
4. De ArticleController ontvangt het artikel (terug via 2) van het model en verwerkt de data.
5. De ArticleController geeft de verwerkte data (via 3) door aan de view.
6. De view genereert daarmee output voor de client (voor 4). Dat zal meestal HTML zijn.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
+------------------------------------+
| |
| +------------+ +-------+ |
--(1)->| Controller |<-(2)->| Model | |
| +------------+ +-------+ |
| | |
| (3) |
| | |
| ? |
| +------+ |
| | View | |
| +------+ |
| | |
+--------(4)-------------------------+
|
?
| |
| +------------+ +-------+ |
--(1)->| Controller |<-(2)->| Model | |
| +------------+ +-------+ |
| | |
| (3) |
| | |
| ? |
| +------+ |
| | View | |
| +------+ |
| | |
+--------(4)-------------------------+
|
?
Bij HMVC bouw je een webpagina op met meerdere views/objecten. Je hebt nu een artikel in HTML, maar de webpagina bevat bijvoorbeeld ook nog reacties op dat artikel, een navigatiebalk, een zoekvak, een paar banners, een footer, enzovoort. Een deel daarvan heeft een eigen controller, vooral wanneer een object niet statisch maar dynamisch is, bijvoorbeeld het zoeksysteem en het bannermanagement.
Op elke lijn in het bovenstaande MVC-model kun je nog een uitbreiding toevoegen. Bij 1 voor de input van de client bijvoorbeeld een front controller (of dispatcher) die de juiste controller aanroept. Een verzoek om een artikel moet bijvoorbeeld naar je ArticleController, maar een zoekopdracht naar een SearchController. De controller laten we via 2 meestal niet direct met een database communiceren maar indirect via een data mapper.
Gewijzigd op 20/09/2013 14:33:23 door Ward van der Put
Via de FrontController vraag ik aan de Router de juiste Route die vervolgens de juiste Controller en Action aan de FrontController terug geeft. In de FrontController roep ik dus de nieuwe Controller aan.
ArticleController: In ArticleController haal ik de data op via mapper, in dit geval gaat het zoals ik het noem een Note. Via de NoteMapper krijg ik dus het Note object terug. Verder heb ik een StateMapper en UserMapper nodig om de ids te koppelen.
Vervolgens moet ik dat Note object + alle andere objecten die ik nodig heb meegeven aan het ArticleModel.
Is bovenstaande zoals het zou moeten?
Hoe krijg ik verder, het Model en eventueel andere object denk aan Request object in mijn view? Moet ik die objecten ook allemaal aanmaken en meegeven in het Model?
Verder zeg je dat een deel van views een eigen controller kan hebben? Maar ik mag toch maar één controller gebruiken?
Alleen hoe roep ik de meerdere controllers dan aan?
Klopt mijn gedachten over het model wel?
(Bijvoorbeeld Zen Cart werkt zo, met allerlei sideboxes die elk andere content tonen: navigatiemenu's, best verkochte producten, nieuwe aanwinsten, de gevoerde merken, een advertentie, enzovoort. Elke sidebox bestaat uit verschillende PHP-bestanden. De configuratie in de database regelt welke sideboxes zijn ingeschakeld en waar ze op de webpagina staan.)
Een deel van de aanroepen is een "nested dispatch", zo ontstaat die H van hiërarchie in het HMVC-pattern. Het plaatje toont bijvoorbeeld bij 1 een event en daaronder bij 2 de reviews van die event. Dat is vergelijkbaar met een artikel/blogpost en de reacties van lezers daarop. Hier kan de dispatcher bijvoorbeeld een true/false voor succes van de controller van 1 doorgeven aan de controller van 2.
In sommige gevallen kun je rechtstreeks een view laden zonder een controller. Denk bijvoorbeeld aan een footer met een copyrightvermelding. Of aan een div'je met de bedrijfs- en contactgegevens. Dit kunnen views (V) zijn die niet dynamisch veranderen via variabelen in een controller (C) of die niet afhankelijk zijn van data uit het datamodel (M).
Het probleem is dat ik hier nu tegen aanloop en nu niet verder kom met mijn applicatie.
En op de manier zoals jij het beschrijft roept mijn router dan geen controller meer aan? Of de router roept een controller aan, en in die controller worden de andere controllers dan weer verwerkt?
Ik loop nu een beetje vast waar ik moet gaan beginnen en wat ik nu wel en niet goed doe.
voorbeeldcode bij het plaatje zegt eigenlijk al veel:
Je zit hier dat de $kernel fungeert als dispatcher, zeg maar een telefoniste die verzoeken doorsluist naar de juiste MVC-module. De dispatch doet dat min of meer zo:
dispatch ( $module , $opdracht , $data )
De Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
# 2. Event Reviews (nested dispatch)
# dispatch is a raw, direct internal request. No modifications are made.
echo $kernel->dispatch('Reviews', 'listForType', array('event', $event->id));
# 3. Map (nested view partial)
# Returns new view template object; echo converts it to string and renders it
echo $view->partial('_map', array('venue' => $event->venue));
# 4. Event Recommentations (nested dispatchRequest)
# dispatchRequest re-uses current Request object just like direct web request
# Will resolve this as 'indexAction($request)'
echo $kernel->dispatchRequest('Events_Recommended', 'index');
# 5. Food Nearby (nested dispatchRequest w/params)
# Will resolve this as 'indexAction($request, $lat, $lon)'
echo $kernel->dispatchRequest('Restaurants_Nearby', 'index', array($event->lat, $event->lon));
?>
# 2. Event Reviews (nested dispatch)
# dispatch is a raw, direct internal request. No modifications are made.
echo $kernel->dispatch('Reviews', 'listForType', array('event', $event->id));
# 3. Map (nested view partial)
# Returns new view template object; echo converts it to string and renders it
echo $view->partial('_map', array('venue' => $event->venue));
# 4. Event Recommentations (nested dispatchRequest)
# dispatchRequest re-uses current Request object just like direct web request
# Will resolve this as 'indexAction($request)'
echo $kernel->dispatchRequest('Events_Recommended', 'index');
# 5. Food Nearby (nested dispatchRequest w/params)
# Will resolve this as 'indexAction($request, $lat, $lon)'
echo $kernel->dispatchRequest('Restaurants_Nearby', 'index', array($event->lat, $event->lon));
?>
Je zit hier dat de $kernel fungeert als dispatcher, zeg maar een telefoniste die verzoeken doorsluist naar de juiste MVC-module. De dispatch doet dat min of meer zo:
dispatch ( $module , $opdracht , $data )
Ik had dit gedeelte even neergelegd omdat ik er niet helemaal meer uitkwam.
Toch wil ik het weer gaan oppakken zodat ik verder kan met mijn website :)
Laten we eventjes beginnen met de stappen:
/artikel/
- ArticleController
- HeaderController
- NavigationController
- FooterView
Dit heb ik nodig wanneer ik /artikel/ opvraag.
Nu is de vraag waar handig ik dit af? Bijvoorbeeld het verhaal van de dispatch?
Als je alle URL's herschrijft naar www·example·com/index.php, dan regelt dit PHP-bestand de routing. Dit wordt dan de dispatcher die bepaalt wat er bij een bepaalde URL moet worden gedaan door andere controllers.
Wat ik nu doe zal ik even proberen uit te leggen.
Alles wordt door gestuurd naar index.php.
Index.php
Code (php)
1
2
3
4
2
3
4
<?
$frontController = new FrontController();
$frontController->execute( $request );
?>
$frontController = new FrontController();
$frontController->execute( $request );
?>
De FrontController haalt vervolgens de Router op die geeft de juiste Route terug.
En vervolgens aan de hand van die Route de juiste Controller en Action.
Waar zou ik nu de afhandeling van de dispatcher moeten doen, en wat doet die dan precies?
Tom Swinkels op 13/12/2013 17:54:09:
De dispatch heb je dan al: aan de hand van de gevonden route de juiste controller een bepaalde actie laten uitvoeren.De FrontController haalt vervolgens de Router op die geeft de juiste Route terug.
En vervolgens aan de hand van die Route de juiste Controller en Action.
Waar zou ik nu de afhandeling van de dispatcher moeten doen, en wat doet die dan precies?
En vervolgens aan de hand van die Route de juiste Controller en Action.
Waar zou ik nu de afhandeling van de dispatcher moeten doen, en wat doet die dan precies?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?
public function execute( $request )
{
$router = $this->getRouter();
$route = $router->getRoute( $request->server( 'REDIRECT_URL' ) );
if( $route )
{
$data = $route->getData();
$controllerName = ucfirst( $data['controller'] ) . 'Controller';
if( class_exists( $controllerName ) )
{
$controller = new $controllerName( $route );
if( in_array( $data['action'], get_class_methods( $controllerName ) ) )
{
$controller->$data['action']();
return true;
}
}
}
}
?>
public function execute( $request )
{
$router = $this->getRouter();
$route = $router->getRoute( $request->server( 'REDIRECT_URL' ) );
if( $route )
{
$data = $route->getData();
$controllerName = ucfirst( $data['controller'] ) . 'Controller';
if( class_exists( $controllerName ) )
{
$controller = new $controllerName( $route );
if( in_array( $data['action'], get_class_methods( $controllerName ) ) )
{
$controller->$data['action']();
return true;
}
}
}
}
?>
Maar nu kom ik terug bij het voorbeeld dat je gaf.
"Bij HMVC bouw je een webpagina op met meerdere views/objecten. Je hebt nu een artikel in HTML, maar de webpagina bevat bijvoorbeeld ook nog reacties op dat artikel, een navigatiebalk, een zoekvak, een paar banners, een footer, enzovoort. Een deel daarvan heeft een eigen controller, vooral wanneer een object niet statisch maar dynamisch is, bijvoorbeeld het zoeksysteem en het bannermanagement."
Wat ik nu moet doen is dus in de juiste controller, in dit voorbeeld ArticleController de juiste models en views bij elkaar zoeken die ik nodig heb om de webpagina op de bouwen. (artikelen zelf, header, navigatie en footer)
Of denk ik nu al verkeerd?
Dat is prima, alleen heb je waarschijnlijk verschillende soorten pagina's. Je moet op dit punt dus beslissen wat de ArticleController eigenlijk doet: een artikel tonen of ruimer een webpagina?
Zou je er dan voor kiezen om een tussen controller te maken? ArticlePageController die dan de juiste controllers en views oproept?