Door
Ozzie PHP
op 12-05-2014 21:52
gewijzigd op 12-05-2014 21:52
4.607 views
Hoi allemaal,
Ik heb 2 OOP vragen, die enigszins met elkaar hebben te maken.
1) Loading
Als we een object hebben, bijvoorbeeld een product, dan kunnen we dat product laden met een mapper. Bijvoorbeeld:
<?php
$product_mapper = new ProductMapper();
$product = $product_mapper->load(12);
?>
Maar wat als we in plaats van één product bijvoorbeeld de 10 laatste toegevoegde producten willen tonen? Hoe werkt dat dan? Gebruiken we daar diezelfde mapper voor? Ik neem aan van niet, want we gaan niet ieder product stuk voor stuk uit de databse ophalen. Maar hoe dan wel?
2) Object in view
Stel ik heb een product ingeladen, hoe krijg ik dan de productinformatie in de view. Ik heb me ooit eens laten vertellen dat je in een view geen objecten mag gebruiken, omdat een view geen "intelligentie" mag bevatten. Dit zou volgens diegene dus niet mogen:
jouw eerste code mag wél. Waar je volgens mij mee in de war bent is het volgende:
je controller roept de view aan:
<?php
// ProductController
public function show() {
// product ophalen
$data = array(
'product' => $product
);
$this->toView($data);
}
?>
Je controller geeft alle data door in een array. nu wil je in de view de indexen uit de array omzetten in variabelen.
$data['product'] naar $product zeg maar
- findAll() // geeft een array van objecten terug
- findOneBy(..) // geeft één object terug (of NULL indien niet gevonden)
- findBy(..) // geeft een array van objecten terug
Ik zie de overeenkomstige factor niet echt, maar goed... :P
Maar wat als we in plaats van één product bijvoorbeeld de 10 laatste toegevoegde producten willen tonen? Hoe werkt dat dan? Gebruiken we daar diezelfde mapper voor? Ik neem aan van niet, want we gaan niet ieder product stuk voor stuk uit de databse ophalen. Maar hoe dan wel?
Sinds wanneer kan een mapper alleen stuk voor stuk dingen uit de database halen?
<?php
class ProductMapper
{
public function getLatestProducts($limit = 10)
{
$products = [];
foreach ($this->db->getResult('SELECT name, price, description FROM products ORDER BY release_date LIMIT '.$limit) as $product) {
$products[] = $this->populate($product);
}
Views mogen best logica bevatten. De view mag van mij zelfs de content-type bepalen.
Templates wil je het liefst zo min mogelijk logica (en absoluut geen 'business logic') geven. Simpele if/else, while loops en dergelijken zijn prima. (google een naar 'logic less templates')
Houd controllers slank (het liefst niet meer dan 20-30 regels per method, inclusief whitespace en commentaar) en dom.
Models is waar de bulk van je logica zich bevind. Services zoals die mappers, de classes waar naartoe gemapt wordt, utility classes etc.
Views bevatten logica om de door de Model laag aangeleverde ruwe data - denk een ISO8601 geformatteerde datum, of een unix timestamp - op te juiste manier te weergeven - in het Nederlandse dd-mm-yyyy formaat. Daar komt logica aan te pas die niet in het model, maar ook niet in de template hoort.
Of HTML escapen: de Model laag hoort niet te weten hoe de data gebruikt gaat worden, de view wel. Al begint het nu een beetje onduidelijk te worden of je dit in de View of de template wilt hebben...
>> jouw eerste code mag wél. Waar je volgens mij mee in de war bent is het volgende:
Het probleem is dat als ik een object in een view plaats, ik in principe ook dit zou kunnen doen:
<?php
echo '<div id="product">' . $product->getName() . '</div>';
$product->setProperty('foo', 'bar');
?>
Waarom ik dit in een view zou willen doen? Geen idee, maar het zou kunnen en daarom hoorde je geen objecten in een view te zetten aldus die persoon. In een view mag je alleen variabelen zetten. Dus dan zou je dus alle objecten weer moeten omzetten naar een array ofzo?
<?php
// ProductController
public function showProducts() {
// producten ophalen
$products_for_view = array();
foreach ($products as $product) {
$products_for_view[]['name'] = $product->getName();
$products_for_view[]['price'] = $product->getPrice();
// enz.
}
}
?>
Dat lijkt me eerlijk gezegd een beetje dubbelop allemaal...
@Wouter:
>> Sinds wanneer kan een mapper alleen stuk voor stuk dingen uit de database halen?
Ah oke.. ik snap wat je bedoelt. Maar gaat de mapper dan niet de taak van het Model (als in MVC) overnemen?
@Dos:
>> Al begint het nu een beetje onduidelijk te worden of je dit in de View of de template wilt hebben...
Kun jij eens uitleggen hoe jij het verschil ziet tussen een view en een template? Ik ken eigenlijk (vanuit de 1e versie van Zend Framework) alleen het begrip view. Een view was dan een stuk HTML code waarin je de variabelen gebruikte die door de controller werden aangeleverd. Eén view was bijvoorbeeld de complete HTML voor een productpagina.
... en daarom hoorde je geen objecten in een view te zetten aldus die persoon.
Ik weet dat symfony of twig en codeigniter het zo doen. Het alternatief is alles in een array zetten. Beetje omslachtig niet? Bovendien geef je alleen de entities mee naar de view. Niet de mappers. en dan nog de waarde van een array kun je ook veranderen in de view. Nee voor mij geen enkel probleem en nogmaals de grote frameworks doen het zo.
Die laatste oplossing, met directe toegang tot een object in $product->getName(), schaalt niet fijn. Stel dat je de naam van een product wilt gebruiken als een titel en een grote kop in een productpagina. Dan zou je verkort zoiets krijgen:
Daarmee ligt het ontwerp van de productpagina erg vast — en misschien wel té vast. Bovendien kunnen we de template alleen gebruiken voor een productpagina, niet voor andere soorten pagina's.
Die beperkingen hebben we niet als we er een controller tussen zetten die bepaalt dat $title = $product->getName(). Dan kunnen we $title namelijk ook op iets anders instellen. En dan kunnen we de template ook hergebruiken voor iets anders dan alleen een productpagina:
Kun jij eens uitleggen hoe jij het verschil ziet tussen een view en een template? Ik ken eigenlijk (vanuit de 1e versie van Zend Framework) alleen het begrip view. Een view was dan een stuk HTML code waarin je de variabelen gebruikte die door de controller werden aangeleverd. Eén view was bijvoorbeeld de complete HTML voor een productpagina.
Je kunt min of meer zeggen dat een template een vorm van een view is. Meestal gebruik ik één template voor één webpagina (eventueel aangevuld met universele templates voor de masthead, de sitenavigatie en een footer). Daarbinnen kunnen paginaonderdelen echter worden opgebouwd met verschillende views. Een voorbeeld zijn advertenties: wil je drie advertenties weergegeven, dan hergebruik je drie keer hetzelfde onderdeel (drie keer één view) op drie posities in één template (een andere view).
En dan kunnen we de template ook hergebruiken voor iets anders dan alleen een productpagina:
Waarom zou je dat willen? Een productpagina en een blogpagina hebben beide een compleet andere lay-out, die krijgen ook mooi hun eigen view. :)
Ozzie
Maar gaat de mapper dan niet de taak van het Model (als in MVC) overnemen?
De DataMapper is de Model. Dit werkt weer precies zoals het template <> view verhaal. "Model" is de naam van een laag in je applicatie, "DataMapper" is een invulling van die laag. "View" is de naam van een laag in je applicatie, "Template" is een invulling van die laag.
[quote="Ward"]En dan kunnen we de template ook hergebruiken voor iets anders dan alleen een productpagina:
Waarom zou je dat willen? Een productpagina en een blogpagina hebben beide een compleet andere lay-out, die krijgen ook mooi hun eigen view. :)[/quote]
Als jij het okay vindt dat www.example.com een compleet andere lay-out heeft dan www.example.com/blog, dan is dat jouw persoonlijke ontwerpbeslissing. Over smaak valt niet te twisten :-)
>> Over smaak valt niet te twisten :-)
Lay-out gaat niet over smaak, dat is design :) Kijk alleen naar deze site. Deze forum topic pagina is toch qua lay-out anders dan een tutorial pagina of de nieuws pagina?