Skip to content

Commit

Permalink
Merge pull request #34 from sunrise-php/release/v2.0.0
Browse files Browse the repository at this point in the history
🎉 v2.0.0
  • Loading branch information
fenric committed Dec 26, 2019
2 parents 85837a0 + 94e858a commit b56a067
Show file tree
Hide file tree
Showing 114 changed files with 8,119 additions and 2,558 deletions.
3 changes: 0 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,5 @@ insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

[*.php]
indent_style = tab

[*.yml]
indent_size = 2
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.php_cs.cache
composer.lock
coverage.xml
phpbench.json
phpcs.xml
phpunit.xml
vendor/
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ before_install:
install:
- travis_retry composer install --no-interaction --prefer-source --no-suggest

script: vendor/bin/phpunit --colors=always --coverage-text
script: php vendor/bin/phpunit --colors=always --coverage-text
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Anatoly Fenric
Copyright (c) 2018 Sunrise // PHP

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
321 changes: 44 additions & 277 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,314 +1,81 @@
### Fast HTTP router with annotations support for PHP 7.1+ based on PSR-7 and PSR-15
## HTTP router for PHP 7.1+ based on PSR-7 and PSR-15<br>with support for annotations and OpenApi

[![Gitter](https://badges.gitter.im/sunrise-php/support.png)](https://gitter.im/sunrise-php/support)
[![Build Status](https://api.travis-ci.com/sunrise-php/http-router.svg?branch=master)](https://travis-ci.com/sunrise-php/http-router)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sunrise-php/http-router/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/sunrise-php/http-router/?branch=master)
[![Build Status](https://scrutinizer-ci.com/g/sunrise-php/http-router/badges/build.png?b=master)](https://scrutinizer-ci.com/g/sunrise-php/http-router/build-status/master)
[![Code Coverage](https://scrutinizer-ci.com/g/sunrise-php/http-router/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/sunrise-php/http-router/?branch=master)
[![Latest Stable Version](https://poser.pugx.org/sunrise/http-router/v/stable?format=flat)](https://packagist.org/packages/sunrise/http-router)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sunrise-php/http-router/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/sunrise-php/http-router/?branch=master)
[![Total Downloads](https://poser.pugx.org/sunrise/http-router/downloads?format=flat)](https://packagist.org/packages/sunrise/http-router)
[![Latest Stable Version](https://poser.pugx.org/sunrise/http-router/v/stable?format=flat)](https://packagist.org/packages/sunrise/http-router)
[![License](https://poser.pugx.org/sunrise/http-router/license?format=flat)](https://packagist.org/packages/sunrise/http-router)

## Awards
---

[![SymfonyInsight](https://insight.symfony.com/projects/62934e27-3e71-439c-9569-4aa57cdb3f36/big.svg)](https://insight.symfony.com/projects/62934e27-3e71-439c-9569-4aa57cdb3f36)

## Benchmark (1k iterations with 1k routes)

> [You can see it here](https://github.com/sunrise-php/http-router-benchmark)
```
+-----------+------+--------------+-------+
| subject | its | mean | diff |
+-----------+------+--------------+-------+
| Sunrise | 1000 | 17,856.609μs | 1.00x |
| FastRoute | 1000 | 20,920.968μs | 1.17x |
| Aura | 1000 | 44,480.588μs | 2.49x |
| Zend | 1000 | 96,778.725μs | 5.42x |
+-----------+------+--------------+-------+
```

## Installation (via composer)
## Installation via composer

```bash
composer require sunrise/http-router
composer require 'sunrise/http-router:^2.0'
```

## How to use?

Study [sunrise/awesome-skeleton](https://github.com/sunrise-php/awesome-skeleton) to understand how this can be used.

#### Annotations
## Examples of using

> This package has annotation support, all the details are [here](https://github.com/sunrise-php/http-router-annotations-support).
#### QuickStart

> The example uses other sunrise packages, but you can use for example `zend/diactoros`, or any other.
```bash
composer require sunrise/http-message sunrise/http-server-request
```
#### Strategy loading routes from configs

```php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Sunrise\Http\Message\ResponseFactory;
use Sunrise\Http\Router\Exception\MethodNotAllowedException;
use Sunrise\Http\Router\Exception\RouteNotFoundException;
use Sunrise\Http\Router\RouteCollection;
use Sunrise\Http\Router\Loader\CollectableFileLoader;
use Sunrise\Http\Router\Router;
use Sunrise\Http\ServerRequest\ServerRequestFactory;

class DemoMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler) : ResponseInterface
{
$response = $handler->handle($request);

$response->getBody()->write(sprintf('URI: "%s"; Attributes: "%s"',
$request->getUri(), print_r($request->getAttributes(), true)
));

return $response;
}
}

$routes = new RouteCollection();

$routes->get('home', '/')
->addMiddleware(new DemoMiddleware);

$routes->group('/api', function($routes)
{
$routes->group('/v1', function($routes)
{
$routes->post('resource.create', '/resource')
->addMiddleware(new DemoMiddleware);

$routes->patch('resource.update', '/resource/{id}')
->addPattern('id', '\d+')
->addMiddleware(new DemoMiddleware);

$routes->delete('resource.delete', '/resource/{id}')
->addPattern('id', '\d+')
->addMiddleware(new DemoMiddleware);

$routes->get('resource.read', '/resource/{id}')
->addPattern('id', '\d+')
->addMiddleware(new DemoMiddleware);

$routes->get('resource.all', '/resource')
->addMiddleware(new DemoMiddleware);
});
});
$loader = new CollectableFileLoader();
$loader->attach('routes/api.php');
$loader->attach('routes/admin.php');
$loader->attach('routes/public.php');

$router = new Router();
$router->addRoutes($routes);

try
{
$response = $router->handle(ServerRequestFactory::fromGlobals());
}
catch (MethodNotAllowedException $e)
{
$response = (new ResponseFactory)->createResponse(405)
->withHeader('allow', implode(',', $e->getAllowedMethods()));

$response->getBody()->write($response->getReasonPhrase());
}
catch (RouteNotFoundException $e)
{
$response = (new ResponseFactory)->createResponse(404);

$response->getBody()->write($response->getReasonPhrase());
}
$router->load($loader);

$headers = $response->getHeaders();
// if the router is used as a request handler
$response = $router->handle($request);

foreach ($headers as $name => $values)
{
foreach ($values as $value)
{
header(sprintf('%s: %s', $name, $value), false);
}
}

header(sprintf('HTTP/%s %d %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
), true);

echo $response->getBody();
```

#### Adding a route to the collection

###### Adds a new route to the collection

```php
$route = $routes->route('route.id', '/route/path', ['HEAD', 'GET']);
```

###### Adds a new route to the collection that will respond to HEAD requests

```php
$route = $routes->head('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to GET requests

```php
$route = $routes->get('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to POST requests

```php
$route = $routes->post('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to PUT requests

```php
$route = $routes->put('route.id', '/route/path');
// if the router is used as middleware
$response = $router->process($request, $handler);
```

###### Adds a new route to the collection that will respond to PATCH requests
#### Strategy loading routes from annotations

```php
$route = $routes->patch('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to DELETE requests

```php
$route = $routes->delete('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to PURGE requests

```php
$route = $routes->purge('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to safe requests

```php
$route = $routes->safe('route.id', '/route/path');
```

###### Adds a new route to the collection that will respond to any requests

```php
$route = $routes->any('route.id', '/route/path');
```

#### Route grouping

```php
// Add a route to the collection with the path: /foo/bar/baz/qux
$routes->group('/foo', function($routes)
{
$routes->group('/bar', function($routes)
{
$routes->group('/baz', function($routes)
{
$route = $routes->get('qux', '/qux');
});
});
});
```

#### Route patterns

```php
$route = $routes->any('resource.action', '/resource/{action}(/{id})')
->addPattern('action', 'create|update|delete|read|all')
->addPattern('id', '\d+');
```

#### Route middlewares

```php
$route
->addMiddleware(new FooMiddleware)
->addMiddleware(new BarMiddleware)
->addMiddleware(new BazMiddleware);
```

#### Router middlewares

```php
$router
->addMiddleware(new FooMiddleware)
->addMiddleware(new BarMiddleware)
->addMiddleware(new BazMiddleware);
```

#### Router matching

```php
$route = $router->match($request);
```

## Useful Middlewares

#### Error handling ([whoops](https://github.com/filp/whoops))
use Doctrine\Common\Annotations\AnnotationRegistry;
use Sunrise\Http\Router\Loader\AnnotationDirectoryLoader;
use Sunrise\Http\Router\Router;

```bash
composer require middlewares/whoops
```
AnnotationRegistry::registerLoader('class_exists');

```php
$router->addMiddleware(new \Middlewares\Whoops());
```
$loader = new AnnotationDirectoryLoader();
$loader->attach('src/Http/RequestHandler');

#### Payload ([payload](https://github.com/middlewares/payload))
$router = new Router();
$router->load($loader);

```bash
composer require middlewares/payload
```
// if the router is used as a request handler
$response = $router->handle($request);

```php
$router->addMiddleware(new \Middlewares\JsonPayload());
$router->addMiddleware(new \Middlewares\UrlEncodePayload());
// if the router is used as middleware
$response = $router->process($request, $handler);
```

#### Encoding ([encoder](https://github.com/middlewares/encoder))

```bash
composer require middlewares/encoder
```
#### Without loading strategy

```php
$router->addMiddleware(new \Middlewares\GzipEncoder());
```
use App\Http\RequestHandler\HomeRequestHandler;
use Sunrise\Http\Router\RouteCollector;
use Sunrise\Http\Router\Router;

## Awesome PSR-15 Middlewares
$collector = new RouteCollector();
$collector->get('home', '/', new HomeRequestHandler());

https://github.com/middlewares
$router = new Router();
$router->addRoute(...$collector->getCollection()->all());

## Test run
// if the router is used as a request handler
$response = $router->handle($request);

```bash
php vendor/bin/phpunit
// if the router is used as middleware
$response = $router->process($request, $handler);
```

## Benchmark run

https://github.com/sunrise-php/http-router-benchmark

## Api documentation

https://phpdoc.fenric.ru/

## Useful links

* https://www.php-fig.org/psr/psr-7/
* https://www.php-fig.org/psr/psr-15/
* https://github.com/middlewares
Empty file added benchmarks/.gitkeep
Empty file.

0 comments on commit b56a067

Please sign in to comment.