Ubiquity framework User guide

Ubiquity-devtools installation

Install Composer

ubiquity utilizes Composer to manage its dependencies. So, before using, you will need to make sure you have Composer installed on your machine.

Install Ubiquity-devtools

Download the Ubiquity-devtools installer using Composer.

composer global require phpmv/ubiquity-devtools 1.0.x-dev

Make sure to place the ~/.composer/vendor/bin directory in your PATH so the Ubiquity executable can be located by your system.

Once installed, the simple Ubiquity new command will create a fresh micro installation in the directory you specify. For instance, Ubiquity new blog would create a directory named blog containing an Ubiquity project:

Ubiquity new blog

You can see more options about installation by reading the Project creation section.

Project creation

After installing Ubiquity-devtools installation, in a bash console, call the new command in the root folder of your web server :

Ubiquity new projectName

Installer arguments

short name name role default Allowed values
b dbName Sets the database name.    
s serverName Defines the db server address. 127.0.0.1  
p port Defines the db server port. 3306  
u user Defines the db server user. root  
w password Defines the db server password. ‘’  
q phpmv Integrates phpMv-UI toolkit. false semantic,bootstrap,ui
m all-models Creates all models from db. false  

Arguments usage

short names

Example of creation of the blog project, connected to the blogDb database, with generation of all models

Ubiquity new blog -b=blogDb -m=true

long names

Example of creation of the blog project, connected to the bogDb database, with generation of all models and integration of phpMv-toolkit

Ubiquity new blog --dbName=blogDb --all-models=true --phpmv=semantic

Note

Markdown doesn’t support a lot of the features of Sphinx, like inline markup and directives. However, it works for basic prose content. reStructuredText is the preferred format for technical documentation, please read `this blog post`_ for motivation.

Project configuration

Normally, the installer limits the modifications to be performed in the configuration files and your application is operational after installation

_images/firstProject.png

Main configuration

The main configuration of a project is localised in the app/conf/config.php file.

app/conf/config.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
return array(
             "siteUrl"=>"%siteUrl%",
             "database"=>[
                             "dbName"=>"%dbName%",
                             "serverName"=>"%serverName%",
                             "port"=>"%port%",
                             "user"=>"%user%",
                             "password"=>"%password%"
             ],
             "namespaces"=>[],
             "templateEngine"=>'Ubiquity\views\engine\Twig',
             "templateEngineOptions"=>array("cache"=>false),
             "test"=>false,
             "debug"=>false,
             "di"=>[%injections%],
             "cacheDirectory"=>"cache/",
             "mvcNS"=>["models"=>"models","controllers"=>"controllers"]
);

Services configuration

Services loaded on startup are configured in the app/conf/services.php file.

app/conf/services.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use Ubiquity\cache\CacheManager;
use Ubiquity\controllers\Router;
use Ubiquity\orm\DAO;

/*if($config["test"]){
\Ubiquity\log\Logger::init();
$config["siteUrl"]="http://127.0.0.1:8090/";
}*/

$db=$config["database"];
if($db["dbName"]!==""){
     DAO::connect($db["dbName"],@$db["serverName"],@$db["port"],@$db["user"],@$db["password"]);
}
CacheManager::startProd($config);
Router::start();
Router::addRoute("_default", "controllers\Main");

Pretty URLs

Apache

The framework ships with an .htaccess file that is used to allow URLs without index.php. If you use Apache to serve your Ubiquity application, be sure to enable the mod_rewrite module.

.htaccess
AddDefaultCharset UTF-8
<IfModule mod_rewrite.c>
     RewriteEngine On
     RewriteBase /blog/
     RewriteCond %{REQUEST_FILENAME} !-f
     RewriteCond %{HTTP_ACCEPT} !(.*images.*)
     RewriteRule ^(.*)$ index.php?c=$1 [L,QSA]
</IfModule>

Nginx

On Nginx, the following directive in your site configuration will allow “pretty” URLs:

location / {
    try_files $uri $uri/ /index.php?c=$query_string;
}

Devtools usage

Project creation

Controller creation

Model creation

All models creation

Cache initialization

URLs

like many other frameworks, if you are using router with it’s default behavior, there is a one-to-one relationship between a URL string and its corresponding controller class/method. The segments in a URI normally follow this pattern:

example.com/controller/method/param
example.com/controller/method/param1/param2

Default method

When the URL is composed of a single part, corresponding to the name of a controller, the index method of the controller is automatically called :

URL :

example.com/Products
example.com/Products/index

Controller :

app/controllers/Products.php
1
2
3
4
5
class Products extends ControllerBase{
    public function index(){
        //Default action
    }
}

Required parameters

If the requested method requires parameters, they must be passed in the URL:

Controller :

app/controllers/Products.php
1
2
3
class Products extends ControllerBase{
    public function display($id){}
}

Valid Urls :

example.com/Products/display/1
example.com/Products/display/10/
example.com/Products/display/ECS

Optional parameters

The called method can accept optional parameters.

If a parameter is not present in the URL, the default value of the parameter is used.

Controller :

app/controllers/Products.php
class Products extends ControllerBase{
    public function sort($field,$order="ASC"){}
}

Valid Urls :

example.com/Products/sort/name (uses "ASC" for the second parameter)
example.com/Products/sort/name/DESC
example.com/Products/sort/name/ASC

Case sensitivity

On Unix systems, the name of the controllers is case-sensitive.

Controller :

app/controllers/Products.php
class Products extends ControllerBase{
    public function caseInsensitive(){}
}

Urls :

example.com/Products/caseInsensitive (valid)
example.com/Products/caseinsensitive (valid because the method names are case insensitive)
example.com/products/caseInsensitive (invalid since the products controller does not exist)

Routing customization

The Router and annotations of controller classes allow you to customize URLs.

Router

Routing can be used in addition to the default mechanism that associates controller/action/{parameters} with an url.
Routing works by using the @route annotation on controller methods.

Routes definition

Creation

app/controllers/Products.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * Controller Products
 **/
class Products extends ControllerBase{

     /**
     * @route("products")
     */
     public function index(){}

}

The method Products::index() will be accessible via the url /products.

Route parameters

A route can have parameters:

app/controllers/Products.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace controllers;
 /**
 * Controller Products
 **/
class Products extends ControllerBase{
     ...
     /**
     * Matches products/*
     *
     * @Route("products/{value}")
     */
     public function search($value){
             // $value will equal the dynamic part of the URL
             // e.g. at /products/brocolis, then $value='brocolis'
             // ...
     }
}

Route optional parameters

A route can define optional parameters, if the associated method has optional arguments:

app/controllers/Products.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace controllers;
 /**
 * Controller Products
 **/
class Products extends ControllerBase{
     ...
     /**
     * Matches products/all/(.*?)/(.*?)
     *
     * @Route("products/all/{pageNum}/{countPerPage}")
     */
     public function list($pageNum,$countPerPage=50){
             // ...
     }
}

Route name

It is possible to specify the name of a route, this name then facilitates access to the associated url.
If the name attribute is not specified, each route has a default name, based on the pattern controllerName_methodName.

app/controllers/Products.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;
 /**
 * Controller Products
 **/
class Products extends ControllerBase{

     /**
     * @route("products","name"=>"products_index")
     */
     public function index(){}

}

URL or path generation

Route names can be used to generate URLs or paths.

Linking to Pages in Twig

<a href="{{ path('products_index') }}">Products</a>

Controllers

A controller is a PHP class inheriting from Ubiquity\controllers\Controller, providing an entry point in the application.
Controllers and their methods define accessible URLs.

Controller creation

The easiest way to create a controller is to do it from the devtools.

From the command prompt, go to the project folder.
To create the Products controller, use the command:

Ubiquity controller Products

The Products.php controller is created in the app/controllers folder of the project.

app/controllers/Products.php
1
2
3
4
5
6
7
8
9
namespace controllers;
 /**
 * Controller Products
 **/
class Products extends ControllerBase{

     public function index(){}

}

It is now possible to access URLs (the index method is solicited by default):

example.com/Products
example.com/Products/index

Note

A controller can be created manually. In this case, he must respect the following rules:

  • The class must be in the app/controllers folder
  • The name of the class must match the name of the php file
  • The class must inherit from ControllerBase and be defined in the namespace controllers
  • and must override the abstract index method

Methods

public

The second segment of the URI determines which public method in the controller gets called.
The “index” method is always loaded by default if the second segment of the URI is empty.

app/controllers/First.php
1
2
3
4
5
6
7
8
namespace controllers;
class First extends ControllerBase{

     public function hello(){
             echo "Hello world!";
     }

}

The hello method of the First controller makes the following URL available:

example.com/First/hello

method arguments

the arguments of a method must be passed in the url, except if they are optional.

app/controllers/First.php
namespace controllers;
class First extends ControllerBase{

     public function says($what,$who="world"){
             echo $what." ".$who;
     }

}

The hello method of the First controller makes the following URLs available:

example.com/First/says/hello (says hello world)
example.com/First/says/Hi/everyone (says Hi everyone)

private

Private or protected methods are not accessible from the URL.

Default controller

The default controller can be set with the Router, in the services.php file

app/config/services.php
Router::start();
Router::addRoute("_default", "controllers\First");

In this case, access to the example.com/ URL loads the controller First and calls the default index method.

views loading

loading

Views are stored in the app/views folder. They are loaded from controller methods.
By default, it is possible to create views in php, or with twig.
Twig is the default template engine for html files.

php view loading

If the file extension is not specified, the loadView method loads a php file.

app/controllers/First.php
namespace controllers;
class First extends ControllerBase{
     public function displayPHP(){
             //loads the view app/views/index.php
             $this->loadView("index");
     }
}
twig view loading

If the file extension is html, the loadView method loads an html twig file.

app/controllers/First.php
namespace controllers;
class First extends ControllerBase{
     public function displayTwig(){
             //loads the view app/views/index.html
             $this->loadView("index.html");
     }
}

view parameters

One of the missions of the controller is to pass variables to the view.
This can be done at the loading of the view, with an associative array:

app/controllers/First.php
class First extends ControllerBase{
     public function displayTwigWithVar($name){
             $message="hello";
             //loads the view app/views/index.html
             $this->loadView("index.html",["recipient"=>$name,"message"=>$message]);
     }
}

The keys of the associative array create variables of the same name in the view.
Using of this variables in Twig:

app/views/index.html
<h1>{{message}} {{recipient}}</h1>

Variables can also be passed before the view is loaded:

//passing one variable
$this->view->setVar("title"=>"Message");
//passing an array of 2 variables
$this->view->setVars(["message"=>$message,"recipient"=>$name]);
//loading the view that now contains 3 variables
$this->loadView("First/index.html");

view result as string

It is possible to load a view, and to return the result in a string, assigning true to the 3rd parameter of the loadview method :

$viewResult=$this->loadView("First/index.html",[],true);
echo $viewResult;

multiple views loading

A controller can load multiple views:

app/controllers/Products.php
namespace controllers;
class Products extends ControllerBase{
     public function all(){
             $this->loadView("Main/header.html",["title"=>"Products"]);
             $this->loadView("Products/index.html",["products"=>$this->products]);
             $this->loadView("Main/footer.html");
     }
}

Important

A view is often partial. It is therefore important not to systematically integrate the html and body tags defining a complete html page.

views organization

It is advisable to organize the views into folders. The most recommended method is to create a folder per controller, and store the associated views there.
To load the index.html view, stored in app/views/First:

$this->loadView("First/index.html");

initialize and finalize

Access control

Forwarding

Dependency injection

namespaces

Super class

ORM

A model class is just a plain old php object without inheritance.
Models are located by default in the app\models folder.
Object Relational Mapping (ORM) relies on member annotations in the model class.

Models definition

A basic model

  • A model must define its primary key using the @id annotation on the members concerned
  • Serialized members must have getters and setters
  • Without any other annotation, a class corresponds to a table with the same name in the database, each member corresponds to a field of this table
app/models/Product.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 namespace models;
 class Product{
     /**
      * @id
     */
     private $id;

     private $name;

     public function getName(){
             return $this->name;
     }
     public function setName($name){
             $this->name=$name;
     }
 }

//TODO

DAO

The DAO class is responsible for loading and persistence operations on models :

Loading data

Loading an instance

Loading an instance of the models\User class with id 5

use Ubiquity\orm\DAO;

$user=DAO::getOne("models\User",5);
BelongsTo loading

By default, members defined by a belongsTo relationship are automatically loaded

Each user belongs to only one category:

$user=DAO::getOne("models\User",5);
echo $user->getCategory()->getName();

It is possible to prevent this default loading ; the third parameter allows the loading or not of belongsTo members:

$user=DAO::getOne("models\User",5, false);
echo $user->getCategory();// NULL
HasMany loading

Loading hasMany members must always be explicit ; the fourth parameter allows the loading of hasmany members.

Each user has many groups:

$user=DAO::getOne("models\User",5,true,true);
foreach($user->getGroupes() as $groupe){
    echo $groupe->getName()."<br>";
}
Composite primary key

Either the ProductDetail model corresponding to a product ordered on a command and whose primary key is composite:

app/models/Products.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 namespace models;
 class ProductDetail{
     /**
      * @id
     */
     private $idProduct;

     /**
      * @id
     */
     private $idCommand;

     ...
 }

The second parameter $keyValues can be an array if the primary key is composite:

$productDetail=DAO::getOne("models\ProductDetail",[18,'BF327']);
echo 'Command:'.$productDetail->getCommande().'<br>';
echo 'Product:'.$productDetail->getProduct().'<br>';

Loading multiple objects

Loading instances of the User class:

$users=DAO::getAll("models\User");
foreach($users as $user){
    echo $user->getName()."<br>";
}

Request

Note

For all Http features, Ubiquity uses technical classes containing static methods. This is a design choice to avoid dependency injection that would degrade performances.

The URequest class provides additional functionality to more easily manipulate native $_POST and $_GET php arrays.

Retrieving data

From the get method

The get method returns the null value if the key name does not exist in the get variables.

use Ubiquity\utils\http\URequest;

$name=URequest::get("name");

The get method can be called with the optional second parameter returning a value if the key does not exist in the get variables.

$name=URequest::get("page",1);

From the post method

The post method returns the null value if the key name does not exist in the post variables.

use Ubiquity\utils\http\URequest;

$name=URequest::post("name");

The post method can be called with the optional second parameter returning a value if the key does not exist in the post variables.

$name=URequest::post("page",1);

The getPost method applies a callback to the elements of the $_POST array and return them (default callback : htmlEntities) :

$protectedValues=URequest::getPost();

Retrieving and assigning multiple data

It is common to assign the values of an associative array to the members of an object.
This is the case for example when validating an object modification form.

The setValuesToObject method performs this operation :

Consider a User class:

class User {
 private $id;
     private $firstname;
     private $lastname;

     public function setId($id){
             $this->id=$id;
     }
     public function getId(){
             return $this->id;
     }

     public function setFirstname($firstname){
             $this->firstname=$firstname;
     }
     public function getFirstname(){
             return $this->firstname;
     }

     public function setLastname($lastname){
             $this->lastname=$lastname;
     }
     public function getLastname(){
             return $this->lastname;
     }
}

Consider a form to modify a user:

<form method="post" action="Users/update">
 <input type="hidden" name="id" value="{{user.id}}">
     <label for="firstname">Firstname:</label>
     <input type="text" id="firstname" name="firstname" value="{{user.firstname}}">
     <label for="lastname">Lastname:</label>
     <input type="text" id="lastname" name="lastname" value="{{user.lastname}}">
     <input type="submit" value="validate modifications">
</form>

The update action of the Users controller must update the user instance from POST values.
Using the setPostValuesToObject method avoids the assignment of variables posted one by one to the members of the object.
It is also possible to use setGetValuesToObject for the get method, or setValuesToObject to assign the values of any associative array to an object.

app/controllers/Users.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 namespace controllers;

 use Ubiquity\orm\DAO;
 use Uniquity\utils\http\URequest;

 class Users extends BaseController{
     ...
     public function update(){
             $user=DAO::getOne("models\User",URequest::post("id"));
             URequest::setPostValuesToObject($user);
             DAO::update($user);
     }
 }

Note

SetValuesToObject methods use setters to modify the members of an object. The class concerned must therefore implement setters for all modifiable members.

Testing the request

isPost

The isPost method returns true if the request was submitted via the POST method:
In the case below, the initialize method only loads the vHeader.html view if the request is not an Ajax request.

app/controllers/Users.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 namespace controllers;

 use Ubiquity\orm\DAO;
 use Uniquity\utils\http\URequest;

 class Users extends BaseController{
     ...
     public function update(){
             if(URequest::isPost()){
                     $user=DAO::getOne("models\User",URequest::post("id"));
                     URequest::setPostValuesToObject($user);
                     DAO::update($user);
             }
     }
 }

isAjax

The isAjax method returns true if the query is an Ajax query:

app/controllers/Users.php
1
2
3
4
5
6
7
 ...
     public function initialize(){
             if(!URequest::isAjax()){
                     $this->loadView("main/vHeader.html");
             }
     }
     ...

isCrossSite

The isCrossSite method verifies that the query is not cross-site.

Response

Note

For all Http features, Ubiquity uses technical classes containing static methods. This is a design choice to avoid dependency injection that would degrade performances.

The UResponse class provides additional functionality to more easily manipulate response headers.

Session

Note

For all Http features, Ubiquity uses technical classes containing static methods. This is a design choice to avoid dependency injection that would degrade performances.

The USession class provides additional functionality to more easily manipulate native $_SESSION php array.

Starting the session

The Http session is started automatically if the sessionName key is populated in the app/config.php configuration file:

<?php
return array(
             ...
             "sessionName"=>"key-for-app",
             ...
 );

If the sessionName key is not populated, it is necessary to start the session explicitly to use it:

use Ubiquity\utils\http\USession;
...
USession::start("key-for-app");

Note

The name parameter is optional but recommended to avoid conflicting variables.

Creating or editing a session variable

use Ubiquity\utils\http\USession;

USession::set("name","SMITH");
USession::set("activeUser",$user);

Retrieving data

The get method returns the null value if the key name does not exist in the session variables.

use Ubiquity\utils\http\USession;

$name=USession::get("name");

The get method can be called with the optional second parameter returning a value if the key does not exist in the session variables.

$name=USession::get("page",1);

Note

The session method is an alias of the get method.

The getAll method returns all session vars:

$sessionVars=USession::getAll();

Testing

The exists method tests the existence of a variable in session.

if(USession::exists("name")){
     //do something when name key exists in session
}

The isStarted method checks the session start

if(USession::isStarted()){
     //do something if the session is started
}

Deleting variables

The delete method remove a session variable:

USession::delete("name");

Explicit closing of the session

The terminate method closes the session correctly and deletes all session variables created:

USession::terminate();

Views

Ubiquity uses Twig as the default template engine (see Twig documentation).
The views are located in the app/views folder. They must have the .html extension for being interpreted by Twig.

Loading

Views are loaded from controllers:

app/controllers/Users.php
1
2
3
4
5
6
7
8
9
 namespace controllers;

 class Users extends BaseController{
     ...
     public function index(){
                     $this->loadView("index.html");
             }
     }
 }

Loading and passing variables

Variables are passed to the view with an associative array. Each key creates a variable of the same name in the view.

app/controllers/Users.php
1
2
3
4
5
6
7
8
9
 namespace controllers;

 class Users extends BaseController{
     ...
     public function display($message,$type){
                     $this->loadView("users/display.html",["message"=>$message,"type"=>$type]);
             }
     }
 }

In this case, it is usefull to call Compact for creating an array containing variables and their values :

app/controllers/Users.php
1
2
3
4
5
6
7
8
9
 namespace controllers;

 class Users extends BaseController{
     ...
     public function display($message,$type){
                     $this->loadView("users/display.html",compact("message","type"));
             }
     }
 }

Displaying in view

The view can then display the variables:

users/display.html
 <h2>{{type}}</h2>
 <div>{{message}}</div>

Variables may have attributes or elements you can access, too.

You can use a dot (.) to access attributes of a variable (methods or properties of a PHP object, or items of a PHP array), or the so-called “subscript” syntax ([]):

{{ foo.bar }}
{{ foo['bar'] }}

External libraries

Ubiquity Caching

Ubiquity dependencies

Indices and tables