Getting started with Simpletools\Mvc

Simpletools\Mvc has been designed to provide you with all benefits of the Model-View-Controller software architectural pattern. Simpletools\Mvc provides scalability, performance and ease of use out of the box.

Requirements

Simpletools framework requires PHP version >= 5.3.0

Setup

Simpletools\Mvc is very easy to setup, all you need is a composer and organise your application files and folders in the normalised way (you can also download all framework directly). Below we have demonstrated all you need to get your first app up and running using Simpletools\Mvc.

And to simplify the setup you can just run:

composer create-project simpletools/helloworld --prefer-dist

Helloworld example can be run stratight away with PHP Built-in web server server as it include a file which emulates mod_rewrite. To start just run:

php -S localhost:8000 server.php

This will start web server listening on port 8000 and localhost domain.

*Keep in mind that PHP web server was designed to aid application development. It may also be useful for testing purposes or for application demonstrations that are run in controlled environments. It is not intended to be a full-featured web server. It should not be used on a public network.

Directory structure

Simpletools\Mvc requires a structural approach to your application directory organisation therefore making it easy to understand, document and maintain.

In order to get your application to work with Simpletools\Mvc the following initial directory structure is required:

app/
    application/
        controllers/
            ErrorController.php
            IndexController.php
        models/
        views/
            Index/
                index.phtml
            Error/
                error.phtml
    public/
        bootstrap.php
    vendor/
        simpletools/
            framework/
                ...
        autoload.php
    composer.json

Bootstrapping

After creating the initial application structure as described above we can move on to create a body of our bootstrap.php script being responsible for booting up our application. The source of that file is very simple:

<?php
    require_once("../vendor/autoload.php"); 

    $router = \Simpletools\Mvc\Router::settings(array(
        "applicationDir" => "../application"
    ));

    $router->dispatch();
?>

Index handler

To handle any requests sent by a user to our application we need to set controllers with actions and views. Controllers, actions and views will be explained further under Components section so till then lets just create an IndexController, indexAction and index view allowing us to handle any requests to our index page using the examples below.

IndexController.php:

<?php
    class IndexController extends \Simpletools\Mvc\Controller
    {
        public function indexAction()
        {

        }
    }
?>

index.phtml:

<html>
    <body>Hello World!</body>
</html>

Errors handler

In addition to creating controllers, actions and views allowing our application to handle desired user requests it is highly recommended to handle requests which we have not intended to support in the first place, e.g. requests to not existing sections of our application. You can find more about Error handling under Components. Error controller is a very simple class which Simpletools\Mvc uses in case of requests which can"t be routed anywhere else. An example of basic Error controller, action and view we are going to use in our application can be seen below.

ErrorController.php:

<?php
    class ErrorController extends \Simpletools\Mvc\Controller
    {
        public function errorAction()
        {

        }
    }
?>

error.phtml:

<html>
    <body>Error occured</body>
</html>

Web server configuration

And finally, to run our application we just need to create web server configuration file routing all requests to our bootstrap.php file.

For our getting started app we have chosen Apache for our web server and below you can see very basic virtual host definition file allowing our app (hosted under example.com) to run. These rules direct all requests to index.php, except when a matching file is found under the DocumentRoot.

<VirtualHost example.com:80>

    ServerName   example.com
    DocumentRoot app/public

    <Location />
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} -s [OR]
        RewriteCond %{REQUEST_FILENAME} -l [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^.*$ - [NC,L]
        RewriteRule ^.*$ /bootstrap.php [NC,L]
    </Location>

</VirtualHost>

Hello world!

After following all steps described under Setup, starting your web server and entering http://example.com in your browser you should be able to see Hello world! as per your index.phtml view.

You can also type anything else e.g. http://example.com/foo to see error.phtml being rendered.

Components

Simpletools\Mvc includes all components needed to run proper MVC application. We have listed and described their role below.

Controllers

Controllers are responsible for arbitrating the application flow. They are responsible for application"s logic - you can look at them as a proxy between your models and application views.

Each controller has a number of methods corresponding to possible actions - all suffixed with a word Action. Actions are a glue between controllers and views and can pass any data to a view.

Actions

Actions are controller"s class methods. They can request data from models, set and update them and then send required data to a view for the final processing.

Actions are a glue between controllers and views and can pass any data to a view by using the following method available for each controller:

$this->setViewProperty($key,$value);

So to pass a variable called foo with value bar into a view you can use the following code:

$this->setViewProperty("foo","bar");

$this->_view can be extened with any property which in returned can then be access by the view.

Views

Views are responsible for the presentation layer. They can access data provided to them by controller actions and present them to a user.

Below you can see an example of a controller"s action sending data to a view

$this->setViewProperty("foo","Bar");

View can display the above set variable by simply echoing $this->username property:

echo $this->foo; //will result in displaying bar.

Views can only access controller"s properties explicitly set for them inside the action under $this->_view, any other variables are not visible to views.

Models

Models are responsible for the business logic. They can interact with databases, files etc.

To define a model you just need to create a simple class as below with the name of your choice followed by word Model and saved it under app/application/models folder inside the file with the same name as the class.

In the example below we are using name Foo for our model hence after the addition of affix - Model - the file name would be FooModel.php

<?php
    class FooModel
    {

    }
?>

Models can be accessed inside the controller"s actions by using the following command:

//just a model name - Foo, no need for affix - Model/FooModel - here
$fooModel = \Simpletools\Mvc\Model::of("Foo"); 

Models can have any methods you wish as well as they can be extended by any other classes.

Routing

An integral part of any MVC framework, in Simpletools\Mvc built in directly into the library so nothing to setup, all works out of box.

Routing is a process responsible for forwarding requests into the appropriate application controllers and their actions allowing to handle user requests as expected.

Routing principles

Simpletools\Mvc framework handles requests dispatching by parsing the path section of the URL in the following manner:

http://example.com/{controller}/{action}

Where {controller} and {action} section will be used to trigger the appropriate controller and its action.

So to use an example with the real values:

http://example.com/user/login

The following url results in Simpletools\Mvc invoking UserController.php and triggering ->loginAction() method of that controller, you can see source of such controller below:

<?php
    class UserController extends SimpleControl
    {
        public function loginAction()
        {

        }
    }
?>

After executing loginAction() by default Simpletools\Mvc moves to rendering view located inside Views/User/login.phtml and completing the routing cycle.

In case of empty values for controller or actions inside the requested url path (more about routing naming convention) Simpletools\Mvc defaults all to index so for controller it results with IndexController, and for action indexAction().

Naming convention

To prevent any confusion regarding how to name controller, action or view"s Simpletools\Mvc is normalising all before triggering each component. The rules how it works for each component have been listed below.

  • Controllers

    Before deciding which controller to use Simpletools\Mvc is parsing the requested name as follow:

    1. lowering down all characters
    2. capitalising the first character
    3. capitalising each character followed by a non-alphanumeric character
    4. removing all non-alphanumeric characters
    5. appending word Controller at the end
  • Actions

    Before deciding which action to trigger Simpletools\Mvc is parsing the requested name as follow:

    1. lowering down all characters
    2. capitalising each character followed by a non-alphanumeric character
    3. removing all non-alphanumeric characters
    4. appending word Action at the end
  • Views folder

    To decide in which folder to find a requested view, Simpletools\Mvc is parsing the requested name as follow

    1. lowering down all characters
    2. capitalising the first character
    3. capitalising each character followed by a non-alphanumeric character
    4. removing all non-alphanumeric characters
  • Views

    Before deciding which view to render Simpletools\Mvc is parsing the requested name as follow:

    1. lowering down all characters
    2. capitalising each character followed by a non-alphanumeric character
    3. removing all non-alphanumeric characters

Errors handling

Requests resulting in missing controller, action or view are being automatically re-routed to the ErrorController.php and triggers errorAction resulting in rendering error.phtml view alongside with 404 HTTP code being returned hence their importance during the initial directory setup structure described above.

Custom routing

Simpletools/Mvc also supports advanced routing allowing you to specify your own routing maps. Custom routing takes precedence over standard routing and is optional in a sense that if no custom route is found, standard routing will be used instead.

<?php
    $router = \Simpletools\Mvc\Router::settings(array(
        "applicationDir"    => "../application",
        "customRoutes"      => [
            "GET"   => [
                "/user/{userName}/settings/{id}"    => "[email protected]",
            ],
            "ANY"   => [
                "/user/{userName}/settings/{id}"    => "[email protected]",
            ]
        ]
    ));
?>

Routing namespaces

Simpletools\Mvc provides unique feature allowing you to organise your application into even more compartmental way enabling you to build apps within an app e.g /api/v1, /api/v2 having its own models, controllers, actions and views yet being able to share anything between themselves.

Setup

So to demonstrate how to setup and why to use a routing namespaces \Simpletools\Mvc provides lets assume that we need to build an api under our already existing application we have built under the Setup section. Also, to make it even more challenging lets assume that we are required to version our api in case we need to have some not backward compatible versions in the future so lets stick to /api/v1, also lets assume we need to provide foo/bar (foo - controller, bar - action) endpoint for our api so the full path looks like /api/v1/foo/bar

As you already know at that point without the routing namespaces you would endup with api as a controller and v1 as its action in which case the question arise, where and how to accommodate for all the endpoints any api must have? And that question is a reason why \Simpletools\Mvc provides the routing namespaces.

OK, so lets go to the setup so you can how easy is to solve all those challenges and how clean your application"s structure will be.

First thing we need to do is to register desired namespaces so \Simpletools\Mvc can differentiate them from normal controllers and actions.

So to enable /api/v1/foo/bar using the example.com directory structure and bootstrap we have created above we need to:

  1. modify our bootstrap slightly to register our /api/v1 namespace:
    <?php
        require_once("../libs/Simpletools/Mvc.php"); 
    
        $mvc = \Simpletools\Mvc::settings(array(
            "applicationDir" => "../application",
            "routingNamespaces" => array(
                "api/v1"
            )
        ));
    
        $mvc->run();
    ?>
  2. add extra directories, controllers and views into our application structure to accommodate for the /api/v1/foo/bar:
    app/
        application/
            controllers/
                Api/
                    V1/
                        FooController.php
                ErrorController.php
                IndexController.php
            models/
                Api/
                    V1/
            views/
                Api/
                    V1/
                        Foo/
                            bar.phtml
                Index/
                    index.phtml
                Error/
                    error.phtml
        libs/
            Simpletools/
                Mvc.php
        public/
            bootstrap.php
  3. Create Foo controller with barAction:
    <?php
        namespace Api/V1;
        
        class FooController extends \Simpletools\Mvc\Controller
        {
            public function barAction()
            {
    
            }
        }
    ?>
  4. Create bar.phtml view
    <html>
        <body>Hello World, I am /api/v1/foo/bar view!</body>
    </html>

And voila, job done!

Controllers

Namespacing allows controllers to communicate between each other even if they are living outside of the current namespace. You can forward requests to controllers in different namespaces or root directory e.g. to root request from our \Api\V1\FooController to \IndexController use:

$this->forward("/Index","index");

or from "\IndexController to \Api\V1\FooController

$this->forward("/Api/V1/FooController","bar");

for the convenience both characters \ and / are accepted as namespace separators.

Views

As in case of controllers namespacing allows actions to render any views, by default the view in the current namespace is being rendered but to render view from different namespace you can simply:

$this->render("\index");

for the convenience both characters \ and / are accepted as namespace separators.

Models

With namespaces models are getting extra organisation layer in form of its dedicate folders under models directory and as well as controllers can forward requests to any other places same with models, controllers can access any moder they wish including those outside of their currently active namespace. E.g. to access api/v1 models from api/v2 located controller:

\Simpletools\Mvc\Model::of("/api/v1/..");

for the convenience both characters \ and / are accepted as namespace separators.

Errors

ErrorController and view are optional in case of namespaces, in case of their non existence default one from the root directory will be used but you are free to overwrite them by creating a different one under each namespace.