Skip to content

Commit fc7ead8

Browse files
tntrexroxblnfk
andauthored
refactor: prevent repeating entity hydration in MtM relation (#188)
* refactor: prevent repeating entity hydration in MtM relation * Apply suggestions from code review Co-authored-by: Aleksei Gagarin <[email protected]> * test: replace heap instead of last save call Co-authored-by: Aleksei Gagarin <[email protected]>
1 parent 1d083d2 commit fc7ead8

File tree

5 files changed

+68
-11
lines changed

5 files changed

+68
-11
lines changed

src/Iterator.php

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,26 @@ final class Iterator implements \IteratorAggregate
2222
private $orm;
2323

2424
/** @var string */
25-
private $class;
25+
private $role;
2626

2727
/** @var iterable */
2828
private $source;
2929

30+
/** @var bool */
31+
private $tryToFindInHeap;
32+
3033
/**
3134
* @param ORMInterface $orm
32-
* @param string $class
33-
* @param iterable $source
35+
* @param string $class
36+
* @param iterable $source
37+
* @param bool $tryToFindInHeap
3438
*/
35-
public function __construct(ORMInterface $orm, string $class, iterable $source)
39+
public function __construct(ORMInterface $orm, string $class, iterable $source, bool $tryToFindInHeap = false)
3640
{
3741
$this->orm = $orm;
38-
$this->class = $class;
42+
$this->role = $this->orm->resolveRole($class);
3943
$this->source = $source;
44+
$this->tryToFindInHeap = $tryToFindInHeap;
4045
}
4146

4247
/**
@@ -57,7 +62,23 @@ public function getIterator(): \Generator
5762

5863
// add pipeline filter support?
5964
60-
yield $index => $this->orm->make($this->class, $data, Node::MANAGED);
65+
yield $index => $this->getEntity($data);
66+
}
67+
}
68+
69+
private function getEntity(array $data)
70+
{
71+
if ($this->tryToFindInHeap) {
72+
$pk = $this->orm->getSchema()->define($this->role, SchemaInterface::PRIMARY_KEY);
73+
$id = $data[$pk] ?? null;
74+
75+
if (null !== $id) {
76+
$e = $this->orm->getHeap()->find($this->role, [
77+
$pk => $id,
78+
]);
79+
}
6180
}
81+
82+
return $e ?? $this->orm->make($this->role, $data, Node::MANAGED);
6283
}
6384
}

src/Relation/ManyToMany.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function init(Node $node, array $data): array
5656
$elements = [];
5757
$pivotData = new \SplObjectStorage();
5858

59-
$iterator = new Iterator($this->orm, $this->target, $data);
59+
$iterator = new Iterator($this->orm, $this->target, $data, true);
6060
foreach ($iterator as $pivot => $entity) {
6161
if (!is_array($pivot)) {
6262
// skip partially selected entities (DB level filter)

src/Relation/Pivoted/PivotedPromise.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ public function __resolve()
143143

144144
$elements = [];
145145
$pivotData = new \SplObjectStorage();
146-
foreach (new Iterator($this->orm, $this->target, $root->getResult()[0]['output']) as $pivot => $entity) {
146+
$iterator = new Iterator($this->orm, $this->target, $root->getResult()[0]['output'], true);
147+
foreach ($iterator as $pivot => $entity) {
147148
$pivotData[$entity] = $this->orm->make(
148149
$this->relationSchema[Relation::THROUGH_ENTITY],
149150
$pivot,

tests/ORM/Fixtures/RbacItemAbstract.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class RbacItemAbstract
1414
*/
1515
public $name;
1616

17+
/** @var string|null */
18+
public $description;
19+
1720
/**
1821
* @var DoctrineCollection|RbacRole[]|RbacPermission[]
1922
* @phpstan-var DoctrineCollection<string,RbacRole|RbacPermission>
@@ -26,9 +29,10 @@ class RbacItemAbstract
2629
*/
2730
public $children;
2831

29-
public function __construct(string $name)
32+
public function __construct(string $name, string $description = null)
3033
{
3134
$this->name = $name;
35+
$this->description = $description;
3236

3337
$this->parents = new ArrayCollection();
3438
$this->children = new ArrayCollection();

tests/ORM/ManyToManySingleEntityTest.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Cycle\ORM\Mapper\Mapper;
99
use Cycle\ORM\Mapper\StdMapper;
1010
use Cycle\ORM\Relation;
11-
use Cycle\ORM\Relation\Pivoted\PivotedCollection;
1211
use Cycle\ORM\Schema;
1312
use Cycle\ORM\Select;
1413
use Cycle\ORM\Tests\Fixtures\RbacItemAbstract;
@@ -27,6 +26,7 @@ public function setUp(): void
2726

2827
$this->makeTable('rbac_item', [
2928
'name' => 'string,primary',
29+
'description' => 'string,nullable',
3030
'_type' => 'string,nullable',
3131
]);
3232

@@ -50,7 +50,7 @@ public function setUp(): void
5050
Schema::DATABASE => 'default',
5151
Schema::TABLE => 'rbac_item',
5252
Schema::PRIMARY_KEY => 'name',
53-
Schema::COLUMNS => ['name', '_type'],
53+
Schema::COLUMNS => ['name', 'description', '_type'],
5454
Schema::RELATIONS => [
5555
'parents' => [
5656
Relation::TYPE => Relation::MANY_TO_MANY,
@@ -157,4 +157,35 @@ public function testClearAndFillRelation(): void
157157

158158
self::assertTrue(true);
159159
}
160+
161+
public function testNotTriggersRehydrate(): void
162+
{
163+
$role = new RbacRole('superAdmin', 'description');
164+
165+
$permission = new RbacPermission('writeUser');
166+
167+
$role->children->add($permission);
168+
$permission->parents->add($role);
169+
170+
$this->save($role);
171+
172+
unset($role, $permission);
173+
174+
$this->orm = $this->orm->withHeap(new Heap());
175+
176+
/** @var RbacRole $fetchedRole */
177+
$fetchedRole = (new Select($this->orm, 'rbac_item'))->wherePK('superAdmin')->fetchOne();
178+
/** @var RbacPermission $fetchedPermission */
179+
$fetchedPermission = (new Select($this->orm, 'rbac_item'))->wherePK('writeUser')->fetchOne();
180+
181+
$fetchedRole->description = 'updated description';
182+
183+
// unlink
184+
$fetchedRole->children->removeElement($fetchedPermission);
185+
$fetchedPermission->parents->removeElement($fetchedRole);
186+
187+
self::assertSame('updated description', $fetchedRole->description);
188+
189+
$this->orm = $this->orm->withHeap(new Heap());
190+
}
160191
}

0 commit comments

Comments
 (0)