kleine views / templates
Ik vraag me af hoe je in OOP hetvolgende doet:
Stel je hebt een webshop met daarop een categoriepagina waar een lijst met producten onder elkaar staat. Van ieder product wordt een korte weergave gegeven. In zo'n "korte weergave" staat bijvoorbeeld een thumbnail van het product, de titel van het product, 5 specs en de prijs.
Nu komen deze "korte weergaves" op meerdere plekken in de webshop terug. Als je bijvorbeeld de zoekfunctie gebruikt, dan krijg je ook weer een lijst met artikelen met daarin diezelfde "korte weergaves" van een product.
Nu vraag ik me hetvolgende af... je kunt natuurlijk overal waar je die korte weergaves nodig hebt de benodigde html kopiëren en in de view plakken. Nadeel is dat je dan straks op misschien wel 5 plekken dezelfde html hebt staan, en bovendien als je iets wil aanpassen dan moet je dat op 5 plekken doen. Niet ideaal dus.
Wat zou je dan wel kunnen doen? Je kunt de benodigde html in een apart bestand zetten, als ware het een template. En overal waar je dan een lijst van producten wil tonen, ga je vervolgens in een foreach lus die template includen. Echter... stel dat de lijst 50 producten bevat, dan moet je 50x dat bestand gaan includen. Dat lijkt me ook geen goed idee!
Wat is dan het alternatief vraag ik me af?
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Controller
==========
<?php
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class PageController extends Controller
{
/**
* @Route("/page/_getlatest/{max}", name="_latest_pages", defaults={"max" = 5})
public function getLastestAction($max)
{
// haal de recentste artikelen op
$articles = ...;
// maak een template met de artikelen (template 1 hieronder)
return $this->render('AcmePageBundle:Page:list.html.twig', array('articles' => $articles));
}
/**
* @Route("/", name="home")
*/
public function indexAction()
{
// ...
// maak de template (template 2 hieronder)
return $this->render('AcmePageBundle:Page:home.html.twig', array(...));
}
}
?>
Template 1: list.html.twig
==========================
{# voor elk artikel #}
{% for article in articles %}
<article>
<h1>{{ article.name }}</h1>
<span>{{ article.price }}</span>
<p>{{ article.intro }}</p>
</article>
{% endfor %}
Template 2: home.html.twig
==========================
{# ... #}
{# include de template van de andere actie #}
{% render 'AcmePageBundle:Page:getLatestAction' with {'max': 5} %}
{# ... #}
==========
<?php
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class PageController extends Controller
{
/**
* @Route("/page/_getlatest/{max}", name="_latest_pages", defaults={"max" = 5})
public function getLastestAction($max)
{
// haal de recentste artikelen op
$articles = ...;
// maak een template met de artikelen (template 1 hieronder)
return $this->render('AcmePageBundle:Page:list.html.twig', array('articles' => $articles));
}
/**
* @Route("/", name="home")
*/
public function indexAction()
{
// ...
// maak de template (template 2 hieronder)
return $this->render('AcmePageBundle:Page:home.html.twig', array(...));
}
}
?>
Template 1: list.html.twig
==========================
{# voor elk artikel #}
{% for article in articles %}
<article>
<h1>{{ article.name }}</h1>
<span>{{ article.price }}</span>
<p>{{ article.intro }}</p>
</article>
{% endfor %}
Template 2: home.html.twig
==========================
{# ... #}
{# include de template van de andere actie #}
{% render 'AcmePageBundle:Page:getLatestAction' with {'max': 5} %}
{# ... #}
Bijvoorbeeld welke template engine je gebruikt en wat de opties van je framework is.
Zelf met smarty gebruik ik het volgende;
{include file="folder/bestand.extension" arrLoop=$arrLoop}
en dan een foreach in het bestand met $arrLoop als variable.
Mocht je framework een ->forward() hebben dan zou je dat ook kunnen gebruiken.
Je forward dan nog een algemeen stuk met de parameters die je nodig hebt en laat de code van het forward je view opbouwen.
Toevoeging op 15/10/2012 09:09:09:
@Wouter J
Nadeel van de render tag is dat het een nieuw request is. (zie je profiler)
Dus die gebruik ik het liefst zo min mogelijk. Omdat het dan weer door de kernel moet.
Je zou dus wat Wouter suggereert een aparte "lijst" view met bijbehorende controller kunnen maken, waarbij de view dus telkens hetzelfde blijft, maar de inhoud die naar de view wordt gestuurd verschillend is. Maar dan zou je dus op 1 pagina meerdere views/controllers krijgen?
Stel de views op het scherm zien er als volgt uit:
Pagina 1, categoriepagina:
Deel 1: stukje tekst en een banner met een tijdelijke actie
Deel 2: de lijst met producten
Pagina 2, zoekpagina:
Deel 1: stukje tekst + vermelding van het zoekwoord
Deel 2: de lijst met producten
Deel 2 is in beide gevallen hetzelfde, maar de input (prodcuten) is verschillend.
Ik kan me voorstellen dat de categoriepagina en zoekpagina beiden een eigen controller hebben. Hoe ga je dan vanuit die 2 controllers de "lijst" controller met bijbehorende view aanspreken?
Gewijzigd op 15/10/2012 09:20:33 door Ozzie PHP
Quote:
Maar dan zou je dus op 1 pagina meerdere views/controllers krijgen?
Dat heb je sowieso wel, denk aan een sidebar met populairste artikelen. Dat is weer een andere controller/view dan de controller voor het tonen van je pagina, en het menu heeft weer een eigen controller.
Quote:
Hoe ga je dan vanuit die 2 controllers de "lijst" controller met bijbehorende view aanspreken?
Ik zou het gewoon in de view doen, zoals ik je aangaf. En ja, dat zal misschien iets langzamer zijn, maar of dat heel veel uitmaakt...
@Remco, ik wist niet dat het een extra request betekende, lijkt me ook best vreemd. Ik ga dat eens uittesten.
Gewijzigd op 15/10/2012 09:46:53 door Wouter J
In Zend framework is hier de partial helper voor. Ik zet dus net als Wouter alles in 1 view. De waarden geef ik als parameter met de view helper mee.
Voorbeeld:
Code (php)
Zo simpel is dat ;-)
Maar ga je nu telkens onderwater dat bestand includen?
Phoe dat is een goede vraag. Ik denk dat Zend dat wel een mooie oplossing voor gevonden heeft. Maar eigenlijk maakt het includen van de zo'n (extra) view ook niet uit hoor. Daar slaap ik beter van dan het feit dat ik 100 keer mijn code gekopieerd heb :-)
Maar stel dat je een productpagina met 50 producten hebt, dan lijkt het me allesbehalve slim om 50x een view te includen. En dat was dus ook de essentie van mijn vraag... hoe regel je zoiets? Een soort template met placeholders die je 1x inlaadt?
Jah, ik denk dat zoiets gebeurd. Zend Framework heeft een mooie placeholder helper die overal voor gebruikt wordt. Waarschijnlijk wordt die techniek ook ingezet bij de partial functionaliteit.
hmmmm, oké... daar moet ik dan tzt zelf eens iets op verzinnen :)
Misschien een goede reden om eens aan een frameworkje te beginnen? =D
... take 20 :D
Haha, tja dan moet je misschien even kijken hoe anders frameworks dat oplossen. Volgens mij niet heel spannend toch?
Nee, zal ook wel goedkomen... maar was gewoon benieuwd of daar een soort standaard manier voor is. Maar zoals ik steeds vaker merk... nergens lijken echt standaard manieren voor te zijn. Het is veel pionierwerk. Veel frameworks worden gebruikt, maar veel gebruikers weten niet exact wat ze gebruiken :)
Maar toch weet je niet exact hoe alles in elkaar zit, en dat kan / hoeft ook niet. Het grappige vind ik dat er vaak vragen gesteld worden (ook door mijzelf) waar dan allerlei verschillende oplossingen voor komen. En ook hoe verschillend de programmeerstijlen van de leden onderling zijn. Wel frapant!
Zeker, iedereen heeft zijn eigen programmeer style. Elk bedrijf heeft ook weer zijn eigen style / coding standards etc.
Ik ben ook bezig met m'n eigen stijl... de Ozzie Style :D
Misschien is het leuk om zo'n discussie te starten? Ik probeer meestal zo pragmatisch mogelijk te zijn.
hehe... lol... ik weet niet hoe je die discussie gaat noemen, maar eh... go ahead!!