PHP Classes

PHP Route One: Parse request URLs and route to a controller

Recommend this page to a friend!
  Info   View files Example   View files View files (17)   DownloadInstall with Composer Download .zip   Reputation   Support forum   Blog    
Ratings Unique User Downloads Download Rankings
Not yet rated by the usersTotal: 107 This week: 1All time: 9,664 This week: 560Up
Version License PHP version Categories
routeone 1.0.1GNU Lesser Genera...5HTTP, PHP 5, Design Patterns
Description 

Author

This package can parse request URLs and route to a controller.

It can take as parameter a value that is the path of the URL of the current request and parses it to extract the base name of a controller class and other request parameters.

The package can return an object that is the controller class, so it can be called to process the current request.

Picture of Jorge Castro
  Performance   Level  
Name: Jorge Castro <contact>
Classes: 30 packages by
Country: Chile Chile
Age: 48
All time rank: 12763 in Chile Chile
Week rank: 106 Up1 in Chile Chile Up
Innovation award
Innovation award
Nominee: 14x

Winner: 2x

Example

<?php

use eftec\routeone\RouteOne;

include
"../vendor/autoload.php";
include
"MiController.php";

$route=new RouteOne(".",null,false);

//var_dump($_GET['req']);
//die(1);

$url=$route->getCurrentUrl();

echo
"<hr>Current url :".$url."<br><ul>";
echo
"<li><a href='{$url}/Mi'>./Mi</a><br></li>";
echo
"<li><a href='{$url}/Wrong'>./Wrong (it show throws an error)</a><br></li>";
echo
"<li><a href='{$url}/Mi/Action2'>./Mi/Action2</a><br></li>";
echo
"<li><a href='{$url}/Mi/ActionWrong'>./Mi/ActionWrong (it show throws an error)</a><br></li>";
echo
"<li><a href='{$url}/Mi/Action2/id'>./Mi/Action2/id</a><br></li>";
echo
"<li><a href='{$url}/Mi/Action2/id/parentid'>./Mi/Action2/id/parentid</a><br></li>";
echo
"<li><a href='{$url}/Mi/Action2/id/parentid?_event=click'>./Mi/Action2/id/parentid?_event=click</a><br></li>";
echo
"<li><a href='{$url}/Mi/Action3/id/parentid?_event=click'>./Mi/Action3/id/parentid?_event=click (method with only id)</a><br></li>";
echo
"<li><a href='{$url}/Mi/ActionHTTPS/id/parentid?_event=click'>./Mi/ActionHTTPS/id/parentid?_event=click redirect to https</a> (https must be enable in the server)<br></li>";
echo
"<li><a href='{$url}/Mi/ActionWWW/id/parentid?_event=click'>./Mi/ActionWWW/id/parentid?_event=click redirect to www.</a> (if www.**domain** is defined) <br></li>";
echo
"<li><a href='{$url}/Mi/ActionWWWS/id/parentid?_event=click'>./Mi/ActionWWWS/id/parentid?_event=click redirect to www (https).</a> (if www.**domain** is defined) <br></li>";
echo
"<li><a href='{$url}/Mi/ActionNaked/id/parentid?_event=click'>./Mi/ActionNaked/id/parentid?_event=click redirect to naked domain.</a> <br></li>";

echo
"</ul><hr>";
echo
"<b>It could show an error. It is expected (if the path is incorrect of the class/method does not exists)</b><br></li>";
$route->fetch();
$route->callObject();
echo
"<hr>";
echo
"<pre>";



var_dump($route);
var_dump($route->getUrl());
var_dump($route->getIdparent());

var_dump("Server:".$route->getCurrentServer());
var_dump("Server:".$route->getCurrentUrl());
echo
"</pre>";


Details

RouteOne

Route for PHP

It reads the url route and parses the values, so it could be interpreted manually or automatically.

Unlikely other libraries, this library does not have dependencies and it is contained in a single class.

This library is based in CoC Convention over Configuration. It reduces the boilerplate but it has fixed functionalities. This library does not allow to change the "route" but it covers practically all cases, so it increases the performance and usability while it sacrifices flexibility.

This library is also as fast as possible and slim as possible.

Build Status Packagist Total Downloads [Maintenance]() [composer]() [php]() [CocoaPods]()

What it does?

Let's say we do the next operation:

An user calls the next website http://somedomain.com/Customer/Insert, he wants want to show a form to insert a customer

$route=new RouteOne('.',null,null); // Create the RouteOneClass
$route->fetch(); // fetch all the input values (from the route, get, post and such).
$route->callObject('somenamespace\\controller\\%sController'); // where it will call the  class CustomerController* 

or

$route=new RouteOne('.',null,null); // Create the RouteOneClass
$route->fetch(); // fetch all the input values (from the route, get, post and such).
$route->callObjectEx('somenamespace\\controller\\{controller}Controller'); // where it will call the  class CustomerController* 

This code calls to the method InsertActionGet (GET), InsertActionPost (POST) or InsertAction (GET/POST) inside the class Customer

The method called is written as follow:

class Customer {
    public function insertAction($id="",$idparent="",$event="") {
        // here we do our operation.
    }
}

What is $id, $idparent and $event?

id

Let's se we want to Update a Customer number 20, then we could call the next page

> http://somedomain.com/Customer/Update/20

where 20 is the "$id" of the customer to edit (it could be a number of a string)

idparent

And what if we want to Update a Customer number 20 of the business APPL

> http://somedomain.com/Customer/Update/20/APPL

Where APPL is the idparent

event

Now, let's say we click on some button or we do some action. It could be captured by the field _event and it is read by the argument $event. This variable could be send via GET or POST.

> http://somedomain.com/Customer/Update/20/APPL?_event=click

Module

Now, let's say our system is modular and we have several customers (interna customers, external, etc.)

$route=new RouteOne('.',null,true); // true indicates it is modular 
$route->fetch(); 
$route->callObject('somenamespace\\%2s%\\controller\\%1sController');

> http://somedomain.com/Internal/Customer/Update/20/APPL?_event=click

Then, the first ramification is the name of the module (Internal) and it calls the class somenamespace\Internal\controller\CustomerController

Getting started

1) Create a .htaccess file

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteCond %{REQUEST_URI} !-L
# l = last
RewriteRule ^(example|test|css|vendors|vendor|js|img|upload)($|/) - [L]
RewriteRule ^(.*)$ router.php?req=$1 [L,QSA]

</IfModule>

where test1.php is the file that it will work as router. ?req=$1 is important because the system will read the route from "req"

// router.php
$route=new RouteOne(); // Create the RouteOneClass
$route->fetch(); // fetch all the input values (from the route, get, post and such).
$route->callObject('somenamespace\\controller\\%sController'); // where it will call the  class \somenamespace\controller\CustomerController  

Routes

API route

> https://localhost/api/controller/{action}/{id}/{idparent}

where https://localhost* is the base (it could be changed on the constructor) apiindicates we are calling an "api". This value could be changed via$this->setPath()* Controller*. It's the controller class to call. Action*. It's the action (method) to call id*. Some unique identifier. idparent*. Some unique identifier (of the parent of object)

// router.php https://locahost/api/Customer/Get/1
$route=new RouteOne(); // Create the RouteOneClass
$route->fetch(); // fetch all the input values (from the route, get, post and such).
if ($route->getType()=='api') {
   var_dump($route->getController()); // Customer
   var_dump($route->getAction()); // Get
   var_dump($route->getId()); // 1
   var_dump($route->getIdparent()); // null
   $route->callFile("api/%s.php",true); // we call the file Customer.php   
} 

WS route

WS is an alternative to API. We could use API/WS or both. The difference is how is it called (/api/ versus /ws/)

> https://localhost/ws/controller/{action}/{id}/{idparent}

where https://localhost* is the base (it could be changed on the constructor) wsindicates we are calling an "ws". This value could be changed via$this->setPath()* Controller*. It's the controller class to call. Action*. It's the action (method) to call id*. Some unique identifier. idparent*. Some unique identifier (of the parent of object)

// router.php https://locahost/ws/Customer/Get/1
$route=new RouteOne(); // Create the RouteOne Class
$route->fetch(); // fetch all the input values (from the route, get, post and such).
if ($route->getType()=='ws') {
   var_dump($route->getController()); // Customer
   var_dump($route->getAction()); // Get
   var_dump($route->getId()); // 1
   var_dump($route->getIdparent()); // null
   $route->callFile("ws/%s.php",true); // we call the file Customer.php   
} 

Controller route

Unlikely "api" and "ws" route, the controller route doesn't have a prefix in the route.

> https://localhost/controller/{action}/{id}/{idparent}

where https://localhost* is the base (it could be changed on the constructor) Controller*. It's the controller class to call. Action*. It's the action (method) to call id*. Some unique identifier. idparent*. Some unique identifier (of the parent of object)

router.php:

// router.php https://locahost/Customer/Get/1
$route=new RouteOne(); // Create the RouteOne Class
$route->fetch(); // fetch all the input values (from the route, get, post and such).
if ($route->getType()=='controller') {
   var_dump($route->getController()); // Customer
   var_dump($route->getAction()); // Get
   var_dump($route->getId()); // 1
   var_dump($route->getIdparent()); // null
   $route->callObject('\\somenamespace\\controller\\%sController'); // we call CustomerController class and we call the method "getAction" / "getActionGet" or "getActionPost"
} 

file CustomerController.php:

namespace somenamespace\controller;
class CustomerController {
    // any action GET or POST
    public function GetAction($id="",$idparent="",$event="") {
        // my code goes here.
        // $event (optional) is read from REQUEST or POST
    }
    // GET only action (optional)
    public function GetActionGet($id="",$idparent="",$event="") {
        // my code goes here.
    }    
    // POST only action (optional)
    public function GetActionPOST($id="",$idparent="",$event="") {
        // my code goes here.
    }        
}

FRONT route

The front route (for the front-end) is different than other routes. Syntactically it is distributed on category, subcategory and subsubcategory.

> This route is not identified automatically so it must be set in the constructor

> https://localhost/category/{subcategory}/{subsubcategory}/{id}

where https://localhost* is the base (it could be changed on the constructor) category* The category that we are calling. subcategory*. (optional) The subcategory subsubcategory*. (optional) The sub-subcategory id. Some unique identifier. (id* is always the last element of the chain, so /category/20, category/subc/20 and /category/subc/subc/20 always returns 20).

Example: (isModule=false)

> http://localhost/Toys/GoodSmileCompany/Nendoroid/Thanos

  • Category = toys
  • Subcategory = GoodSmileCompany
  • Subsubcategory = Nendoroid
  • id = Thanos

Example: (isModule=true)

> http://localhost/Retail/Toys/GoodSmileCompany/Nendoroid/Thanos

  • Module = Retail
  • Category = toys
  • Subcategory = GoodSmileCompany
  • Subsubcategory = Nendoroid
  • id = Thanos (id is always the last element)
  • idparent = (it does not work on frontal)

Example: (isModule=false)

> http://localhost/Toys/GoodSmileCompany/Thanos

  • Category = toys
  • Subcategory = GoodSmileCompany
  • Subsubcategory = Thanos
  • id = Thanos
// router.php https://locahost/Products/New/123
$route=new RouteOne('.','front'); // Create the RouteOne Class for the front end.  It is required to indicate the type as "front". Otherwise it will be interpreted as a "controller route".
$route->fetch(); // fetch all the input values.
if ($route->getType()=='front') {
   var_dump($route->getCategory()); // Products
   var_dump($route->getSubCategory()); // New
   var_dump($route->getSubSubCategory()); // null
   var_dump($route->getId()); // 123  
} 

Methods

__construct($base='', $forcedType=null, $isModule=false)

  • string $base base url
  • string $forcedType=['api','ws','controller','front'][$i]<br> <b>api</b> then it expects a path as api/controller/action/id/idparent<br> <b>ws</b> then it expects a path as ws/controller/action/id/idparent<br> <b>controller</b> then it expects a path as controller/action/id/idparent<br> <b>front</b> then it expects a path as /category/subcategory/subsubcategory/id<br>
  • bool $isModule if true then the route start reading a module name<br> <b>false</b> controller/action/id/idparent<br> <b>true</b> module/controller/action/id/idparent<br>

getQuery($key,$valueIfNotFound=null)

It gets a query value (URL).

>Note: This query does not include the values "req","_event" and "_extra"

Example:

// http://localhost/..../?id=hi
$id=$router->getQuery("id"); // hi
$nf=$router->getQuery("something","not found"); // not found

setQuery($key,$value)

It sets a query value

Example:

$route->setQuery("id","hi");
$id=$router->getQuery("id"); // hi

fetch()

Fetch the values from the route, and the values are processed.

callObject($classStructure='%sController',$throwOnError=true)

Call a method inside an object using the current route.

  • $classStructure

    * The first %s (or %1s) is the name of the controller.<br> * The second %s (or %2s) is the name of the module (if any and if ->isModule=true)<br> * Example: namespace/%sClass if the controller=Example then it calls namespace/ExampleClass<br> * Example: namespace/%2s/%1sClass it calls namespace/Module/ExampleClass<br>

  • throwOnError if true and it fails then it throws an error. If false then it only returns the error message.

The name of the method is obtained via the current action

1) {nameaction}Action exists then it's called. 2) Otherwise, if $istpostback=false then it calls the method {nameaction}ActionGet 3) Otherwise, if $istpostback=true then it calls the method {nameaction}ActionPost

callObjectEx($classStructure, $throwOnError, $method, $methodGet, $methodPost,$arguments

It creates and object (for example, a Controller object) and calls the method.<br> Note: It is an advanced version of this::callObject()<br> This method uses {} to replace values based in the next variables:<br>

| Tag | Description | |------------------|----------------------------------------------------| | {controller} | The name of the controller | | {action} | The current action | | {event} | The current event | | {type} | The current type of path (ws,controller,front,api) | | {module} | The current module (if module is active) | | {id} | The current id | | {idparent} | The current idparent | | {category} | The current category | | {subcategory} | The current subcategory | | {subsubcategory} | The current subsubcategory |

<b>Example:</b>

// controller example http://somedomain/Customer/Insert/23
$this->callObjectEx('cocacola\controller\{controller}Controller');
// it calls the method cocacola\controller\Customer::InsertAction(23,'','');

// front example: http://somedomain/product/coffee/nescafe/1
$this->callObjectEx('cocacola\controller\{category}Controller' // the class to call
        ,false // if error then it throw an error
        ,'{subcategory}' // the method to call (get or post)
        ,null // the method to call (method get)
        ,null // the method to call (method post)
        ,['subsubcategory','id']); // the arguments to call the method
// it calls the method cocacola\controller\product::coffee('nescafe','1');

Call a method inside an object using the current route.

callFile($fileStructure='%s.php',$throwOnError=true)

It calls (include) a php file using the current name of the controller

  • $fileStructure The current name of the controller. "%s" is the name of the current controller. Example :/Customer/Insert -> calls the file Customer.php
  • throwOnError if true then it throws an error. If false then it only returns the error message.

getCurrentUrl($withoutFilename = true)

Returns the current base url without traling space, paremters or queries

> <b>Note</b>: this function relies on $_SERVER['SERVER_NAME'] and it could be modified by the end-user

getCurrentServer()

It returns the current server without trailing slash.

$route->getCurrentServer(); // http://somedomain

getUrl($extraQuery = '',$includeQuery=false)

It gets the (full) url based in the information in the class.

$route->getUrl(); // http://somedomain/controller/action/id
$route->getUrl('id=20'); // http://somedomain/controller/action/id?id=20
$route->getUrl('id=20',true); // http://somedomain/controller/action/id?id=20&field=20&field2=40

url($module,$controller,$action,$id,$idparent)

It builds an url based in custom values

$route->url(null,"Customer","Update",20); // Customer/Update/20

urlFront($module,$category,$subcategory,$subsubcategory,$id)

It builds an url (front) based in custom values

$route->url(null,"Daily","Milk",20); // Daily/Milk/20

alwaysWWW($https = false)

If the subdomain is empty or different to www, then it redirect to www.domain.com.<br> <b>Note: It doesn't work with localhost, domain without TLD (netbios) or ip domains. It is on purpose.</b><br> <b>Note: If this code needs to redirect, then it stops the execution of the code. Usually it must be called at the top of the code</b>

$route->alwaysWWW();  // if the domain is somedomain.dom/url, then it redirects to www.somedomain.dom/url
$route->alwaysWWW(true);  // if the domain is http: somedomain.dom/url, then it redirects to https: www.somedomain.dom/url

alwaysHTTPS()

If the page is loaded as http, then it redirects to https. <b>Note: It doesn't work with localhost, domain without TLD (netbios) or ip domains. It is on purpose.</b><br> <b>Note: If this code needs to redirect, then it stops the execution of the code. Usually it must be called at the top of the code</b>

$route->alwaysHTTPS(); // http://somedomain.com ---> https://somedomain.com
$route->alwaysHTTPS(); // http://localhost ---> // http://localhost
$route->alwaysHTTPS(); // http://127.0.0.1 ---> // http://127.0.0.1
$route->alwaysHTTPS(); // http://mypc ---> // http://mypc

alwaysNakedDomain($https = false)

If the subdomain is www (example www.domain.dom) then it redirect to a naked domain domain.dom<br> <b>Note: It doesn't work with localhost, domain without TLD (netbios) or ip domains. It is on purpose.</b><br> <b>Note: If this code needs to redirect, then it stops the execution of the code. Usually, it must be called at the top of the code</b>

$route->alwaysNakedDomain();  // if the domain is www.somedomain.dom/url, then it redirects to somedomain.dom/url
$route->alwaysNakedDomain(true);  // if the domain is http: www.somedomain.dom/url, then it redirects to https: somedomain.dom/url

fields

$isPostBack (field)

if true then the form is called as POST (i.e. a submit button).

$type

it returns the current type

> Also obtained via getType()

|type|url expected|description| |----|------------|------------| | api |domain.dom/api/controller/action/id | {module}\api\controller\action\id\{idparent}?_event=event | | ws |domain.dom/ws/controller/action/id | {module}\ws\controller\action\id\{idparent}?_event=event | | controller |domain.dom/controller/action/id | {module}\controller\action\id\{idparent}?_event=event | | front |domain.dom/cat/subcat/subsubcat/id | {module}\category\subcategory\subsubcategory\id?_event=event |

Example:

$route=new RouteOne('.',null,false);  // null means automatic type
$route->fetch(); 
if($route->type==='api') {
    $route->callObject('somenamespace\\api\\%sApi');
} else {
    $route->callObject('somenamespace\\controller\\%sController');
}

Example:

$route=new RouteOne('.',null,false);  // null means automatic type
$route->fetch(); 

$route->callObject('somenamespace\\%3s%\\%sController'); // somespace/api/UserController , somespace/controller/UserController, etc.

Changelog

  • 2020-03-27 1.11 * added alwaysNakedDomain()
  • 2020-03-27 1.10.1 * a small fix for alwaysHTTPS()
  • 2020-03-27 1.10 * added method alwaysHTTPS() and alwaysWWW()
  • 2020-02-15 1.9 * added new arguments to callObject() * new method callObjectEx()
  • 2020-02-03 1.8 * new method getNonRouteUrl() * new method setExtra() * new method isPostBack() * new method setIsPostBack() * Some fixes for getUrl()

  Files folder image Files  
File Role Description
Files folder imageexamples (3 files, 1 directory)
Files folder imagelib (1 file)
Files folder imagetests (3 files)
Accessible without login Plain text file .travis.yml Data Auxiliary data
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file LICENSE Lic. License text
Accessible without login Plain text file phpunit.xml Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files  /  examples  
File Role Description
Files folder imagefullexample (3 files, 1 directory)
  Accessible without login Plain text file .htaccess Data Auxiliary data
  Plain text file MiController.php Class Class source
  Accessible without login Plain text file router.php Example Example script

  Files folder image Files  /  examples  /  fullexample  
File Role Description
Files folder imagecontroller (2 files)
  Accessible without login Plain text file .htaccess Data Auxiliary data
  Plain text file BootstrapUtil.php Class Class source
  Accessible without login Plain text file router.php Example Example script

  Files folder image Files  /  examples  /  fullexample  /  controller  
File Role Description
  Plain text file CustomerController.php Class Class source
  Plain text file HomeController.php Class Class source

  Files folder image Files  /  lib  
File Role Description
  Plain text file RouteOne.php Class Class source

  Files folder image Files  /  tests  
File Role Description
  Accessible without login Plain text file bootstrap.php Aux. Auxiliary script
  Accessible without login Plain text file MyController.php Aux. Auxiliary script
  Plain text file RouterOneTest.php Class Class source

 Version Control Unique User Downloads Download Rankings  
 100%
Total:107
This week:1
All time:9,664
This week:560Up