Kirjoittaja: Teuro
Kirjoitettu: 07.03.2009 – 14.12.2011
Tagit: ohjelmointitavat, koodi näytille, vinkki
Keskustelussa tulee toisinaan esiin tilanteita, joissa koodin luettavuus on kärsinyt pahasti, koska sisältöä, toiminnallisuutta ja ulkoasua ei ole eriytetty mitenkään toisistaan. Tämän vinkin tarkoituksena on hiukan valottaa miten asiaa voisi lähteä muuttamaan.
Sivupohjien käyttö vapauttaa nettisivujen ohjelmoijan keskittymään varsinaiseen ohjelmoinnin toteutukseen, koska graafikko tai joku muu on tehnyt valmiin pohjan, johon vain lisätään generoitu sisältö. Tämä kyseinen sivupohja tosin toimii aivan yhtä hyvin perinteisten .html sivujen kanssa. Sivupohjan ainoa vaatimus on, että generoitujen tai staattisten sivujen on noudatettava hyvää XML merkkausta. Toisin sanoen sivun tullessa näkyviin on se takuulla XHTML 1.0 Strict mukainen dokumentti.
Mallin avulla voidaan myös liittää jokaiselle sivulle samat yhteiset asiat, kuten vaikkapa käyttäjien tunnistus tai muokkauslinkki jokaiseen elementtiin. Malli on luonnollisesti myös laajennettavissa helpohkosti isommaksi, koska sillä ei ole juurikaan kytköksiä esitettävään sisältöön. Ainoa konkreettinen yhteys on rajapinta sisällössä olevaan sisältösolmuun, jonka tulee olla jokaisella sivulla saman niminen.
Sivusto muunnetaan mallien avulla toimivaksi .htaccess tiedostolla, jolla kerrotaan minkätyyppiset tiedostot käytetään mallin kautta.
Koodin seassa on jonkun verran kommentteja, mutta koodin pitäisi olla melko selkeää luettaavaa. Viimeisessä koodilistauksessa on pieni esimerkkisivu, jossa vielä demonstroidaan mallin toimintaa käytännössä. Esimerkki valaisee samalla hieman DOM rajapinnan käyttöä nettisivujen teossa.
Kaikenlaiset vinkit ja kommentit tästä ovat enemmän kuin tervetulleita, koska järjestelmä on käytössä sivulla, joka löytyy profiilistani. Siellä ja omalla palvelimellani tuntuu toimivan oikein hyvin.
Koodivinkin pohjana toimii http://appro.mit.jyu.fi/sovellukset/demot/demo9/
htaccess
Action oma-template http://localhost/template.tmpl AddHandler oma-template .php
pohja.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="fi"> <head> <title xml:id="title" id="title"></title> </head> <body> <p><a href="index.php"><img src="tyylit/kuvat/manssi_logo.jpg" alt="manssi_logo" /></a></p> <ul class="navigointi"> <li><a href="ekasivu.php" title="Ensimmäinen sivuni">Eka sivu :)</a></li> </ul> <div xml:id="content" id="content"> </div> </body> </html>
template.tmpl
<?php /* Käsittelyyn otettavan tiedoston polku */ $tiedosto = $_SERVER["PATH_TRANSLATED"]; ob_start("template"); require( $tiedosto ); ob_end_flush(); function template( $buffer ){ /* Tyylit scriptit jne... */ require( "liita/asetukset.php" ); $pohja = new Domdocument( "1.0", "UTF-8" ); $pohja -> formatOutput = true; /* Ladataan pohjalle tuleva tiedosto */ $pohja -> load( "pohja.xml" ); $sisalto = new Domdocument( "1.0", "UTF-8" ); /* Ladataan puskurista tullut sisältö */ $sisalto->loadHTML( $buffer ); /* Tyylien asetus sivupohjaan */ $tyyli = $pohja -> createElement( "link" ); $tyyli -> setAttribute( "rel", "StyleSheet" ); $tyyli -> setAttribute( "href", "tyylit/" . $asetukset['tyyli'] ); $tyyli -> setAttribute( "type", "text/css" ); $pohja->getElementsByTagName("head")->item(0)->appendChild($tyyli); /* Importoidaan sisältö sivupohjaan */ $teksti = $pohja->importNode($sisalto->getElementsByTagName("div")->item(0), true); /* Noudetaan otsikkoelementti pohjasta. TÄSSÄ EI OLE SISÄLTÖÄ VIELÄ */ $otsikko = $pohja -> getElementById("title"); $pohja->getElementById("title")->removeAttribute("xml:id"); /* Haetaan puskurista tullut otsikon sisältö */ $otsikkoSisalto = $sisalto -> getElementsByTagName( "title" )->item(0)->textContent; /* Lisätään tyhjään otsikkoon puskurista tullut otsikko */ $otsikko -> appendChild($pohja->createTextNode($otsikkoSisalto)); /* Liimataan elementit malliin kiinni */ while ($teksti->firstChild) { $pohja->getElementById("content")->appendChild($teksti->firstChild); } $pohja->getElementById("content")->removeAttribute("xml:id"); return $pohja->saveXML(); }
esimerkki.php
<?php $sivu = new Domdocument("1.0", "UTF-8"); $sivu -> formatOutput = true; $html = $sivu -> createElement("html"); $sivu -> appendChild($html); $head = $sivu -> createElement("head"); $html -> appendChild($head); $title = $sivu -> createElement("title", "Esimerkki"); $head -> appendChild($title); $body = $sivu -> createElement("body"); $html -> appendChild($body); $con = $sivu -> createElement("div"); $con -> setAttribute("id", "content"); $body -> appendChild($con); $h1 = $sivu -> createElement("h1", "Demosivu malleista"); $con -> appendChild($h1); $p = $sivu -> createElement("p", "Mallin avulla luotu nettisivu, jos luet tätä, niin malli toimii oikein."); $con -> appendChild($p); echo $sivu -> saveXML(); ?>
Pohjassa on latin9 kun taas template ja esimerkki puskevat UTF-8. Suosittelisin taas esim. Zendin konventioita. Ylimääräiset välit aiheuttavat vaan pitkiä rivejä ja hankaloittavat lukemista, sitä varten on syntaksiväritys. Ja samojen konventioiden mukaan; kun kyse on Document Object Modelista, niin Domdocument
-> DOMDocument
.
Kommentoinen tarkemmin, kunhan kerkiää tutustua systeemiin.
Mitäs perkuletta molemmissa oli alkujaan UTF-8 merkkaus laitettu, mutta jostain syystä oli toiseen lipsahtanut ISO-8859-1 merkkaus. Kiitos kommentista!
Kyllä tuollaisen high-tech systeemin koodin lukeminen on mielestani paljon työläämpää, kuin perus PHP-virityksen.
Mutta tämä on tietysti vain minun mielipide.
Tämä aukeaa ehkä helpommin, jos kokeilet sitä omalla palvelimella. Tämän tarkoituksena onkin siirtää sivujen yhteiset osat yhteen paikkaan, jolloin sivujen päivitys helpottuu aivan olennaisesti.
Voisiko vinkkiä sinusta parantaa jollakin tavalla? Kerro toki, niin katson josko kirjoittaisin tuon vaikka uusiksi vielä.
vaikuttaa hirveän monimutkaiselta ihmo verrattaen yksinkertaiseen homaaan. voin katsoa itse jos osaan tehdä hienompaa :)
edit: olihan siinä joku ajatuskin näköjään jota en huomannut aluksi. Eli ei tämä sitten ihan vastaa tuota, mutta jätän nyt kuitenkin jos vaikka saa jotain ideaa.
tässä olisi oma versio, ei mitenkää niin hyvä kun toivoin kun en ole php:hen onneksi joutunu koskeamaan pitkään aikaan *oksennus*
// pohja.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="fi"> <head> <title xml:id="title" id="title"></title> </head> <body> <ul class="navigointi"> <li><a href="ekasivu.php" title="Ensimmäinen sivuni">Eka sivu :)</a></li> </ul> <div xml:id="content" id="content"> </div> </body> </html>
// render.php <?php function renderXML($filename, $array) { $pohja = new DOMDocument("1.0", "UTF-8"); $pohja->formatOutput = true; $pohja->load($filename); foreach($array as $key => $value) { $elem = $pohja->getElementById($key); if(is_string($value)) { $elem->nodeValue = $value; } else if(is_a($value, "DOMNode")) { $elem->appendChild($value); } else if(is_a($value, "DOMNodeList")) { foreach($value as $node) { $elem->appendChild($pohja->importNode($node, TRUE)); } } else { continue; } $elem->removeAttribute("xml:id"); } return $pohja->saveXML(); } ?>
<?php require("render.php"); $dummyDoc = new DOMDocument("1.0", "UTF-8"); $root = $dummyDoc->createElement("root"); $root->appendChild($dummyDoc->createElement("h1", "Demosivu malleista")); $root->appendChild($dummyDoc->createElement("p", "Mallin avulla luotu nettisivu, jos luet tätä, niin malli toimii oikein.")); $content = $root->childNodes; $data = array("title" => "Esimerkki", "content" => $content); echo renderXML("pohja.xml", $data); ?>
en ole ihan varma että olisiko sinun rakenteessa jotain hienoa jota en nyt pikaisesti tajunnut, mutta imho oma on vähän yksinkertaisempi(hyvässä mielessä)
Perimmäisin ajatushan tässä uskoakseni on se, että näin toimimalla ei tarvitse kirjoittaa yhtä paljon HTML:ää ja PHP:tä sekaisin. Ja sehän on aina hyvä. Tämä lähestymistapahan on itse asiassa esim ASP.NETin peruslähtökohtia.
Kuriositeetti:
Pohja.xml:n ei tarvitse välttämättä olla XML:ää, eikä edes hyvinmuodostettu, koska meillä on DOMDocument::loadHTMLFile. https://www.php.net/manual/en/domdocument.
Triskal kirjoitti:
Perimmäisin ajatushan tässä uskoakseni on se, että näin toimimalla ei tarvitse kirjoittaa yhtä paljon HTML:ää ja PHP:tä sekaisin.
Näin on asian laita.
Triskal kirjoitti:
Pohja.xml:n ei tarvitse välttämättä olla XML:ää, eikä edes hyvinmuodostettu, koska meillä on DOMDocument::loadHTMLFile. https://www.php.net/manual/en/domdocument.
loadhtmlfile.php
Mitä konkreettista hyötyä on tuottaa epävalidia html höttöä, kun DOMDopcument::Load() hoitaa hommaan himaan ja asetuksista riippuen jopa kertoo tehdyt merkkausvirheet.
On tuolla kyllä aikas työläs koittaa vääntää sivuja. Esimerkki pätkä soittolistan generoinnista:
<?php $li = $list->appendChild( new DOMElement( 'li', " - " ) ); $artistSpan = $li->insertBefore( new DOMElement( 'span', $artist ), $li->firstChild ); $artistSpan->setAttribute( 'class', 'artist' ); $titleSpan = $li->appendChild( new DOMElement( 'span', $title ) ); $titleSpan->setAttribute( 'class', 'title' ); ?> Lopputuloksena siis: <li> <span class="artist">funk machine</span> - <span class="title">dance on the groove and do the funk</span> </li>
Sama perinteiseen malliin:
<?php $li = "<li><span class='artist'>$artist</span> - " . "<span class='title'>$title</span></li>\n";
Itseasiassa jälkimmäinen olisi se, mitä tuohon ylempäänkin oli tarkoitus laittaa, mutten keksinyt, miten tuon väliviivan saa edes DOM:lla toteutettua. Javascript tyylinen innerHTML-funktio olisi aika pop :D
Edit: keksinpäs sittenkin.. Ei vaan ensimmäisenä tullut mieleen ajatella, että tuolla $li:llä on lapsi.. Eihän tuo asioita mitenkään yksinkertaistanut. Viisi riviä vs. oneliner.. Edelleenkin se innerHTML tekisi tuosta vähän käyttökelpoisemman muussakin kuin akateemisessa näpräyksessä.. :-)
<?php /** * Aloitusjutut ... * $sivu = newDOMDocument * $con = $sivu->createElement("div"); * $body->appendChild($con); * . * . * . */ $ul = $sivu->createElement("ul"); $con->appendChild($ul); while($listan_alkioita){ $li = $sivu->createElement("li", "$artist - $title"); $ul->appendChild($li); }
Eli ei se nyt niin kamalan paljon hankalampi olekaan. Lisänä tulee tietty vielä tagien automaaginen sulkeminen.
Onko hankala lisätä eri koodeja kuten vaikkapa kävijälaskuri, google-mainokset, bannerinvaihto jne?
Tuo kirjautumislomake voisi olla ihan näkyvillä.
Tuo demosivu ei toimi.
Myös sisennykset kannattaa muistaa!