Skip to content

Commit 6f992b6

Browse files
authored
Merge pull request #12 from WyriHaximus/advance-join-clauses
Advance join clauses
2 parents 90b56f8 + 9dee73d commit 6f992b6

File tree

10 files changed

+210
-160
lines changed

10 files changed

+210
-160
lines changed

src/Annotation/Clause.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WyriHaximus\React\SimpleORM\Annotation;
4+
5+
use Doctrine\Common\Annotations\Annotation\Target;
6+
7+
/**
8+
* @Annotation
9+
* @Target("ANNOTATION")
10+
* @psalm-suppress PropertyNotSetInConstructor
11+
*/
12+
final class Clause
13+
{
14+
/** @var string */
15+
private $local_key;
16+
17+
/** @var string|null */
18+
private $local_cast;
19+
20+
/** @var string|null */
21+
private $local_function;
22+
23+
/** @var string */
24+
private $foreign_key;
25+
26+
/** @var string|null */
27+
private $foreign_cast;
28+
29+
/** @var string|null */
30+
private $foreign_function;
31+
32+
public function __construct(array $table)
33+
{
34+
/** @psalm-suppress RawObjectIteration */
35+
foreach ($this as $name => $value) {
36+
if (isset($table[$name])) {
37+
$this->$name = $table[$name];
38+
}
39+
}
40+
}
41+
42+
public function getLocalKey(): string
43+
{
44+
return $this->local_key;
45+
}
46+
47+
public function getForeignKey(): string
48+
{
49+
return $this->foreign_key;
50+
}
51+
52+
public function getLocalCast(): ?string
53+
{
54+
return $this->local_cast;
55+
}
56+
57+
public function getForeignCast(): ?string
58+
{
59+
return $this->foreign_cast;
60+
}
61+
62+
public function getLocalFunction(): ?string
63+
{
64+
return $this->local_function;
65+
}
66+
67+
public function getForeignFunction(): ?string
68+
{
69+
return $this->foreign_function;
70+
}
71+
}

src/Annotation/InnerJoin.php

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,8 @@ final class InnerJoin implements JoinInterface
1414
/** @var string */
1515
private $entity;
1616

17-
/** @var string */
18-
private $local_key;
19-
20-
/** @var string */
21-
private $local_cast;
22-
23-
/** @var string */
24-
private $foreign_key;
25-
26-
/** @var string */
27-
private $foreign_cast;
17+
/** @var Clause[] */
18+
private $clause;
2819

2920
/** @var string */
3021
private $property;
@@ -49,28 +40,16 @@ public function getType(): string
4940
return 'inner';
5041
}
5142

52-
public function getLocalKey(): string
53-
{
54-
return $this->local_key;
55-
}
56-
57-
public function getForeignKey(): string
43+
/**
44+
* @return Clause[]
45+
*/
46+
public function getClause(): array
5847
{
59-
return $this->foreign_key;
48+
return $this->clause;
6049
}
6150

6251
public function getProperty(): string
6352
{
6453
return $this->property;
6554
}
66-
67-
public function getLocalCast(): ?string
68-
{
69-
return $this->local_cast;
70-
}
71-
72-
public function getForeignCast(): ?string
73-
{
74-
return $this->foreign_cast;
75-
}
7655
}

src/Annotation/JoinInterface.php

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ public function getEntity(): string;
88

99
public function getType(): string;
1010

11-
public function getLocalKey(): string;
12-
13-
public function getForeignKey(): string;
14-
1511
public function getProperty(): string;
1612

17-
public function getLocalCast(): ?string;
18-
19-
public function getForeignCast(): ?string;
13+
/**
14+
* @return Clause[]
15+
*/
16+
public function getClause(): array;
2017
}

src/Annotation/LeftJoin.php

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,8 @@ final class LeftJoin implements JoinInterface
1414
/** @var string */
1515
private $entity;
1616

17-
/** @var string */
18-
private $local_key;
19-
20-
/** @var string */
21-
private $local_cast;
22-
23-
/** @var string */
24-
private $foreign_key;
25-
26-
/** @var string */
27-
private $foreign_cast;
17+
/** @var Clause[] */
18+
private $clause;
2819

2920
/** @var string */
3021
private $property;
@@ -49,28 +40,16 @@ public function getType(): string
4940
return 'left';
5041
}
5142

52-
public function getLocalKey(): string
53-
{
54-
return $this->local_key;
55-
}
56-
57-
public function getForeignKey(): string
43+
/**
44+
* @return Clause[]
45+
*/
46+
public function getClause(): array
5847
{
59-
return $this->foreign_key;
48+
return $this->clause;
6049
}
6150

6251
public function getProperty(): string
6352
{
6453
return $this->property;
6554
}
66-
67-
public function getLocalCast(): ?string
68-
{
69-
return $this->local_cast;
70-
}
71-
72-
public function getForeignCast(): ?string
73-
{
74-
return $this->foreign_cast;
75-
}
7655
}

src/Entity/Join.php

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace WyriHaximus\React\SimpleORM\Entity;
44

5+
use WyriHaximus\React\SimpleORM\Annotation\Clause;
56
use WyriHaximus\React\SimpleORM\InspectedEntityInterface;
67

78
final class Join
@@ -12,30 +13,18 @@ final class Join
1213
/** @var string */
1314
private $type;
1415

15-
/** @var string */
16-
private $localKey;
17-
18-
/** @var string|null */
19-
private $localCast;
20-
21-
/** @var string */
22-
private $foreignKey;
23-
24-
/** @var string|null */
25-
private $foreignCast;
26-
2716
/** @var string */
2817
private $property;
2918

30-
public function __construct(InspectedEntityInterface $entity, string $type, string $localKey, ?string $localCast, string $foreignKey, ?string $foreignCast, string $property)
19+
/** @var Clause[] */
20+
private $clause;
21+
22+
public function __construct(InspectedEntityInterface $entity, string $type, string $property, Clause ...$clause)
3123
{
3224
$this->entity = $entity;
3325
$this->type = $type;
34-
$this->localKey = $localKey;
35-
$this->localCast = $localCast;
36-
$this->foreignKey = $foreignKey;
37-
$this->foreignCast = $foreignCast;
3826
$this->property = $property;
27+
$this->clause = $clause;
3928
}
4029

4130
public function getEntity(): InspectedEntityInterface
@@ -48,28 +37,16 @@ public function getType(): string
4837
return $this->type;
4938
}
5039

51-
public function getLocalKey(): string
52-
{
53-
return $this->localKey;
54-
}
55-
56-
public function getLocalCast(): ?string
57-
{
58-
return $this->localCast;
59-
}
60-
61-
public function getForeignKey(): string
62-
{
63-
return $this->foreignKey;
64-
}
65-
66-
public function getForeignCast(): ?string
40+
public function getProperty(): string
6741
{
68-
return $this->foreignCast;
42+
return $this->property;
6943
}
7044

71-
public function getProperty(): string
45+
/**
46+
* @return Clause[]
47+
*/
48+
public function getClause(): array
7249
{
73-
return $this->property;
50+
return $this->clause;
7451
}
7552
}

src/EntityInspector.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,8 @@ private function getJoins(ReflectionClass $class): iterable
7979
yield $annotation->getProperty() => new Join(
8080
new LazyInspectedEntity($this, $annotation->getEntity()),
8181
$annotation->getType(),
82-
$annotation->getLocalKey(),
83-
$annotation->getLocalCast(),
84-
$annotation->getForeignKey(),
85-
$annotation->getForeignCast(),
86-
$annotation->getProperty()
82+
$annotation->getProperty(),
83+
...$annotation->getClause()
8784
);
8885
}
8986
}

src/Repository.php

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -165,28 +165,36 @@ private function buildJoins(QueryBuilder $query, InspectedEntityInterface $entit
165165
$this->tableAliases[$tableKey] = 't' . $i++;
166166
}
167167

168-
$foreignTable = $join->getEntity()->getTable();
169-
$onLeftSide = $this->tableAliases[$tableKey] . '.' . $join->getForeignKey();
170-
if ($join->getForeignCast() !== null) {
171-
/** @psalm-suppress PossiblyNullOperand */
172-
$onLeftSide = 'CAST(' . $onLeftSide . ' AS ' . $join->getForeignCast() . ')';
173-
}
174-
175-
$onRightSide =
176-
$this->tableAliases[\spl_object_hash($entity) . '___' . $rootProperty] . '.' . $join->getLocalKey();
177-
if ($join->getLocalCast() !== null) {
178-
/** @psalm-suppress PossiblyNullOperand */
179-
$onRightSide = 'CAST(' . $onRightSide . ' AS ' . $join->getLocalCast() . ')';
180-
}
181-
182168
$query = $query->innerJoin(
183-
$foreignTable,
169+
$join->getEntity()->getTable(),
184170
$this->tableAliases[$tableKey]
185-
)->on(
186-
$onLeftSide,
187-
$onRightSide
188171
);
189172

173+
foreach ($join->getClause() as $clause) {
174+
$onLeftSide = $this->tableAliases[$tableKey] . '.' . $clause->getForeignKey();
175+
if ($clause->getForeignFunction() !== null) {
176+
/** @psalm-suppress PossiblyNullOperand */
177+
$onLeftSide = $clause->getForeignFunction() . '(' . $onLeftSide . ')';
178+
}
179+
if ($clause->getForeignCast() !== null) {
180+
/** @psalm-suppress PossiblyNullOperand */
181+
$onLeftSide = 'CAST(' . $onLeftSide . ' AS ' . $clause->getForeignCast() . ')';
182+
}
183+
184+
$onRightSide =
185+
$this->tableAliases[\spl_object_hash($entity) . '___' . $rootProperty] . '.' . $clause->getLocalKey();
186+
if ($clause->getLocalFunction() !== null) {
187+
/** @psalm-suppress PossiblyNullOperand */
188+
$onRightSide = $clause->getLocalFunction() . '(' . $onRightSide . ')';
189+
}
190+
if ($clause->getLocalCast() !== null) {
191+
/** @psalm-suppress PossiblyNullOperand */
192+
$onRightSide = 'CAST(' . $onRightSide . ' AS ' . $clause->getLocalCast() . ')';
193+
}
194+
195+
$query = $query->on($onLeftSide, $onRightSide);
196+
}
197+
190198
foreach ($join->getEntity()->getFields() as $field) {
191199
$this->fields[$this->tableAliases[$tableKey] . '___' . $field->getName()] = $this->tableAliases[$tableKey] . '.' . $field->getName();
192200
}
@@ -238,19 +246,23 @@ private function buildTree(array $row, InspectedEntityInterface $entity, string
238246

239247
if ($join->getType() === 'inner' && $entity->getClass() === $join->getEntity()->getClass()) {
240248
$tree[$join->getProperty()] = new Promise(function (callable $resolve, callable $reject) use ($row, $join, $tableKey): void {
241-
if ($row[$this->tableAliases[$tableKey]][$join->getLocalKey()] === null) {
242-
$resolve(null);
249+
foreach ($join->getClause() as $clause) {
250+
if ($row[$this->tableAliases[$tableKey]][$clause->getLocalKey()] === null) {
251+
$resolve(null);
243252

244-
return;
253+
return;
254+
}
245255
}
246256

247257
$where = [];
248258

249-
$where[] = [
250-
$join->getForeignKey(),
259+
foreach ($join->getClause() as $clause) {
260+
$where[] = [
261+
$clause->getForeignKey(),
251262
'=',
252-
$row[$this->tableAliases[$tableKey]][$join->getLocalKey()],
263+
$row[$this->tableAliases[$tableKey]][$clause->getLocalKey()],
253264
];
265+
}
254266

255267
$this->client
256268
->getRepository($join->getEntity()
@@ -268,11 +280,13 @@ private function buildTree(array $row, InspectedEntityInterface $entity, string
268280
function () use ($row, $join, $tableKey) {
269281
$where = [];
270282

271-
$where[] = [
272-
$join->getForeignKey(),
273-
'=',
274-
$row[$this->tableAliases[$tableKey]][$join->getLocalKey()],
275-
];
283+
foreach ($join->getClause() as $clause) {
284+
$where[] = [
285+
$clause->getForeignKey(),
286+
'=',
287+
$row[$this->tableAliases[$tableKey]][$clause->getLocalKey()],
288+
];
289+
}
276290

277291
return $this->client->getRepository($join->getEntity()->getClass())->fetch($where);
278292
},

0 commit comments

Comments
 (0)