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.

mvc pattern

MVC stands for Model-View-Controller, a pattern widely used in web application development.
First, lets take a look at the three parts:

ModelViewController

Controller

For each part of your application you use a different controller. It executes a different set of instructions based on the request, manages the models, and constructs the view.

Typically, after a request is made, following steps are undertaken by the controller:

  • check if the request is valid, else return an error message
  • update data if the request wishes to do so
  • retrieve all data needed in the view
  • construct a view object, and let it render the view

Model

a model is an object which stores data, and most of the time represents an object from the real world which is managed by the application. It is the primary form of communication between your views and your controllers.

View

the view is responsible for displaying information received from the controller such as models.

Why use this pattern?

This pattern allows a loose coupling between Application Logic and View Logic. This has some numerous advantages:

  • extensibility & maintainability
  • if you have to redesign the application, you would not need to rewrite already working application logic, you only have to replace the view, and vice versa
  • easy for other developers to understand what you were doing

I’ve made an example in php: github

I explain this example in detail here

repository pattern

This pattern is an application of the separation of concerns principle. It basically separates the consumer from the supplier of data.

For the consumer of an RSS feed it is irrelevant if the feed is read out from the storage, or downloaded from the internet. This is where the Repository Pattern jumps into action; it provides a simple API for the consumer, and takes care of resolving the data from the best source available.

A small example (c#):

internal class RssRepository
{
    public List<RssItem> GetRssItems()
    {
        if (DeviceHelper.HasInternet)
        {
            return RssHelper.DownloadFeedItems();
        }
        else
        {
            return StorageHelper.RetrieveCachedFeedItems();
        }
    }
}