-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 770644e
Showing
22 changed files
with
3,124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: MAIN | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
tests-php8: | ||
runs-on: ubuntu-20.04 | ||
|
||
strategy: | ||
fail-fast: true | ||
matrix: | ||
php-versions: ['8.1', '8.2', '8.3'] | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name: Setup PHP | ||
uses: shivammathur/setup-php@v2 | ||
with: | ||
php-version: ${{ matrix.php-versions }} | ||
|
||
- name: Install dependencies | ||
run: composer require -W phpunit/phpunit | ||
|
||
- name: Run tests | ||
run: composer run-script test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
vendor | ||
composer.lock | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
# PHP URI Template | ||
|
||
This is a URI Template implementation in PHP based on [RFC 6570 URI Template](http://tools.ietf.org/html/rfc6570). In addition to URI expansion, it also supports URI extraction. | ||
|
||
* This repository is strictly typed, cleaner version of [rize/UriTemplate](https://github.com/rize/UriTemplate) | ||
* To ensure that the package functions properly, tests are duplicated exactly as they are. | ||
|
||
## Installation | ||
|
||
Installation via `composer`: | ||
|
||
``` | ||
composer require ozdemirrulass/uri-template | ||
``` | ||
|
||
|
||
## Usage | ||
|
||
### Expansion | ||
|
||
A very simple usage (string expansion). | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
$uri->expand('/{username}/profile', ['username' => 'john']); | ||
|
||
>> '/john/profile' | ||
``` | ||
|
||
`Ozdemirrulass\UriTemplate` supports all `Expression Types` and `Levels` specified by RFC6570. | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
$uri->expand('/search/{term:1}/{term}/{?q*,limit}', [ | ||
'term' => 'john', | ||
'q' => ['a', 'b'], | ||
'limit' => 10, | ||
]) | ||
|
||
>> '/search/j/john/?q=a&q=b&limit=10' | ||
``` | ||
|
||
#### `/` Path segment expansion | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
$uri->expand('http://{host}{/segments*}/{file}{.extensions*}', [ | ||
'host' => 'www.host.com', | ||
'segments' => ['path', 'to', 'a'], | ||
'file' => 'file', | ||
'extensions' => ['x', 'y'], | ||
]); | ||
|
||
>> 'http://www.host.com/path/to/a/file.x.y' | ||
``` | ||
|
||
`Ozdemirrulass\UriTemplate` accepts `base-uri` as a 1st argument and `default params` as a 2nd argument. This is very useful when you're working with API endpoint. | ||
|
||
Take a look at real world example. | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate('https://api.twitter.com/{version}', ['version' => 1.1]); | ||
$uri->expand('/statuses/show/{id}.json', ['id' => '210462857140252672']); | ||
|
||
>> https://api.twitter.com/1.1/statuses/show/210462857140252672.json | ||
``` | ||
|
||
### Extraction | ||
|
||
It also supports URI Extraction (extract all variables from URI). Let's take a look at the example. | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate('https://api.twitter.com/{version}', ['version' => 1.1]); | ||
|
||
$params = $uri->extract('/search/{term:1}/{term}/{?q*,limit}', '/search/j/john/?q=a&q=b&limit=10'); | ||
|
||
>> print_r($params); | ||
( | ||
[term:1] => j | ||
[term] => john | ||
[q] => Array | ||
( | ||
[0] => a | ||
[1] => b | ||
) | ||
|
||
[limit] => 10 | ||
) | ||
``` | ||
|
||
Note that in the example above, result returned by `extract` method has an extra keys named `term:1` for `prefix` modifier. This key was added just for our convenience to access prefix data. | ||
|
||
#### `strict` mode | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
$uri->extract($template, $uri, $strict = false) | ||
``` | ||
|
||
Normally `extract` method will try to extract vars from a uri even if it's partially matched. For example | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
$params = $uri->extract('/{?a,b}', '/?a=1') | ||
|
||
>> print_r($params); | ||
( | ||
[a] => 1 | ||
[b] => null | ||
) | ||
``` | ||
|
||
With `strict mode`, it will allow you to extract uri only when variables in template are fully matched with given uri. | ||
|
||
Which is useful when you want to determine whether the given uri is matched against your template or not (in case you want to use it as routing service). | ||
|
||
```php | ||
<?php | ||
|
||
use Ozdemirrulass\UriTemplate; | ||
|
||
$uri = new UriTemplate(); | ||
|
||
// Note that variable `b` is absent in uri | ||
$params = $uri->extract('/{?a,b}', '/?a=1', true); | ||
|
||
>>> null | ||
|
||
// Now we give `b` some value | ||
$params = $uri->extract('/{?a,b}', '/?a=1&b=2', true); | ||
|
||
>>> print_r($params) | ||
( | ||
[a] => 1 | ||
[b] => 2 | ||
) | ||
``` | ||
|
||
#### Array modifier `%` | ||
|
||
By default, RFC 6570 only has 2 types of operators `:` and `*`. This `%` array operator was added to the library because current spec can't handle array style query e.g. `list[]=a` or `key[user]=john`. | ||
|
||
Example usage for `%` modifier | ||
|
||
```php | ||
<?php | ||
|
||
$uri->expand('{?list%,keys%}', [ | ||
'list' => [ | ||
'a', 'b', | ||
), | ||
'keys' => [ | ||
'a' => 1, | ||
'b' => 2, | ||
), | ||
]); | ||
|
||
// '?list[]=a&list[]=b&keys[a]=1&keys[b]=2' | ||
>> '?list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2' | ||
|
||
// [] get encoded to %5B%5D i.e. '?list[]=a&list[]=b&keys[a]=1&keys[b]=2' | ||
$params = $uri->extract('{?list%,keys%}', '?list%5B%5D=a&list%5B%5D=b&keys%5Ba%5D=1&keys%5Bb%5D=2', ) | ||
|
||
>> print_r($params); | ||
( | ||
[list] => Array | ||
( | ||
[0] => a | ||
[1] => b | ||
) | ||
|
||
[keys] => Array | ||
( | ||
[a] => 1 | ||
[b] => 2 | ||
) | ||
) | ||
``` | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "ozdemirrulass/uri-template", | ||
"description": "Enhanced PHP URI Template (RFC 6570) supports both expansion & extraction", | ||
"keywords": ["URI", "Template", "RFC 6570"], | ||
"type": "library", | ||
"license": "MIT", | ||
"autoload": { | ||
"psr-4": { | ||
"Ozdemirrulass\\": "src/Ozdemirrulass/" | ||
} | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "ozdemirrulass", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"scripts": { | ||
"test": "vendor/bin/phpunit test/" | ||
}, | ||
"minimum-stability": "stable", | ||
"require": { | ||
"php": "^8.0" | ||
}, | ||
"require-dev": { | ||
"phpunit/phpunit": "^11.2@dev" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Ozdemirrulass; | ||
|
||
use Ozdemirrulass\UriTemplate\Parser; | ||
|
||
class UriTemplate | ||
{ | ||
public function __construct( | ||
protected string $base_uri = '', | ||
protected array $params = [], | ||
protected Parser $parser = new Parser() | ||
) { | ||
} | ||
|
||
public function expand(string $uri, array $params = array()): string | ||
{ | ||
$params += $this->params; | ||
$uri = $this->base_uri.$uri; | ||
$result = array(); | ||
|
||
if ((strpos($uri, '{')) === false) { | ||
return $uri; | ||
} | ||
|
||
$parser = $this->parser; | ||
$nodes = $parser->parse($uri); | ||
|
||
foreach ($nodes as $node) { | ||
$result[] = $node->expand($params); | ||
} | ||
|
||
return implode('', $result); | ||
} | ||
|
||
public function extract(string $template, string $uri, bool $strict = false) | ||
{ | ||
$params = array(); | ||
$nodes = $this->parser->parse($template); | ||
|
||
foreach ($nodes as $node) { | ||
if ($strict && !strlen((string)$uri)) { | ||
return null; | ||
} | ||
|
||
$match = $node->match($this->parser, $uri, $params, $strict); | ||
|
||
list($uri, $params) = $match; | ||
} | ||
|
||
if ($strict && strlen((string)$uri)) { | ||
return null; | ||
} | ||
|
||
return $params; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Ozdemirrulass\UriTemplate\Node; | ||
|
||
use Ozdemirrulass\UriTemplate\Parser; | ||
|
||
abstract class Abstraction | ||
{ | ||
public function __construct(private readonly string $token) | ||
{ | ||
} | ||
|
||
public function expand(array $params = array()): ?string | ||
{ | ||
return $this->token; | ||
} | ||
|
||
public function match(Parser $parser, string $uri, array $params = array(), bool $strict = false): ?array | ||
{ | ||
$length = strlen($this->token); | ||
if (substr($uri, 0, $length) === $this->token) { | ||
$uri = substr($uri, $length); | ||
} elseif ($strict) { | ||
return null; | ||
} | ||
|
||
return array($uri, $params); | ||
} | ||
|
||
public function getToken(): string | ||
{ | ||
return $this->token; | ||
} | ||
} |
Oops, something went wrong.