MVC - Part I

Hier möchte ich zeigen, wie ein einfacher MVC mittels einer Request-Klasse so erweitert wird, dass man damit mehrere Templates ansprechen kann. Wir werden sehen, daß dieses Beispiel nicht wirklich intelligent ist, da wir im aktuellen Fall doch wieder statischen Code in unserem Template haben (seite1.tpl.php).

Natürlich könnte man, je nach übergebenen Request, jetzt im Controller eine umfangreiche Switch-Abfrage starten. Diese könnte, je nach Request, Daten aus dem Model holen und an die Templates übergeben. Naja, man kann es aber auch besser bauen, das soll dann im Part II kommen. 

Dieses Beispiel dient also nur der Implementierung einer Request-Klasse und soll nicht als Vorbild dienen :) Die Request-Klasse selber wurde mir schon vor Jahren von einem befreundeten Programmierer gegeben und seitdem x-mal modifiziert. Für unser Beispiel ist sie fast schon zu mächtig, aber ich wollte sie trotzdem nicht kürzen.

./index.php
define ('BASEPATH', realpath(dirname(__FILE__)));
include(BASEPATH.DIRECTORY_SEPARATOR.'classes' .DIRECTORY_SEPARATOR.'autoload.class.php');

$controller = new Controller();
echo $controller->display();
./classes/autoload.class.php
function __autoload ($classe) {
	
	$class = strtolower($classe);	
	$class = $class.'.class.php';
	
	if (file_exists(BASEPATH.DIRECTORY_SEPARATOR.'classes' .DIRECTORY_SEPARATOR.$class)) {
		include(BASEPATH.DIRECTORY_SEPARATOR.'classes' .DIRECTORY_SEPARATOR.$class);
	}
}
./classes/controller.class.php
class Controller {

	private $template;
	private $view;
	private $data;
	private $request;

	public function __construct() {
		
		// Das bisherige Script wird um den Request erweitert ...
		
		$this->request = new Request();
		
		// ... und soll jetzt ein anderes Template, je nach Request laden
		// ... der benoetigte Request-Parameter soll 'template' sein
		// ... Beispielsweise index.php?template=seite1
		
		$this->view = new View($this->request->getVar('template'));
		$this->data = Model::getData();
	}

	public function display() {
		
		$this->view->setContent("title", "OOP mit PHP");
		$this->view->setContent("content", $this->data);
		$this->view->setContent("footer", "&copy 2011 by mausernetwork\n");

		return $this->view->parseTemplate();
	}

}
./classes/request.class.php
class Request {
	
	protected $_request = array (
			'METHOD' => array (),
			'GET' => array (),
			'POST' => array (),
			'COOKIE' => array (),
			'FILES' => array (),
			'SERVER' => array (),
			'ENV' => array () 
	);
	protected $_params = array ();
	protected $_requestUri;
	protected $_baseUrl;
	protected $_pathInfo;
	protected $_method;
	
	
	public function __construct() {
		
		$this->_request ['GET'] 	= & $_GET;
		$this->_request ['POST'] 	= & $_POST;
		$this->_request ['COOKIE'] 	= & $_COOKIE;
		$this->_request ['FILES'] 	= & $_FILES;
		$this->_request ['SERVER'] 	= & $_SERVER;
		$this->_request ['ENV'] 	= & $_ENV;
		
		$this->_method = strtoupper ( $this->_request ['SERVER'] ['REQUEST_METHOD'] );
		
		switch ($this->_method) {
			case 'POST' :
				$this->_request ['METHOD'] = & $this->_request ['POST'];
				break;
			case 'COOKIE' :
				$this->_request ['METHOD'] = & $this->_request ['COOKIE'];
				break;
			case 'GET' :
			default :
				$this->_request ['METHOD'] = & $this->_request ['GET'];
		}
		
		$this->setVar ( 'REQUEST_URI', $this->getRequestUri (), 'SERVER' );
		$this->setVar ( 'PATH_INFO', $this->getPathInfo (), 'SERVER' );
	}
	
	
	public function __get($name) {
		
		if (isset ( $this->_request ['METHOD'] [$name] )) {
			return $this->_request ['METHOD'] [$name];
		}
		return null;
	}
	
	
	public function __set($name, $value) {
		$this->_request ['METHOD'] [$name] = $value;
	}
	
	
	public function __isset($name) {
		return isset ( $this->_request ['METHOD'] [$name] );
	}
	
	
	public function has($name) {
		return $this->__isset ( $name );
	}
	
	
	public function get($name, $default = null) {
		
		if ($this->__isset ( $name )) {
			return $this->__get ( $name );
		}
		return $default;
	}
	
	
	public function set($name, $value) {
		$this->__set ( $name, $value );
	}
	
	
	public function getVar($name, $filter = 'striped', $default = null, $method = 'METHOD') {
		
		$method = strtoupper ( $method );
		
		if ($method === 'METHOD') {
			$method = $this->getMethod ();
		}
		
		if (isset ( $this->_request [$method] [$name] )) {
			$var = $this->_request [$method] [$name];
			
			if ($method != 'FILES' && $var != $default) {
				if (get_magic_quotes_gpc ()) {
					$var = $this->_stripSlashesRecursive ( $var );
				}
			}
		} else {
			$var = $default;
		}
		return $var;
	}
	
	
	public function setVar($name, $value = null, $method = 'METHOD', $overwrite = true) {
		
		$method = strtoupper ( $method );
		
		if ($method === 'METHOD') {
			$method = $this->getMethod ();
		}
		
		if ($overwrite != true && array_key_exists ( $name, $this->_request [$method] [$name] )) {
			return $this->_request [$method] [$name];
		}
		
		$previous = array_key_exists ( $name, $this->_request [$method] ) ? $this->_request [$method] [$name] : null;
		
		if (isset ( $this->_request [$method] )) {
			$this->_request [$method] [$name] = $value;
		}
		return $previous;
	}
	
	
	public function getParam($name, $default = null) {
		
		if (isset ( $this->_params [$name] )) {
			return $this->_params [$name];
		}
		return $default;
	}
	
	
	public function getParams() {
		return $this->_params;
	}
	
	
	public function setParam($name, $value) {
		$this->_params [$name] = $value;
	}
	
	
	public function setParams(array $params) {
		
		foreach ( $params as $key => $value ) {
			$this->setParam ( $key, $value );
		}
	}
	
	
	public function isPost() {
		return $this->_method == 'POST';
	}
	
	
	public function getMethod() {
		return $this->_method;
	}
	
	
	public function setRequestUri($requestUri = null) {
		
		if ($requestUri === null) {
			if (isset ( $this->_request ['SERVER'] ['REQUEST_URI'] )) {
				$requestUri = $this->_request ['SERVER'] ['REQUEST_URI'];
			} elseif (isset ( $this->_request ['SERVER'] ['HTTP_X_REWRITE_URL'] )) {
				$requestUri = $this->_request ['SERVER'] ['HTTP_X_REWRITE_URL'];
			} else {
				return false;
			}
		}
	}
	
	
	public function getRequestUri() {
		
		if ($this->_requestUri === null) {
			$this->setRequestUri ();
		}
		return $this->_requestUri;
	}
	
	
	public function setBaseUrl($baseUrl = null) {
		
		if ($baseUrl === null) {
			$filename = basename ( $this->_request ['SERVER'] ['SCRIPT_NAME'] );
			
			if (basename ( $this->_request ['SERVER'] ['SCRIPT_NAME'] ) === $filename) {
				$baseUrl = $this->_request ['SERVER'] ['SCRIPT_NAME'];
			} elseif (basename ( $this->_request ['SERVER'] ['PHP_SELF'] ) === $filename) {
				$baseUrl = $this->_request ['SERVER'] ['PHP_SELF'];
			} elseif (isset ( $this->_request ['SERVER'] ['ORIG_SCRIPT_NAME'] ) && basename ( $this->_request ['SERVER'] ['ORIG_SCRIPT_NAME'] ) === $filename) {
				$baseUrl = $this->_request ['SERVER'] ['ORIG_SCRIPT_NAME'];
			} else {
				return false;
			}
			
			if (($requestUri = $this->getRequestUri ()) === null) {
				return false;
			}
			
			if (($pos = strpos ( $requestUri, $baseUrl )) === false || $pos !== 0) {
				$baseUrl = dirname ( $baseUrl );
			}
		}
		
		$this->_baseUrl = rtrim ( $baseUrl, '/' );
	}
	
	
	public function getBaseUrl() {
		
		if ($this->_baseUrl === null) {
			$this->setBaseUrl ();
		}
		
		return $this->_baseUrl;
	}
	
	
	public function setPathInfo($pathInfo = null) {
		
		if ($pathInfo === null) {
			if (($baseUrl = $this->getBaseUrl ()) === null) {
				return false;
			}
			
			if (($requestUri = $this->getRequestUri ()) === null) {
				return false;
			}
			
			if ($pos = strpos ( $requestUri, '?' )) {
				$requestUri = substr ( $requestUri, 0, $pos );
			}
			
			if (($pathInfo = substr ( $requestUri, strlen ( $baseUrl ) )) === false) {
				$pathInfo = '';
			}
		}
		$this->_pathInfo = $pathInfo;
	}
	
	
	public function getPathInfo() {
		
		if ($this->_pathInfo === null) {
			$this->setPathInfo ();
		}
		return $this->_pathInfo;
	}
	
	
	protected function _stripSlashesRecursive($value) {
		
		if (is_array ( $value )) {
			$value = array_map ( array (
					$this,
					'_stripSlashesRecursive' 
			), $value );
		} else {
			$value = stripslashes ( $value );
		}
		return $value;
	}
	
}
./classes/model.class.php
class Model {

	public function __construct() {
		// ich hole hier spaeter die Datenbankverbindung :)
	}

	public static function getData() {
		
		$text = "Link zu Seite 1: <a href='index.php?template=seite1'>Seite 1</a><br />";
		$text .= "Link zu Seite 2: <a href='index.php?template=seite2'>Seite 2</a><br />";
		
		return $text;
	}
}
./classes/view.class.php
class View {

	private $path 		= 'templates';
	private $content 	= array();
	private $template;
	
	public function __construct($template) {
		
		// Hier wird jetzt ein anderes Template geladen...
		// ... oder, wenn nicht vorhanden, wird das default Template geladen
		
		if (file_exists($this->path . DIRECTORY_SEPARATOR . $template . '.tpl.php')) {
			$this->template = $this->path . DIRECTORY_SEPARATOR . $template. '.tpl.php';
		} else {
			$this->template = $this->path . DIRECTORY_SEPARATOR  . 'default.tpl.php';
		}
		
		return $this->template;
	}

	public function setContent($key, $value){
		$this->content[$key] = $value;
	}

	public function parseTemplate() {

		if (file_exists($this->template)) {

			ob_start();
			include $this->template;
			$output = ob_get_contents();
			ob_end_clean();

			return $output;
		}
		return "Kann das Template ".$this->template." nicht finden";
	}
}
./templates/default.tpl.php
<html>
<head>
	<title><?php echo $this->content['title']; ?></title>
</head>
<body>
<?php echo $this->content['content']; ?>
<br />
<?php echo $this->content['footer']; ?>
</body>
./templates/seite1.tpl.php
<html>
<head>
<title>Seite 1</title>
</head>
<body>
<?php echo $this->content['content']; ?>
<br />
<?php echo $this->content['footer']; ?>
</body>
./templates/seite2.tpl.php
<html>
<head>
<title>Seite 2</title>
</head>
<body>
<?php echo $this->content['content']; ?>
<br />
<?php echo $this->content['footer']; ?>
</body>

Ok, und wie funktioniert das nun? Das ist wirklich ziemlich simpel:

  • Neben der schon vorgestellten Funktionsweise des MVC holen wir jetzt im Controller mittels ...
  • $this->request = new Request();
  • $this->view = new View($this->request->getVar('template'));
  • ... den für unser Template notwendigen Parameter 'template' aus dem Request und übergeben ihn an den View.
  • Im View steht jetzt, dass das neue Template geladen werden soll, oder, wenn nicht vorhanden, ein default-Template zur Verfügung steht.

Download des MVC - Part I

Download Download (7,9 kB)

Kommentare