Skip to content

Commit

Permalink
almost completed the documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
IngeniozIT committed Feb 29, 2024
1 parent 9db01df commit 13b9940
Showing 1 changed file with 242 additions and 2 deletions.
244 changes: 242 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,266 @@ composer require ingenioz-it/router

### Overview

Create your routes, instantiate the router and handle the request:
Here is the whole process of using this router :
- Create your routes
- Instantiate the router
- Handle the request:

```php
use IngeniozIT\Router\RouteGroup;
use IngeniozIT\Router\Route;
use IngeniozIT\Router\Router;

// Create your routes

$routes = new RouteGroup([
Route::get('/hello', fn() => new Response('Hello, world!')),
Route::get('/bye', fn() => new Response('Goodbye, world!')),
]);

// Instantiate the router

/** @var Psr\Container\ContainerInterface $container */
$container = new Container();
$router = new Router($routes, $container);

// Handle the request

/** @var Psr\Http\Message\ServerRequestInterface $request */
$request = new ServerRequest();
/** @var Psr\Http\Message\ResponseInterface $response */
$response = $router->handle($request);
```

@todo continue working on the documentation (create a wiki ?)
### Basic routing

The simplest route consists of a path and a handler.

The path is a string, and the handler is a callable that will be executed when the route is matched. The handler returns a PSR-7 ResponseInterface.

```php
Route::get('/hello', fn() => new Response('Hello, world!'));
```

### Organizing routes

Route groups allow you to group several routes together.
They also allows you to visually organize your routes according to your application's logic.

This is useful when you want to apply the same conditions, middlewares, or attributes to several routes at once (as we will see later).

```php
new RouteGroup([
Route::get('/hello', fn() => new Response('Hello, world!')),
Route::get('/bye', fn() => new Response('Goodbye, world!')),
]);
```

Route groups can be nested to create a hierarchy of routes that will inherit everything from their parent groups.

```php
new RouteGroup([
Route::get('/', fn() => new Response('Welcome !')),
new RouteGroup([
Route::get('/hello', fn() => new Response('Hello, world!')),
Route::get('/hello-again', fn() => new Response('Hello again, world!')),
]),
Route::get('/bye', fn() => new Response('Goodbye, world!')),
]);
```

### HTTP methods

You can specify the HTTP method that the route should match by using the corresponding method on the Route class:

```php
Route::get('/hello', MyHandler::class);
Route::post('/hello', MyHandler::class);
Route::put('/hello', MyHandler::class);
Route::patch('/hello', MyHandler::class);
Route::delete('/hello', MyHandler::class);
Route::options('/hello', MyHandler::class);
```

If you want a route to match multiple HTTP methods, you can use the `some` method:

```php
Route::some(['GET', 'POST'], '/hello', MyHandler::class);
```

You can also use the `any` method to match all HTTP methods:

```php
Route::any('/hello', MyHandler::class);
```

### Path parameters

#### Basic usage

You can define route parameters by using the `{}` syntax in the route path.

```php
Route::get('/hello/{name}', MyHandler::class);
```

The matched parameters will be available in the request attributes.

```php
class MyHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$name = $request->getAttribute('name');
return new Response("Hello, $name!");
}
}

Route::get('/hello/{name}', MyHandler::class);
```

#### Custom parameter patterns

By default, the parameters are matched by the `[^/]+` regex (any characters that are not a `/`).

You can specify a custom pattern by using the `where` parameter:

```php
// This route will only match if the name contains only letters
Route::get('/hello/{name}', MyHandler::class, where: ['name' => '[a-zA-Z]+']);
```

#### Custom parameter patterns in a group

Parameters patterns can also be defined globally for all routes inside a group:

```php
$routes = new RouteGroup(
[
Route::get('/hello/{name}', MyHandler::class),
Route::get('/bye/{name}', MyOtherHandler::class),
],
where: ['name' => '[a-zA-Z]+'],
);
```

### Route handlers

#### Closures

The simplest way to define a route handler is to use a closure.
The closure should return a PSR-7 ResponseInterface.

```php
Route::get('/hello', fn() => new Response('Hello, world!'));
```

Closures can take in parameters: the request and a request handler (the router itself).

```php
Route::get('/hello', function (ServerRequestInterface $request) {
return new Response('Hello, world!');
});

Route::get('/hello', function (ServerRequestInterface $request, RequestHandlerInterface $router) {
return new Response('Hello, world!');
});
```

#### RequestHandlerInterface

A route handler can be a callable, but it can also be a PSR RequestHandlerInterface.

```php
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Server\ServerRequestInterface;
use Psr\Http\Server\ResponseInterface;

class MyHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new Response('Hello, world!');
}
}

Route::get('/hello', new MyHandler());
```

#### MiddlewareInterface

Sometimes, you might want a handler to be able to "refuse" to handle the request, and pass it to the next handler in the chain.

This is done by using a PSR MiddlewareInterface as a route handler :

```php
use Psr\Http\Server\MiddlewareInterface;

class MyHandler implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (someResourceDoesNotExist()) {
// We don't want this handler to continue processing the request,
// so we pass the responsability to the next handler
return $handler->handle($request);
}

/* ... */
}
}

$routes = new RouteGroup([
Route::get('/hello', fn() => new MyHandler()), // This handler will be called first
Route::get('/hello', fn() => new Response('Hello, world!')), // This handler will be called second
]);
```

#### Dependency injection

Instead of using a closure or a class instance as a handler, you can use a class name. The router will then resolve the class using its PSR container.

```php
Route::get('/hello', MyHandler::class);
```

*The router will resolve this handler by calling `get(MyHandler::class)` on the container. This means that you can use any value that the container can resolve into a valid route handler.*

### Additional attributes

You can add additional attributes to a route by using the `with` method.
Just like path parameters, these attributes will be available in the request attributes.

```php
class MyHandler implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$name = $request->getAttribute('name');
return new Response("Hello, $name!");
}
}

// Notice there is no name parameter in the route path
Route::get('/hello', MyHandler::class, with: ['name' => 'world']);
```

Attributes can also be defined globally for all routes inside a group:

```php
$routes = new RouteGroup(
[
Route::get('/hello', MyHandler::class),
Route::get('/bye', MyOtherHandler::class),
],
with: ['name' => 'world'],
);
```

### Middlewares

### Conditions

### Naming routes

@todo continue working on the documentation

0 comments on commit 13b9940

Please sign in to comment.