Guide to Using MVC Pattern

Introduction

Wave Framework is loosely based on Hierarchical Model-View-Controller architecture principle that separates three logical components of software. A Model is a data representation object, usually for something like a row object from a Database. A View is a component that is rendered for User Interface. And Controller is the object that receives input, validates input and executes other aspects of software within the system.

MVC is hierarchical in Wave Framework, which means that every object can load other objects. It is possible for a view to load another Controller or Model or vice versa, or an entire API call itself. There is more information on this in Creating Objects documentation.

Wave Framework comes with an example Model, View and Controller that are stored in '/models/', '/views/' and '/controllers/' subfolders.

It is recommended for MVC Objects to be extended from WWW_Factory class, which adds additional functionality to the objects that can be used to access variety of features of Wave Framework and its API.

Models

Models are used as data-representation layer in the system. In most cases, a model would be an object representation of Database row and would include methods for editing that information, saving and updating it, deleting it and so on.

The main purpose of a model is to make the data object in infosystem independent from what actual method is used for storing that data. For example, if you used MySQL at first and now wish to use another Database format or simply store an object in Filesystem, then all you have to do is replace the model that is being used and called in your system. As long as the methods and input-output remain the same, then the system will continue working without problems.

Parameters of a model are usually representations of Database column names and it is recommended to make the model methods work in input and output through an array, so that the models methods return an array if you fetch data.

Here is an example model:

	
	// WWW_Factory is parent class for all MVC classes of Wave Framework
	class WWW_model_example extends WWW_Factory {

		// All the variables of this model should be stored here
		public $id=0;
		public $name='';
		
		// This is like __construct() but for Factory-created objects
		public function __initialize(){
			// Do something here
			return true;
		}
		
		// This is intended to load data from database
		// * id - Identifier of the object loaded
		public function load($id){
			// Actual database query should be built here
			$this->id=$id;
			$this->name='Lorem Ipsum #'.rand(1,1000); // This is used for simply testing cache
			return true;
		}
		
		// This returns all of the data of currently open object
		public function get(){
			// Data is returned as an array
			return array(
				'id' => $this->id,
				'name'=>$this->name
			);
		}

		// This function is intended to save data to database
		public function save(){
			// Actual database query should be built here
			return true;
		}

	}
	

This example would have, in Database, just an ID and name that would be loaded from Database. In load() method you would have the functions that load from Database. In get() method you would have functionality that returns an array representation of current Models data. In save() method you would write current information to Database.

You can name your model methods whatever you want, since your own designed system actually calls these methods. The only thing that Wave Framework forbids is the use of __construct() method in a class that is extended from WWW_Factory class. For this you can use __initialize() method that is called by Factory when object is created.

Models should be stored in '/models/' subfolder, with a filename of 'model.[name].php' and class name of 'WWW_model_[name]'.

Views

Views are objects in the system that are used to display HTML or other visuals in the system. By default, Wave Framework expects that Views write to output buffer - technically they don't have to, but it simplifies the production of HTML views in the system.

Wave Framework does not use a separate templating system and templating language, since PHP itself is a natural templating language in many ways. While it is not recommended to write logic in your views, you can do so. Wave Framework does not restrict your abilities when using the language.

It is also possible to make API calls, load other views and more within views. This allows you to create nested views and generate any kind of web pages you can think of.

Here is an example view:

	
	// WWW_Factory is parent class for all MVC classes of Wave Framework
	class WWW_view_example extends WWW_Factory {

		// WWW_controller_url calls this function as output for page content
		public function render($input){
		
			// An example of getting a sitemap array
			$sitemap=$this->getSitemap();
			
			// An example of getting current translations array
			$translations=$this->getTranslations();
		
			echo '<h1>Hello World</h1>';
			
		}

	}
	

You can name your View methods whatever you want, but Wave Frameworks core View Controller assumes 'render()' as the method by default. A different method can be called if a different method is set in Sitemap file.

The only thing that Wave Framework forbids is the use of __construct() method in a class that is extended from WWW_Factory class. For this you can use __initialize() method that is called by Factory when object is created.

Views should be stored in '/views/' subfolder, with a filename of 'view.[name].php' and class name of 'WWW_view_[name]'. This same view name should be defined in the Sitemap in /resources/[language].sitemap.ini file, so that the default View Controller could load a View for a requested URL.

Controllers

Controllers are the objects in Wave Framework that are the first objects called by API. Any API call - the ones done over HTTP as well as internal calls - load a controller first and foremost and execute a method in that controller.

Public methods of Controllers act as API calls, where the 'www-command' value would essentially be [controller]-[method]. Private methods cannot be called through API.

Controllers would be used for mainly validating input and then returning output to the client or function that called the API and thus the controller. Controllers can be used for anything: user logins, getting tweets from Twitter API, validating or converting input data and more.

Here is an example controller that also loads a Model and returns a specific ID from that model as a response:

	
	// WWW_Factory is parent class for all MVC classes of Wave Framework
	class WWW_controller_example extends WWW_Factory {
		
		// Simple example call (from API it would be called as 'example-get' command)
		// Please note that only public methods can be called through API, protected and private methods remain hidden
		public function get(){
			// New objects can be created through Factory easily
			$example=$this->getModel('example');
			// This 'loads' model with ID of 1. Note that the function call here can be anything you need, this is just used as an example
			$example->load(1);
			// Returning the result of controller call
			return $example->get();
		}
		
	}
	

This example returns just an array as the response, but usually it is recommended to return a standardized Wave Framework array. There is more information about this below in Returning Standardized Array section.

You can name your Controller methods whatever you want, since your own designed system actually calls these methods. The only thing that Wave Framework forbids is the use of __construct() method in a class that is extended from WWW_Factory class. For this you can use __initialize() method that is called by Factory when object is created.

Controllers should be stored in '/controllers/' subfolder, with a filename of 'controller.[name].php' and class name of 'WWW_controller_[name]'.

Returning Standardized Arrays

Wave Framework Controllers are the direct connection point between the client and the API request. This means that what the controller returns is what will be returned to the client as well through the system.

Wave Framework allows you to return any type of arrays as a result from the Controller method and the client that made the request can then do whatever they want with the response from the controller.

But Wave Framework has a recommended standard for returning arrays. This standard tells Wave Framework and API itself a little more about what the Controller did. Wave Framework needs to know only two things to take full advantage of the returned response: Verbose message about what was done and a response code.

You can read more about response codes in a documentation page about the topic, but in general, Wave Framework has five response code namespaces:

Implementing this type of response is relatively easy. Your returned array should have two additional keys:

You can add these to the returned array yourself, or use one of the helper functions when returning data, for example:

	
	// This returns an error array
	return $this->resultError('Bad things happened');
	// This returns an error array with additional custom data
	return $this->resultError('Bad things happened',array('some-data'=>'some-value'));
	// This returns an error array with a custom response code (if not defined, it would be 300)
	return $this->resultError('Bad things happened',array('some-data'=>'some-value'),384);
	
	// This returns a failure array with a custom response code (if not defined, it would be 400)
	return $this->resultFalse('Something failed',array('some-data'=>'some-value'),412);
	
	// This returns a success array with a custom response code (if not defined, it would be 500)
	return $this->resultFalse('Something went OK!',array('some-data'=>'some-value'),501);
	

It is recommended to document your 3XX, 4XX and 5XX errors somewhere in your API, such as in your API method comments, as these are not part of Wave Framework itself.

The difference between Failure and Error is that an Error causes the system to throw an error. This means that something was done in the Controller that should not have been done, or that something failed in unexpected ways.

Failure messages are used for negative responses, for example when something did not work, but you still want to display that information in User Interface. For example, when user log-in fails, then that would be returned as a Failed response and not an Error.

Success messages should be used when Controllers method call was considered a success, such as when a user has successfully logged in.

Wave Framework uses the response code internally to see if the method call was considered a success or not, or if an error was encountered. This is important when returning binary data (that just returns 1 or 0 to the client), or for API Wrapper that can have callbacks set for different type of responses. This is detailed more in API documentation.

Array Conversion to XML/RSS

When data is requested through API, then the data that Controller returns is converted to the specific format that is requested from the API. This means that the array, which you return from Controller methods, will be converted to XML, JSON, INI or other text-based formats. Most of these conversions are pretty simple and easy to understand, but XML and RSS are a special case. While conversion to XML and RSS works as expected, it is also possible to assign 'attributes' in the array, that will be converted to XML attributes in the output.

Below is an example of array that is returned from Controller method and how the API returns it after conversion:

	
		...
		// Data returned from Controller
		return array(
			'id'=>1,
			'name'=>'Thomas',
			'@name'=>array('myattribute'=>'myvalue')
		);
		...
		// How it appears through API Handler when XML is requested
		<www>
			<id>1</id>
			<name myattribute="myvalue">Thomas</name>
		</www>
	

Comments and Documenting

You should always document your variables and methods. There are a number of ways and guidelines how to document your code in PHP and while Wave Framework does not enforce you to use one type of documenting style over another, there are some things that you should keep in mind when documenting your MVC objects.

Controller documentation is actually reflected in API Info Developer Tool. This tool is situated in '/tools/api-info.php' file and can be technically considered the preliminary documentation for your actual API. This API Info tool generates documentation page for all of your public methods of your defined Controllers and whether they are accessible over API and if they are, then by what API Profiles (which are defined in '/resources/api.profiles.ini' file).

Models and View documentation and comments are not visible through any tool and are only a guide to the developer who is implementing these Models and Views.

File Headers

MVC class definition header should give a brief overview about what the class is about as well as its version number, license information and author information. This data is needed since if someone stumbles upon the file, they should get a general idea about what this class does and how it can be used.

Here is a recommended header for a MVC class definition file:

	
	/**
	 * Project Name 
	 * Brief Class Description
	 *
	 * Detailed class description about what the Model, View, or 
	 * Controller class does and how it can be used.
	 *
	 * @package    Package of this class (or what it is extended from) 
	 * @author     My Name  (name and e-mail)
	 * @copyright  Copyright (c) 2012, My Name (copyright information)
	 * @license    License  (class license and use restriction)
	 * @tutorial   /doc/class.htm (link to a document that shows how to use this class)
	 * @since      1.0.0 (version this class was originally implemented)
	 * @version    1.0.0 (since when has this class has been edited)
	 */
	

Model/View Function Comments

Model and View classes include methods that should also be well documented and commented. Differently from class documentation, it is not really needed to define author information and license information and version information, unless these methods have a different information in those fields than in the class itself.

Method/function comments however also need two other variables:

Here is a simple example documented method:

	
	/**
	 * This adds two numbers together.
	 *
	 * @param integer $a first variable
	 * @param integer $b second variable
	 * @return integer
	 */
	public function example($a,$b){
		return $a+$b;
	}
	

Controller Function Comments

Controller functions should be documented similarly to Model/View class methods. But since Wave Framework also uses Controllers for the API, there are some notable differences.

Public methods of Controllers are also shown in API Info tool as described above. Public methods of Controllers can thus be used by the Wave Framework API. And the way Wave Framework functions is that it executes the Controller method by generally using one array for input and (generally) returning an array as output.

This means that two new parameters should be defined for Controller comments:

Here is a simple example documented Controller method:

	
	/**
	 * This adds two numbers together.
	 *
	 * @param array $input input data array
	 * @input [a]* first variable
	 * @input [b]* second variable
	 * @return array
	 * @output [result] result of the function
	 * @response [512] response code description
	 */
	public function example($input){
		return array('www-response-code'=>512,'result'=>$input['a']+$input['b']);
	}
	

Also note that if something is always required, then you should write an asterisk (*) after the input data, such as in the above example the 'a' and 'b' keys. The same aterisk should be used for output as well, for exampel to define keys that you know your Controller always returns, but this is not required.

As a result, the documentation will be detailed also in API Info tool. Though you can write your documentation in any way you wish (and it would be shown in API Info as well), it is recommended to stay consistent with documentation so that it is understood by most developers who happen to look into your code or work with it.