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:

<?php

echo '<div id="product">' . $product->getName() . '</div>';

?>
Volgens die persoon moet je in de controller de benodigde variabelen doorsturen/beschikbaar maken in de view. Dus zoiets:

<?php
// ProductController

public function show() {
// product ophalen
$this->toView('product_name', $product->getName());
}

// view

echo '<div id="product">' . $product_name . '</div>';

?>
Zijn jullie het er mee eens dat je in de view geen objecten maar uitsluitend variabelen mag gebruiken?
ik reageer op vraag twee:

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

dat doe je met de php functie extract: http://nl1.php.net/extract

Toevoeging op 12/05/2014 22:32:24:

wat betreft vraag één verander load() gewoon in

- 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);
}

return $products;
}
}
?>
2)

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...
@Frank:

>> 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.
Ozzie PHP op 13/05/2014 00:11:03

... 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.
>> Ik weet dat symfony of twig en codeigniter het zo doen.
>> Nee voor mij geen enkel probleem en nogmaals de grote frameworks doen het zo.

Oké, even om alle misverstanden uit de weg te ruimen... met "doen het zo" bedoel je het gebruik van objecten in views, correct?

<?php
echo '<div id="product">' . $product->getName() . '</div>';
?>
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:

<!DOCTYPE html>
<html>
  <head>
    <title><?php echo $product->getName(); ?></title>
  </head>
  <body>
    <h1><?php echo $product->getName(); ?></h1>
  </body>
</html>

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:


<!DOCTYPE html>
<html>
  <head>
    <title><?php echo $title; ?></title>
  </head>
  <body>
    <h1><?php echo $title; ?></h1>
  </body>
</html>


Ozzie PHP op 13/05/2014 00:11:03

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).
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. :)

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.
Wouter J op 13/05/2014 09:17:47

[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?

Reageren