Skip to content

Commit c3f6536

Browse files
committed
Support middleware on the client level
1 parent 15f89b2 commit c3f6536

13 files changed

+326
-9
lines changed

infection.json.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"IncrementInteger": {
2929
"ignore": [
30+
"WyriHaximus\\React\\SimpleORM\\Repository::create",
3031
"WyriHaximus\\React\\SimpleORM\\Repository::count",
3132
"WyriHaximus\\React\\SimpleORM\\Repository::buildTree",
3233
"WyriHaximus\\React\\SimpleORM\\Repository::translateFieldName"

phpstan.neon

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ parameters:
22
ignoreErrors:
33
- '#Class WyriHaximus\\React\\Tests\\SimpleORM\\Stub\\[a-zA-Z0-9_]+ is neither abstract nor final.#'
44
- '#Cannot call method getDocBlockTypes() on Roave\\BetterReflection\\Reflection\\ReflectionProperty|null.#'
5-
- '#Constructor in WyriHaximus\\React\\SimpleORM\\Client has parameter \$annotationReader with default value.#'
65
- '#Argument of an invalid type WyriHaximus\\React\\SimpleORM\\Annotation\\[a-zA-Z0-9_]+ supplied for foreach, only iterables are supported.#'
76
- '#Variable property access on \$this\(WyriHaximus\\React\\SimpleORM\\Annotation\\[a-zA-Z0-9_]+\).#'
87
classesAllowedToBeExtended:

src/Client.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Plasma\SQL\Grammar\PostgreSQL;
99
use Plasma\SQL\QueryBuilder;
1010
use Rx\Observable;
11+
use WyriHaximus\React\SimpleORM\Middleware\ExecuteQueryMiddleware;
12+
use WyriHaximus\React\SimpleORM\Middleware\GrammarMiddleware;
13+
use function ApiClients\Tools\Rx\unwrapObservableFromPromise;
1114

1215
final class Client implements ClientInterface
1316
{
@@ -20,10 +23,37 @@ final class Client implements ClientInterface
2023
/** @var Repository[] */
2124
private $repositories = [];
2225

23-
public function __construct(PgClient $client, ?Reader $annotationReader = null)
26+
/** @var MiddlewareRunner */
27+
private $middlewareRunner;
28+
29+
/**
30+
* @param array<int, MiddlewareInterface> $middleware
31+
*/
32+
public static function create(PgClient $client, MiddlewareInterface ...$middleware): self
33+
{
34+
return new self($client, new AnnotationReader(), ...$middleware);
35+
}
36+
37+
/**
38+
* @param array<int, MiddlewareInterface> $middleware
39+
*/
40+
public static function createWithAnnotationReader(PgClient $client, Reader $annotationReader, MiddlewareInterface ...$middleware): self
41+
{
42+
return new self($client, $annotationReader, ...$middleware);
43+
}
44+
45+
/**
46+
* @param array<int, MiddlewareInterface> $middleware
47+
*/
48+
private function __construct(PgClient $client, Reader $annotationReader, MiddlewareInterface ...$middleware)
2449
{
2550
$this->client = $client;
26-
$this->entityInspector = new EntityInspector($annotationReader ?? new AnnotationReader());
51+
$this->entityInspector = new EntityInspector($annotationReader);
52+
53+
$middleware[] = new GrammarMiddleware(new PostgreSQL());
54+
$middleware[] = new ExecuteQueryMiddleware($this->client);
55+
56+
$this->middlewareRunner = new MiddlewareRunner(...$middleware);
2757
}
2858

2959
public function getRepository(string $entity): RepositoryInterface
@@ -37,8 +67,6 @@ public function getRepository(string $entity): RepositoryInterface
3767

3868
public function query(QueryBuilder $query): Observable
3969
{
40-
$query = $query->withGrammar(new PostgreSQL());
41-
42-
return $this->client->executeStatement($query->getQuery(), $query->getParameters());
70+
return unwrapObservableFromPromise($this->middlewareRunner->query($query));
4371
}
4472
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM\Middleware;
4+
5+
use PgAsync\Client as PgClient;
6+
use Plasma\SQL\QueryBuilder;
7+
use React\Promise\PromiseInterface;
8+
use WyriHaximus\React\SimpleORM\MiddlewareInterface;
9+
use function React\Promise\resolve;
10+
11+
final class ExecuteQueryMiddleware implements MiddlewareInterface
12+
{
13+
/** @var PgClient */
14+
private $client;
15+
16+
public function __construct(PgClient $client)
17+
{
18+
$this->client = $client;
19+
}
20+
21+
public function query(QueryBuilder $query): PromiseInterface
22+
{
23+
return resolve($this->client->executeStatement($query->getQuery(), $query->getParameters()));
24+
}
25+
}

src/Middleware/GrammarMiddleware.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM\Middleware;
4+
5+
use Plasma\SQL\GrammarInterface;
6+
use Plasma\SQL\QueryBuilder;
7+
use React\Promise\PromiseInterface;
8+
use WyriHaximus\React\SimpleORM\MiddlewareInterface;
9+
use function React\Promise\resolve;
10+
11+
final class GrammarMiddleware implements MiddlewareInterface
12+
{
13+
/** @var GrammarInterface */
14+
private $grammer;
15+
16+
public function __construct(GrammarInterface $grammer)
17+
{
18+
$this->grammer = $grammer;
19+
}
20+
21+
public function query(QueryBuilder $query): PromiseInterface
22+
{
23+
return resolve($query->withGrammar($this->grammer));
24+
}
25+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM\Middleware;
4+
5+
use PgAsync\Client as PgClient;
6+
use Plasma\SQL\QueryBuilder;
7+
use React\Promise\PromiseInterface;
8+
use WyriHaximus\React\SimpleORM\MiddlewareInterface;
9+
use function React\Promise\resolve;
10+
11+
final class QueryCountMiddleware implements MiddlewareInterface
12+
{
13+
private const ZERO = 0;
14+
15+
/** @var int */
16+
private $count = self::ZERO;
17+
18+
public function query(QueryBuilder $query): PromiseInterface
19+
{
20+
$this->count++;
21+
22+
return resolve($query);
23+
}
24+
25+
public function getCount(): int
26+
{
27+
return $this->count;
28+
}
29+
30+
public function resetCount(): void
31+
{
32+
$this->count = 0;
33+
}
34+
}

src/MiddlewareInterface.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM;
4+
5+
use Plasma\SQL\QueryBuilder;
6+
use React\Promise\PromiseInterface;
7+
8+
interface MiddlewareInterface
9+
{
10+
/**
11+
* Returns the (modified) query through a promise.
12+
*
13+
* @param QueryBuilder $query
14+
*
15+
* @return PromiseInterface
16+
*/
17+
public function query(QueryBuilder $query): PromiseInterface;
18+
}

src/MiddlewareRunner.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM;
4+
5+
use Plasma\SQL\QueryBuilder;
6+
use Psr\Http\Message\ServerRequestInterface;
7+
use React\Promise\PromiseInterface;
8+
9+
final class MiddlewareRunner
10+
{
11+
/** @var MiddlewareInterface[] */
12+
private $middleware;
13+
14+
/**
15+
* @param array<int, MiddlewareInterface> $middleware
16+
*/
17+
public function __construct(MiddlewareInterface ...$middleware)
18+
{
19+
$this->middleware = $middleware;
20+
}
21+
22+
public function query(QueryBuilder $query): PromiseInterface
23+
{
24+
return $this->call($query, 0);
25+
}
26+
27+
private function call(QueryBuilder $query, int $position): PromiseInterface
28+
{
29+
// final request handler will be invoked without hooking into the promise
30+
if (!array_key_exists($position + 1, $this->middleware)) {
31+
return $this->middleware[$position]->query($query);
32+
}
33+
34+
return $this->middleware[$position]->query($query)->then(function (QueryBuilder $query) use ($position) {
35+
return $this->call($query, $position + 1);
36+
});
37+
}
38+
}

tests/ClientTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ protected function setUp(): void
4040

4141
$this->pgClient = $this->prophesize(PgClient::class);
4242
$this->annotationReader = $this->prophesize(Reader::class);
43-
$this->client = new Client($this->pgClient->reveal(), $this->annotationReader->reveal());
43+
$this->client = Client::createWithAnnotationReader($this->pgClient->reveal(), $this->annotationReader->reveal());
4444
}
4545

4646
public function testGetRepository(): void

0 commit comments

Comments
 (0)