In this page:
Memorable URLs and a well-defined structure are crucial for user experience and SEO. Instead of cryptic URLs like
http://example.com/view-something?something={a-something}
, user-friendly URLs like
http://example.com/view-something/{a-something}
are easier to remember and navigate. This clarity benefits both users and search engines.
Routing, a web development technique, maps user requests (URLs) to the appropriate resources. It allows creating user-friendly, SEO-friendly URLs without manually creating individual files, streamlining development and enhancing website visibility.
Routing, a core function within WebFiori, directs user requests to their intended destinations. The
webfiori\framework\router\Router
class facilitates this process, enabling developers to define custom URL structures that map to specific resources.
By mastering the topics in this documentation, developers can effectively harness WebFiori's routing system for enhanced navigation and user experience.
Web servers leverage configuration files, like
.htaccess
in Apache and
web.config
in IIS, to define pre-execution behavior. WebFiori utilizes a custom
.htaccess
to rewrite requested URLs and redirect them to the
index.php
file within the
public
directory.
Code
ReWriteRule ^(.*)$ index.php [L,QSA]
Similarly, a custom
web.config
file achieves the same redirection.
Code
<rule name="Bloom The Seed" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<!--Send all trafic to framework seed and make your work bloom.-->
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
Upon reaching
index.php
, the application initializes. Following successful initialization, the final step involves routing the request to its designated destination and sending back the response.
Routing Orchestration
The
webfiori\framework\router\Router
class plays a pivotal role in WebFiori's routing mechanism. It takes the requested URL as input using the
Router::route()
method. If a corresponding resource is found, the request is directed there. Otherwise, a 404 error is generated.
Note:
mod_rewrite
for rewrite rules.
Router
The
Router
class sits at the heart of WebFiori, responsible for establishing routes and directing incoming client requests to their designated resources. These resources can encompass various elements, from static files like text, images, and web pages to dynamic reports generated by processing and displaying data in a user-friendly format.
The Router empowers developers to create four primary types of routes:
Each route type in WebFiori has a corresponding static method within the
Router
class for efficient creation:
In general, the idea of creating route for each type of routes will be the same. The only difference will be the location of the resource that the route will point to in addition to middleware group that the route will be assigned to by default.
This type is a route that will point to a web page. The page can be simple HTML page or dynamic PHP web page. Usually, the folder
[APP_DIR]/pages
of the application will contain all pages. The method
Router::page()
is used to create such route.
In order to make it easy for developers, they can use the class
[APP_DIR]/ini/routes/PagesRoutes
to create routes to all pages. The developer can modify the body of the method
PagesRoutes::create()
to add new routes as needed.
Assuming that there exist 3 pages inside the folder
[APP_DIR]/pages
as follows:
[APP_DIR]/pages/HomeView.html
[APP_DIR]/pages/LoginView.php
[APP_DIR]/pages/system-views/DashboardView.php
Also, assuming that the base URL of the website is
https://example.com/
. Assuming that the developer would like from the user to see the pages as follows:
https://example.com/
should point to the view
HomeView.html
https://example.com/home
should point to the view
HomeView.html
https://example.com/user-login
should point to the class
LoginView.php
https://example.com/dashboard
should point to the view
DashboardView.html
The following sample code shows how to create such a URL structure using the class
ViewRoutes
.
Code
namespace app\ini\routes;
use webfiori\framework\router\Router;
use webfiori\framework\router\RouteOption;
class PagesRoutes {
public static function create(){
Router::page([
RouteOption::PATH => '/',
RouteOption::TO => '/HomeView.html'
]);
Router::page([
RouteOption::PATH => '/home',
RouteOption::TO => '/HomeView.html'
]);
Router::page([
RouteOption::PATH => '/user-login',
RouteOption::TO => \app\pages\LoginView::class
]);
Router::page([
RouteOption::PATH => '/dashboard',
RouteOption::TO => '/system-views/DashboardView.html'
]);
}
}
Note: The forward slash is optional at the start of the path and the resource and can be ignored.
An API route is a route that will point to a PHP class that exist in the folder
[APP_DIR]/apis
. Usually the class will extend the class
WebServicesManager
or the class
ExtendedWebServicesManager
. To execute one of the services at which the class manages, the developer have to include an extra
GET
or
POST
parameter which has the name
service-name
or
service
. More information about web services can be found
here
.
Suppose that there exist 3 services classes as follows:
[APP_DIR]/apis/UserServicesManager.php
[APP_DIR]/apis/ArticleServicesManager.php
[APP_DIR]/apis/ContentServicesManager.php
Assuming that the base URL of the website is
https://example.com/
, Assuming that the developer would like to have the URLs of the APIs (or services) to be like that:
https://example.com/web-apis/user/add-user
should point to
UserServicesManager.php
https://example.com/web-apis/user/update-user
should point to
UserServicesManager.php
https://example.com/web-apis/user/delete-user
should point to
UserServicesManager.php
https://example.com/web-apis/article/publish-article
should point
ArticleServicesManager.php
https://example.com/web-apis/article/revert-publish
should point
ArticleServicesManager.php
https://example.com/web-apis/article-content/add-content
should point to
ContentServicesManager.php
https://example.com/web-apis/article-content/remove-content
should point to the view
ContentServicesManager.php
One thing to note about creating APIs is that API name (or service name) must be passed alongside request body as a GET or POST parameter (e.g.
service=add-user
or
service-name=add-user
). As noticed from the above URLs, the name of the service is appended to the end of the URL. The router will know that this is a route to a web service if Generic Route is used.
A generic route is a route that has some of its path parts unknown. They can be used to serve dynamic content passed as path parameter. A path parameter is a value that is enclosed between
{}
while creating the route. For example, the first 3 APIs can have one URL in the form
https://example.com/web-apis/user/{service-name}
or
https://example.com/web-apis/user/{service}
.
The following sample code shows how to create such a URL structure using the class
APIRoutes
. Note that the value of path parameter must be
action
,
service-name
or
service
or the API call will fail.
Code
namespace app\ini\routes;
use webfiori\framework\router\Router;
use webfiori\framework\router\RouteOption;
use ContentServices;
class APIRoutes {
public static function create(){
Router::api([
RouteOption::PATH => '/web-apis/user/{service}',
RouteOption::TO => '/UserAPIs.php'
]);
Router::api([
RouteOption::PATH => '/web-apis/article/{service}',
RouteOption::TO => '/writer/ArticleAPIs.php'
]);
Router::api([
RouteOption::PATH => '/web-apis/article-content/{service}',
RouteOption::TO => ContentServices::class
]);
}
}
A closure route is a route to a user defined code that will be executed when the resource is requested. In other terms, it is a function that will be called when a request is made. It is simply an Anonymous Function. Suppose that a developer would like to create a route to a function that will output
Hello Mr.{A_Name}
When it's called. The URL that will be requested will have the form
https://example.com/say-hello-to/{A_Name}
. As noticed,a generic path parameter in the URL is added which will hold the name that the function will say hello to.
The value of the parameter can be accessed using the method
Router::getParameterValue()
. All what needed to be done is to pass parameter name and the method will return its value. The following code sample shows how it's done.
Code
namespace app\ini\routes;
use webfiori\framework\router\Router;
use webfiori\framework\router\RouteOption;
use webfiori\framework\Response;
class ClosureRoutes {
public static function create(){
Router::closure([
RouteOption::PATH => '/say-hello-to/{A_Name}',
RouteOption::TO => function(){
$name = Router::getVarValue('A_Name');
Response::apped('Hello Mr.'.$name);
}
]);
}
}
A custom route is a route that points to a file which exist in a folder that was created by the developer outside the folder
apis
or
pages
. The folder must exist inside application scope in order to create a route to it.
Assuming that there exist a folder which has the name
sys-files
and inside this folder,there exist two folders. One has the name
views
which contains web pages and another one has the name
apis
which contains system's web APIs. Assuming that the
views
folder has a view which has the name
HomeView.php
and the folder
apis
has one file which has the name
AuthAPI.php
. The following code shows how to create a route to each file:
Code
namespace app\ini\routes;
use webfiori\framework\router\Router;
use webfiori\framework\router\RouteOption;
class ClosureRoutes {
public static function create(){
Router::addRoute([
RouteOption::PATH => '/index.php',
RouteOption::TO => 'sys-files/views/HomeView.php'
]);
Router::addRoute([
RouteOption::PATH => '/apis/auth/{service}',
RouteOption::TO => 'sys-files/apis/AuthAPI.php',
RouteOption::API => true
]);
}
}
It is possible to have a route to a PHP class. When such route is created, the router will try to create an instance of the class at which the route is pointing to.
Code
namespace app\ini\routes;
use webfiori\framework\router\Router;
use webfiori\framework\router\RouteOption;
use my\super\HomePage;
class ClosureRoutes {
public static function create(){
Router::addRoute([
RouteOption::PATH => '/rout-to-class',
RouteOption::TO => HomePage::class
]);
}
}
Also, it is possible to have the route point to specific method in the class by using the option
action
. This is useful when using MVC in building the application and want from the route to point to specific controller method.
Code
use my\super\FrontController;
class ClosureRoutes {
public static function create(){
Router::addRoute([
RouteOption::PATH => '/rout-to-class',
RouteOption::TO => FrontController::class,
RouteOption::ACTION => 'index'
]);
}
}
This type of route is used to redirect specific request to another web page or website. This type of route can be added using the method
Router::redirect()
Suppose that there exist a website that publishes news. Each post will have its own link. Each post have a URI structure that looks like
https://example.com/news/some_post
. One way to route the user to the correct post is to create a unique route for each post. If there are 1000 posts, then developer have to create 1000 routes which is overwhelming.
WebFiori framework provides a way to create one route to all posts. This can be archived by using route parameters while creating your route. By adding parameters, the developer just created a generic route which can serve content based on the value of the variable.
A URI parameter is a string which is a part of URI's path which can have many values. It is a string which is placed between
{}
. The value of the parameter can be specified when sending a request to the resource that the URI represents. In the following example, the value of the parameter most probably will be the name of the post.
Code
Router::closure([
RouteOption::PATH => '/news/{post-title}',
RouteOption::TO => function(){}
]);
URI parameters can be also used to replace query string parameters to make URIs user-friendly.
In order to add a parameter to a route, the developer have to enclose the name of the parameter between two curly braces
{}
. To access the value of the parameter, the method
Router::getParameterValue()
is used. The following sample code shows how to use URI parameters in creating generic routes.
Code
use webfiori\framework\Response;
class ClosureRoutes {
public static function create(){
Router::closure([
RouteOption::PATH => '/news/{post-title}',
RouteOption::TO => function(){
$name = Router::getParameterValue('post-title');
Response::append('You tried to open the post which has the title "'.$name.'"');
}
]);
}
}
It is possible to have URI parameters as optional. In this case, the route will be resolved even if no value is provided in the path. To mark a parameter as optional, a question mark can be added to the end of parameter name as follows:
{var?}
.
Code
use webfiori\framework\Response;
class ClosureRoutes {
public static function create(){
Router::closure([
RouteOption::PATH => '/news/{post-title?}',
RouteOption::TO => function () {
$name = Router::getParameterValue('post-title');
if ($name === null) {
Response::append('No title is provided.');
} else {
Response::append('You tried to open the post which has the title "' . $name . '".');
}
}
]);
}
}
One of the features of the router is the ability to group routes which share same part of the path. Suppose that there are 3 pages with following links:
https://example.com/users
https://example.com/users/view-user/{user-id}
https://example.com/users/add-user
One thing to notice about the routes is that they share the same
users
path part. It is possible to create each route by itself but there is a better way that can be used to group the routes. The following code shows how to group routes.
Code
Router::group([
RouteOption::PATH => '/users',
RouteOption::CASE_SENSITIVE => false,
RouteOption::MIDDLEWARE => [
'sample-middleware','sample-middleware-2'
],
RouteOption::REQUEST_METHODS => 'get',
RouteOptions::SUB_ROUTES => [
[
RouteOption::PATH => '/',
RouteOption::TO => ListUsersPage::class,
],
[
RouteOption::PATH => 'view-user/{user-id}',
RouteOption::TO => ViewUserPage::class,
]
[
RouteOption::PATH => 'add-user',
RouteOption::TO => AddUserPage::class,
]
]
]);
By grouping routes, the developer can achieve the following:
Each method which is used to add new route supports options which can be used to customize the route. The options are kept as constants in the class
webfiori\framework\router\RouteOption
. This section explains each option in more details.
The option
RouteOption::SITEMAP
is a boolean which is used to tell if the URI will be in the sitemap which is generated automatically or not. Default value of this option is
false
Note: To create a sitemap using added routes, the method
Router::incSiteMapRoute()
. The sitemap will be accessible throughhttp://example/sitemap.xml
.
One of the available options is
RouteOption::CASE_SENSITIVE
. This option is used to make the URI case-sensitive or not. If this one is set to false, then if a request is made to the URI
https://example.com/one/two
, It will be the same as requesting the URI
https://example.com/OnE/tWO
. By default, this one is set to true.
The option
RouteOption::LANGS
is used to tell which languages the URI supports. The option accepts an array that contains language codes (such as
AR
). This one is used only when
generating sitemap
of the website to tell search engines about the languages at which the page is available on.
The option
RouteOption::VALUES
is used in generating the sitemap of the website. The option accepts sub-associative arrays. The key of the array represents the name of variable name and the value is a sub array that contains possible variable values.
The option
RouteOption::MIDDLEWARE
is used to specify which middleware the request will go through when a request is made to the given resource. This option accepts middleware name or an array that holds middleware names. Also, this option can have the name of middleware group or an array of middleware groups. For more information about middleware,
here
.
By default, a route to a resource can be called using any request method. But it is possible to restrict that to specific request method (or methods). The option
RouteOption::REQUEST_METHODS
can have a string which represents the method at which the resource can be fetched with (e.g. 'GET') or it can be an array that holds the names of request methods at which the resource can be fetched with.
The
RouteOption::ACTION
option is used when the route is pointing to a class and the developer would like to call one action from the class. This option can make your application more MVC-like.
Next:
The Class
Response
Previous: Basic Usage