mvc pattern in php

This is an implementation in php of the MVC pattern as described before.

First, we need to ensure all requests go to one file only, the index.php file. There we will construct our controller, and run the application. We do this by placing a correctly configured .htaccess file in the root directory of our webpage. I’ve commented out the commands, feel free to take a look.

The actual code in the index.php file is quite simple:

// (skipped code for including files)

//construct the controller
$controller = new HomeController($_SERVER["REQUEST_URI"]);
//execute the application
echo $controller->execute();

That was easy. Let’s take a look at our controller:

class HomeController {
	private $params;
	
	/**
	 * HomeController constructor.
	 *
	 * @param $params : the request URL
	 */
	public function __construct($params) {
		$this->params = $params;
	}
	
	/**
	 * execute the application
	 *
	 * @return string
	 */
	public function execute() {
		if ($this->params == "/") {
			$view = new HomeView("hallo welt!");
			return $view->renderHome();
		}
		else {
			if ($this->params == "/famoser") {
				$view = new HomeView();
				$person = new PersonModel("famoser", "01.01.1990");
				return $view->renderPerson($person);
			}
			else {
				if ($this->params == "/famoser/multiple") {
					$view = new HomeView();
					$persons = array();
					for ($i = 0; $i < 5; $i++) $persons[] = new PersonModel("famoser (" . $i . ")", "01.01.1990"); return $view->renderMultiplePersons($persons);
				}
				else {
					$view = new HomeView("not found");
					$view->addKeyValue("url", $this->params);
					return $view->renderError();
				}
			}
		}
	}
}

As you can see, the controller checks if the $params variable is a valid url. If it is, it contructs an object called the HomeView, and passes models and text to it. Then it lets the HomeView render the templates, and returns the received data.

Let take a look at a simplified HomeView (full code at github):

/**
* a simplyfied HomeView, I've removed the constructor and other for this example irrelevant code
*/
class HomeView {
	private $message;
	private $keyValues;

	public function getMessage() {
		return $this->message;
	}
	
	/**
	 * use this function to pass simple data to the view
	 */
	public function addKeyValue($key, $value) {
		$this->keyValues[$key] = $value;
	}
	
	/**
	 * retrieves values added by addKeyValue from the controller
	 */
	public function getValue($key) {
		return $this->keyValues[$key];
	}
	
	/**
	 * render the home template
	 */
	public function renderHome() {
		return $this->includeFile("index");
	}
	
	/**
	 * render the person template
	 */
	public function renderPerson(PersonModel $person) {
		$this->person = $person;
		return $this->includeFile("person");
	}

	/**
	 * render multiple persons
	 */
	public function renderMultiplePersons(array $persons) {
		$result = "";
		foreach ($persons as $person) {
			$this->person = $person;
			$result .= "

" . $this->includeFile("person") . "

";
		}
		return $result;
	}
	
	/**
	 * renders a file, writes the output it produces into a variable and returns that.
	 */
	private function includeFile($fileName) {
                //shorted
                include $filename;

	}
}

As you can see, the HomeView basically serves as a container for all data it needs to display. As the controller calls a function as renderHome, it loads a specific template and returns the rendered content to the controller.
Lastly, lets take a look at a template file:

if ($this instanceof HomeView) {
	echo $this->getMessage();
}

As I’m including the file from the HomeView, the context in this file ($this) is still the view. Now I can call the methods from the view to retrieve the data I have to render to human readable information.

What advantages has this approach?

  • reuse of templates is made easy: from one template, I can include others by calling functions provided by the view object (for example renderMultiplePersons)
  • a clear separation of view & logic: the controller does not care how the data he provides is displayed, he simply constructs the view with the appropriate data, and the view does not care where the data comes from, and just loads the appropriate templates.

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *