Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
razonyang committed Feb 23, 2018
0 parents commit 1d92190
Show file tree
Hide file tree
Showing 13 changed files with 2,513 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .coveralls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
service_name: travis-ci
coverage_clover: build/logs/clover.xml
json_path: build/logs/coveralls-upload.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor/
38 changes: 38 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
language: php

php:
- 7.0
- 7.1
- 7.2
- master

env:
matrix:
- DEPENDENCIES="high"
- DEPENDENCIES="low"
global:
- DEFAULT_COMPOSER_FLAGS="--no-interaction --no-ansi --no-progress --no-suggest"

before_install:
- composer self-update
- composer clear-cache

install:
- if [[ "$DEPENDENCIES" = 'high' ]]; then travis_retry composer update $DEFAULT_COMPOSER_FLAGS; fi
- if [[ "$DEPENDENCIES" = 'low' ]]; then travis_retry composer update $DEFAULT_COMPOSER_FLAGS --prefer-lowest; fi
- wget -c -nc --retry-connrefused --tries=0 https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar
- chmod +x coveralls.phar
- php coveralls.phar --version

before_script:
- echo 'zend.assertions=1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- echo 'assert.exception=On' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- mkdir -p build/logs
- ls -al

script:
- phpunit --coverage-clover build/logs/clover.xml

after_success:
- travis_retry php coveralls.phar -v
- bash <(curl -s https://codecov.io/bash)
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2018, Razon Yang
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
172 changes: 172 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# PHP Routing

[![Build Status](https://travis-ci.org/razonyang/php-routing.svg?branch=master)](https://travis-ci.org/razonyang/php-routing)
[![Coverage Status](https://coveralls.io/repos/github/razonyang/php-routing/badge.svg?branch=master)](https://coveralls.io/github/razonyang/php-routing?branch=master)
[![Latest Stable Version](https://poser.pugx.org/razonyang/php-routing/v/stable.svg)](https://packagist.org/packages/razonyang/php-routing)
[![Total Downloads](https://poser.pugx.org/razonyang/php-routing/downloads.svg)](https://packagist.org/packages/razonyang/php-routing)
[![License](https://poser.pugx.org/razonyang/php-routing/license.svg)](LICENSE)

A fast, flexible and scalable HTTP router for PHP.

## Features

- **Easy to design RESTful API**
- **Full Tests**
- **Flexible and scalable**: it allows you to define your own handler to deal with [`Not Found`](#not found handler), [`Method Not Allowed`](#method not allowed handler) and [`OPTIONS`](#options handler) request.
- **No third-party library dependencies**
- **Named Param Placeholder**
- **Detect all request methods of the specify path**
- **Straightforward documentation**

## Requirements

- PHP - `7.0`, `7.1`, `7.2` and `master` are supported.

## Install

```
composer require razonyang/php-routing:0.1.0
```

## Documentation

```php
include '/path-to-vendor/autoload.php';

use RazonYang\Routing\Router;

// create an router instance
$router = new Router();
```

### Register handler

```php
Router::handle($method, $path, $handler);
```

- `method` - `string` or `array`, **case-sensitive**, such as `GET`, `GET|POST`(split by `|`, without spaces), `['GET', 'POST']`
- `path` - the path **MUST** start with slash `/`, such as `/`, `/users`, `/users/<username>`.
- `handler` - `mixed`, whatever you want.


Examples

| Method | Path | Handler | Matched | Unmatched |
|:---------------------------|:-------------------------------|:--------|:-----------------------------------|----------------------------------------|
| `GET` | `/` | handler | `GET /` | `POST /` `get /` |
| <code>GET&#124;POST</code> | `/users` | handler | `GET /users` `POST /users` | |
| `['GET', 'POST']` | `/merchants` | handler | `GET /merchants` `POST /merchants` | |
| `GET` | `/users/<username>` | handler | `GET /users/foo` `GET /users/bar` | |
| `GET` | `/orders/<order_id:\d+>` | handler | `GET /orders/123456` | `GET /orders/letters` |

It also provides a few shortcuts for registering handler:

- `Router::delete`
- `Router::get`
- `Router::post`
- `Router::put`

```php
$router->get('/', 'handler');

$router->handle('GET|POST', '/users', 'handler');

$router->handle(['GET', 'POST'], '/merchants', 'handler');

$router->get('/users/<username>', 'handler');

$router->get('/orders/<order_id:\d+>', 'handler');
```

### Dispatch request

```php
Router::dispatch($method, $path);
```

- `method` - request method.
- `path` - URI path.

If matched, a [`Route`](route.php) instance will be returns, `null` otherwise or NotFoundException/MethodNotAllowedException will be thrown.

```php
$path = '/users/baz';
$route = $router->dispatch(Router::METHOD_GET, $path);

// handle requset
$handler = $route->handler; // 'handler'
$params = $route->params; // ['username' => 'baz']
```

### Named Params Placeholder

As the examples shown above, Router has ability to detect the param's value of the path.

In general, an placeholder pattern MUST be one of `<name>` and `<name:regex>`, it will be
converted to `([^/]+)` and `(regex)` respectively.
You can also change it via replace the `Router::$replacePatterns` and `Router::$replacements`.

| Pattern | Path | Matched | Params |
|:--------------------------------------------|:-------------------------------------------|:--------|:-----------------------------------------------------------------|
| `/guests/<name>` | `/guests/小明` | YES | `['name' => '小明']` |
| `/guests/<name:\w+>` | `/guests/foo` | YES | `['name' => 'foo']` |
| `/guests/<name:\w+>` | `/guests/小明` | NO | |
| `/orders/<order_id:\d+>` | `/orders/123` | YES | `['order_id' => '123']` |
| `/orders/<order_id:\d+>` | `/orders/letters` | NO | |
| `/posts/<year:\d{4}>/<month:\d{2}>/<title>` | `/posts/2017/10/hello-world` | YES | `['year' => '2017', 'month' => '10', title' => 'hello-world']` |
| `/posts/<year:\d{4}>/<month:\d{2}>/<title>` | `/posts/201/10/hello-world` | NO | |
| `/posts/<year:\d{4}>/<month:\d{2}>/<title>` | `/posts/2017/9/hello-world` | NO | |
| `/posts/<year:\d{4}><month:\d{2}>/<title>` | `/posts/201710/hello-world` | YES | `['year' => '2017', 'month' => '10', title' => 'hello-world']` |

### RESTful API

As the examples shown above, it is obviously easy to design a RESTful API application.

```php
$router->get('/products', 'products');
$router->post('/products', 'create product');
$router->get('/products/<product_id:\d+>', 'product detail');
$router->put('/products/<product_id:\d+>', 'update product');
$router->delete('/products/<product_id:\d+>', 'delete product');
```

### Not Found Handler

```
$router->notFoundHandler = function($method, $path) {
throw new \Exception('404 Not Found');
};
```

### Method Not Allowed Handler

```
$router->methodNotAllowedHandler = function($method, $path, $allowedMethods) {
throw new \Exception('405 Method Not Allowed');
};
```

### OPTIONS Handler

```
$router->optionsHandler = function($method, $path, $allowedMethods) {
header('Allow: ' . implode(',', $allowedMethods));
};
```

### Custom

## FAQ

### Package Not Found

Please add the following repository into `repositories` when `composer` complains about
that `Could not find package razonyang/php-routing ...`.

```json
{
"type": "git",
"url": "https://github.com/razonyang/php-routing.git"
}
```
32 changes: 32 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "razonyang/php-routing",
"type": "library",
"description": "a fast and flexible HTTP Router",
"keywords": [
"http",
"router",
"routing",
"RESTful API"
],
"homepage": "https://github.com/razonyang/php-routing",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/razonyang/php-routing/issues"
},
"authors": [
{
"name": "Razon Yang",
"email": "razonyang@gmail.com"
}
],
"require": {
},
"require-dev": {
"phpunit/phpunit": "^6.3"
},
"autoload": {
"psr-4": {
"RazonYang\\Routing\\": "src"
}
}
}

0 comments on commit 1d92190

Please sign in to comment.