Lav dit eget CMS - del 2 4. okt 2010

Du har gennemgået Lav dit eget CMS - del 1 og er nu klar til næste skridt

Du har lavet dine sider om til .php og de inkluderer nu alle sammen den samme menu-komponent. Når du skal tilføje en ny side, skal den altså kun tilføjes menu.php – ah, hvilken lyksagelighed!

Det næste skridt – markér den aktive side i menuen

Men nu er menuen jo ens på alle sider – altså helt ens – det ville være praktisk hvis den kunne finde ud af at markere hvilken side der p.t. bliver vist. Førhen, da hver eneste side havde sin egen udgave af menuen, kunne du bare tilføje class="active" til <li>-tag'et for den aktuelle side, men nu deles alle siderne om den samme menu-komponent, så hvad stiller man op?

Det viser sig at PHP faktisk godt ved hvilken side der p.t. bliver vist, og eftersom du allerede er i gang med at indføre noget PHP-kode, hvorfor så ikke bare fortsætte. En .php fil kaldes også for et script (et script er et lille program) og variablen $_SERVER["SCRIPT_NAME"] indeholder altid den fulde adresse på den aktuelle PHP-fil. Din forside hedder forside.php, og fordi den ligger i roden af din hjemmeside – altså på adressen www.hjemmeside.dk/forside.php – så vil dens SCRIPT_NAME være /forside.php – med skråstregen!

Variabler i PHP starter altid med dollartegn ($), og de fleste interne variabler – dem der ikke er defineret af dine egne programmer – har en underscore (_) umiddelbart efter. Firkantparenteser angiver at variablen er et associativt array (det der også kaldes dictionaries eller maps i andre programmeringssprog) altså at variablen indeholder flere navngivne variabler – variablen $_SERVER indeholder for eksempel også "REMOTE_ADDR" der fortæller os ip-adressen på den browser der viser siden.

Da menu.php altid bliver inkluderet af en anden .php-fil, vil SCRIPT_NAME være den inkluderende php-fil, og ikke menu.php. Det vil sige at menu-komponenten kan finde ud af hvilken side den p.t. bliver vist af. Så hvis du ændrer hvert eneste <li>-tag til at teste om linket er til den aktuelt viste side, og i så fald skrive class="active", så begynder din menu at se mere rigtig ud.

I PHP tester man om to variabler er ens ved at skrive

if( $variabel1 == $variabel2 ) {
 … php-kode der skal udføres hvis de er ens …
}

Altså if, efterfulgt af en parentes med det udtryk man ønsker at teste, efterfulgt af en tuborg-parentes med det kode der skal udføres. For at teste om den aktuelle side svarer til /forside.php skal du altså skrive:

if( $_SERVER["SCRIPT_NAME"] == "/forside.php" ) {

Husk at der skal være to lighedstegn efter hinanden – hvis du kun skriver et enkelt, vil PHP forsøge at ændre den første variabel, så den er lig med den anden. Med andre ord betyder x = y, det samme som "sæt x lig med y" mens x == y, er spørgsmålet "er x lig med y?".

Her i dit tilfælde er der jo faktisk ikke noget PHP-kode der skal udføres – der skal bare stå class="active" i den færdige webside. Det er måske lige på sin plads at genopfriske hvordan den færdige webside bygges op. Normalt læser webserveren en .htm-fil og sender den tegn for tegn ud på internettet, men med en .php-fil bliver der kun sendt tegn ud indtil webserveren møder <?php i filen – derefter bliver der udført PHP-kode, og først efter ?> bliver filens indhold igen sendt ud. Men der er ikke noget krav om at PHP-koden skal være et sammenhængende program før der bliver afsluttet med ?> – det vil sige at du sagtens kan sende tekst ud til den færdige webside midt i din PHP-kode, eller for eksempel i den tuborg-parentes afgrænsede blok der kun skal udføres i tilfælde af at det foregående if-udtryk går op.

Tyg lige lidt på den, og se hvordan dit <li>-tag for forsiden kommer til at se ud:

<li <?php if($_SERVER["SCRIPT_NAME"] == "/forside.php") { ?> class="active" <?php } ?> >

Hvis den aktuelle side svarer til "/forside.php" så bliver PHP-koden i mellem { og } udført – men der er slet ikke noget PHP-kode, i stedet afsluttes PHP, og teksten class="active" bliver sendt ud som en del af den færdige webside. Hvis if-udtrykket derimod ikke går op, så springer webserveren over { } og alt hvad der står imellem dem – også selv om noget af det ikke er PHP-kode. Fancy!

Hvis du synes at det er lige lovligt svært at kapere, så frygt ikke – det er faktisk en grim måde at skrive sin PHP-kode på, for det kan meget hurtigt gå hen og blive helt uoverskueligt hvad der egentlig bliver til en del af den færdige webside. Der er mere elegante metoder, og en af dem lærer du senere i denne artikel.

Men nu er det jo bare at gentage mønsteret for samtlige menupunkter.

<div id="menu">
<ul>
<li <?php if( $_SERVER["SCRIPT_NAME"]=="/forside.php") { ?>
class="active" <?php } ?> ><a href="/forside.php">forsiden</a></li>

<li <?php if( $_SERVER["SCRIPT_NAME"]=="/om.php") { ?>
class="active" <?php } ?> ><a href="/om.php">Om os</a></li>

<li <?php if( $_SERVER["SCRIPT_NAME"]=="/produkter.php") { ?> 
class="active" <?php } ?> ><a href="/produkter.php">Produkter</a></li>

<li <?php if( $_SERVER["SCRIPT_NAME"]=="/kontakt.php") { ?>
class="active" <?php } ?> ><a href="/kontakt.php">Kontakt</a></li>

</ul>
</div>

For hvert eneste menupunkt, altså hvert eneste <li>-tag, tester PHP-koden om SCRIPT_NAME, altså den aktuelle side, svarer til den side som der linkes til i det pågældende menupunkt – og hvis det er tilfældet, så bliver class="active" tilføjet til <li>-tag'et.

Det virker fortrinligt, nu har du en menu-komponent der kan vise den valgte side, og du behøver ikke ændre mere end et sted – eller i hvert fald ikke i mere end én fil – når der skal ændres i menuen.

Undgå gentagelser – gør det lidt elegant og funktionelt

Nu var ideen med denne her menu-komponent jo fortrinsvist at undgå gentagelser, og det er da delvist lykkedes, men prøv engang at kigge nærmere på selve menu-komponenten. Hver eneste linje ligner en gentagelse af den foregående – kun linket og menupunktets navn er til forskel. Hvis du vil tilføje et menupunkt, skal du altså kopiere en eksisterende linje, ændre det der står i <a>-tag'ets indhold og href-attribut, og huske at skrive det samme ind i sammenligningen med SCRIPT_NAME. Det er måske ikke ligefrem besværligt, men det er lidt kikset, og det er den slags gentagelser vi gerne vil undgå.

Når man som programmør støder på gentagelser, så pakker man dem enten ind i en løkke eller en funktion. En løkke udfører en gruppe programlinjer et forudbestemt antal gange, en funktion udfører en gruppe programlinjer hver gang den bliver kaldt, og kan altså kaldes fra mange forskellige dele af et program. En løkke er især anvendelig hvis programlinjerne skal gøre præcis det samme hver gang, eller hvis den eneste ting der varierer er en form for tæller der viser hvor langt i løkken man er. En funktion er især anvendelig når der er andet og mere der varierer, og da du ikke rigtig har nogen tæller, men fire forskellige sider du vil vise links for, så lav en funktion!

Det er nemt at lave funktioner i PHP, du skriver blot function og et navn for funktionen efterfulgt af et sæt almindelige parenteser og et sæt tuborg-parenteser til at indkapsle de kodelinjer der skal indgå i funktionen. Så for at lave en funktion kaldet menulink, skal du skrive:

<?php
	function menulink() {
		… noget PHP-kode …
	}
?>

Det er tit enklest at lave en funktion så den udfører én meget bestemt opgave – og først når det virker, så kan man bruge tid på at gøre den mere generel. Så start med at lade menulink-funktionen lave et <li>-tag til forsiden – og når det engang virker, så gør den mere generel, så den kan lave et hvilket som helst <li>-tag i menuen.

Det første skridt er at kopiere PHP-koden der laver <li>-tag'et ind i funktionen … men nu var der jo ikke ret meget PHP-kode, nærmere noget HTML med en smule indlejret PHP-kode. Det er dog ikke noget problem, for man kan sagtens stoppe og starte PHP med ?> og <?php inde i en funktion – det kommer til at gælde hver gang funktionen bliver udført, og altså ikke kun her hvor funktionen bliver oprettet. Så start din funktion med at stoppe PHP, og kopiér derefter et <li>-tag fra det foregående program ind, og husk at starte PHP igen før funktionen afsluttes med }.

<?php
	function menulink() { ?>
<li <?php if( $_SERVER["SCRIPT_NAME"]=="/forside.php") { ?> class="active" <?php } ?> ><a href="/forside.php">forsiden</a></li>
<?php
	}
?>

Så har du en fin funktion der kan lave et link til forsiden. For at bruge funktionen skal du blot skrive dens navn efterfulgt af parenteser, på det sted i PHP-koden hvor den skal udføres.

For eksempel kan du ændre din menu til noget i stil med

<div id="menu">
<ul>
<?php
   menulink();
?>
<li <?php if( $_SERVER["SCRIPT_NAME"]=="/om.php") { ?> class="active" <?php } ?> ><a href="/om.php">Om os</a></li>
… 
og så videre

Det er i øvrigt god skik at afslutte sine PHP-kodelinjer med semikolon. Det fortæller at den pågældende linje er slut, og at linjeskiftet ikke blot er der af kosmetiske grunde.

Og nu vi taler om kosmetik, så er menulink-funktionen jo egentlig ret grim – og lidt uoverskuelig med de mange gange PHP bliver startet og stoppet. I stedet for at stoppe PHP for at sende tekst ud til den færdige webside, så kan man bruge PHP-kommandoen echo til det. Skriv echo efterfulgt af den tekst du vil have ud på den færdige webside – teksten skal være omgivet af anførselstegn, så du er nødt til at bruge apostroffer rundt om class og href-attributterne. Her er et bud på en noget pænere menulink-funktion:

function menulink() {
	echo "<li";
	if( $_SERVER["SCRIPT_NAME"]=="/forside.php") { echo "class='active'"; }
	echo ">";
	echo "<a href='/forside.php'>";
	echo "forsiden";
	echo "</a></li>";
}

Bemærk at der ikke skal være semikolon efter tuborg-parenteser.

Det er noget mere overskueligt nu – de første linjer laver <li>-tag'et, hvor linje 3 indsætter et eventuelt class='active' og de de sidste linjer laver <a>-tag'et med linket i linje 5 og navnet i linje 6. Det eneste problem er at funktionen kun kan lave menupunktet for forsiden, og den skulle jo gerne være lidt mere generel.

For at lave et menupunkt for en anden side end forsiden, skal linket i linje 3 og 5 og navnet i linje 6 ændres. Alt det andet er det samme – kun de to ting varierer, og når noget varierer, så bruger man en variabel. Der skal være én variabel for navnet og en anden for linket – kald de to for henholdsvis $name og $link (som du læste i starten af denne artikel, så starter variabler i PHP altid med et dollartegn). Ret så i funktionens PHP-kode, og erstat "/forside.php" med $link og "forsiden" med $name, således:

	echo "<li";
	if( $_SERVER["SCRIPT_NAME"] == $link ) { echo "class='active'"; }
	echo ">";
	echo "<a href='$link'>";
	echo $name;
	echo "</a></li>";
}

Når du vil udskrive indholdet af en variabel til den færdige webside, så er det ikke nødvendigt med anførselstegn. Variabler virker fint både med og uden anførselstegn, noget du måske ikke ligefrem er vant til fra andre programmeringssprog. Men sådan er PHP så – ja, anderledes …

De to variabler skal noget indhold, altså de skal sættes til at være henholdsvis "/forside.php" og "forsiden" første gang funktionen kaldes, "/om.php" og "Om os" anden gang, og så fremdeles. Det er her parentesen efter funktionsnavnet kommer ind – den skal indeholde en liste over de variabler der bliver brugt i funktionen. I funktionserklæringen, altså der hvor du opretter funktionen, skal der stå navnene på variablerne, og i funktionskaldet, altså der hvor du bruger funktionen, skal der stå indholdet af variablerne. Det vil sige at funktionen skal oprettes således:

function menulink( $link, $name ) { 

Og den skal kaldes således, når den skal bruges til at lave menupunktet til forsiden:

menulink( "/forside.php", "forsiden");

og således til om-siden:

menulink( "/om.php", "Om os");

Og så videre i samme stil. Alt i alt kommer den nye samlede menu-komponent til at se sådan ud:

<div id="menu">
<?php
function menulink( $link, $name ) {
	echo "<li ";
	if( $_SERVER["SCRIPT_NAME"] == $link ) { echo "class='active'"; }
	echo ">";
	echo "<a href='$link'>";
	echo $name;
	echo "</a></li>";
}

echo "<ul>";
menulink( "/forside.php", "forsiden" );
menulink( "/om.php", "Om os" );
menulink( "/produkter.php", "Produkter" );
menulink( "/kontakt.php", "Kontakt" );
echo "</ul>";
?>
</div>

Menulink-funktionen udføres fire gange, en for hvert menupunkt. Så nu er det meget nemt at redigere i menuen – tilføj, fjern og ændr et menulink-funktionskald, og menuen vil automatisk få markering af den aktive side, og korrekt link og det hele. Hvis du får lyst til at ændre noget i <li> eller <a>-tag'ene for hvert eneste punkt, så er det også nemt at rette inde i menulink-funktionen.

Opsummering

Det begynder at ligne et smart system det her! Og du kan i den grad læne dig stolt tilbage, for det har da været en ordentlig mundfuld denne gang. Lige for at opsummere:

  • Webserveren læser .php filer, og sender HTML direkte videre, mens PHP-kode bliver udført.

  • <?php og ?> bliver brugt til at skifte mellem PHP-kode og HTML i .php filen.

  • Du kan lave en blok PHP-kode ved at indkapsle den i tuborg-parenteser { }.

  • Du kan skifte mellem PHP-kode og HTML i en tuborg-blok, og HTML bliver kun sendt videre hvis PHP-koden også bliver udført.

  • En if-sætning bruges til at udføre en blok kode, hvis for eksempel to variabler er ens.

  • Du sammenligner to variabler med dobbelt-lighedstegn ==

  • Variabler i PHP har altid et navn der starter med $

  • Du kan lave en funktion ved at skrive function efterfulgt af funktionens navn, efterfulgt af en parentes med en liste over navnene på de variabler funktionen skal modtage, efterfulgt af en tuborg-parentes-blok med PHP-koden for funktionen.

  • Du kalder/udfører en funktion ved at skrive dens navn, efterfulgt af en parentes med indholdet til de variabler den skal modtage.

  • PHP-linjer bør afsluttes med semikolon.

  • Du kan udskrive HTML med kommandoen echo – tekst skal være indkapslet i anførselstegn, men variabler behøver ikke.

Leg endelig videre med koden, eksperimenter, prøv forskellige ideer – måske det ikke lykkes i første omgang, men så gem ideen, og se om de kommende artikler hjælper dig mere på vej!

Og giv mig endelig nogle kommentarer hvis der er noget du undrer dig over, eller noget du synes kunne være forklaret anderledes.

Tilføj kommentar

www.peterlind.dk

Nyeste blog-indlæg