torugo/router

Simple route system using PHP Attributes

1.0.4 2024-10-02 17:19 UTC

This package is auto-updated.

Last update: 2025-04-30 18:32:23 UTC


README

A simple PHP router system.
Uses the PHP Attributes feature.

Table of Contents

Requirements

  • PHP 8.2+
  • Composer 2+ (Package manager)
  • PHPUnit 11+ (Automated tests)

Installing

composer require torugo/router

Usage

Routing

use Torugo\Router\Attributes\Request\Controller;
use Torugo\Router\Attributes\Request\Get;

#[Controller("/users")]
class UsersController {
    #[Get()] // endpoint: GET /users
    public function findAll(): array
    {
        return [/* list of users */];
    }

    #[Get("/{id}")] // endpoint: GET /users/<the user id>
    public function findOne(string $id): array
    {
        return [/* user data */];
    }
}

Registering Controllers

All controllers must use the Controller attribute.

use Torugo\Router\Router;

$router = new Router;

$router->registerMany([
    UsersController::class,
    CostumersController::class,
    SuppliersController::class,
    StockController::class,
]);

try {
    $router->autoResolve();
} catch (\Throwable $th) {
    // Handle errors
}

Additionally you can register controllers individually.

$router->register(UsersController::class);
$router->register(CostumersController::class);
$router->register(SuppliersController::class);
$router->register(StockController::class);

Resolving the requests

Auto Resolve

try {
    $router->autoResolve();
} catch (\Throwable $th) {
    // Handle errors
}

Resolving manually

$uri = Request::getUri();
$requestMethod = Request::getMethod();

// Here you can filter the uri
// The request method must be a member of RequestMethod Enum

try {
    $router->resolve($uri, $requestMethod);
} catch (\Throwable $th) {
    // Handle errors
}

Prefixing all routes

If your API has a prefixed route like '/v1' you can configure the router to handle it.

use Torugo\Router\Router;

$router = new Router;
$router->setPrefix("/v1");

/**
 * If you receive a GET request with the URI '/v1/users/12345', the router will execute '/users/12345'
 */

Getting request data

You can access the request data anywhere using the method getData() from Torugo\Router\Request.

use Torugo\Router\Attributes\Request\Controller;
use Torugo\Router\Attributes\Request\Post;
use Torugo\Router\Request;

#[Controller("/users")]
class UsersController {
    #[Post()]
    public function add(): array
    {
        $userData = Request::getData();
        
        /* ADD NEW USER DATA ON DATABASE */
        
        return [/* new user data */];
    }
}

Responses

When a controller method returns array it is converted to a Json string, other types are not converted.

use Torugo\Router\Attributes\Request\Controller;
use Torugo\Router\Attributes\Request\Get;

#[Controller("users")]
class UsersController {
    #[Get()]
    public function findAll(): array
    {
        $users = [
            [
                "id" => "1",
                "name" => "User 1",
                "email" => "user1@host.com"
            ],
            [
                "id" => "2",
                "name" => "User 2",
                "email" => "user2@host.com"
            ],
            [
                "id" => "3",
                "name" => "User 3",
                "email" => "user3@host.com"
            ],
        ];

        return $users;
        // '[{"id":"1","name":"User 1","email":"user1@host.com"},{"id":"2","name":"User ... ]'
    }
}

Full example

  • Controller class

    <?php declare(strict_types=1);
    
    namespace MyApi\Modules\Users;
    
    use Torugo\Router\Attributes\Request\Controller;
    use Torugo\Router\Attributes\Request\Delete;
    use Torugo\Router\Attributes\Request\Get;
    use Torugo\Router\Attributes\Request\Post;
    use Torugo\Router\Attributes\Request\Put;
    
    #[Controller("/users")]
    class UsersController {
        #[Get()] // endpoint: GET /users
        public function findAll(): array
        {
            return [/* list of users */];
        }
    
        #[Get("/{id}")] // endpoint: GET /users/<the user id>
        public function findOne(string $id): array
        {
            return [/* user data */];
        }
    
        #[Delete("/{id}")] // endpoint: DELETE /users/<the user id>
        public function deleteUser(string $id): string
        {
            return "Deleted user with $id";
        }
    
        #[Post()] // endpoint: POST /users
        public function addUser(): array
        {
            return [/* new user data */];
        }
    
        #[Put("/{id}")] // endpoint: PUT /users/<the user id>
        public function updateUser(string $id): array
        {
            return [/* updated user data */];
        }
    }
  • Main app file "index.php"

    <?php declare(strict_types=1);
    
    use MyApi\Modules\Users\UsersController;
    use Torugo\Router\Router;
    
    require "../vendor/autoload.php";
    
    $router = new Router;
    
    $router->register(UsersController::class);
    // OR $router->register('MyApi\Modules\Users\UsersController');
    
    try {
        $router->autoResolve();
    } catch (\Throwable $th) {
        http_response_code(400);
        echo $th->getMessage();
    }

Tests

With Makefile

To run the tests with make use:

make test

or with PHPUnit testdox

make testdox

Manually

Tip

  • You will need to use two terminal windows to run the tests manually.
  • All commands must be executed from the project root.

1. Start Test Server

In the first window terminal type:

php -S localhost\:8000 -t tests/ServerTests/Server/

2. Run the tests

In the second window, from the project root type:

./vendor/bin/phpunit

Contribute

It is currently not open to contributions, I intend to make it available as soon as possible.

License

Router is licensed under the MIT License - see the LICENSE file for details.