HTML mit PHP intelligent verkn├╝pfen

Musstest du schon einmal eine PHP-Webseite erstellen? Wie bist du dabei vorgegangen? Wahrscheinlich hast du dir zun├Ąchst eine HTML-Struktur vorbereitet und danach die PHP-Variablen oder Werte aus deiner Datenbank eingef├╝gt.

Den Header und Footer hast du dann wie ├╝blich in eigene Dateien ausgelagert.

 

Es gibt eine Menge verschiedener Herangehensweisen, wie die PHP-Variablen in einer HTML-Struktur ausgegeben werden k├Ânnen.

Sehr viele Content Management Systeme bauen ihren Inhalt ebenfalls auf einer HTML-Struktur auf und verbinden diese stark mit dem PHP-Algorithmus. Wenn du schon einmal mit einem WordPress- oder ModX-Template gearbeitet hast wei├čt du wovon ich schreibe.

Bei kleineren Projekten kann das durchaus ausreichen. Aber was, wenn mehrere Entwickler an einem riesigen Projekt arbeiten?

 

In den letzten Wochen habe ich mir ein anderes Konzept f├╝r die Aufbereitung von strukturierten Inhalten ├╝berlegt, um die Struktur klar vom Algorithmus zu trennen, nachdem mir das st├Ąndige Suchen nach einer bestimmten Struktur einfach zu viel Zeit in Anspruch genommen hatte.

Wenn du schon einmal mit Typo3 gearbeitet hast, wird dir dieses Konzept vielleicht bekannt vorkommen.

In diesem Beitrag m├Âchte ich dir meine Idee n├Ąher bringen. (Vorsicht: Du solltest bereits Erfahrungen mit PHP gesammelt haben)

Falls dir die Vererbung in PHP noch nicht g├Ąngig ist, findest du am Ende des Beitrags eine kleine Einf├╝hrung. Ich gehe nicht detailliert darauf ein, jedoch erh├Ąltst du einen Einblick in die Objekt Orientierte Programmierung mit PHP.

Die Idee: Verwendung von Strukturen und Platzhaltern

Die Grundidee ist relativ einfach erkl├Ąrt. F├╝r meinen Algorithmus verwende ich HTML-Dateien in denen verschiedene Platzhalter vorhanden sind.

Der PHP-Code beinhaltet eine Array, die aus den Platzhaltern und deren zu austauschenden Werte besteht.

Diese Art zu entwickeln hat mehrere Vorteile:

  • Man kann PHP-Klassen verwenden, die sich um unterschiedliche Bestandteile der Webseite k├╝mmern
  • Die Programmstruktur ist wesentlich einfacher aufgebaut, da es einen Ordner im Projekt gibt, der sich nur um die HTML-Strukturen k├╝mmert und einen, der sich ausschlie├člich um die Logik k├╝mmert
  • In WordPress kann man es externen Programmierern erleichtern die HTML-Strukturen zu bearbeiten, ohne das Webseiten-Template anzufassen
  • Die HTML-Strukturen mit dessen Platzhaltern k├Ânnen in CMS-Unabh├Ąngigen Systemen auch von Nicht-Programmierern bearbeitet werden, da man nur HTML-Kenntnisse ben├Âtigt
  • Platzhalter sind einfach erweiterbar, auch von externen Programmierern (Ebenfalls in WordPress-Projekten)
  • Die HTML-Elemente bleiben atomar und k├Ânnen sehr einfach in verschiedenen Ansichten wiederverwendet werden

Vorbereitung einer HTML-Struktur

Eine Struktur kann mithilfe einer einfachen HTML-Datei erstellt werden. Diese beinhaltet die Struktur inklusive Platzhalter.

Als Entwickler muss man sich f├╝r eine Platzhalter-Struktur entscheiden. Ich verwende gerne einen Key innerhalb zweier Prozentzeichen: %KEY%

Die HTML-Struktur kann zum Beispiel so aussehen:

<div %CLASS%>
	<img src="%IMAGE%" />
	<%HEADLINE_TAG%>%HEADLINE%</%HEADLINE_TAG%>
	%CONTENT%
</div>

Das ist ein sehr rudiment├Ąres Beispiel. Unser Inhalt wird von einem <div>-Tag umschlossen. Zudem kann dieses umschlie├čende Element eine Klasse besitzen, die von einem PHP-Code erstellt und mit dem Platzhalter %CLASS% ersetzt wird. Ich verwende nicht class='%CLASS%', da es auch vorkommen kann, dass das Attribut nicht ben├Âtigt wird. Andernfalls w├╝rde ein leeres Attribut class='' gesetzt werden.

Innerhalb des Elements gibt es ein Bild, eine ├ťberschrift und den Inhalt, wobei die ├ťberschrift von einem <h>-Tag umschlossen wird. Den Platzhalter %HEADLINE_TAG% kannst du auch entfernen und einen fixen Wert eintragen.

Da ich ├╝berwiegend WordPress-Entwickler bin, denke ich bei dem "H-Tag"-Platzhalter an einen Shortcode. ├ťber die Attribute dieses Shortcodes kann ein Redakteur das HTML-Tag w├Ąhlen. Dadurch wird das Element ein wenig dynamischer und anpassbarer.

Ein Platzhalter muss nicht nur eine einzelne Zeichenkette abbilden. Du kannst auch eine Struktur innerhalb einer anderen Struktur durch einen Platzhalter austauschen lassen, wodurch du du zum Beispiel in einer index.html den Header und Footer hinzuf├╝gen kannst.

Platzhalter f├╝r die Struktur definieren

Die Platzhalter werden als assoziative Array erstellt, damit wir den Platzhalter als Index verwenden k├Ânnen.

Der Wert des Array-Items stellt den Platzhalter dar, wodurch der Wert in der Array ersetzt werden soll.

Dank dieser Struktur k├Ânnen Frontend-Entwickler die Platzhalter jederzeit Verschieben, ohne den Backend-Entwickler zu konsultieren. Jedoch m├╝ssen die Backend-Programmierer beauftragt werden, falls neue Platzhalter ben├Âtigt werden.

<?php
	
	$placeholders = array(
		'CLASS'		=> 'content_container',
		'IMAGE'		=> '<img src="path/to/image.jpg" />',
		'HEADLINE'	=> 'Eine ├ťberschrift',
		'HEADLINE_TAG'	=> 'h3',
		'CONTENT'	=> '<p>Lorem ipsum dolor sit amet</p>'
	);
	
?>

Die Platzhalter werden sp├Ąter aus der Datenbank entnommen. Die Array oben soll nur als Beispiel dienen.

Im n├Ąchsten Schritt m├╝ssen wir die Platzhalter nur noch durch eine foreach-Schleife jagen, damit sie ausgetauscht werden.

 

Die Umsetzung der notwendigen Funktionen

Damit der Algorithmus f├╝r jede Struktur und alle m├Âglichen Platzhalter funktioniert, ben├Âtigen wir ein paar wesentliche Funktionen, die wir im Anschluss als PHP-Klasse umsetzen werden.

Zun├Ąchst erkl├Ąre ich dir aber den funktionellen Aufbau des Programms.

Ersetzen der Platzhalter

Wie bereits beschrieben, ben├Âtigen wir f├╝r das Austauschen der Platzhalter nur eine Schleife. Durch die Funktion str_replace werden die Platzhalter durch die tats├Ąchlichen Werte ersetzt.

<?php

function replace_strings( $structure, $replacements ) {
	
	// Durchl├Ąuft jeden einzelnen Platzhalter aus der Array "$replacements" und ersetzt die Vorkommnisse in der Variable "$structure"
	foreach( $replacements as $placeholder => $replacement ) {
		
		// Die Prozent-Zeichen kannst du auch durch andere, eindeutige Zeichen ersetzen. Bearbeite die entsprechenden Stellen auch in deiner Struktur!
		$placeholder = "%$placeholder%";
		$structure = str_replace( $placeholder, $replacement, $structure );
		
	}
	
	return $structure;
	
}

?>

Die HTML-Struktur laden

Nun ben├Âtigen wir eine Funktion, die die Struktur aus einer Datei l├Ądt. Du kannst auch einen Fallback innerhalb der Funktion angeben, falls die Funktion "file_get_contents" nicht auf dem Server funktioniert oder die Datei nicht existiert.

<?php

function get_container_structure() {
	
	// Sollte es die Datei "structure.html" geben, wird der Inhalt daraus unsere Content-Container Struktur
	$structure = "";
	$structure_file_path = "path/to/structure.html";
	if( file_exists( $structure_file_path ) ) {
		$structure = file_get_contents( $structure_file_path );
	}
	
	// Das ist ein Fallback, falls es unsere Struktur nicht gibt. Du kannst das Laden der Datei auch komplett entfernen, wenn du m├Âchtest.
	// Eine Alternative w├Ąre hier eine Fehlermeldung auszugeben, dass die Datei nicht geladen werden konnte.
	if( empty( $structure ) ) {
		ob_start();
		?>
			<div %CLASS%>
				<img src="%IMAGE%" />
				<%HEADLINE_TAG%>%HEADLINE%</%HEADLINE_TAG%>
				%CONTENT%
			</div>
		<?php
		$structure = ob_get_clean();
	}
	
	// Damit andere Entwickler ├änderungen an der Struktur vornehmen k├Ânnen, ohne unseren Code anzufassen, stellt WordPres die Funktion "appyly_filters" zur Verf├╝gung
	$structure = apply_filters( 'edit_container_structure', $structure );
	
	return $structure;
	
}

?>

Verwende ein Caching-Tool! Dadurch muss der Algorithmus nicht bei jedem einzelnen Aufruf der Webseite neu ausgef├╝hrt werden. Das Google Pagespeed Modul kannst du einfach auf deinem Webserver installieren und konfigurieren, um deine Inhalte zu cachen.

Vorbereitung der Platzhalter

Die Platzhalter kannst du nach belieben und pro Element bestimmen. Im nachfolgendem Beispiel verwende ich WordPress-Funktionen, um an die Text-Bausteine zu gelangen.

Du kannst bei einem unabh├Ąngigen System auch eine SQL-Abfrage starten, um die Daten in deinem PHP-Script vorzubereiten.

<?php

function get_container_replacements() {
	
	// Der nachfolgende Code ist f├╝r WordPress geeignet. Solltest du ein anderes CMS verwenden, kannst du die Platzhalter nach Belieben bearbeiten.
	global $post;
	$container_replacements = array(
		'CLASS'			=> get_classes( array( 'content_container', 'has_image' ) ),
		'IMAGE'			=> get_the_post_thumbnail_url( $post->ID, 'full' ),
		'HEADLINE'		=> $post->post_title,
		'HEADLINE_TAG'		=> 'h3',
		'CONTENT'		=> $post->post_excerpt
	);
	
	// Damit andere Entwickler weitere Platzhalter vorbereiten k├Ânnen, ohne unseren Code anzufassen, stellt WordPres die Funktion "appyly_filters" zur Verf├╝gung
	$container_replacements = apply_filters( 'edit_container_replacements', $container_replacements );
	
	return $container_replacements;
	
}

?>

Aufbereitung der CSS-Klassen

Mit einer Mini-Funktion zur Erstellung des Attributs "class" bist du an kein bestimmtes Element gebunden. Du kannst durch eine einfache Array alle notwendigen Klassen angeben.

Ich finde diese Art der Klassen-Aufbereitung sehr sch├Ân, da ich einfach nur eine Array angeben muss. Diese Daten k├Ânnen auch einfach zwischengespeichert, von anderen Entwicklern manipuliert oder weiterverarbeitet werden.

<?php

function get_classes( array $classes = array() ) {
	
	// Erstellt einen String aus der Array und f├╝gt diesen in ein Attribut "class" ein
	$classes = trim( join( " ", $classes ) );
	return "class='$classes'";
	
}

?>

Nicht ben├Âtigte Platzhalter entfernen

Sollten nicht alle Platzhalter in der $replacements-Array angegeben werden, die in der HTML-Struktur vorkommen, werden die Platzhalter 1 zu 1 im HTML-Code ausgegeben.

Damit das nicht geschieht, k├Ânnen alle Platzhalter die dem System fremd sind, nach dem ersetzen gel├Âscht werden.

Solltest du eine andere Platzhalter-Struktur als ich verwenden (%KEY%), musst du das RegEx in der Funktion preg_replace anpassen.

<?php

function clean_placeholders( string $structure = "" ) {
	
	// R├Ąumt alle Platzhalter auf, die durch das Ersetzen nicht ├╝berschrieben wurden
	return preg_replace( "/\%(.*)\%/gU", '', $structure );
	
}

?>

Meine Regular Expressions plane ich immer mit dem Tool Regex101. Damit kann ich genau ├╝berpr├╝fen, welche Bestandteile der Struktur ausgew├Ąhlt werden, bevor ich meinen Code teste.

Setze die Funktionen zusammen

Nachdem die wichtigsten Funktionen zusammengesetzt wurden, ben├Âtigen wir noch eine Funktion die alles zusammensetzt und ausgeben kann.

Zuerst wird die Struktur und die Platzhalter in Variablen gespeichert. Danach wenden wir die Funktion "replace_strings()" an, um die Platzhalter in der Struktur auszutauschen. Den R├╝ckgabewert sichern wir in einer Variable, bevor wir den "return" darauf anwenden. Dadurch haben wir sp├Ąter noch die M├Âglichkeit Filter anzuwenden.

Bevor das HTML-Element geliefert wird, sollen jedoch alle nicht-umgesetzten Platzhalter gel├Âscht werden. Dies geschieht durch unsere Funktion "clean_placeholders()".

<?php

function get_content_container() {
	
	// Erhalte die HTML-Struktur des Containers
	$container_structure = get_container_structure();
	// Erhalte alle Platzhalter des Containers
	$container_replacements = get_container_replacements();
	
	// Ersetze alle Platzhalter
	$parsed_container = replace_strings(
		$container_structure,
		$container_replacements
	);
	
	return clean_placeholders( $parsed_container );
	
}

?>
 

Eine Klasse als Vorlage erstellen

Damit wir diese Funktionen nicht immer wieder f├╝r verschiedene Elemente aufbauen m├╝ssen und damit wir eine bessere ├ťbersicht erhalten, bereiten wir uns aus diesen Funktionen eine Klasse auf.

Die Parent-Klasse "Structure" enth├Ąlt alle wichtigen Funktionen, die wir immer wieder verwenden k├Ânnen.

Eine Child-Klasse (als Beispiel "Container") verwendet die Funktionen der Parent-Klasse und f├╝gt die individuellen Elemente "Platzhalter" und "Struktur" ein.

Die Eltern-Klasse

Die Eltern-Klasse beinhaltet alle Funktionen, die immer wieder ben├Âtigt werden. Damit du dich hier zurechtfindest, habe ich die Funktionsnamen aus dem obigen Beispiel nicht ge├Ąndert. Du kannst sie nat├╝rlich nach belieben anpassen.

Folgende Funktionen ben├Âtigt unsere Parent-Klasse:

  • Der Konstruktor bereitet die wichtigen Variablen vor. Damit sind die Struktur und die Platzhalter gemeint.
  • Die Funktion zur R├╝ckgabe des umgesetzten HTML-Elements "get_content_container()"
  • Die Funktion zum Austauschen der Platzhalter "replace_strings()"
  • Eine Funktion zum Erhalt der Platzhalter "get_container_replacements()". Diese wird sp├Ąter von der Child-Klasse ├╝berschrieben. Du kannst auch eine abstrakte Funktion daraus erstellen.
  • Die abstrakte Funktion "get_container_structure()". Diese muss in der Child-Klasse erstellt werden.
  • Eine Funktion "get_container_structure_from_file()" hilft beim Erhalt der Struktur aus einer Datei. Der Pfad wird im Konstruktor der Parent-Klasse angegeben.
  • Die Funktion "get_classes()" bereitet die ├╝bergebene Array als HTML-Attribut "class" auf und gibt diese zur├╝ck.
  • Zuletzt die Funktion "clean_placeholders()", die alle Platzhalter einer HTML-Struktur entfernt. Sie sollte erst nach der Funktion "replace_strings()" aufgerufen werden.
<?php
	
	abstract class Structure {
		
		protected $structure_file_path;
		protected $replacements;
		function __construct( string $structure_file_path = "", array $replacements = array() ) {
			
			$this->structure_file_path = $structure_file_path;
			$this->replacements = $replacements;
			
		}
		
		public function get_content_container() {
			
			$container_structure = $this->get_container_structure();
			$container_replacements = $this->get_container_replacements();
			
			$parsed_container = $this->replace_strings(
				$container_structure,
				$container_replacements
			);
			
			return $this->clean_placeholders( $parsed_container );
			
		}
		
		protected function replace_strings( string $structure, array $replacements = array() ) {
			
			foreach( $replacements as $placeholder => $replacement ) {
				
				$placeholder = "%$placeholder%";
				$structure = str_replace( $placeholder, $replacement, $structure );
				
			}
			
			return $structure;
			
		}
		
		protected function get_container_replacements() {
			
			$container_replacements = $this->replacements;
			return $container_replacements;
			
		}
		
		abstract protected function get_container_structure();
		
		protected function get_container_structure_from_file() {
			
			$structure = "";
			if( !empty( $this->structure_file_path ) && file_exists( $this->structure_file_path ) ) {
				$structure = file_get_contents( $this->structure_file_path );
			}
			
			return $structure;
			
		}
		
		protected function get_classes( array $classes = array() ) {
			
			// Erstellt einen String aus der Array und f├╝gt diesen in ein Attribut "class" ein
			$classes = trim( join( " ", $classes ) );
			return "class='$classes'";
			
		}
		
		protected function clean_placeholders( string $structure = "" ) {
			
			return preg_replace( "/\%(.*)\%/gU", '', $structure );
			
		}
		
	}
	
?>

Die Kind-Klasse

Die nachfolgende Kind-Klasse kannst du als Vorlage f├╝r alle weiteren Elemente verwenden. Wichtig ist, dass du die Platzhalter als Array und die HTML-Struktur vorbereitest bevor du die Funktion testest.

Der Pfad der HTML-Struktur wird an die Eltern-Klasse ├╝bergeben. Genauso wie die R├╝ckgabe der Funktion "get_container_replacements()", die die Platzhalter-Array zur├╝ckgibt.

Die Struktur soll durch einen WordPress-Filter von einem externen Programmierer bearbeitet werden k├Ânnen. Deshalb wird die Funktion "get_container_replacements()" nicht in der Eltern-Klasse erstellt. Durch die eigenst├Ąndige Funktion k├Ânnen wir einen individuellen Filter-Aufruf "edit_container_replacements" definieren.

<?php
	
	class Container extends Structure {
		
		function __construct() {
			
			parent::__construct( 'path/to/container.html', $this->get_container_replacements() );
			
		}
		
		protected function get_container_replacements() {
			
			global $post;
			$container_replacements = array(
				'CLASS'			=> $this->get_classes( array( 'content_container', 'has_image' ) ),
				'IMAGE'			=> get_the_post_thumbnail_url( $post->ID, 'full' ),
				'HEADLINE'		=> $post->post_title,
				'HEADLINE_TAG'		=> 'h3',
				'CONTENT'		=> $post->post_excerpt
			);
			
			$container_replacements = apply_filters( 'edit_container_replacements', $container_replacements );
			
			return $container_replacements;
			
		}
		
		protected function get_container_structure() {
			
			$structure = $this->get_container_structure_from_file();
			if( !empty( $structure ) ) {
				
				return $structure;
				
			}
			
			$structure = apply_filters( 'edit_container_structure', $structure );
			
			return $structure;
			
		}
		
	}
	
?>

Ein Element aus der Kind-Klasse erhalten

Damit dein Element auf deiner Webseite erscheint, muss diese noch auf deiner eigentlichen Seite platziert werden.

Bevor du das Element verwenden kannst, musst du eine neue Variable (im nachfolgenden Beispiel "$container") erstellen in der das Object "Container" definiert ist.

Mit einem "echo" und dem Funktions-Aufruf "get_content_container()" wird dann das umgesetzte HTML-Konstrukt auf deiner Webseite ausgegeben.

<?php
	
	$container = new Container();
	echo $container->get_content_container();
	
?>

Beispiel f├╝r das atomare PHP herunterladen

Damit du den Aufbau der Ordner-Struktur meines Skripts richtig verstehst, habe ich dir alles in einer ZIP-Datei vorbereitet.

Du findest in dieser Datei eine index.php, die die Container-Klasse erstellt. Der Ordner "structures" beinhaltet alle HTML-Strukturen die du auch nach Belieben in Unterordner packen kannst. Im Ordner "inc" findest du die PHP-Klassen.

Beispiel herunterladen

Fazit

Durch das "Aufbrechen" der verschiedenen Webseiten-Bestandteile und Elemente werden Strukturen von der Logik strikt getrennt.

Somit k├Ânnen gro├če Teams Aufgaben auch wesentlich besser aufteilen, indem man ein Teil des Teams f├╝r die Erstellung der HTML-Strukturen und CSS-Stile einteilt und ein anderes Team ausschlie├člich f├╝r die Programmierung.

Diese saubere Trennung der Webseiten-Bestandteile f├╝hrt zu einer Optimierung der Kernt├Ątigkeiten und somit eine Fokusierung der einzelnen Mitarbeiter. Zudem resultiert diese Trennung in einer besseren ├ťbersichtlichkeit des Programmcodes, dadurch k├Ânnen neue Mitarbeiter schneller in ein bestehendes Projekt einsteigen.

 

Hat dir mein Beitrag gefallen? Schreibe mir in den Kommentaren, wie du in deinen Projekten vorgehst!

 

Codepalm
Atomare Webseiten-Struktur mit HTML und PHP