Tutorials: Basic MVC Guide

Routing

Framework is unique by using two completely independent MVC APIs, each supporting its own routing system.

Routing of requests

To add a route managed by STDOUT MVC API, open stdout.xml and add a <route> in <routes> tag. Example:

<route url="user/info" controller="UserInfoController" view="user_info"/>

this route will match when relative location of requested resource is user/info. Routes can also be parameterized:

<route url="user/info/(id)" controller="UserInfoController" view="user_info"/>

this route will match when relative location of requested resource is, for example, user/info/31254. In this case, MVC API will register a path parameter available in controllers as:

$this->request->getValidator()->parameters("id")

Routing of uncaught exceptions

To add a route managed by STDERR MVC API, open stderr.xml and add an <exception> in <exceptions> tag. Example:

<exception class="MyException" controller="CustomExceptionController" view="my_exception"/>

this route will match when class name of current handled exception is MyException. Routes can also be namespaced:

<exception class="\Foo\Bar\MyException" controller="CustomExceptionController" view="my_exception"/>

this route will match when class name of current handled exception is MyException using \Foo\Bar namespace.

Controllers

Since framework uses two completely independent MVC APIs, controllers' behavior mirrors that of routes they are defined into.

Controllers managed by STDOUT MVC API

These controllers bind requests to responses using models. Their class name is identified from "controller" attribute in matching <route> XML tag above and located on disk in application/controllers folder. If, for example, route is:

<route url="user/info" controller="UserInfoController" view="user_info"/>

then controller located will be application/controllers/UserInfoController.php. Controllers can also be in subfolders:

<route url="user/info" controller="foo/bar/UserInfoController" view="user_info"/>

then controller located will be application/controllers/foo/bar/UserInfoController.php. Controllers can also be namespaced:

<route url="user/info" controller="\Foo\Bar\UserInfoController" view="user_info"/>

then controller located will be application/controllers/UserInfoController.php using \Foo\Bar namespace.

In order to be recognized as such, controller classes MUST extend Lucinda\MVC\STDOUT\Controller and thus implement a public run method. Example:

require_once("application/models/dao/Users.php"); class UserInfoController extends \Lucinda\MVC\STDOUT\Controller { public function run() { $userID = $this->request->getValidator()->parameters("id"); $users = new Users(); $this->response->attributes("info", $users->getInfo($userID)); } }

To learn more about STDOUT controllers, check their dedicated section!

Controllers managed by STDERR MVC API

These controllers bind uncaught exceptions to responses. Their class name is identified from "controller" attribute in matching <exception> XML tag above and located on disk in application/controllers folder. If, for example, route is:

<exception class="MyException" controller="CustomExceptionController" view="my_exception"/>

then controller located will be application/controllers/CustomExceptionController.php. Controllers can also be in subfolders:

<exception class="MyException" controller="foo/bar/CustomExceptionController" view="my_exception"/>

then controller located will be application/controllers/foo/bar/CustomExceptionController.php. Controllers can also be namespaced:

<exception class="MyException" controller="\Foo\Bar\CustomExceptionController" view="my_exception"/>

then controller located will be application/controllers/CustomExceptionController.php using \Foo\Bar namespace.

In order to be recognized as such, controllers MUST extend Lucinda\MVC\STDERR\Controller and thus implement a public run method. Example:

class CustomExceptionController extends \Lucinda\MVC\STDERR\Controller { public function run() { if ($this->request->getException() instanceof MyException) { $this->response->setView($this->application->getViewsPath()."/my_exception"); } else { $this->response->setView($this->application->getViewsPath()."/custom_exception"); } } }

To learn more about STDERR controllers, check their dedicated section!

Models

Models are PHP classes performing logic (querying databases, for example), used by controllers mainly and found in application/models folder. Framework comes with a few, but the vast majority are to be done by developers.

How to implement models that work with databases

For example, let's imagine we have a MySQL table with this structure expressing an users concept:

create table users ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL, password CHAR(20) NOT NULL, name VARCHAR(255) NOT NULL, age TINYINT UNSIGNED NOT NULL, PRIMARY KEY(id), UNIQUE(username) )

And your application requires two operations on the users concept: login and get all. In that case you should create a class in application/models/dao/entities folder that encapsulates coordinates of concept:

class User { public $id; public $name; public $age; }

Then create another in application/models/dao that encapsulates operations on concept:

require_once("entities/User.php"); class Users { public function login($username, $password) { return SQL("SELECT id FROM users WHERE username=:username AND password=:password", array( ":username"=>$username, ":password"=>sha1($password) ))->toValue(); } public function getAll() { $output = array(); $resultSet = SQL("SELECT * FROM users"); while ($row = $resultSet->toRow()) { $user = new User(); $user->id = $row["id"]; $user->name = $row["name"]; $user->age = $row["age"]; $output[] = $user; } return $output; } }

In order for this to work, you MUST configure stdout.xml to setup SQL databases (see below how).

Views

Framework by default supports html and json for both STDOUT views and STDERR views.

Creating HTML Views

By default, all HTML views can be templated using View Language API. All views are located in application/views folder as HTML files based on value of "view" attribute in matching <route> or <exception> tag. Example:

<route url="user/info" controller="UserInfoController" view="user_info"/>

then view located will be application/views/user_info.html. Views can also be in subfolders:

<route url="user/info" controller="UserInfoController" view="foo/bar/user_info"/>

then view located will be application/views/foo/bar/user_info.html.

Let us create view application/views/user_info.html, using ViewLanguage templating:

<import file="header"/> <p>User info is:</p> <user:info name="${data.info.name}" age="${data.info.age}"> <import file="footer"/>

As one can see above, view is nothing but a combination of tags and expressions. Some tags are HTML standard (<p>), others load other views (<import>) and others are user defined (<user:info>). All user defined tags have this structure:

<libraryName:tagName attribute1="value1" ... />

where tagName reflects into a html file by same name found in libraryName folder, itself found in application/tags folder. To create <user:info> tag we will thus need to have application/tags/user/info.html file with a body like:

name = $[name]<br/> age = $[age]

To learn more about View Language API and how it templates HTML views, click on its link. To learn more how is HTML resolved when this API is used, go to dedicated STDOUT or STDERR sections!

Creating JSON Views

JSON views are handled automatically by framework based on response status and data sent by controllers to response via attributes. If response was successful, then view will look like this example:

{"status":"ok", "body":["hello":"world"]}

This assumes controller sent to response a:

$this->response->attributes("hello", "world");

If, however, response was unsuccessful, then view will look like this example:

{"status":"error", "body":"ERROR MESSAGE"}

To learn more how is JSON resolved, go to dedicated STDOUT or STDERR sections!


Share