Skip to content

Commit 08938cd

Browse files
authored
Route binding (#18)
* refs #17 Added alternative for binding params * Update config for phpunit * Update cs-fixer * Fix styling
1 parent ea4f409 commit 08938cd

22 files changed

+341
-46
lines changed

.github/workflows/php-cs-fixer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- name: Run PHP CS Fixer
1616
uses: docker://oskarstark/php-cs-fixer-ga
1717
with:
18-
args: --config=.php_cs.dist --allow-risky=yes
18+
args: --config=.php_cs.dist.php --allow-risky=yes
1919

2020
- name: Commit changes
2121
uses: stefanzweifel/git-auto-commit-action@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ coverage
77
.idea
88
.php_cs
99
.php_cs.cache
10+
.php-cs-fixer.cache

.php_cs.dist renamed to .php_cs.dist.php

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,24 @@
1010
->ignoreDotFiles(true)
1111
->ignoreVCS(true);
1212

13-
return PhpCsFixer\Config::create()
13+
return (new PhpCsFixer\Config())
1414
->setRules([
15-
'@PSR12' => true,
16-
'declare_strict_types' => true,
17-
'array_syntax' => [
18-
'syntax' => 'short',
19-
],
20-
'ordered_imports' => [
21-
'sortAlgorithm' => 'alpha',
22-
],
15+
'@PSR2' => true,
16+
'array_syntax' => ['syntax' => 'short'],
17+
'ordered_imports' => ['sort_algorithm' => 'alpha'],
2318
'no_unused_imports' => true,
2419
'no_whitespace_before_comma_in_array' => true,
2520
'not_operator_with_successor_space' => true,
26-
'trailing_comma_in_multiline_array' => true,
21+
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
2722
'phpdoc_scalar' => true,
2823
'unary_operator_spaces' => true,
2924
'binary_operator_spaces' => [
30-
'align_double_arrow' => true,
31-
'align_equals' => false,
25+
'operators' => [
26+
'=>' => 'align_single_space',
27+
],
3228
],
3329
'blank_line_before_statement' => [
34-
'statements' => [
35-
'break',
36-
'continue',
37-
'declare',
38-
'return',
39-
'throw',
40-
'try',
41-
],
30+
'statements' => ['continue', 'declare', 'return', 'throw', 'try'],
4231
],
4332
'phpdoc_separation' => true,
4433
'phpdoc_align' => true,
@@ -47,14 +36,13 @@
4736
'phpdoc_var_without_name' => true,
4837
'class_attributes_separation' => [
4938
'elements' => [
50-
'method',
39+
'method' => 'one',
5140
],
5241
],
5342
'method_argument_space' => [
54-
'on_multiline' => 'ensure_fully_multiline',
55-
'keep_multiple_spaces_after_comma' => true,
43+
'on_multiline' => 'ignore',
5644
],
57-
'single_trait_insert_per_statement' => true,
5845
'trim_array_spaces' => true,
46+
'single_trait_insert_per_statement' => false,
5947
])
6048
->setFinder($finder);

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@
5656
"laravel": {
5757
"providers": [
5858
"Sajya\\Server\\ServerServiceProvider"
59-
]
59+
],
60+
"aliases": {
61+
"RPC": "Sajya\\Server\\Facades\\RPC"
62+
}
6063
}
6164
}
6265
}

phpunit.xml.dist

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit backupGlobals="false"
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
backupGlobals="false"
34
backupStaticAttributes="false"
45
bootstrap="vendor/autoload.php"
56
colors="true"
@@ -9,17 +10,21 @@
910
processIsolation="false"
1011
stopOnFailure="false"
1112
stopOnError="false"
12-
verbose="true">
13+
verbose="true"
14+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
15+
<coverage processUncoveredFiles="true">
16+
<include>
17+
<directory suffix=".php">./src</directory>
18+
</include>
19+
<report>
20+
<clover outputFile="clover.xml"/>
21+
</report>
22+
</coverage>
1323
<testsuites>
1424
<testsuite name="Unit">
1525
<directory suffix="Test.php">./tests</directory>
1626
</testsuite>
1727
</testsuites>
18-
<filter>
19-
<whitelist processUncoveredFilesFromWhitelist="true">
20-
<directory suffix=".php">./src</directory>
21-
</whitelist>
22-
</filter>
2328
<php>
2429
<server name="APP_NAME" value="Sajya"/>
2530
<server name="APP_DEBUG" value="true"/>
@@ -32,7 +37,5 @@
3237
<server name="QUEUE_CONNECTION" value="sync"/>
3338
<server name="SESSION_DRIVER" value="array"/>
3439
</php>
35-
<logging>
36-
<log type="coverage-clover" target="clover.xml"/>
37-
</logging>
40+
<logging/>
3841
</phpunit>

src/Binding.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sajya\Server;
6+
7+
use Closure;
8+
use Illuminate\Container\Container;
9+
use Illuminate\Routing\RouteBinding;
10+
use Illuminate\Support\Arr;
11+
use Illuminate\Support\Str;
12+
use Sajya\Server\Http\Request;
13+
14+
class Binding
15+
{
16+
/**
17+
* The IoC container instance.
18+
*
19+
* @var \Illuminate\Container\Container
20+
*/
21+
protected $container;
22+
23+
/**
24+
* The registered route value binders.
25+
*
26+
* @var array
27+
*/
28+
protected $binders = [];
29+
30+
/**
31+
* Application constructor.
32+
*
33+
* @param Container $container
34+
*/
35+
public function __construct(Container $container)
36+
{
37+
$this->container = $container;
38+
}
39+
40+
/**
41+
* Register a model binder for a wildcard.
42+
*
43+
* @param string $key
44+
* @param string $class
45+
* @param \Closure|null $callback
46+
*
47+
* @return void
48+
*/
49+
public function model(string $key, string $class, Closure $callback = null)
50+
{
51+
$this->bind($key, RouteBinding::forModel($this->container, $class, $callback));
52+
}
53+
54+
/**
55+
* Add a new route parameter binder.
56+
*
57+
* @param string $key
58+
* @param Closure|string $binder
59+
*
60+
* @return void
61+
*/
62+
public function bind(string $key, $binder)
63+
{
64+
$this->binders[$key] = RouteBinding::forCallback(
65+
$this->container, $binder
66+
);
67+
}
68+
69+
/**
70+
* @param Request $request
71+
*
72+
* @return array
73+
*/
74+
public function bindResolve(Request $request): array
75+
{
76+
$possibleBindings = Arr::dot($request->getParams());
77+
78+
return collect($possibleBindings)
79+
->map(fn ($value, string $key) => with($value, $this->binders[$key] ?? null))
80+
->mapWithKeys(function ($value, string $key) {
81+
$nameForArgument = (string)Str::of($key)->replace('.', '_')->camel();
82+
83+
return [$nameForArgument => $value];
84+
})
85+
->toArray();
86+
}
87+
}

src/Facades/RPC.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sajya\Server\Facades;
6+
7+
use Illuminate\Support\Facades\Facade;
8+
use Sajya\Server\Binding;
9+
10+
/**
11+
* Class RPC
12+
*
13+
* @method static void bind(string $key, string|callable $binder)
14+
* @method static void model(string $key, string $class, \Closure|null $callback = null)
15+
*
16+
* @see \Sajya\Server\Binding
17+
*/
18+
class RPC extends Facade
19+
{
20+
/**
21+
* Initiate a mock expectation on the facade.
22+
*
23+
* @return string
24+
*/
25+
protected static function getFacadeAccessor(): string
26+
{
27+
return Binding::class;
28+
}
29+
}

src/Guide.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ public function handleProcedure(Request $request, bool $notification): Response
104104
}
105105

106106
$result = $notification
107-
? HandleProcedure::dispatchAfterResponse($procedure)
108-
: HandleProcedure::dispatchNow($procedure);
107+
? HandleProcedure::dispatchAfterResponse($procedure, $request)
108+
: HandleProcedure::dispatchNow($procedure, $request);
109109

110110
return $this->makeResponse($result, $request);
111111
}

src/HandleProcedure.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,34 @@
1616
use Sajya\Server\Exceptions\InternalErrorException;
1717
use Sajya\Server\Exceptions\InvalidParams;
1818
use Sajya\Server\Exceptions\RuntimeRpcException;
19+
use Sajya\Server\Facades\RPC;
20+
use Sajya\Server\Http\Request;
1921
use Symfony\Component\HttpKernel\Exception\HttpException;
2022

2123
class HandleProcedure implements ShouldQueue
2224
{
23-
use Dispatchable;
24-
use InteractsWithQueue;
25-
use Queueable;
26-
use SerializesModels;
25+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
2726

2827
/**
2928
* @var string
3029
*/
3130
protected string $procedure;
3231

32+
/**
33+
* @var Request
34+
*/
35+
protected $request;
36+
3337
/**
3438
* Create a new job instance.
3539
*
36-
* @param string $procedure
40+
* @param string $procedure
41+
* @param Request $request
3742
*/
38-
public function __construct(string $procedure)
43+
public function __construct(string $procedure, Request $request)
3944
{
4045
$this->procedure = $procedure;
46+
$this->request = $request;
4147
}
4248

4349
/**
@@ -48,7 +54,7 @@ public function __construct(string $procedure)
4854
public function handle()
4955
{
5056
try {
51-
return App::call($this->procedure);
57+
return App::call($this->procedure, RPC::bindResolve($this->request));
5258
} catch (HttpException | RuntimeException | Exception $exception) {
5359
$message = $exception->getMessage();
5460

src/ServerServiceProvider.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ public function register(): void
3737
$this->commands($this->commands);
3838
$this->registerViews();
3939

40-
Route::macro('rpc', fn(string $uri, array $procedures = [], string $delimiter = null) => Route::post($uri, [JsonRpcController::class, '__invoke'])
40+
Route::macro('rpc', fn (string $uri, array $procedures = [], string $delimiter = null) => Route::post($uri, [JsonRpcController::class, '__invoke'])
4141
->setDefaults([
4242
'procedures' => $procedures,
4343
'delimiter' => $delimiter,
4444
]));
45+
46+
$this->app->singleton(Binding::class, fn ($container) => new Binding($container));
4547
}
4648

4749
/**
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"jsonrpc": "2.0",
3+
"method": "binding@deepValue",
4+
"params": {
5+
"name": {
6+
"deep": {
7+
"value": "Alexandr"
8+
}
9+
}
10+
},
11+
"id": 1
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"jsonrpc": "2.0",
3+
"method": "binding@getModel",
4+
"params": {
5+
"fixtureModel": 13
6+
},
7+
"id": 1
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"jsonrpc": "2.0",
3+
"method": "binding@subtract",
4+
"params": {
5+
"a": 4,
6+
"b": 2
7+
},
8+
"id": 1
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"jsonrpc": "2.0",
3+
"method": "binding@subtract",
4+
"params": {
5+
"a": 4,
6+
"b": 2
7+
},
8+
"id": 1
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "1",
3+
"result": "Alexandr",
4+
"jsonrpc": "2.0"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "1",
3+
"result": "bind-13",
4+
"jsonrpc": "2.0"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "1",
3+
"result": 2,
4+
"jsonrpc": "2.0"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"id": "1",
3+
"result": 98,
4+
"jsonrpc": "2.0"
5+
}

0 commit comments

Comments
 (0)