PHPackages                             ddn/router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. ddn/router

ActiveLibrary[Framework](/categories/framework)

ddn/router
==========

Routing for Web applications

016PHP

Since Jul 10Pushed 2y ago1 watchersCompare

[ Source](https://github.com/ddn-code/webrouter)[ Packagist](https://packagist.org/packages/ddn/router)[ RSS](/packages/ddn-router/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

DDN Web API
===========

[](#ddn-web-api)

A library to ease the development of PHP web applications.

Installation
------------

[](#installation)

TBD

```
composer require ddn/router dev-main

```

Doc
---

[](#doc)

### Base web application

[](#base-web-application)

The underlying idea is to provide tools to deal with URLs like the next one:

```
https://my.server/app/path/to/op?token=12345

```

The server points URL `https://my.server/app` to the `app` directory. In that folder, we'll need a file called `index.php`, which is the entry point for the application. In the folder we need a file `.htaccess`, used to configure the access to the application.

Example content for **.htaccess**:

```
RewriteEngine On
RewriteBase /
RewriteRule ^/index\.php$ - [L]
RewriteRule ^/favicon\.ico$ - [L]

# If it is a php file, but it is not index.php, pass it as _OPERATION parameter
RewriteCond %{REQUEST_URI} ^(.*)\.php$
RewriteCond %{REQUEST_FILENAME} !index.php$
RewriteRule ^(.*)$ index.php?_OPERATION=$1 [L,QSA]

# If it is other file that exists, serve it
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ - [L,QSA]

# Finally, if the file does not exist nor is a folder, pass it as _OPERATION parameter
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_OPERATION=$1 [L,QSA]

```

This fragment of `.htaccess` configures the router to use the `index.php` file as entry point. Any file that is not `index.php` will be passed as `_OPERATION` get parameter to the `index.php` file.

And now we need a file called **`index.php`**:

```
use ddn\api\Router;
use ddn\api\Renderer;
use ddn\api\Router\Op;

require_once('vendor/autoload.php');

// First create the router for our application; it is a simple router thet we must manage
$router = new ddn\api\Router("_OPERATION");

if (defined('__CUSTOM_ROUTES') && (is_callable(__CUSTOM_ROUTES)))
    call_user_func_array(__CUSTOM_ROUTES, [ $router ]);

class SayHello extends ddn\api\Router\Op {
    function _default_op() {
        echo "executed the default op";
    }
}

ddn\api\Renderer::set_default("template/renderer.pug");
$router->add("/", 'SayHello', 'template/example.pug');
$ops = $router->exec();
if ($ops === false) {
    header("HTTP/1.0 404 Not Found");
    echo "Not found";
    exit;
}

$ops->render();
```

### Web application model

[](#web-application-model)

A web application consists of:

- A set of *endpoints* that define paths in the web application that will be served.
- A set of operations (i.e. classes derived from `Op` class) that implement the actions at an *endpoin* (e.g. creating or deleting an object, log in a user, etc.).
- A set of *views*, that show the result of the execution of an opration.
- A set of *renderers*, that show the views.

Detaching the *renderers* from the *views* makes it easy to create an homogeneous web application. The *renderer* can be understood as a *layout* for the web application, and the *view* is estrictly the output of a web operation.

If it is not needed this kind of distinction, it is possible to render each *view* as a whole output and ignore the *renderer* (i.e. define the renderer as `($view) => { echo $view; }`).

At the end:

- A *view* is an html fragment that shows the output of an operation.
- A *renderer* is a html layout in which a view is placed.

#### Workflow

[](#workflow)

When a request arrives to the web server

1. The router evaluates whether there is a route defined or not
2. If there is no route that matches the URI, finalize.
3. Retrieve the parameters from the URI and instantiate the `Op` class that implements the operation.
4. Call funcion `_do` from `Op`
5. `_do` will chech whether there is a sub-operation defined; if not, it will call `_do_default_operation`. If there is a sub-operation, it will be executed.
6. Generate the view for the operation
    - `pug files`: var `_OP_HANDLER` will be available.
    - other file or function: global var `$_OP_HANDLER` will be available
7. Render the final layout:
    - `pug files`: vars `_OP_HANDLER` and `_VIEW` will be available.
    - other file or function: global vars `$_OP_HANDLER` and `$_VIEW` will be available

(\*) a view will not be generated unless the result of the `exec()` call is rendered (i.e. method `render()` is called).

### Router

[](#router)

The router is the main class for web applications.

To create the web application, it is needed to create a *router* and set the default renderer:

```
// _OPERATION is the GET parameter in which the operations are included. If using the suggested setup, apache (or nginx) will set this parameter to the accessed path; so if requesting URI https://my.server/path/to/my/op?v=1, '_OPERATION' will be set to path/to/my/op, and 'v' will still be 1.
$router = new ddn\api\Router("_OPERATION");

// This is the default renderer, which contains the default layout for out application (it can be either a function, a php file, an html file or a pug file, which will be interpreted)
ddn\api\Renderer::set_default("template/renderer.pug");
```

Then we need to define our routes:

```
// In path /hello we will have an operation, which will be served by class 'SayHello' and, after executing _do method of that class, we will show the view 'template/example.pug'. The renderer is the default (so we set it to null).
$router->add("/hello", 'SayHello', 'template/example.pug', null);
```

Once defined we need to exec the operation, according to the URI and render the output:

```
$ops = $router->exec();
if ($ops === false) {
    header("HTTP/1.0 404 Not Found");
    echo "Not found";
    exit;
}

$ops->render();
```

#### Methods:

[](#methods)

- `__construct($path_varname)`: Builds the object
    - $path\_varname: is the name of the variable in the "\_GET" array from which to get the path
- `add($url, $classname, $template)`: Adds a route the the router
    - $url: is the path definition that will match the route. It is possible to define the route using parameters: > /path/to/&lt;parameter&gt;/&lt;?optionalparam=default value&gt;/end
    - $classname: is the class that implements the operation (it is a `Op` subclass and/or it has to implement `_do` function). If null, there will not be any operation.
    - $template: is the template that shows the output of the operation.
- `exec()`: Checks if an URI endpoint has been hit and if it is, executes the operations and returns a `Renderer` object to be able to render the output.

### The `Op` class

[](#the-op-class)

The `Op` class is devoted to implement an operation in an end-point of the server. E.g if we define the next route: `$router->add("/", 'SayHello', 'template/example.pug');`, if the accesed endpoint matches `/`, an instance of class `SayHello` will be created. Then its class `_do` will be called.

The execution of an operation may vary depending on the values set by the action of the user. This is why the `Op` class also includes helpers to execute different functions depending on the values of `$_GET` or `$_POST` supervars.

In this way, the same class will be valid for multiple functions. E.g. it is possible to have a class `OpUsers` that implements `login`, `logout` or `update_data` depending on either a `$_POST` var is set and even depending on its value.

An example of class will be the next:

```
class OpUser extends ddn\api\Router\Op {
    const _FUNCTIONS = [
        "login" => "_login",
        "logout" => "_logout",
        "update" => [
            "" => "_update_data",
            "password" => "_update_password",
        ]
    ];

    function _login() {
        echo "executed the login op";
    }
    function _logout() {
        echo "executed the logout op";
    }
    function _update_data() {
        $_POST["name"] = $_POST["name"]??null;
        $_POST["email"] = $_POST["email"]??null;
        echo "would set:\n- user to {$_POST['name']}\n- email to {$_POST['email']}";
        echo "executed the update data op";
    }
    function _update_password() {
        echo "executed the update password op";
    }
    function _default_op() {
        echo "executed the default op";
    }
}
```

The reading for `_FUNCTIONS` is:

- if executing this class with `_POST["login"]`, execute function `_login`
- if executing this class with `_POST["logout"]`, execute function `_login`
- if executing this class with `_POST["update"]` set to `password`, execute function `_update_password`
- if executing this class with `_POST["update"]` set to other thing than `password`, execute function `_update_password`
- else, execute `_default_op`

#### Permissions

[](#permissions)

It is possible to define the const array `_PERMS` that defines the permissions needed to grant the access to the execution of this operation.

If defined, the permissions are checked and if not met, the function `forbidden` of this operation will be executed.

Permissions rely on the usage of class `ACLManager` and the definition of the ACL entries depending on the membership of the user that is using the operation to different groups.

The permissions also rely on the implementation of several functions for the operation (either for the class or the object):

- `get_app_user`: returns the user that is using the operation. The user must implement `ACLUser` interface
- `is_owner`: returns wheter a user is the owner of the object with wich is dealing the operation.
- `forbidden`: notifies the user that the access to the operation is forbidden

It is possible to define permissions such as "grant access if the user is the owner", "grant access if the user is logged in", "grant access if the user belongs to admin group", etc.

(\*) The definition of permissions is a richful automation feature, but complex to describe. So at this time, it is better to check the code than explaining.

###  Health Score

14

—

LowBetter than 2% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity22

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/f1268b2ae59f35712ab999a073be669e833ccc11a0cfe2fe7b72fef1335816b4?d=identicon)[caralla](/maintainers/caralla)

---

Top Contributors

[![dealfonso](https://avatars.githubusercontent.com/u/10501975?v=4)](https://github.com/dealfonso "dealfonso (13 commits)")

### Embed Badge

![Health badge](/badges/ddn-router/health.svg)

```
[![Health](https://phpackages.com/badges/ddn-router/health.svg)](https://phpackages.com/packages/ddn-router)
```

###  Alternatives

[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[nolimits4web/swiper

Most modern mobile touch slider and framework with hardware accelerated transitions

41.8k177.2k1](/packages/nolimits4web-swiper)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k36.7M259](/packages/laravel-dusk)[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

712181.8M596](/packages/laravel-prompts)[cakephp/chronos

A simple API extension for DateTime.

1.4k47.7M121](/packages/cakephp-chronos)[laravel/pail

Easily delve into your Laravel application's log files directly from the command line.

91545.3M590](/packages/laravel-pail)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
