Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Sivun layout funktioissa, kyllä vai ei?

Sivun loppuun

creepy [20.02.2013 14:15:53]

#

Toisessa keskustelussa tuli esiin tälläinen esimerkki ja siihen kommentti että ei näin. miksi?

func.php

function layout_yla(){
echo "<html>jnejne _ navi yms";
}
function layout_ala(){
echo "footer </html>";
}

ja käyttö sitten
index.php

require 'func.php'

layout_yla();

echo"sisältöö";

layout_ala();

Miksi noin ei voisi php sivuja rakentaa, tai miten te teette layoutin ettei joka sivulle tarvitse sitä html alustusta / navia yms laittaa = ylläpito vaikeaa

Lebe80 [20.02.2013 14:25:38]

#

Miksi ei saisi.


Itse tosin mieluummin pitäisin aina kaikki avatut tägit samassa tiedostossa suljettujen kanssa.


eli:

<html>
<head><?php echo head() ?></head>
<body>
<?php

echo $content;

?>
</body>
</html>

creepy [20.02.2013 14:33:35]

#

Joo, tuota voisi kehittää näin

Toisessa keskustelussa tuli esiin tälläinen esimerkki ja siihen kommentti että ei näin. miksi?

func.php

function layout($content){
echo "<html>{$content}</html>";
}

ja käyttö sitten
index.php

require 'func.php'

$content="sisältöö";

layout($content);

Macro [20.02.2013 15:22:10]

#

Kyllähän noin saa tehdä, mutta ehkä järkevämpi ja helpompi tapa olisi tehdä jotenkin näin.

*** func.php

function getHeader($title) {
?>
<html>
	<head>
		<title><?php echo $title ?></title>
	</head>
	<body>
<?php
}

function getFooter() {
?>
	</body>
</html>
<?php
}
*** käyttöesimerkki

<?php
include("func.php");

getHeader("Otsikko");
?>

...

<?php
getFooter();
?>

HTML:n kirjoittaminen on selvästi helpompaa erilliseen tiedostoon kuin PHP:n joukkoon.

creepy [20.02.2013 15:28:48]

#

Tuonne ei varmaan pysty sitten dynaamista sisältöä laittamaan ?

esim titleä tai sitte aiemman esimerkin tyyliin koko sisältöä $content

ja eikö tuossa olisi sama sitten jättää functiotkin pois ja suoraan index.php nuo file_get_contentsit?

t0ll0 [20.02.2013 15:42:30]

#

Macro - toisesta ketjusta kirjoitti:

Toivottavasti HTML-koodisi ei muuten ole oikeasti tuolla funktioiden sisällä..

Kysymys ei tainnut olla siitä etteikö niin saisi tehdä vaan että on parempiakin tapoja? Enivei, kuulostaa omaan korvaan jotenkin takaperoiselta hakea "header" ja "footer" sisällön ympärille kun voisi hakea sisällöt headerin ja footerin väliin.

edit, noniin sitähän se macro meinasi..

Macro [20.02.2013 15:42:55]

#

Muuttelin vähän esimerkkiäni..

Mietippä, onko tuossa layout-funktiossasi jotain ideaa. Eikö niitä html-tageja voi tulosaa muuten?

t0ll0 kirjoitti:

Enivei, kuulostaa omaan korvaan jotenkin takaperoiselta hakea "header" ja "footer" sisällön ympärille kun voisi hakea sisällöt headerin ja footerin väliin.

Niin, voisihan sen niinkin tehdä, mutta jos halutaan jokainen sivu staattiseksi (etusivu.php, yhteystiedot.php) niin tämä taitaa olla aika helppo tapa.

Metabolix [20.02.2013 18:15:57]

#

Lebe80 kirjoitti:

Itse tosin mieluummin pitäisin aina kaikki avatut tägit samassa tiedostossa suljettujen kanssa.

Tämä ei ole mitenkään ristiriidassa sen kanssa, että käyttäisi kahta funktiota: voihan ne funktiot kirjoittaa peräkkäin samaan tiedostoon.

Minusta erilliset header- ja footer-funktiot ovat selvempi ratkaisu, koska silloin sisältöosan voi tulostaa ilman kikkailuja. Jos tehtäisiin vain yksi funktio, sisältö pitäisi jotenkin pyydystää muuttujaan. Minulla ei myöskään ole Lebe80:n ennakkoluuloja tagien sijoittelusta, kunhan yläosan tulostava funktio loppuu johonkin avaavaan tagiin (esim. <div id="sisalto">).

HC-olio-ohjelmoinnissa voi kyllä helposti toteuttaa myös ratkaisun, jossa yläosa ja alaosa ovat samassa funktiossa ja välissä tulostetaan sisältö. Silloin yksittäistä sivua kuvaava luokka vain korvaa sisältöosan tulostavan funktion omallaan.

Macro kirjoitti:

Jos halutaan jokainen sivu staattiseksi (etusivu.php, yhteystiedot.php)

Erillisen tiedoston tekeminen on ihan eri asia kuin staattisuus. PHP-sivu on lähtökohtaisesti aina dynaaminen. Staattinen sivu tarkoittaa sivua, joka ei muutu.

The Alchemist [20.02.2013 19:12:28]

#

Metabolix kirjoitti:

Lebe80 kirjoitti:

Itse tosin mieluummin pitäisin aina kaikki avatut tägit samassa tiedostossa suljettujen kanssa.

Tämä ei ole mitenkään ristiriidassa sen kanssa, että käyttäisi kahta funktiota: voihan ne funktiot kirjoittaa peräkkäin samaan tiedostoon.

Höpö höpö. Jos jokin elementti tulostetaan auki funktiossa X, niin se pitää sulkea samassa funktiossa (== samassa kontekstissa), tai koodi on paskaa. Niin yksinkertaista, niin helppoa. Aivan naurettava vaatimus, että kahden funktion pitäisi sijaita "lähietäisyydellä toisistaan", jotta niiden toiminnan voisi ymmärtää.

Itse olen sitä mieltä, ettei funktioiden toteutuksissa saa olla lainkaan html:ää. Ainoa poikkeus ovat yksinkertaiset ns. view helperit, jotka rendaavat esimerkiksi yksittäisen elementin kuten input-tagin tai labelin. Kaikki isompi merkkaus pitää laittaa erilliseen template-tiedostoon, joka käytännössä on staattista html:ää, johon upotetaan muutaman muuttujan arvot. Yksi template per yksi "komponentti", paitsi jos kyse on suuremmasta kokonaisuudesta, joka sisältää kopioitavissa olevia osasia.

Monissa template-moottoreissa templatet eivät edes ole php-tiedostoja, joten ne eivät voi sisältää php-koodia. Tällöin template-moottori toteuttaa joitakin yksinkertaisia kielirakenteita kuten silmukat. Itse pidän enemmän php:n sallivista templateista, koska osaan olla käyttämättä niitä väärin.

Kaiken takana on yksinkertainen mantra: toteutus on pidettävä erillään näyttömuodosta. Modulaarisuus, moduulien testattavuus, koodin uudelleenkäytettävyys ja sitä rataa.

Suosittelen lämpimästi tutustumaan esimerkiksi Zend Framework 2:een tai Symfony 2:een, jotka on tehty mielestäni erittäin hyvin teknisessä mielessä.

Metabolix [20.02.2013 20:02:38]

#

The Alchemist kirjoitti:

Kaiken takana on yksinkertainen mantra: toteutus on pidettävä erillään näyttömuodosta.

Mielestäni tämä koko keskustelu koskee pelkästään näyttömuodon toteuttamista eikä millään tavalla liity näyttömuodon ja logiikan väliseen suhteeseen.

The Alchemist kirjoitti:

Itse olen sitä mieltä, ettei funktioiden toteutuksissa saa olla lainkaan html:ää. – – Kaikki isompi merkkaus pitää laittaa erilliseen template-tiedostoon,

On aivan pöljää kikkailla include-riveillä tai kehittää jokin erillinen systeemi templateja varten, kun aivan hyvin voi käyttää samoja keinoja kuin muussakin koodissa: laitetaan komponentit funktioihin ja luokkiin ja käytetään autoloadia. Funktiot ovat käytännöllinen tapa toteuttaa komponentteja. Onko sinulla yhtään järkevää perustelua, miksi näin ei pitäisi tehdä eli miksi include("template/x.php") tai $templateEngine->outputTemplate("x") olisi parempi kuin yksinkertainen funktiokutsu template\x()?

The Alchemist kirjoitti:

Suosittelen lämpimästi tutustumaan esimerkiksi Zend Framework 2:een tai Symfony 2:een, jotka on tehty mielestäni erittäin hyvin teknisessä mielessä.

Onko tämä mielestäsi sitten hyvä tapa ohjelmoida? Näyttää aika väkinäiseltä PHP-purismilta ja tarpeettomalta sotkulta.

The Alchemist [20.02.2013 21:15:34]

#

Metabolix kirjoitti:

On aivan pöljää kikkailla include-riveillä tai kehittää jokin erillinen systeemi templateja varten, kun aivan hyvin voi käyttää samoja keinoja kuin muussakin koodissa: laitetaan komponentit funktioihin ja luokkiin ja käytetään autoloadia. Funktiot ovat käytännöllinen tapa toteuttaa komponentteja. Onko sinulla yhtään järkevää perustelua, miksi näin ei pitäisi tehdä eli miksi include("template/x.php") tai $templateEngine->outputTemplate("x") olisi parempi kuin yksinkertainen funktiokutsu template\x()?

Ilmeisesti vertaat nyt näitä kahta tapausta:

1. print_header(), print_footer(), print_my_element()
2. $engine->render('layout/header'), $engine->render('layout/footer')

Minusta vastaus on aivan selvä: tehdään asiat oikein. Käyttöliittymän rendaavassa koodissa ei saa tehdä mitään muuta. Se siis tekee vain yhden asian: renderöi käyttöliittymän. Miksi joudut välillä kutsumaan funktiota print_header() ja välillä print_footer(), kun haluat aina tehdä vain saman asian: renderöidä käyttöliittymän (osan siitä). Kuulostaa minusta aika oudolta, en tiedä teistä.

Ongelma taas liittyy tuohon jälleen kerran toistamaani mantraan: näyttömuoto on pidettävä erillään toteutuksesta. Jos teet funktion print_header(), niin olet juuri sitonut käyttöliittymän tekniseen toteutukseen. Jos haluat myöhemmin tulostaa jollekin toiselle sivulle erilaisen headerin, niin joudut tekemään uuden funktion. Mutta mikä sen nimeksi, kun nimi "print_header" on jo varattu? Ja miksi tarvitset kaksi funktiota saman asian tekemiseen?

Kyllä koodarin pitäisi alkaa tässä vaiheessa ihmetellä, miksi hän tekee saman työn useilla eri tavoilla. "Miksi minä kirjoitan aina uuden funktion, kun oikeasti haluan vain muuttaa yhden parametrin arvoa?" (Vinkki: kyseinen parametri on käyttöliittymän komponentin tunniste.)

Vertaa tähän: teet itsellesi sovellusta kotitehtävien laskemiseen. Huomaat, että on monia ynnäyksiä, joissa toinen luvuista on 3. Kirjoitat siis funktion kolme_plus_x($luku2). Seuraavaksi huomaat, että monissa ynnäyksissä toinen luvuista on 5. Kirjoitat siis funktion viisi_plus_x($luku2). Alkaisitko jossain välissä ihmetellä, miksi kirjoitat uuden tällaisen funktion aina, kun huomaat jonkin tietyn luvun toistuvan monta kertaa laskuissa? Tulisitko kenties siihen tulokseen, että yksi ainoa funktio, "summaa_luvut($luku1, $luku2)", riittäisi?

Metabolix kirjoitti:

Onko tämä mielestäsi sitten hyvä tapa ohjelmoida? Näyttää aika väkinäiseltä PHP-purismilta ja tarpeettomalta sotkulta.

Ehkä tuo Zend-esimerkin koodi näyttää vähän sotkulta, koska se ei ole kovinkaan puristinen. Siinä määritellään css-luokkia ja muita html-elementtien attribuutteja sekä kenttien labeleita lomakeluokassa, vaikka ne eivät ole osa lomakkeen tietorakennetta vaan juurikin näyttömuotoa. (Nämä asiat voi halutessaan tehdä Zendissä myös ideologisesti oikein view-skriptin puolella.)

Esimerkin viimeinen osa - lomakkeen renderöinti - on tehty pitkimmän kaavan kautta. Sen voi tehdä paljon yksinkertaisemminkin, jopa yhdellä funktiolla. Esimerkin pointti on kuitenkin se tärkein: ei ole mitään järkeä tehdä mekaanista työtä, jonka voi siirtää helposti koodin vastuulle.

Jälleen kerran vähänkään koodarin vikaa omaava ihminen alkaisi miettiä vaihtoehtoja siinä vaiheessa, kun jokaisen lomakkeen html:ssä on kaksikymmentä lähestulkoon identtistä rakennetta (kentät) käsin kirjoitettuna kaikkine wrapper-elementteineen ja selitetekstien sekä virheilmoitusten tulostuksineen. Viimeistään siinä vaiheessa, kun ulkoasumuutosten takia lomakkeiden rakenteeseen täytyykin tehdä jokin muutos, jota ei pelkällä css:llä ratkaise. Tai jos vaikka aluksi jätettiin kenttäkohtaisten virheilmoitusten tulostus pois, mutta myöhemmin se halutaankin lisätä lomakkeille.

Mikäli koodari ei ala ihmetellä sitä, että hän copy-pasteaa triviaaleja rivejä paikasta toiseen, niin silloin ei osaa asiaansa.

Koodailin itse tuollaisia lomakeluokkia jo kauan ennen kuin edes tutustuin Zendiin tai sen filosofiaan. Olen itse asiassa yllättynyt monta kertaa, miten Zendissä on tehty asioita kuten olin itse tehnyt niitä omia kehyksiäni värkkäillessä, vaikken toki yhtä täydellistä kokonaisuutta osaisi edelleenkään tehdä.

Lisään vielä sen, että vaikka tuo Zendin lomakehässäkkä näyttää tarpeettomankin monimutkaistetulta, niin tuollaiseen tulokseen tullaan auttamatta. Siitä tulee itsestäänselvyyksien rekursio. Kun olioistaa yhden kohdan lomakkeiden käsittelystä, niin havaitsee heti perään, että se on mahdollista tehdä seuraavallekin välivaiheelle. Ja tämän jälkeen sitä seuraavalle, ja sitä seuraavalle, ja niin edespäin. Tämä on henkilökohtainen tuntemukseni omien kokeiluideni perusteella.

Metabolix [20.02.2013 22:34:11]

#

Nyt kyllä trollaat. :D

The Alchemist kirjoitti:

Ilmeisesti vertaat nyt näitä kahta tapausta:

1. print_header(), print_footer(), print_my_element()
2. $engine->render('layout/header'), $engine->render('layout/footer')

Minusta vastaus on aivan selvä: tehdään asiat oikein. Käyttöliittymän rendaavassa koodissa ei saa tehdä mitään muuta.

Mitä yrität sanoa? Millä tavalla mielestäsi print_header() sisältää enemmän "muuta" kuin $engine->render('layout/header')? Ethän pysty tuon rivin perusteella tietämään ollenkaan, mitä kyseiset funktiot sisältävät, ja sisältö voi olla vaikka täsmälleen sama.

The Alchemist kirjoitti:

Templaatin tunkeminen koodin sekaan on hoopoa. – – Sanoisin, että jos – – templaatit ovat funktion sisällä, niin – – olisikohan vain parempi siirtää ne omiin tiedostoihinsa ja sillä saada koodista siistiä. (Viestiä muokattu myöhemmin.)

Ymmärrätkö vain tahallasi väärin vai vahingossa? Kyllähän funktio voi olla omassa tiedostossaan. Templaatti ei silloin ole mitenkään massivisesti "koodin seassa", vaan funktiota varten tarvitaan tasan kaksi (namespacella kolme) koodiriviä. Samalla tulee dokumentoitua samaan tiedostoon, mitä dataa templaatille välitetään; ei tarvitse sitäkään arvailla tai etsiä muualta koodista.

The Alchemist kirjoitti:

Miksi joudut välillä kutsumaan funktiota print_header() ja välillä print_footer(), kun haluat aina tehdä vain saman asian: renderöidä käyttöliittymän (osan siitä). – – "Miksi minä kirjoitan aina uuden funktion, kun oikeasti haluan vain muuttaa yhden parametrin arvoa?" (Vinkki: kyseinen parametri on käyttöliittymän komponentin tunniste.)

Header ja footer ovat eri osia, joiden tulostamisella ei ole juurikaan tekemistä keskenään. Millä tavalla tilanne muuttuu mielestäsi erilaiseksi siitä, että kirjoitetaankin print_part("header") ja print_part("footer")? Miksi joudut ilmoittamaan funktiolle mielivaltaisella tekstillä, mitä haluat tehdä?

Tämä on täysin mielipiteisiin perustuva rajanveto. Sinun logiikallasi voitaisiin edelleen määrätä, että koko kielessä on vain yksi funktio, jolle annetaan kaikki parametrina: f("print", "header"), f("add", $x, 2). Tarkoitushan on nimittäin parametreista riippumatta aina tehdä jotain. Nyt tarvitaan tietenkin jokin muu syntaksi, jolla näitä uusia funktion toimintoja voidaan määritellä lisää, mutta ei se mitään: päästiinpä ainakin ylimääräisistä funktioista eroon!

Jos siis kieltäydyt käyttämästä funktioita, joudut toteuttamaan aivan vastaavan toiminnallisuuden (nimen yhdistäminen tiettyyn koodiin, tässä tapauksessa templaatin HTML- ja PHP-koodiin) jollain muulla tavalla etkä ole lopulta saavuttanut yhtään mitään.

Sinulle on selvästi jokin ideologinen kynnyskysymys, mikä asia voi olla nimeltään funktio ja mihin funktioita voi kirjoittaa. Selvennän. Funktio on koodilohko, jolla on nimi. Myös tiedosto on koodilohko, jolla on nimi. Näihin pätevät PHP:ssä melko samanlaiset rajoitukset. Eräs funktion etu on, että sille voi antaa parametreja: saadaan helposti dokumentoitua, mitä dataa on käytössä. Eräs tiedoston etu on, että sen alkuun ja loppuun ei tarvita välttämättä riviäkään PHP-koodia.

The Alchemist kirjoitti:

Jos haluat myöhemmin tulostaa jollekin toiselle sivulle erilaisen headerin, niin joudut tekemään uuden funktion. Mutta mikä sen nimeksi, kun nimi "print_header" on jo varattu? Ja miksi tarvitset kaksi funktiota saman asian tekemiseen?

Jos haluat myöshemmin tulostaa jollekin toiselle sivulle erilaisen headerin, niin joudut tekemään uuden templaatin. Mutta mikä sen nimeksi, kun "layout/header" on jo varattu? Ja miksi tarvitset kaksi templaattia saman asian tekemiseen?

The Alchemist kirjoitti:

Vertaa tähän: – – kolme_plus_x, viisi_plus_x

Vertauksesi ei ole millään tavalla suhteessa tähän tilanteeseen. Ihan samaa vertausta voi soveltaa sinullekin: itse tekisit ilmeisesti valmiita tiedostoja "3+2.template", "5+4.template" ja niin edelleen ja lukisit vastaukset sieltä. Tätäkö ideaa puolustat?

The Alchemist kirjoitti:

Ehkä tuo Zend-esimerkin koodi näyttää vähän sotkulta, koska se ei ole kovinkaan puristinen. – – (Nämä asiat voi halutessaan tehdä Zendissä myös ideologisesti oikein view-skriptin puolella.)

On aika koomista, että kehotat tutustumaan Zendiin ja sitten kuitenkin heidän oma manuaalinsa onkin "väärin". Ehkä tässä pitikin tutustua The Alchemistin tapaan, joka on implisiittisesti ainoa ideologisesti oikea ja toimiva ratkaisu.

Lebe80 [21.02.2013 00:01:43]

#

The Alchemist kirjoitti:

Metabolix kirjoitti:

Lebe80 kirjoitti:

Itse tosin mieluummin pitäisin aina kaikki avatut tägit samassa tiedostossa suljettujen kanssa.

Tämä ei ole mitenkään ristiriidassa sen kanssa, että käyttäisi kahta funktiota: voihan ne funktiot kirjoittaa peräkkäin samaan tiedostoon.

Höpö höpö. Jos jokin elementti tulostetaan auki funktiossa X, niin se pitää sulkea samassa funktiossa (== samassa kontekstissa), tai koodi on paskaa. Niin yksinkertaista, niin helppoa.

Juurikin näin.

qeijo [21.02.2013 10:07:23]

#

Hei, alla kahvitauolla sutaistu yksinkertainen esimerkki layout koneesta. Esimerkki on puutteellinen mm. virhehallinnan osalta ja Template luokan content - muuttujan nimen riippuvuus itse sivupohjatiedostoon on huono asia.
Tulee varmaan valtava vyöry 'parannusehdotuksia', mutta esimerkin avulla ehkä saat ehkä käsityksen miten asioita voisi toteuttaa.

<!DOCTYPE html>
<html>
    <head>
        <!-- header.html -->
        <meta charset="UTF-8">

        <!--[if lt IE 9]>
            <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->

        <title><?= htmlspecialchars($title); ?></title>

    </head>
    <body>

        <?= $content; ?>

        <!-- Sivupohja voisi sisältäisi tietenkin myös muita kiinteitä rakenneosia -->

    </body>
</html>
<!-- content.html -->

<!-- Täälä ei mielellään tehtäisi muuta kuin yksinkertaisia ehtolauseita, silmukoita ja tulostuksia -->

<article>
    <h1>Tuotteet:</h1>

    <ul>

        <?php foreach($tuotteet as $tuote) : ?>
            <li><?= htmlspecialchars($tuote); ?></li>
        <?php endforeach; ?>

    </ul>

</article>

<?= $subcontent; ?>
<!-- subcontent.html -->
<!-- Tänne voitaisiin tuoda muuttujia halutessa -->

<aside>
    Esimerkki pienestä näkymäosasta, jota halutaan ehkä renderoida toisen näkymän sisälle
</aside>
<!-- header.html -->
<!-- Tänne voitaisiin myös tuoda muuttujia halutessa -->

<header>
    <h1>Yritys Oy</h1>
</header>
<!-- foter.html -->
<!-- Tänne voitaisiin myös tuoda muuttujia halutessa -->

<footer>
    info@yritysoy.fi
</footer>
<?php

interface IView {

    public function __set($index, $value);
    public function render();
}

class View implements IView {

    protected $view;
    protected $vars = array();

    public function __construct($view) {

        $this->view = $view;
    }

    public function __set($index, $value) {

        $this->vars[$index] = $value;
    }

    public function render() {

        ob_start();
        extract($this->vars);
        include($this->view);
        return ob_get_clean();
    }
}

class Template extends View {

    private $views = array();

    public function addView(View $view) {

        $this->views[] = $view;
    }

    public function __toString() {

        $this->vars['content'] = '';

        foreach ($this->views as $view)
            $this->vars['content'] .= $view->render();

        return $this->render();
    }
}

/* Käyttö */

$content = new View('content.html');
$content->tuotteet = array('Kukka', 'Keppi', 'Kilistin', 'Kala');

$subcontent = new View('subcontent.html');
$content->subcontent = $subcontent->render();

$page = new Template('template.html');
$page->title = 'Yritys Oy';

$page->addView(new View('header.html'));
$page->addView($content);
$page->addView(new View('footer.html'));

print $page;

t0ll0 [21.02.2013 11:31:04]

#

No entäpä näin? Tätä rakennetta tulee käytettyä pienissä ja nopeissa projekteissa mitkä ei yleensä alkuinnostusta pidemmälle selviä. Niissä ei ainakaan "rajat" ole tullut vielä vastaan vaikkei tämä älyttömyyksiin taivukkaan ;)

Eli kuinka "huono" tapa tämmöinen on ja onko tässä jotain räikeää virhettä tai koodin raiskausta?

<?php // functiot.php
function check_user(){ // esim käyttäjän tunnistus
 return false;
}

function openSQL(){ // avataan yhteys..
 return true;
}
?>
<?php // sisalto.php
function etusivu($special = false, $user = false){
if($special){
 switch ($special) {
  case 'title': return "Etusivun otsikko"; break; // yms
  default: return false; break;
 }
}
// itse sisältö
 echo 'Tämä on etusivu';
}

function toinensivu($special = false, $user = false, $sql = false){
if($special){
 switch ($special) {
  case 'title': return "Toisen sivun otsikko"; break; // yms
  default: return false; break;
 }
}
// itse sisältö
 echo 'Nyt ollaan täällä ja tietokantayhteyskin on..';
}


function error($special = false, $user = false){
if($special){
 switch ($special) {
  case 'title': return "404"; break; // yms
  default: return false; break;
 }
}
// itse sisältö
 echo 'Höh, annettua sivua ei löydy.';
}
?>
<?php // index.php
if(!isset($_GET['page']) || empty($_GET['page'])){
 $page = 'etusivu';
}elseif(function_exists($_GET['page'])){
 $page = $_GET['page'];
}else{
 $page = 'error';
}
?>

<!DOCTYPE html>
<html>
<head>
 <title>Sivusto <?php echo $page('title'); ?></title>
</head>
<body>
<?php $page(false, check_user(), openSQL()); ?>
</body>
</html>

Itse pidän tästä nimenomaan sen takia että joka sivulla on selvää mitä minulla on käytössä. Globaaleja en tykkää käyttää koska sen tiedän olevan "huono tapa".

qeijo [21.02.2013 11:46:16]

#

t0ll0 kirjoitti:

No entäpä näin?

Juuri tuollainen osittain vaarallinen toteutus on herkkä hajoamaan käsin kun se kasvaa riittävän isoksi. Lisäksi se on yllättävän epäselvä, noin lyhyeksi koodiksi.

Parempi olisi jos sivujen funktiot olisivat käärittynä action - tyyppisesti omaan aiheeseen kuuluvaan luokkaan ja jokaisella sivulla (metodilla) olisi automaattisesti oma näkymätiedosto.

Siinä jaettaisiin roolit selkeemmin datan hakeminen/luominen/prosessointi ja tietojen esitys.

Tässä on vielä aika epämääräisesti sekoitettu 'tietokantakerros' mukaan taikinaan.
Sen toteuttaisin täysin erillään kaikesta näkymään liittyvästä ohjelmakoodista.

Vaarallisella tarkoitin sitä että käyttäjä voi kutsua periaatteessa mitä tahansa funktiota muuttamalla osoiterivin parametreja, aiheuttaen ainakin odottamattomia virheitä.

The Alchemist [21.02.2013 12:04:36]

#

Metabolix kirjoitti:

Nyt kyllä trollaat. :D

The Alchemist kirjoitti:

Ilmeisesti vertaat nyt näitä kahta tapausta:

1. print_header(), print_footer(), print_my_element()
2. $engine->render('layout/header'), $engine->render('layout/footer')

Minusta vastaus on aivan selvä: tehdään asiat oikein. Käyttöliittymän rendaavassa koodissa ei saa tehdä mitään muuta.

Mitä yrität sanoa? Millä tavalla mielestäsi print_header() sisältää enemmän "muuta" kuin $engine->render('layout/header')? Ethän pysty tuon rivin perusteella tietämään ollenkaan, mitä kyseiset funktiot sisältävät, ja sisältö voi olla vaikka täsmälleen sama.

Et voi jälkikäteen enää muokata funktion tuottamaa tulosta rikkomatta taaksepäin yhteensopivuutta. Jos haluat jossain toisessa tilanteessa tulostaa erilaisen headerin, niin joudut tekemään duplikaatin print_header()-funktiosta ja keksimään sille jonkin vielä huonomman nimen, mikä aiheuttaa jälkikäteen ihmetystä, kun on kaksi samaan käyttötarkoitukseen tehtyä funktiota.

Yritin myös sanoa, että käyttöliittymäkomponentin nimen kovakoodaaminen funktioon vie asiat liian spesifistiselle tasolle. Joka tapauksessa näille kaikille funktioille tulisi taustalle yksi geneerinen ratkaisu: hae leiska tiedostosta foobar.html ja syötä sille annetut muuttujat (mikäli noudatetaan separation of concerns -periaatetta eikä view yritä itse huudella tarvitsemansa datan perään.)

Metabolix kirjoitti:

The Alchemist kirjoitti:

Templaatin tunkeminen koodin sekaan on hoopoa. – – Sanoisin, että jos – – templaatit ovat funktion sisällä, niin – – olisikohan vain parempi siirtää ne omiin tiedostoihinsa ja sillä saada koodista siistiä. (Viestiä muokattu myöhemmin.)

Ymmärrätkö vain tahallasi väärin vai vahingossa? Kyllähän funktio voi olla omassa tiedostossaan. Templaatti ei silloin ole mitenkään massivisesti "koodin seassa", vaan funktiota varten tarvitaan tasan kaksi (namespacella kolme) koodiriviä. Samalla tulee dokumentoitua samaan tiedostoon, mitä dataa templaatille välitetään; ei tarvitse sitäkään arvailla tai etsiä muualta koodista.

Ainoa etu tässä on tuo dokumentoinnin pakottaminen. Mutta aivan yhtä hyvin voit toisaalta myös kirjoittaa templaatin ylälaitaan kommentteihin, mitä dataa se tarvitsee.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Miksi joudut välillä kutsumaan funktiota print_header() ja välillä print_footer(), kun haluat aina tehdä vain saman asian: renderöidä käyttöliittymän (osan siitä). – – "Miksi minä kirjoitan aina uuden funktion, kun oikeasti haluan vain muuttaa yhden parametrin arvoa?" (Vinkki: kyseinen parametri on käyttöliittymän komponentin tunniste.)

Header ja footer ovat eri osia, joiden tulostamisella ei ole juurikaan tekemistä keskenään. Millä tavalla tilanne muuttuu mielestäsi erilaiseksi siitä, että kirjoitetaankin print_part("header") ja print_part("footer")? Miksi joudut ilmoittamaan funktiolle mielivaltaisella tekstillä, mitä haluat tehdä?

On aivan hyödytöntä kirjoittaa yhdestä geneerisestä funktiosta kymmeniä erikoistapauksia, joita ei loppupeleissä tarvitse kuin yhden kerran: kun tulostetaan leiska. Jos joudut tulostamaan yhtä ja samaa leiskaa (kokonaisena) useassa eri paikassa, niin rikot tällöin DRY-periaatetta (don't repeat yourself).

Metabolix kirjoitti:

Sinulle on selvästi jokin ideologinen kynnyskysymys, mikä asia voi olla nimeltään funktio ja mihin funktioita voi kirjoittaa. Selvennän. Funktio on koodilohko, jolla on nimi. Myös tiedosto on koodilohko, jolla on nimi. Näihin pätevät PHP:ssä melko samanlaiset rajoitukset. Eräs funktion etu on, että sille voi antaa parametreja: saadaan helposti dokumentoitua, mitä dataa on käytössä. Eräs tiedoston etu on, että sen alkuun ja loppuun ei tarvita välttämättä riviäkään PHP-koodia.

Tiedostojen includettelu viewissä rikkoo jälleen kerran separation of concerns -periaatetta. Sidot tiedostojärjestelmän toteutuksen sovelluksen käyttöliittymään. Kuulostaa aika pöhköltä, kun sen meni sanomaan ääneen. On myös pöhköä sitoa tiedostojärjestelmän toteutus useisiin eri funktioihin (kaikki print_layout_part()-funktion erikoistapaukset). Kaiken voi tehdä yksinkertaisesti tekemällä funktion, jolle annetaan haettavan komponentin tunniste, ja funktion sisällä päätellään, mistä tiedostosta tms. kyseisen komponentin sisältö löytyy.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Jos haluat myöhemmin tulostaa jollekin toiselle sivulle erilaisen headerin, niin joudut tekemään uuden funktion. Mutta mikä sen nimeksi, kun nimi "print_header" on jo varattu? Ja miksi tarvitset kaksi funktiota saman asian tekemiseen?

Jos haluat myöshemmin tulostaa jollekin toiselle sivulle erilaisen headerin, niin joudut tekemään uuden templaatin. Mutta mikä sen nimeksi, kun "layout/header" on jo varattu? Ja miksi tarvitset kaksi templaattia saman asian tekemiseen?

Turha funktio koodissa tarkoittaa minulle bloattia rajapintaa. Jossain sen datan on oltava, ja olen jo ilmaissut mielipiteeni siitä, että suurten staattisten kokonaisuuksien pitäisi olla erillisissä tiedostoissa, eikä funktioissa, koska funktioiden on tarkoitus tuottaa dynaamista dataa.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Vertaa tähän: – – kolme_plus_x, viisi_plus_x

Vertauksesi ei ole millään tavalla suhteessa tähän tilanteeseen. Ihan samaa vertausta voi soveltaa sinullekin: itse tekisit ilmeisesti valmiita tiedostoja "3+2.template", "5+4.template" ja niin edelleen ja lukisit vastaukset sieltä. Tätäkö ideaa puolustat?

Vertaus havainnollisti sinun luomaasi ongelmaa. Ongelma on rajapinnan bloattaantuminen liian yksityiskohtaisten/rajoittuneiden funktioiden takia.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Ehkä tuo Zend-esimerkin koodi näyttää vähän sotkulta, koska se ei ole kovinkaan puristinen. – – (Nämä asiat voi halutessaan tehdä Zendissä myös ideologisesti oikein view-skriptin puolella.)

On aika koomista, että kehotat tutustumaan Zendiin ja sitten kuitenkin heidän oma manuaalinsa onkin "väärin". Ehkä tässä pitikin tutustua The Alchemistin tapaan, joka on implisiittisesti ainoa ideologisesti oikea ja toimiva ratkaisu.

Ylitulkitset aivan suotta. Viittasin siihen, että toteutus voi näyttää sotkulta ajatusmalliin tottumattomille, koska kyseinen esimerkki ei oikeastaan edes toteuta asioita aivan pilkulleen niin kuin ideologisesti olisi oikein, vaan tekee ehkä käytännön syistä asioita "oikoen".

Kerroin myös selvästi sen, että halutessaan asioita voi tehdä ns. yksinkertaisesti tai ns. monimutkaisesti, riippuen ihan omista mieltymyksistä tai myös siitä, miten asioiden koetaan helpottavan esimerkiksi komponenttien testaamista tai koodin uusiokäyttöä.

Jätin sanomatta sen, että minä teen itsekin asiat suurin piirtein noin kuin ne lainaamassasi esimerkissä olivat, mutta on myös olemassa muita tapoja tehdä samat asiat. Kyse on oikeastaan siitä, miten pitkälle asiat haluaa pitää mahdollisimman abstrakteina.

t0ll0 [21.02.2013 12:29:17]

#

qeijo kirjoitti:

Juuri tuollainen osittain vaarallinen toteutus on herkkä hajoamaan käsin kun se kasvaa riittävän isoksi. Lisäksi se on yllättävän epäselvä, noin lyhyeksi koodiksi.

Parempi olisi jos sivujen funktiot olisivat käärittynä action - tyyppisesti omaan aiheeseen kuuluvaan luokkaan ja jokaisella sivulla (metodilla) olisi automaattisesti oma näkymätiedosto.

Siinä jaettaisiin roolit selkeemmin datan hakeminen/luominen/prosessointi ja tietojen esitys.

Tässä on vielä aika epämääräisesti sekoitettu 'tietokantakerros' mukaan taikinaan.
Sen toteuttaisin täysin erillään kaikesta näkymään liittyvästä ohjelmakoodista.

Vaarallisella tarkoitin sitä että käyttäjä voi kutsua periaatteessa mitä tahansa funktiota muuttamalla osoiterivin parametreja, aiheuttaen ainakin odottamattomia virheitä.

Totta juu, eipä ole tuota ("onneksi") tullut käytettyä missään "julkisella" sivulla vaan omia räpellyksiä varten nopeisiin testauksiin :)

creepy [21.02.2013 13:31:24]

#

Tulipas opettavainen keskustelu.

Kiitos qeijolle, tuohon sinun tapaan täytyy tutustua.

Alunperin on ollut takoitus pitää varsinaiset sisältösivut mahdollisimman "tyhjinä" , eli siistinä koodista.

Metabolix [21.02.2013 13:41:53]

#

The Alchemist kirjoitti:

Et voi jälkikäteen enää muokata funktion tuottamaa tulosta rikkomatta taaksepäin yhteensopivuutta

Virheellinen perustelu, täsmälleen sama pätee mihin tahansa muuhunkin ratkaisuun. Vai väitätkö, että templaatin muuttaminen ei muuta render-funktiosi tulosta?

Sama koskee monia muitakin perustelujasi: väität, että funktioiden käyttö aiheuttaisi ongelmia, vaikka on ilmeistä, että joko ongelma esiintyy muissakin toteutuksissa (vaikka et myöntäisi sitä) tai olet aiheuttanut ongelman itse mielessäsi tulkitsemalla koko funktioratkaisun jotenkin kapeasti tai omalla tavallasi.

The Alchemist kirjoitti:

Tiedostojen includettelu viewissä rikkoo jälleen kerran separation of concerns -periaatetta.

Aiemmin kuitenkin olet jo kertonut, että käytät PHP:tä templaateissa. Voisitko valaista, miten se onnistuu ilman funktioita, includea ja evalia?

The Alchemist kirjoitti:

Suurten staattisten kokonaisuuksien pitäisi olla erillisissä tiedostoissa.

Mistä lähtien keskustelu on käsitellyt suuria staattisia kokonaisuuksia? Vielä äsken puhe oli templaateista, joista itsekin kirjoitit, että yksi template vastaa yhtä komponenttia. Mielestäni komponentti ei ole lähtökohtaisesti suuri eikä staattinen.

The Alchemist [21.02.2013 16:50:49]

#

Metabolix kirjoitti:

The Alchemist kirjoitti:

Et voi jälkikäteen enää muokata funktion tuottamaa tulosta rikkomatta taaksepäin yhteensopivuutta

Virheellinen perustelu, täsmälleen sama pätee mihin tahansa muuhunkin ratkaisuun. Vai väitätkö, että templaatin muuttaminen ei muuta render-funktiosi tulosta?

Kun komponentin tunniste annetaan parametrina eikä funktion nimessä kovakoodattuna, niin parametrin arvoa on helppo muuttaa. Jos jossain tarvitaan jokin muu komponentti, niin annetaan vain funktiolle eri tunniste parametrina; no problem.

Metabolix kirjoitti:

Sama koskee monia muitakin perustelujasi: väität, että funktioiden käyttö aiheuttaisi ongelmia, vaikka on ilmeistä, että joko ongelma esiintyy muissakin toteutuksissa (vaikka et myöntäisi sitä) tai olet aiheuttanut ongelman itse mielessäsi tulkitsemalla koko funktioratkaisun jotenkin kapeasti tai omalla tavallasi.

The Alchemist kirjoitti:

Tiedostojen includettelu viewissä rikkoo jälleen kerran separation of concerns -periaatetta.

Aiemmin kuitenkin olet jo kertonut, että käytät PHP:tä templaateissa. Voisitko valaista, miten se onnistuu ilman funktioita, includea ja evalia?

En enää ymmärrä, mistä oikein puhut. Minulle keskustelussa on ollut kaksi pointtia:

1. Html funktion sisällä kovakoodattuna vs. template-tiedostot.
2. Jokaista komponenttia varten oman funktion teko vs. geneerinen template-moottori.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Suurten staattisten kokonaisuuksien pitäisi olla erillisissä tiedostoissa.

Mistä lähtien keskustelu on käsitellyt suuria staattisia kokonaisuuksia? Vielä äsken puhe oli templaateista, joista itsekin kirjoitit, että yksi template vastaa yhtä komponenttia. Mielestäni komponentti ei ole lähtökohtaisesti suuri eikä staattinen.

Hyvin suuri osa käyttöliittymän html:stä on täysin staattista.

Otetaan nyt esimerkiksi tämän foorumin viestiketju: käytännössä koko viestien ketju on staattista sisältöä. Kaikilla viesteillä on sama rakenne, jonka tuottamiseen ei php:tä tarvitse. Ainoat dynaamiset osat ovat käyttäjänimi, kellonaika ja viestin sisältö sekä linkkien osoitteet.

Jos tekisin templaten tätä sivua varten, niin se näyttäisi jotakuinkin tältä:

<div id="messages">
  <ul id="message-list">
    <?php foreach ($messages as $m): ?>
      <li class="message-item">
        <header>
          <a class="username" href="<?= ... ?>"><?= $m->user->username ?></a>
          <span class="timestamp"><?= $m->timestamp ?></span>
          <a class="quote-link" href="<?= ... ?>">Quote</a>
          <a class="message-link" href="<?= ... ?>">#</a>
        </header>
        <div class="content">
          <?= $m->content ?>
        </div>
      </li>
    <?php endforeach ?>
  </ul>
</div>

Kun puhuin suurista staattisista kokonaisuuksista, tarkoitin juuri tämänkaltaisia kokonaisuuksia. Staattiseen rakenteeseen upotetaan muuttujista vähän dataa, mikään ei olennaisesti muutu. Itse html pysyy täysin samana.

Metabolix [21.02.2013 20:02:03]

#

The Alchemist kirjoitti:

Kun puhuin suurista staattisista kokonaisuuksista, tarkoitin juuri tämänkaltaisia kokonaisuuksia.

Sinulla on sitten hyvin kummallinen käsitys staattisesta.

The Alchemist kirjoitti:

Kun komponentin tunniste annetaan parametrina eikä funktion nimessä kovakoodattuna, niin parametrin arvoa on helppo muuttaa.

Pitää olla jokin henkinen vamma, jos on jotenkin vaikeampi muuttaa tekstiä ennen sulkumerkkiä kuin sulkumerkin jälkeen.

The Alchemist kirjoitti:

Html funktion sisällä kovakoodattuna vs. template-tiedostot.

Et ole vieläkään perustellut, millä tavalla funktion sisällä koodi olisi jotenkin enemmän kovakoodattua kuin sama koodi ilman funktiota.

The Alchemist kirjoitti:

Jokaista komponenttia varten oman funktion teko vs. geneerinen template-moottori.

Korjaan: jokaista komponenttia varten oman funktion teko vs. jokaista komponenttia varten oman tiedoston teko ilman funktiota, ja toisaalta geneerinen PHP:n tapa kutsua funktioita vs. "geneerinen" tapa kutsua tietyn olion tiettyä funktiota tietyllä parametrilla, jotta se lataa tiedostosta lisää koodia ja suorittaa sen.

Onko sinulla mitään todellisia perusteluja, vai aiotko jatkossakin vain heitellä jaloja periaatteita ja epätarkkoja vihjauksia katsomatta peiliin?

The Alchemist kirjoitti:

Jos tekisin templaten tätä sivua varten, niin se näyttäisi jotakuinkin tältä: [PHP-koodia]

Niin, äsken siis kysyin, miten saat tuon templaatissa olevan PHP-koodin suoritettua, jos templaattia ei saa liittää includella eikä templaatti voi sijaita funktiossa. Vai kävikö nyt niin, että templaattimoottorissa tapahtuvaa includea ei lasketa? Poissa silmistä, poissa mielestä...

The Alchemist [22.02.2013 11:05:36]

#

Metabolix kirjoitti:

The Alchemist kirjoitti:

Kun puhuin suurista staattisista kokonaisuuksista, tarkoitin juuri tämänkaltaisia kokonaisuuksia.

Sinulla on sitten hyvin kummallinen käsitys staattisesta.

Sinulla on vain vaikeuksia ymmärtää lukemaasi. Olen koko ajan puhunut staattisesta rakenteesta. Muuttujien sisältämä data ei ole pääsääntöisesti osa rakennetta vaan siinä näytettävää informaatiota.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Kun komponentin tunniste annetaan parametrina eikä funktion nimessä kovakoodattuna, niin parametrin arvoa on helppo muuttaa.

Pitää olla jokin henkinen vamma, jos on jotenkin vaikeampi muuttaa tekstiä ennen sulkumerkkiä kuin sulkumerkin jälkeen.

Kun teet funktiokutsun foobar(), niin et voi enää vaikuttaa siihen, kutsutaanko funktiota foobar() vai barbar(). Sama pätee myös olioihin: oliota vaihtamatta ei voi vaikuttaa kutsuttavaan funktioon eikä myöskään sen tulokseen.

Parametri ei ole mikään absoluuttinen arvo vaan pelkkä vihje siitä, mitä pitäisi tapahtua. Zendissä on esimerkiksi helppoa vaihtaa templaatin tunnistetta vastaavaa templaattitiedostoa pelkästään muokkaamalla moduulin konfigurointitiedostoa; koodia ei tarvitse muokata riviäkään.

Se myös parantaa koodin uudelleenkäytettävyyttä, kun ei ole niin väliä, tuleeko templaattien data tiedostosta, tietokannasta vai vaikka netin yli ladatusta datasta.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Html funktion sisällä kovakoodattuna vs. template-tiedostot.

Et ole vieläkään perustellut, millä tavalla funktion sisällä koodi olisi jotenkin enemmän kovakoodattua kuin sama koodi ilman funktiota.

Ei minun tarvitse perustella väittämiä, joita en ole itse tehnyt.

Olen jo kertonut, että yksittäisten komponenttien kääriminen omiin funktioihin on tyhmää, koska funktiot ovat liian rajoittuneita ja ovat sellaisia täysin vailla perusteita.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Jokaista komponenttia varten oman funktion teko vs. geneerinen template-moottori.

Korjaan: jokaista komponenttia varten oman funktion teko vs. jokaista komponenttia varten oman tiedoston teko ilman funktiota, ja toisaalta geneerinen PHP:n tapa kutsua funktioita vs. "geneerinen" tapa kutsua tietyn olion tiettyä funktiota tietyllä parametrilla, jotta se lataa tiedostosta lisää koodia ja suorittaa sen.

Onko sinulla mitään todellisia perusteluja, vai aiotko jatkossakin vain heitellä jaloja periaatteita ja epätarkkoja vihjauksia katsomatta peiliin?

The Alchemist kirjoitti:

Jos tekisin templaten tätä sivua varten, niin se näyttäisi jotakuinkin tältä: [PHP-koodia]

Niin, äsken siis kysyin, miten saat tuon templaatissa olevan PHP-koodin suoritettua, jos templaattia ei saa liittää includella eikä templaatti voi sijaita funktiossa. Vai kävikö nyt niin, että templaattimoottorissa tapahtuvaa includea ei lasketa? Poissa silmistä, poissa mielestä...

Vaahtoat ihan mistä sattuu, vaikea edelleenkään ymmärtää, mitä yrität tällä saavuttaa. Etkö muka ymmärrä itse ohjelmistosuunnittelusta sen vertaa, että sinusta on ihan sama, käytetäänkö includea 20 eri paikassa vai vain yhdessä?

Siinä vaiheessa, kun kutsutaan includea, syntyy riippuvuus koodin ja tiedostojärjestelmän välille. On aivan uskomattoman hölmöä levitellä tällaisia riippuvuuksia minne sattuu. Varsinkin kun todennäköisesti ohessa duplikoidaan muitakin riippuvuuksia; esimerkiksi siihen, miten ladattavalle templaatille välitetään sen tarvitsema data, tai siihen miten templaatin todellinen sijainti päätellään. Turhanpäiväistä copy-pasteilua.

Vielä hölmömpää olisi huudella includea suoraan käyttöliittymän koodissa. Tällöin jokainen templaatti paritetaan tiukasti tiedostojärjestelmän kanssa, ja kaikenlainen siirrettävyys voidaan unohtaa.

Suunnitteluvirhe ei koskaan tule yksin, koska yksi pöhkö ratkaisu vaatii vieläkin pöhkömpiä korjausliikkeitä. Lopputuloksena on kasa purkkaa. Siksi on myös vaikea yrittää antaa täydellisen tarkkoja vastauksia, koska ilman todellista järjestelmää ei voi antaa esimerkkejä todellisista käyttötapauksista. Kaikki viat eivät päde jokaiseen järjestelmään, vaikka niiden toteutuksissa olisikin tehty samoja virheitä.

Tästä syystä meillä on teoriatason ratkaisuita ("ideologia") siitä, millaista hyvä koodi on arkkitehtuuriltaan.

Metabolix [22.02.2013 18:45:08]

#

The Alchemist kirjoitti:

Olen koko ajan puhunut staattisesta rakenteesta

Erikoista, nimittäin mainitset staattisen ja rakenteen yhdessä ensimmäisen kerran tuon äskeisen koodiesimerkkisi yhteydessä.

The Alchemist kirjoitti:

Etkö muka ymmärrä itse ohjelmistosuunnittelusta sen vertaa, että sinusta on ihan sama, käytetäänkö includea 20 eri paikassa vai vain yhdessä?

Olenko muka väittänyt jossain, että includea pitäisi käyttää monessa paikassa? En ole. Itse taas olet vaahdonnut siinä niin kovasti kaikkea vastaan, että kuulosti, ettei koodissasi saa olla yhtäkään includea, ja siksi ihmettelin.

The Alchemist kirjoitti:

Kun teet funktiokutsun foobar(), niin et voi enää vaikuttaa siihen, kutsutaanko funktiota foobar() vai barbar(). Sama pätee myös olioihin: oliota vaihtamatta ei voi vaikuttaa kutsuttavaan funktioon eikä myöskään sen tulokseen.

En edelleenkään ymmärrä, millä tavalla tämä mielestäsi eroaa parametrista. Kun teet kutsun foo("bar"), et voi enää vaikuttaa siihen, annetaanko parametriksi "bar" vai "foobar". Miksi parametri on sinusta niin merkittävästi eriarvoisessa asemassa kuin olio tai funktion nimi?

Esimerkiksi PHP:ssä on maaginen metodi __call, jolla kutsusta $x->printX() tulee kutsu $x->__call("printX"). Vastaavasti $x välittyy automaattisesti nimellä $this melkein kuin parametri. Näin sekä oliosta että funktiosta tulikin oikeastaan parametreja. Miten nyt suu pannaan?

Järkkymättömästä asenteestasi arvelen, että ohjelmoit aina pelkästään imperatiivista koodia. Siinä tapauksessa voisi olla valaisevaa kokeilla joskus vaikka funktionaalista ohjelmointia.

The Alchemist kirjoitti:

Metabolix kirjoitti:

The Alchemist kirjoitti:

Html funktion sisällä kovakoodattuna vs. template-tiedostot.

Et ole vieläkään perustellut, millä tavalla funktion sisällä koodi olisi jotenkin enemmän kovakoodattua kuin sama koodi ilman funktiota.

Ei minun tarvitse perustella väittämiä, joita en ole itse tehnyt.

Mikähän tuossa lainauksen alussa sitten on ellei sinun tekemäsi (implisiittinen) väite? Tai jos asiaan ei liity mitään väitettä, miksi nostat sen esiin keskustelun pointtina?

Toinen mainitsemasi pointti:

The Alchemist kirjoitti:

Jokaista komponenttia varten oman funktion teko vs. geneerinen template-moottori.

Funktioiden käyttö ei mitenkään sulje pois geneeristä moottoria. Moottori voi ladata templaatit jäljempänä olevan esimerkkini mukaan. Vastaavasti geneerisen moottorin rajapintana on aivan mahdollista käyttää funktiokutsuja, jotka ohjautuvat __call-metodille.

The Alchemist kirjoitti:

Olen jo kertonut, että yksittäisten komponenttien kääriminen omiin funktioihin on tyhmää, koska funktiot ovat liian rajoittuneita ja ovat sellaisia täysin vailla perusteita.

Minusta funktiot ovat monella tavalla vähemmän rajoittuneita ja käytännöllisempiä kuin esittämäsi ratkaisu, jossa ilmeisesti annetaan render-metodille merkkijono, joka lopulta johtaa includeen, jonka seurauksena suoraan tapahtuu tulostus.

Esimerkiksi tässä ovat funktioiden sisällä kuvakomponentti ja listakomponentti:

<?php return function ($src, $alt = "") { ?>
	<img
		src="<?= htmlspecialchars($src); ?>"
		alt="<?= htmlspecialchars($alt); ?>"
	/>
<?php } ?>
<?php return function ($arvot, $tulostaja = null) {
	$tulostaja = $tulostaja ?: (function ($s) { echo htmlspecialchars($s); });
	?>
	<ul>
		<?php foreach ($arvot as $arvo): ?>
			<li><?php $tulostaja($arvo) ?></li>
		<?php endforeach ?>
	</ul>
<?php } ?>

Komponentit voi ladata muuttujiin, ja kuvafunktiota voi käyttää listan arvojen tulostajana:

class Moottori {
	public function lataa($t) {
		return require("komponentit/{$t}.php");
	}
}
$m = new Moottori();
$kuva = $m->lataa("kuva");
$lista = $m->lataa("lista");
$lista(array("a.png", "b.png"), $kuva);

Heitin ihan lonkalta, joten koodi ei ole mitenkään täydellisyyteen hiottu. Mielestäni tämä ratkaisumalli on kuitenkin aivan muuta kuin rajoittunut ja joustamaton.

Toki tämänkin esimerkin toteutus funktioilla on vähän kyseenalainen, kun oikeastaan pitäisi käyttää luokkia ja rajapintoja, mutta kyllä funktio on silti tässä paljon selvempi ja loogisempi kuin se $engine->render("kuva")-henkinen vaihtoehto, jossa $lista-funktiolle (ts. sitä vastaavalle render-kutsulle) annettaisiin $kuva-funktion sijaan erikseen arvot $engine ja "kuva".

qeijo [23.02.2013 10:32:01]

#

Mielestäni esimerkissäsi sekoitetaan helppareiden ja templaatien roolit keskenään, hyvin väkinäisellä tyylillä.

<!-- spesifinen templaatti, kuvalista.html -->
<ul class="imagelist">

    <?php foreach($listItems as $image) : ?>
        <li>
            <figure>
                <figcaption><?= htmlspecialchars($image->figcaption); ?></figcaption>
                <img src="<?= htmlspecialchars($image->src); ?>" alt="<?= htmlspecialchars($image->alt); ?>" />
            </figure>
        </li>
    <?php endforeach; ?>

</ul>
class Image {

    private $src, $alt, $figcaption, $class, $id;

    public function __construct($src, $alt = '', $figcaption = '', $class = '', $id = '') {

        $this->src = $src;
        $this->alt = $alt;
        $this->figcaption = $figcaption;
        $this->class = $class;
        $this->id = $id;
    }

    public function __get($var) {

        return $this->$var;
    }
}

$kuvalista = new View('kuvalista.html');

$kuvalista->listItems = array(
    new Image('lorikeet.jpg'),
    new Image('pelican.jpg', 'Hieno Pelikaani'),
    new Image('kookaburra.jpg', 'Hieno Kokonurra', 'Kokoburra')
);

print $kuvalista->render();

The Alchemist [25.02.2013 20:53:28]

#

Metabolix kirjoitti:

The Alchemist kirjoitti:

Kun teet funktiokutsun foobar(), niin et voi enää vaikuttaa siihen, kutsutaanko funktiota foobar() vai barbar(). Sama pätee myös olioihin: oliota vaihtamatta ei voi vaikuttaa kutsuttavaan funktioon eikä myöskään sen tulokseen.

En edelleenkään ymmärrä, millä tavalla tämä mielestäsi eroaa parametrista. Kun teet kutsun foo("bar"), et voi enää vaikuttaa siihen, annetaanko parametriksi "bar" vai "foobar". Miksi parametri on sinusta niin merkittävästi eriarvoisessa asemassa kuin olio tai funktion nimi?

Esimerkiksi PHP:ssä on maaginen metodi __call, jolla kutsusta $x->printX() tulee kutsu $x->__call("printX"). Vastaavasti $x välittyy automaattisesti nimellä $this melkein kuin parametri. Näin sekä oliosta että funktiosta tulikin oikeastaan parametreja. Miten nyt suu pannaan?

Jos joudut käyttämään magic methodeita tällä tavoin koodissasi "koska se nyt vaan oli huono idea käyttää funktiota parametrin sijaan", niin myönnät, että nyt on ongelma, joka pitää korjata.

Kokeillaan nyt havainnollistaa taka-ajatustani lyhyellä snippetillä:

function get_template_config() {
  return array(
    'foo' => 'database',
    'bar' => 'templates/bar.php',
  );
}

function get_template($name) {
  $conf = get_template_config();

  if ($conf[$name] == 'database') {
    // Luetaan template poikkeuksellisesti tietokannasta.
    return db_get_template($name);
  } else {
    return file_get_contents($name . '.php');
  }
}

// vs.

function get_template_foo() {
  // Tätä ei sitten voidakaan enää muokata koskematta funktion toteutukseen.
  require 'templates/foo.php';

  // ...paitsi näin:
  return get_template('foo');
  // HUOH!
}

Metabolix kirjoitti:

Järkkymättömästä asenteestasi arvelen, että ohjelmoit aina pelkästään imperatiivista koodia. Siinä tapauksessa voisi olla valaisevaa kokeilla joskus vaikka funktionaalista ohjelmointia.

Php ei ole funktionaalinen kieli eikä sovellu funktionaaliseen ohjelmointiin. Mielelläni käyttäisin funktionaalisia piirteitä paljon useammin, mutta php:n kanssa se harvoin tuntuu pätevältä ratkaisulta.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Jokaista komponenttia varten oman funktion teko vs. geneerinen template-moottori.

Funktioiden käyttö ei mitenkään sulje pois geneeristä moottoria. Moottori voi ladata templaatit jäljempänä olevan esimerkkini mukaan. Vastaavasti geneerisen moottorin rajapintana on aivan mahdollista käyttää funktiokutsuja, jotka ohjautuvat __call-metodille.

Ei todellakaan sulje pois geneeristä ratkaisua, niin. Juuri tästä syystä vastustan komponenttien käärimistä omiin funktioihinsa. Jos geneerinen ratkaisu olisi liian geneerinen, niin olisi perusteltua kääriä se spesifistisempiin funktioihin, mutta tässä tapauksessa ei sellaisesta voida puhua. Olen toistanut, että komponenttikohtaiset funktiot ovat - tarkastelun kohteena olevassa käyttötarkoituksessa - hyödyttömiä, koska ne tuovat tarpeettomia rajoituksia hyvän geneerisen ratkaisun käyttöön.

// Yksinkertainen geneerinen funktio.
function print_template($name, $data) {
  extract($data);
  require $name . '.php';
}

// Sidotaan templaten nimi turhaan funktion nimeen, ei vähennä kompleksisuutta.
function print_foo($p1, $p2) {
  print_template('foo', compact('p1', 'p2'));
}

Metabolix kirjoitti:

The Alchemist kirjoitti:

Olen jo kertonut, että yksittäisten komponenttien kääriminen omiin funktioihin on tyhmää, koska funktiot ovat liian rajoittuneita ja ovat sellaisia täysin vailla perusteita.

Minusta funktiot ovat monella tavalla vähemmän rajoittuneita ja käytännöllisempiä kuin esittämäsi ratkaisu, jossa ilmeisesti annetaan render-metodille merkkijono, joka lopulta johtaa includeen, jonka seurauksena suoraan tapahtuu tulostus.

--

Komponentit voi ladata muuttujiin, ja kuvafunktiota voi käyttää listan arvojen tulostajana:

class Moottori {
	public function lataa($t) {
		return require("komponentit/{$t}.php");
	}
}
$m = new Moottori();
$kuva = $m->lataa("kuva");
$lista = $m->lataa("lista");
$lista(array("a.png", "b.png"), $kuva);

Heitin ihan lonkalta, joten koodi ei ole mitenkään täydellisyyteen hiottu. Mielestäni tämä ratkaisumalli on kuitenkin aivan muuta kuin rajoittunut ja joustamaton.

Tuo ratkaisuhan on täydellinen kopio minun puolustamastani mallista; siihen on vain väkipakolla survottu funktiot mukaan. Templaten kääriminen funktioon ei tässä palvele mitään tarkoitusta. Hyvinkin teennäistä, kuten qeijokin huomautti.

Funktionaalisen piirteen voisi yhtä hyvin redundantin toistamisen sijaan kääriä template-moottorin sisälle:

class Engine {
    function load($name) {
        $file = sprintf('foo/%s.php', $name);

        return function(array $data) use ($file) {
            extract($data);
            require $file;
        }
    }
}

Kutsuisin esimerkkiäsi lähinnä suorituskykyä parantavaksi purkaksi oman ratkaisumallini ympärillä; siinä riittää, että templaatti luetaan tiedostosta yhden kerran ja sitä voi sittemmin toistaa vaikka silmukassa ilman ylimääräistä penalttia. Oma ratkaisuni kai johtaisi koodin parsimiseen uudestaan ja uudestaan jokaisella iteraatiolla (en ole varma php:n sisäisistä optimoinneista) ja pahimmillaan jopa saman tiedoston lukemiseen levyltä kerta toisensa perään.

Metabolix [25.02.2013 22:13:36]

#

The Alchemist kirjoitti:

Jos joudut käyttämään magic methodeita – –

Nostin ne esiin pelkästään siksi, että väität, että niin ei voi tehdä.

The Alchemist kirjoitti:

Olen toistanut, että komponenttikohtaiset funktiot ovat - tarkastelun kohteena olevassa käyttötarkoituksessa - hyödyttömiä, – –

Mikähän se käyttötarkoitus nyt tarkalleen on? Olemme ehkä siitäkin eri mieltä, kun vieläkin teet tuollaisia tarkoituksella huonosti tehtyjä esimerkkejä, joissa funktioita edustaa print_foo. Kyllä osaan tehdä ihan yhtä huonoja versioita sinun "geneerisistä" tavoistasi, turha siitä on kilpailla. Yritä mieluummin tehdä esimerkki, joka kertoo jotain poikkeuksellisen hyvää omasta tavastasi.

The Alchemist kirjoitti:

Metabolix kirjoitti:

Komponentit voi ladata muuttujiin, ja kuvafunktiota voi käyttää listan arvojen tulostajana:

class Moottori {
	public function lataa($t) {
		return require("komponentit/{$t}.php");
	}
}
$m = new Moottori();
$kuva = $m->lataa("kuva");
$lista = $m->lataa("lista");
$lista(array("a.png", "b.png"), $kuva);

Tuo ratkaisuhan on täydellinen kopio minun puolustamastani mallista; siihen on vain väkipakolla survottu funktiot mukaan. Templaten kääriminen funktioon ei tässä palvele mitään tarkoitusta.

Funktiot palvelevat tuossa selvää tarkoitusta: niiden avulla saadaan templaatista itsenäinen objekti, jota voi liikutella paikasta toiseen ja käyttää muiden templaattien osana. Kyseessä on suunnitteluratkaisu, jonka voi nähdä halunsa mukaan joko turhana tai hyödyllisenä.

The Alchemist kirjoitti:

Funktionaalisen piirteen voisi yhtä hyvin redundantin toistamisen sijaan kääriä template-moottorin sisälle: – –

Silloin menetetään aiemmin mainitsemani funktioiden puoli, templaatin yhteydessä dokumentoitu rajapinta. Esittämäsi extract-kikka on aika hurja esimerkki geneerisestä laatukoodista. Aiemmin jo puolustauduit myös, että voihan muuttujat kertoa kommenteissa, mutta mielestäni kommentit ovat vain purkkaratkaisu koodin tasolla tapahtuvaan dokumentointiin verrattuna.

The Alchemist [02.03.2013 13:12:06]

#

Metabolix kirjoitti:

The Alchemist kirjoitti:

Jos joudut käyttämään magic methodeita – –

Nostin ne esiin pelkästään siksi, että väität, että niin ei voi tehdä.

En minä edelleenkään sanoisi, että mitä tahansa voi tehdä, vaikka se olisikin teknisesti mahdollista. Lisäksi tuo pätee vain oliomalliin, globaaleita funktioita ei voi ylikirjoittaa.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Olen toistanut, että komponenttikohtaiset funktiot ovat - tarkastelun kohteena olevassa käyttötarkoituksessa - hyödyttömiä, – –

Mikähän se käyttötarkoitus nyt tarkalleen on? Olemme ehkä siitäkin eri mieltä, kun vieläkin teet tuollaisia tarkoituksella huonosti tehtyjä esimerkkejä, joissa funktioita edustaa print_foo. Kyllä osaan tehdä ihan yhtä huonoja versioita sinun "geneerisistä" tavoistasi, turha siitä on kilpailla. Yritä mieluummin tehdä esimerkki, joka kertoo jotain poikkeuksellisen hyvää omasta tavastasi.

Lähinnä käytän esimerkkejä havainnollistaakseni ongelmia vastapuolen ideologiassa. Minun perusväittämänihän on ollut oikeastaan se, että kun asiat tekee oikein, niin ongelmia tulee vähemmän. En tiedä, miten tätä voisi havainnollistaa muutoin kuin osoittamalla viat sellaisissa malleissa, joiden koen olevan huonoja.

Lisäksi olet jo itse lainannut yhtä Zend-esimerkkiä suoraan virallisesta dokumentaatiosta ja kutsuit sitä sekavaksi (mitä se tavallaan olikin).

Metabolix kirjoitti:

The Alchemist kirjoitti:

Metabolix kirjoitti:

Komponentit voi ladata muuttujiin, ja kuvafunktiota voi käyttää listan arvojen tulostajana:

class Moottori {
	public function lataa($t) {
		return require("komponentit/{$t}.php");
	}
}
$m = new Moottori();
$kuva = $m->lataa("kuva");
$lista = $m->lataa("lista");
$lista(array("a.png", "b.png"), $kuva);

Tuo ratkaisuhan on täydellinen kopio minun puolustamastani mallista; siihen on vain väkipakolla survottu funktiot mukaan. Templaten kääriminen funktioon ei tässä palvele mitään tarkoitusta.

Funktiot palvelevat tuossa selvää tarkoitusta: niiden avulla saadaan templaatista itsenäinen objekti, jota voi liikutella paikasta toiseen ja käyttää muiden templaattien osana. Kyseessä on suunnitteluratkaisu, jonka voi nähdä halunsa mukaan joko turhana tai hyödyllisenä.

Millä tavoin se on sen enempää itsenäinen objekti funktioon käärittynä kuin ilman sitä? Ainoa erohan tässä nyt on se, että funktiolla on jokin tietty toteutus - se tekee jonkin tietyn asian. Templaatin tunnisteen sisältävä parametri sidotaan siis jo ylimmällä tasolla johonkin tiettyyn toteutukseen sen sijaan, että todellinen tulos määräytyisi vasta sitten, kun jotain halutaan oikeasti tulostaa ulos. Lisäksi koskaan ei voida olla varmoja, että tehdylle työlle olisi mitään käyttöä, koska kaikissa tilanteissa ei välttämättä halutakaan tulostaa kaikkia ladattuja templaatteja.

Metabolix kirjoitti:

The Alchemist kirjoitti:

Funktionaalisen piirteen voisi yhtä hyvin redundantin toistamisen sijaan kääriä template-moottorin sisälle: – –

Silloin menetetään aiemmin mainitsemani funktioiden puoli, templaatin yhteydessä dokumentoitu rajapinta. Esittämäsi extract-kikka on aika hurja esimerkki geneerisestä laatukoodista. Aiemmin jo puolustauduit myös, että voihan muuttujat kertoa kommenteissa, mutta mielestäni kommentit ovat vain purkkaratkaisu koodin tasolla tapahtuvaan dokumentointiin verrattuna.

Muuttujien dokumentointia ei yleensäkään pidetä kovin tärkeänä seikkana; kaikki tuntemani templaattiratkaisut perustuvat juuri samaan malliin, jota itsekin olen lobannut.

Muuttujien dokumentointi on merkityksellistä lähinnä silloin, kun aikomuksena on voida käyttää samaa templaattia useiden eri "end-pointtien" kanssa. Tämä on oikeastaan täysin päinvastainen ajattelutapa kuin mitä yleisesti noudatetaan. Käsittääkseni yleensä halutaan suunnitella järjestelmä niin, että "end-pointin" data voidaan näyttää useissa eri muodoissa. (Toki osa "alitemplaateista" voi olla tarkoitettu uudelleenkäytettäviksi.)

Esimerkiksi ajax-pyynnön yhteydessä data rendattaisiin json-oliona, tavalliseen "webbisivupyyntöön" taas vastattaisiin html-dokumentilla; kenties mobiiliselaimen tekemään pyyntöön vielä eri dokumentilla kuin tavallisesti. Joskus kenties halutaankin tulostaa pdf-tiedostoon. Täten tarkoitus onkin vain rakentaa näyttömuoto jo etukäteen tunnetun datan ympärille.

Lisäksi kaikkea viewin tarvitsemaa dataa ei tarvitse saada suoraan controllerilta. View voi hankkia osan datasta ns. view helpereiden välityksellä, joilla voi olla yhteys tietokantaan tai jotka voivat jatkokäsitellä jotain tietoelementtiä. En ole vielä kovinkaan tarkasti tutustunut siihen, milloin kannattaisi käyttää view helpereitä ja koska taas data pitäisi saada suoraan controllerilta.

Voisin kuvitella erään esimerkin olevan vaikka sellainen, että controller antaa viewille aina tiedon aktiivisesta käyttäjästä - joka joko on tai ei ole kirjautuneena sisään - ja esimerkiksi käyttäjän statuksen (tavan käyttäjä, moderaattori, ei kirjautunut) haetaan jotain käyttäjälle relevanttia dataa näytölle. Controllerit pullistuisivat aika nopeasti, jos kaikki eri skenaariot pitäisi käsitellä niiden sisällä. Puhumattakaan siitä turhasta työstä, jos vaikka sivun mobiiliversiossa ei halutakaan näyttää kaikkia osioita.

Toinen esimerkki: puhutaan vaikka sivusta, jonka on tarkoitus näyttää keskustelualueen viestejä. Controller hakisi viestit, mutta sivun laitaan tulostettava mainosbanneri noudettaisiin vasta viewin päässä.

Metabolix [03.03.2013 22:54:28]

#

The Alchemist kirjoitti:

Lähinnä käytän esimerkkejä havainnollistaakseni ongelmia vastapuolen ideologiassa.

Havainnollistat ongelmia, jotka itse aiheutat koodaamalla väkisin niin huonosti, ettei siihen mikään auta. Jos mielestäsi esimerkkisi oli onnistunut, sitten varmaan tämäkin kuvastaa vakavia ongelmia sinun ideassasi (noudatellen puheena olleen esimerkkisi "parempaa" puolta):

function get_template($name) {
	switch ($name) {
		case "foo":
			return db_get_template($name);
		case "bar":
			return file_get_contents("templates/bar.php");
		case "baz":
			return file_get_contents("templates/zab.php");
	}
}

Onpa kauhea, joudutaan toistamaan file_get_contents-kutsuja ja "templates/*.php"-tekstejä!

Ennen kuin sanot, että eihän sitä noin kuulu tehdä, muistutan, että sanoin ihan samaa sinun "esimerkistäsi" ja olin sitä ennen jo näyttänyt funktioita käyttävän moottorin, johon kömpelö purkkakoodisi ei millään päde. Kai nyt sentään ymmärrät, ettei tahallinen tyhmyys kelpaa väittelyssä perusteluksi.

The Alchemist kirjoitti:

Millä tavoin se [templaatti] on sen enempää itsenäinen objekti funktioon käärittynä kuin ilman sitä?

Se on itsenäinen siten, että sen toiminta ei enää riipu mitenkään templaattimoottorista tai sen takana olevista osista kuten tietokannasta tai tiedostojärjestelmästä. Siis käyttövalmis muuttuja $x on itsenäisempi entiteetti kuin toinen muuttuja $y, jonka käyttämiseksi pitää saada jostain TemplateEngine-luokan olio ja kutsua $engine->load($y).

The Alchemist kirjoitti:

Kaikki tuntemani templaattiratkaisut perustuvat juuri samaan malliin, jota itsekin olen lobannut.

Siinähän tuli lyömätön perustelu.

Ehkä et sitten tunne kovin monta templaattiratkaisua, tai ehkä "juuri sama malli" mielestäsi kattaa hyvin monenlaisia ratkaisuja mutta ei missään nimessä juuri funktioita. Heitän nyt kuitenkin pari mielestäni erilaista vaihtoehtoa:

Apache Wicket on Java-kirjasto, joka hieman muistuttaa näitä ehdottamiasi mutta toisaalta ei: templaatti on XML-koodia eikä yritäkään sisältää mitään toiminnallisuutta (silmukoita, ehtoja); templaatti täytetään ja elementit tarvittaessa piilotetaan tai monistetaan Java-koodissa. Wicketin MVC-ajattelun Model-osa on kyllä vähän kummallinen.

XSLT erottaa vielä puhtaammin logiikan ja esityksen. Se on XML-pohjainen kieli, jolla XML-muotoisesta tiedosta saa tehtyä XHTML-sivun. Näin ollen XSLT toimii monilla eri ohjelmointikielillä, ja monet selaimet tukevat sitä myös suoraan niin, että templaattitouhut voi ulkoistaa selaimelle.

The Alchemist kirjoitti:

Muuttujien dokumentointi on merkityksellistä lähinnä silloin, kun aikomuksena on voida käyttää samaa templaattia useiden eri "end-pointtien" kanssa. Tämä on oikeastaan täysin päinvastainen ajattelutapa kuin mitä yleisesti noudatetaan.

Niinpä niin. Yleensä ei käytetä samaa templaattia moneen kertaan, vaan jos sellainen tilanne tulisikin eteen, templaatista tehdään "helpperi", jolloin yllättäen onkin luvallista laittaa koodia funktioon – hei, sehän on vain helpperi! Äsken jo qeijo ehti tarjota helppereitä vaihtoehdoksi templaattiesimerkilleni, tosin en ihan ymmärrä, mihin hän niitä halusi käyttää, kun ei hänen koodinsakaan liittynyt mitenkään asiaan.

Myös ehdottamasi view helpperit, jotka hakevat dataa ohjaimen ohi, mielestäni rikkovat ihan samalla tavalla niitä hienoja periaatteita, joista koko ajan jaksat vaahdota. Miksei tätäkin voi tehdä oikein (kuten Wicketissä): tehdä komponentteja, joita käytetään uudestaan, ja periä luokkia toisista, jolloin saadaan kantaluokalta (ja sen templaatilta) yhteiset raamit?

qeijo [04.03.2013 09:29:38]

#

Metabolix kirjoitti:

Äsken jo qeijo ehti tarjota helppereitä vaihtoehdoksi templaattiesimerkilleni, tosin en ihan ymmärrä, mihin hän niitä halusi käyttää, kun ei hänen koodinsakaan liittynyt mitenkään asiaan.

Tarkoitukseni ei ollut demota helppareiden käytön ko. tilanteessa, vaan ainostaan esittää vaihtoehtoisen toteutustavan, mielestäni fundamentaalisesti toteutetulle ratkaisulle.
Mielestäni helpparit ovat monesti "oikotie onneen", heittäen samalla hienot ideologiat ja patternit mäkeen. Noudatetaan systemaattisesti tiettyä kaavaa ja yhtäkkiä luodaan "helppa(e)ri" joka sotii omia linjauksia vastaan.

The Alchemist sallii mainosbannerin latauksen view:issä. Itse tekisin bannerista komponentin joka luodaan ohjaimessa ja esitetään näkymässä, makuasia.

timoh [05.03.2013 15:14:34]

#

qeijo kirjoitti:

The Alchemist sallii mainosbannerin latauksen view:issä. Itse tekisin bannerista komponentin joka luodaan ohjaimessa ja esitetään näkymässä, makuasia.

Yleensä controlleria käytetään jos on tarve muokata tjms. model dataa. Jos käytät mainosbannerin hakuun aina controlleria, niin tuo tuntuu koodin duplikoinnilta. Siinä mielessä view helper on luonnollinen ratkaisu mainosbannerin tööttäämiseen. Kutsut sitä mistä vaan templatesta, niin saat bannerin ja thats it.

The Alchemist kirjoitti:

En ole vielä kovinkaan tarkasti tutustunut siihen, milloin kannattaisi käyttää view helpereitä ja koska taas data pitäisi saada suoraan controllerilta.

Yleensä tässä vaikuttaa mm. tuo että muokataanko dataa, sekä onko matsku spesifisesti juuri kyseiseen controlleriin liittyvää. Jos ei ole, joutuisit koodin monistamaan jokaiseen controlleriin minkä takana materiaalia tarvitaan.

Yksi klassinen esimerkki on päivämäärien muotoilu. Modelista data tulee aina samassa muodossa, mutta jos päivämäärä halutaan esittää toisella tavalla, niin controllereissa joutuisi duplikoimaan koodia. Mutta view helper on yksi luonnollinen paikka missä tämän toiminnon voi tehdä eristetysti omana toimintonaan.

qeijo [05.03.2013 16:00:44]

#

timoh kirjoitti:

Jos käytät mainosbannerin hakuun aina controlleria, niin tuo tuntuu koodin duplikoinnilta. Siinä mielessä view helper on luonnollinen ratkaisu mainosbannerin tööttäämiseen. Kutsut sitä mistä vaan templatesta, niin saat bannerin ja thats it.

Todellisessa tilanteessa täytyisi varmaan myös punnita asian kompleksisuus, eli kuinka monesta eri asioihin riippuvista ja vaikuttavista osista banneri koostuu.

Yksinkertaisimmillaan bannerin on kuva, vastaavasti se voi olla paikkatietojen ja muiden muuttujien perusteella esittettävä materiaali, jonka esitykseen halutaan ehkä tapauskohtaisesti vaikuttaa. Näihin voidaan toki vaikuttaa näkymän kautta, mutta mielestäni se hieman hämärtää järjestelmän eri osien roolit.

Tietysti jos banneri on näkymässä

<?= ViewHelpers::banner("x"); ?>

niin haitanneeko tuo nyt ketään.

Haluaisin nähdä miten hieman monipuolisemmassa view helperissä on esim. kommunikointi tietokannan kanssa toteutettu.

timoh [05.03.2013 21:55:12]

#

Voit view helperissä käyttää tietokantaa kuten muuallakin - sillä erotuksella, että operaatio tulisi olla read-only.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta