Skip to content

Commit

Permalink
Merge pull request #7 from jaumarar/allow-global-middlewares
Browse files Browse the repository at this point in the history
Allow global middlewares
  • Loading branch information
alexdodonov committed Oct 12, 2020
2 parents 71996f8 + 99f7ad2 commit 11de1b7
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 40 deletions.
8 changes: 8 additions & 0 deletions .gitignore
@@ -0,0 +1,8 @@
# IDEs
.idea

# composer
/vendor/*

# phpunit
.phpunit*
32 changes: 28 additions & 4 deletions Mezon/Router/Tests/MiddlewareUnitTest.php
Expand Up @@ -26,16 +26,22 @@ public function testMiddleware(): void
// setup
$route = '/route-with-middleware/';
$router = new Router();
$router->registerMiddleware('*', function () {
return [
1,
2
];
});
$router->addRoute($route, function (int $i, int $j) {
return [
$i,
$j
];
});
$router->registerMiddleware($route, function () {
$router->registerMiddleware($route, function (int $i, int $j) {
return [
1,
2
$i,
$j
];
});

Expand All @@ -61,6 +67,7 @@ public function testMultipleMiddlewaresInOrderAndOmitMalformed(): void
});

$router->registerMiddleware($route, function (string $route, array $parameters) {
$parameters['_second'] = $parameters['id'];
$parameters['id'] += 9;

return [
Expand All @@ -71,10 +78,23 @@ public function testMultipleMiddlewaresInOrderAndOmitMalformed(): void

// This middleware is broken, don't parse the result
$router->registerMiddleware($route, function (string $route, array $parameters) {
$parameters['_dont_set_this'] = true;

return null;
});

$router->registerMiddleware($route, function (string $route, array $parameters) {
$parameters['_third'] = $parameters['id'];
$parameters['id'] *= 2;

return [
$route,
$parameters
];
});

$router->registerMiddleware('*', function (string $route, array $parameters) {
$parameters['_first'] = $parameters['id'];
$parameters['id'] *= 2;

return [
Expand All @@ -87,6 +107,10 @@ public function testMultipleMiddlewaresInOrderAndOmitMalformed(): void
$result = $router->callRoute('/route/1');

// assertions
$this->assertEquals(20, $result['id']);
$this->assertEquals(22, $result['id']);
$this->assertEquals(1, $result['_first']);
$this->assertEquals(2, $result['_second']);
$this->assertEquals(11, $result['_third']);
$this->assertTrue(empty($result['_dont_set_this']));
}
}
12 changes: 10 additions & 2 deletions Mezon/Router/UrlParser.php
Expand Up @@ -280,11 +280,19 @@ public function registerMiddleware(string $router, callable $middleware): void
*/
private function getMiddlewareResult(string $route): array
{
$middleWares = $this->middleware[$this->calledRoute] ?? null;
$middleWares = [];

if (isset($this->middleware['*'])) {
$middleWares = $this->middleware['*'];
}

if ($this->calledRoute !== '*' && isset($this->middleware[$this->calledRoute])) {
$middleWares = array_merge($middleWares, $this->middleware[$this->calledRoute]);
}

$result = [$route, $this->parameters];

if (!isset($middleWares)) {
if (!count($middleWares)) {
return $result;
}

Expand Down
77 changes: 43 additions & 34 deletions README.md
Expand Up @@ -240,67 +240,76 @@ You can also worm cache without dumping:
$router->warmCache();
```

## Middleware and model binding
## Middleware and parameters modification

You can register your own middleware wich will be called before the route handler will be executed. This middleware can transform common parameters $route and $parameters into something different.
Types of middlewares that you can add which will be called before the route handler will be executed. This middleware can transform common parameters $route and $parameters into something different.
- Multiple global middlewares that will be **called in order of attachment**
- Multiple route specific middlewares that **will be called in order of attachment**

Let's look at the example:
Order of execution of the middlewares
1. Global middlewares ``$router->addRoute('*', ...)``
2. Before calling route callback ``$router->addRoute('/example', ...)`` all those matching the route will be executed

Let's look at a simple example:

```php
$router = new Router();
$router->addRoute('/user/[i:id]', function(string $route, array $parameters){
$userModel = new UserModel();
$userObject = $userModel->getUserById($parameters[$id]);
$userObject = $userModel->getUserById($parameters['id']);

// use $userObject for any purpose you need
});
```

Quite simple, but you can register middleware wich will do all dirty job:
Now let's watch an example with all the possibilities

```php
$router = new Router();
$router->addRoute('/user/[i:id]', function(UserObject $userObject){
// here we get $userObject directly
// use use it in any way we need
});
$router->registerMiddleware('/user/[i:id]', function(string $route, array $parameters){
$userModel = new UserModel();
$userObject = $userModel->getUserById($parameters[$id]);
return $userObject;

// First step. We have an API that talks JSON, convert the body
$router->registerMiddleware('*', function (string $route, array $parameters){
$request = Request::createFromGlobals();

$parameters['_request'] = $request;
$parameters['_body'] = json_decode($request->getContent(), true);

return $parameters;
});
```

### Multiple middleware and invalid result omitting
// Second step. Ensure that we are logged in when we are in the private area
$router->registerMiddleware('*', function (string $route, array $parameters){
// Is not a private area
if (mb_strpos($route, '/user') !== 0 || empty($parameters['user_id'])) {
return $parameters;
}

You can specify multiple middleware for one route. For example:
$token = $parameters['_request']->headers->get('oauth_token');

```php
$router->registerMiddleware('/user/[i:id]', function (string $route, array $parameters) {
// here we for example validate user existence
$auth = new SomeAuth();
$auth->validateTokenOrFail(
$token,
$parameters['user_id']
);

return [
$route,
$parameters
];
// We don't need to return nothing
});

// This middleware is broken, don't parse the result
$router->registerMiddleware('/user/[i:id]', function (string $route, array $parameters) {
return null;
// Last step. Now we will modify the parameters so the handler can work with them
$router->registerMiddleware('/user/[i:user_id]', function(string $route, array $parameters){
$userModel = new UserModel();

return $userModel->getUserById(
$parameters['user_id']
);
});

$router->registerMiddleware('/user/[i:id]', function (string $route, array $parameters) {
// and here we return existing user because in the previous
// middleware we have checked that it exists
$userModel = new UserModel();
$userObject = $userModel->getUserById($parameters[$id]);
return $userObject;
// Final destination. We have ended the middlewares, now we can work with the processed data
$router->addRoute('/user/[i:user_id]', function (UserObject $userObject){
// Do everything
});
```

Middleware will be executed in the order they were attached to the route.

## PSR-7 routes processing

Originally Mezon Router was not designed to be PSR-7 compatible. But one of the latest features have made it possible. You can use middleware for this purpose. For example:
Expand Down

0 comments on commit 11de1b7

Please sign in to comment.