Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
evgsavosin committed Sep 5, 2022
1 parent b2946d5 commit 3e85bc8
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 45 deletions.
144 changes: 107 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,62 +14,132 @@ Install via composer:
composer require evgsavosin/choco-router
```

## Usage (deprecated)
Basic usage:
## Usage
### Basic usage
To use it is necessary to define the call of classes using for example PSR-11 implementation.
```php
<?php

declare(strict_types=1);

require 'vendor/autoload.php';

use ChocoRouter\Router;
use ChocoRouter\Exceptions\HttpException;
use ChocoRouter\SimpleRouter;
use ChocoRouter\HttpMethod;

// Create router instance
$router = new Router();
$router = new SimpleRouter();

// Add route with GET method
$router->get('/foo', 'foo');
$router->get('/foo/bar', function () {
// ...
});
$router->addRoute(HttpMethod::GET, '/foo', fn (): string => 'Foo!' );
$router->addRoute(
HttpMethod::POST,
'/foo/{bar}',
fn (mixed $value): string => "Foo bar and {$value}!",
['bar' => '[0-9]+']
);

try {
$result = $router->dispatch(
$_SERVER['REQUEST_METHOD'],
$_SERVER['REQUEST_URI']
);

// Call class method or function
call_user_func($result['handler'], $result['args']);
$router->resolve(
$_SERVER['REQUEST_METHOD'],
$_SERVER['REQUEST_URI']
)->callableResolve(function (mixed $handler, array $arguments): mixed {
if (is_string($handler)) {
[$controllerName, $methodName] = explode('@', $handler);

// PSR-11 implementation for classes: controllers, actions and etc...
} elseif (is_callable($handler)) {
$handler(...$arguments);
}
});
} catch (HttpException $e) {
if ($e->getCode() == HttpException::NOT_FOUND) {
// Handle not found page
if ($e->getCode() === HttpException::NOT_FOUND) {
// Handle 404...
} else if ($e->getCode() === HttpException::BAD_REQUEST) {
// Handle 400...
}
}
```

// Declare function
function foo(array $args) {
// ...
}
### Route definition
The route can be defined with method: `addRoute(HttpMethod $httpMethod, string $uri, mixed $handler, array $parameters = []): void`. Parameters can be passed `{bar}` or `{bar?}` with regular expressions `['bar' => '[0-9]+']`.
Real example:
```php
$router->addRoute(HttpMethod::GET, '/foo/{bar?}', 'foo-bar', ['bar' => '[0-9]+']);
```
> A question mark means the parameter is optional.
The route group is defined using `addGroup(string $prefix, callable $callback): void` method. Real example:
```php
$router->addGroup('/gorge', function (RouteCollection $r): void {
$router->addRoute(HttpMethod::GET, '/foo/{bar?}', 'foo-bar', ['bar' => '[0-9]+']);
});
```

### HTTP Methods

Full list of methods:

Available methods:
```php
$router->group('/foo', function () use ($router) {
$router->get('/bar', 'foo');
$router->post('/bar', 'foo');
$router->delete('/bar', 'foo');
$router->put('/bar', 'foo');
$router->map(['POST', 'GET'], '/bar/baz', 'foo');
});
HttpMethod::CONNECT
HttpMethod::HEAD
HttpMethod::GET
HttpMethod::POST
HttpMethod::PUT
HttpMethod::DELETE
HttpMethod::OPTIONS
```

Parameters:
### Configuration

You can set the configuration when initializing a simple router:
```php
$router->get('/foo/{bar}/{baz?}', 'foo', [
'bar' => '[a-zA-Z]',
'baz' => '[0-9]'
$router = new SimpleRouter([
'cacheDisable' => false,
'cacheDriver' => FileDriver::class,
'cacheOptions' => []

/*
For memcached driver, there passed array of servers.
For file driver, there passed path to cache directory.
*/
]);
```

> A question mark means the parameter is optional
### Attributes

The router supports attributes from PHP 8.0. Example:

```php
use App\Action\FooAction;

$router = new SimpleRouter();
$router->load([FooAction::class]);
$router->resolve(/*...*/)->callableResolve(/*...*/);
```

### Cache

Router has support cache system with defined drivers:
- `ChocoRouter\Cache\Drivers\FileDriver::class`;
- `ChocoRouter\Cache\Drivers\ApcuDriver::class`;
- `ChocoRouter\Cache\Drivers\MemcachedDriver::class`.

For use cache move definition routes to cache callback:
```php
$router = new SimpleRouter([
'cacheDriver' => FileDriver::class
]);

$router->cache(static function (RouteCollection $r): void {
$r->addRoute(HttpMethod::GET, '/foo/{bar}', App\Actions\FooAction::class, ['bar' => '[0-9]+']);
});

$router->resolve(/*...*/)->callableResolve(/*...*/);
```

## Contributing

The author has not yet had time to write instructions, but any pull request or issue will be glad.

## License

Choco Router has MIT License.
4 changes: 2 additions & 2 deletions src/HttpMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
* @author Evgeny Savosin <[email protected]>
*/
enum HttpMethod: string {
CASE CONNECT = 'CONNECT';
CASE HEAD = 'HEAD';
case CONNECT = 'CONNECT';
case HEAD = 'HEAD';
case GET = 'GET';
case POST = 'POST';
case PUT = 'PUT';
Expand Down
11 changes: 9 additions & 2 deletions src/Resolver/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,23 @@ public function resolve(string $httpMethod, string $uri): ?ResolverResult
return new ResolverResult(
$route,
$uri,
$this->matchParameters($route->getParameters(), $matches)
$this->matchParameters(
$route->getParameters(),
$matches ?? []
)
);
}
}

return null;
}

public function matchParameters(array $parameters, array $values): array
public function matchParameters(array $parameters, array $values = []): ?array
{
if ($parameters === []) {
return [];
}

$i = 1;
$parameterValues = [];

Expand Down
5 changes: 5 additions & 0 deletions src/Resolver/ResolverResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ public function getParameters(): array
{
return $this->parameters;
}

public function callableResolve(callable $handler): mixed
{
return $handler($this->getHandler(), $this->getParameters());
}
}
7 changes: 7 additions & 0 deletions src/SimpleRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace ChocoRouter;

use ChocoRouter\Attribute\AttributeLoader;
use ChocoRouter\Cache\{Cache, CacheKey, DisableCacheException};
use ChocoRouter\Resolver\ResolverResult;
use Closure;
Expand All @@ -30,6 +31,12 @@ public function __construct(array $options = [])

$collection = new RouteCollection();
$this->router = new Router($collection);
$this->attributeLoader = new AttributeLoader($collection);
}

public function load(array $classes): void
{
$this->attributeLoader->load($classes);
}

public function getCollection(): RouteCollection
Expand Down
40 changes: 36 additions & 4 deletions tests/SimpleRouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use ChocoRouter\Cache\Drivers\FileDriver;
use PHPUnit\Framework\TestCase;
use Tests\Controllers\{FooController, BazAction};
use ChocoRouter\Resolver\ResolverResult;
use ChocoRouter\HttpMethod;
use ChocoRouter\RouteCollection;
Expand All @@ -16,10 +17,12 @@ final class SimpleRouterTest extends TestCase
public function testOneParameterHandling(): void
{
$router = new SimpleRouter();
$router->addRoute(HttpMethod::GET, '/foo/{bar}', 'foo-bar', ['bar' => '[0-9]+']);
$router->addRoute(HttpMethod::GET, '/foo/{bar}', fn (): string => 'foo-bar', ['bar' => '[0-9]+']);
$result = $router->resolve('GET', '/foo/1');

$this->assertInstanceOf(ResolverResult::class, $result);
$this->assertEquals(
'foo-bar',
$result->callableResolve(fn (mixed $handler, array $arguments): mixed => $handler($arguments))
);
}

public function testTwoParametersHandling(): void
Expand All @@ -35,18 +38,47 @@ public function testTwoParametersHandling(): void
$this->assertInstanceOf(ResolverResult::class, $result);
}

public function testGroup(): void
{
$router = new SimpleRouter();

$router->addGroup('/gorge', function (RouteCollection $r): void {
$r->addRoute(HttpMethod::GET, '/foo/{bar}/{quxx?}', 'foo-bar', [
'quxx' => '[a-zA-Z]+',
'bar' => '[0-9]+'
]);
});

$result = $router->resolve('GET', '/gorge/foo/1/');

$this->assertInstanceOf(ResolverResult::class, $result);
}

public function testCacheViaFileDriver(): void
{
$router = new SimpleRouter([
'cacheDisable' => false,
'cacheDriver' => FileDriver::class
]);

$router->cache(static function (RouteCollection $r) {
$router->cache(static function (RouteCollection $r): void {
$r->addRoute(HttpMethod::GET, '/foo/{bar}', 'foo-bar', ['bar' => '[0-9]+']);
});

$result = $router->resolve('GET', '/foo/1');
$this->assertInstanceOf(ResolverResult::class, $result);
}

public function testLoadController(): void
{
$router = new SimpleRouter();

$router->load([
FooController::class,
BazAction::class
]);

$result = $router->resolve('GET', '/foo');
$this->assertInstanceOf(ResolverResult::class, $result);
}
}

0 comments on commit 3e85bc8

Please sign in to comment.