PHP/Tutorials/Templates/Verarbeitung

Aus SELFHTML-Wiki
< PHP‎ | Tutorials‎ | Templates
Wechseln zu: Navigation, Suche

Bei der Verarbeitung von Daten innerhalb der Geschäftslogik kommt es zwangsläufig dazu, dass ein Ergebnis ausgegeben werden muss. Das bedeutet, dass im HTML-Dokument, das an den Browser gehen wird, dieses Ergebnis an irgendeiner Stelle mit passendem HTML-Code versehen eingetragen werden muss. Aber wie und wo? Und wann soll das wo in welchem Teil des PHP-Programms entschieden werden?

Die Idee mit den festen Seitenbestandteilen

Kehren wir zurück zu unserem ersten Beispiel aus der Einführung, in dem wir feste Bestandteile der Seite mittels include-Anweisungen eingefügt haben. Das Beispiel war unnötig stark aufgeteilt worden, um zu zeigen, welche Problematiken sich beim Zusammensetzen ergeben. Wie wäre es denn, wenn wir

  1. mit einem vollständigen und korrekten HTML-Dokument anfingen, in dem die festen Seitenbestandteile schon alle eingetragen stehen und
  2. dann nur die angeforderten Inhalte dynamisch eingefügt werden müssen?
vollständiges HTML-Dokument als Vorlage
<!DOCTYPE html>
<html lang="de">
  <head>
    <meta charset="utf-8">
    <title>Unsere Firma</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <header>
      <a href="/">Unsere Firma - Kompetenz in allen Fingern</a>
    </header>
    <main>
      <h1>Willkommen auf unserer Website!</h1>
      <p>Das Motto unserer Firma ist "Kompetenz in allen Fingern",
         denn bei uns arbeitet mehr als nur eine Hand.</p>
    </main>
    <nav>
      <h2>Unterseiten</h2>
      <ul>
        <li><a href="products.html">Produkte</a></li>
        <li><a href="team.html">Wer wir sind</a></li>
        <li><a href="contact.html">Kontakt/Impressum</a></li>
      </ul>
    </nav>
    <footer>(C) 2010 Unsere Firma</footer>
  </body>
</html>

Für ein so simples Konzept wie eine online-Visitenkarte mit wenigen Unterseiten ist dieses Template schon fast die fertige Seite. Wenn also die Homepage (im Sinne von "Einstiegsseite") aufgerufen wird, kann das Template unverändert an den Browser gegeben werden. Soll allerdings eine Unterseite ausgegeben werden, so müsste nur der Inhalt des <main>-Elements ausgetauscht werden.

Unterseiten mit „ohne“

Die Inhalte der jeweiligen Unterseite könnten dann in einem ganz kahlen aber vollständigen HTML-Dokument stehen:

Unterseite als HTML-Dokument
<!DOCTYPE html>
<html lang="de">
  <head>
    <meta charset="utf-8">
    <title>Wer wir sind</title>
  </head>
  <body>
    <h1>Wer wir sind</h1>
    <p>Wir sind ein mittelständisches Unternehmen,
       das sich zufriedene Kunden auf seine Fahnen
       geschrieben hat.</p>
  </body>
</html>

Aus dem HTML-Dokument der Unterseite benötigen wir den Inhalt des title- und des body-Elements, um ihn in unserem Template-Dokument einzufügen. Im Falle des Seitentitels bietet es sich an, den vorherigen Inhalt dort stehen zu lassen und den Titel der Unterseite davor einzufügen. Was den Inhalt des body-Elements betrifft, so ersetzt er alles, was im Template-Dokument im main-Element stand:

gewünschtes Ergebnis
<!DOCTYPE html>
<html lang="de">
  <head>
    <meta charset="utf-8">
    <title>Wer wir sind - Unsere Firma</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <header>
      <a href="/">Unsere Firma - Kompetenz in allen Fingern</a>
    </header>
    <main>
    <h1>Wer wir sind</h1>
    <p>Wir sind ein mittelständisches Unternehmen,
       das sich zufriedene Kunden auf seine Fahnen
       geschrieben hat.</p>
    </main>
    <nav>
      <h2>Unterseiten</h2>
      <ul>
        <li><a href="index.php/products">Produkte</a></li>
        <li><a href="index.php/team">Wer wir sind</a></li>
        <li><a href="index.php/contact">Kontakt/Impressum</a></li>
      </ul>
    </nav>
    <footer>(C) 2010 Unsere Firma</footer>
  </body>
</html>

Man erkennt es an der nicht ganz passenden Einrückung, dass hier der body-Inhalt ersatzweise eingefügt wurde. Auch am Seitentitel erkennt man die Veränderung im Vergleich.

Zusammenführen von Inhalt und Vorlagen

Bei der Verwendung der DOM-Klassen ist eine solche Ersetzung schnell gemacht.

Zusammenführen der Vorlagen
<?php
// home.html as default
$tmp = DOMDocument -> loadHTMLFile('home.html');

// nur Demo - wir sparen uns hier den Mechanismus
// zur echten Erkennung der gewünschten Seite
$requested = 'team';

if (is_file("$requested.html")) {
  $page = DOMDocument -> loadHTMLFile("$requested.html");

  // get <title> contents
  $title = '';

  foreach ($page -> getElementsByTagName('title') as $node) {
    $title = $node -> textContent;
  }

  // into template
  foreach ($tmp -> getElementsByTagName('title') as $node) {
    $node -> insertBefore(
      $tmp -> createTextNode("$title - "),
      $node -> firstChild
    );
  }

  // insert <body> contents into template's <main>
  foreach ($tmp -> getElementsByTagName('main') as $main) {

    // empty <main>
    while ($main -> firstChild) {
      $main -> removeChild($main -> firstChild);
    }

    // copy contents into template
    foreach ($page -> getElementsByTagName('body') as $body) {

      while ($body -> firstChild) {

        $main -> appendChild(
          $tmp -> importNode($body -> firstChild, true)
        );

        // remove copied node from original
        $body -> removeChild($body -> firstChild);
      }
    }
  }
}

echo $template -> saveHTML();
In der ersten Zeile wird unsere Template-Datei in ein DOMDocument-Objekt eingelesen. In der letzten Zeile wird das DOMDocument-Objekt zu HTML-Code serialisiert und an den Browser ausgegeben. Für die Startseite mag das als völlig unnötig erscheinen, aber sollte im HTML-Code ein formaler Fehler sein, so wird der Browser durch die DOMDocument-Klasse garantiert mit korrektem HTML beliefert.

Die Methode getElementsByTagName liefert eine Array-artige Liste an gefundenen Elementknoten zurück, in der jeweils nur ein Element vorhanden sein sollte. Der Einfachheit halber wurde der Zugriff auf dieses innerhalb einer foreach-Schleife notiert, obwohl es höchstens eines gibt. Falls der Elementknoten aber nicht gefunden werden sollte, so wird die Schleife überhaupt nicht ausgeführt. Ohne Schleife hätten wir mühsam die Existenz des Elementknotens prüfen müssen und eine if-Verzweigung gebraucht.

Das Umkopieren aus der Unterseite ins Template benötigt zwei eigenständige Instanzen der DOMDocument-Klasse, für jede HTML-Datei eine eigene. Damit das Template-Dokument einen DOM-Knoten aus dem anderen Dokument verarbeiten kann, muss dieser mittels importNode zuerst ins eigene Dokument importiert werden. Der zweite Parameter (hier mit dem Wert true) entscheidet, ob Kindknoten ebenfalls importiert werden sollen.

Diese Art Template ist die einfachste. Man nimmt im Grunde fertige Bausteine und fügt sie passend aneinander. Damit die formale Korrektheit des HTML-Codes gegeben ist, greift man auf eine Klasse zurück, die diese Korrektheit garantiert.

ToDo (weitere ToDos)

Dieses Tutorial beschreibt die Grundlagen.
Interessant wäre es, jetzt alle HTML-Dokumente eines Ordners zu erfassen und neben header und footer auch eine Navigation zu erstellen. Diese würde aus den Dateinamen (URL) und den Inhalten der title-Elemente vom Script automatisch erstellt werden.

Dabei könnte auf das Beispiel im 2. Kapitel (PHP/Tutorials/Templates/Dateien_mit_include_nachladen#Auslagern_der_Navigation) zurückgegriffen werden.

--Matthias Scharwies (Diskussion) 14:59, 21. Okt. 2022 (CEST)