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

Main configuration¶
The main configuration of a project is localised in the app/conf/config.php
file.
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.
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.
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;
}
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 :
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 :
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 :
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 :
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)
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¶
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:
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:
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.
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.
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.
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.
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
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.
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:
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:
<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:
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
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:
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.
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.
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:
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
}
Explicit closing of the session¶
The terminate method closes the session correctly and deletes all session variables created:
USession::terminate();
Cookie¶
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 UCookie class provides additional functionality to more easily manipulate native $_COOKIES php array.
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:
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.
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 :
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:
<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'] }}