Skip to content

Commit 133ea72

Browse files
committed
Modernize properties with PHP 8.4+ features and tighten visibility
- Replace trivial getters/setters with asymmetric visibility (public private(set)) on Collection, Filtered, Typed, Composite properties - Add virtual property hooks: Collection::$hasChildren, $more, Filtered::$identifierOnly, AbstractMapper::$style - Use constructor promotion with readonly for Typed::$type, Composite::$compositions, Filtered::$filters - Make NotPersistable a final readonly class - Cache tail node in Collection::$last for O(1) chain stacking - Tighten visibility: AbstractMapper::$collections and tryHydration() to private, Collection::findMapper()/resolveMapper() to private - Remove all trivial getters (getName, getCondition, getNext, getParent, getChildren, isRequired, getFilters, getType, getCompositions), setters (setMapper, setCondition, setParent, setRequired), and boolean methods (hasChildren, hasMore, isIdentifierOnly, getStyle) - Inline single-use variables and convert verbose conditionals to ternaries across Style classes - Exclude PSR2.Classes.PropertyDeclaration from PHPCS (4.0.x cannot parse property hooks) - Update all callers in src and tests to use direct property access
1 parent 3f39ede commit 133ea72

19 files changed

Lines changed: 254 additions & 374 deletions

phpcs.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
<rule ref="Respect">
1818
<exclude name="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix" />
19+
<!-- PHPCS 4.0.x cannot parse property hooks (PHP 8.4+), remove when fixed -->
20+
<exclude name="PSR2.Classes.PropertyDeclaration.Multiple" />
21+
<exclude name="PSR2.Classes.PropertyDeclaration.ScopeMissing" />
1922
</rule>
2023

2124
<!-- Test code and stub entities use snake_case properties matching DB columns -->

src/AbstractMapper.php

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,26 @@
99
use Respect\Data\Collections\Filtered;
1010
use SplObjectStorage;
1111

12-
use function assert;
1312
use function count;
1413

1514
abstract class AbstractMapper
1615
{
17-
/** @var SplObjectStorage<object, mixed> */
16+
/** @var SplObjectStorage<object, true> */
1817
protected SplObjectStorage $new;
1918

20-
/** @var SplObjectStorage<object, mixed> */
19+
/** @var SplObjectStorage<object, Collection> */
2120
protected SplObjectStorage $tracked;
2221

23-
/** @var SplObjectStorage<object, mixed> */
22+
/** @var SplObjectStorage<object, true> */
2423
protected SplObjectStorage $changed;
2524

26-
/** @var SplObjectStorage<object, mixed> */
25+
/** @var SplObjectStorage<object, true> */
2726
protected SplObjectStorage $removed;
2827

2928
/** @var array<string, Collection> */
30-
protected array $collections = [];
29+
private array $collections = [];
30+
31+
public Styles\Stylable $style { get => $this->entityFactory->style; }
3132

3233
public function __construct(
3334
public readonly EntityFactory $entityFactory = new EntityFactory(),
@@ -38,11 +39,6 @@ public function __construct(
3839
$this->new = new SplObjectStorage();
3940
}
4041

41-
public function getStyle(): Styles\Stylable
42-
{
43-
return $this->entityFactory->style;
44-
}
45-
4642
abstract public function flush(): void;
4743

4844
abstract public function fetch(Collection $collection, mixed $extra = null): mixed;
@@ -66,10 +62,9 @@ public function markTracked(object $entity, Collection $collection): bool
6662

6763
public function persist(object $object, Collection $onCollection): bool
6864
{
69-
$next = $onCollection->getNext();
65+
$next = $onCollection->next;
7066
if ($onCollection instanceof Filtered && $next !== null) {
71-
$next->setMapper($this);
72-
$next->persist($object);
67+
$this->persist($object, $next);
7368

7469
return true;
7570
}
@@ -107,7 +102,7 @@ public function isTracked(object $entity): bool
107102

108103
public function registerCollection(string $alias, Collection $collection): void
109104
{
110-
$collection->setMapper($this);
105+
$collection->mapper = $this;
111106
$this->collections[$alias] = $collection;
112107
}
113108

@@ -118,7 +113,7 @@ protected function postHydrate(SplObjectStorage $entities): void
118113

119114
foreach ($entities as $instance) {
120115
foreach ($this->entityFactory->extractProperties($instance) as $field => $v) {
121-
if (!$this->getStyle()->isRemoteIdentifier($field)) {
116+
if (!$this->style->isRemoteIdentifier($field)) {
122117
continue;
123118
}
124119

@@ -131,22 +126,6 @@ protected function postHydrate(SplObjectStorage $entities): void
131126
}
132127
}
133128

134-
/** @param SplObjectStorage<object, Collection> $entities */
135-
protected function tryHydration(SplObjectStorage $entities, object $sub, string $field, mixed &$v): void
136-
{
137-
$tableName = (string) $entities[$sub]->getName();
138-
$primaryName = $this->getStyle()->identifier($tableName);
139-
140-
if (
141-
$tableName !== $this->getStyle()->remoteFromIdentifier($field)
142-
|| $this->entityFactory->get($sub, $primaryName) != $v
143-
) {
144-
return;
145-
}
146-
147-
$v = $sub;
148-
}
149-
150129
/**
151130
* @param SplObjectStorage<object, Collection> $entities
152131
*
@@ -159,15 +138,18 @@ protected function buildEntitiesInstances(
159138
$entitiesInstances = [];
160139

161140
foreach (CollectionIterator::recursive($collection) as $c) {
162-
assert($c instanceof Collection);
163-
if ($c instanceof Filtered && !$c->getFilters()) {
141+
if (!$c instanceof Collection) {
164142
continue;
165143
}
166144

167-
$entityInstance = $this->entityFactory->createByName((string) $c->getName());
145+
if ($c instanceof Filtered && !$c->filters) {
146+
continue;
147+
}
148+
149+
$entityInstance = $this->entityFactory->createByName((string) $c->name);
168150

169151
if ($c instanceof Composite) {
170-
$compositionCount = count($c->getCompositions());
152+
$compositionCount = count($c->compositions);
171153
for ($i = 0; $i < $compositionCount; $i++) {
172154
$entitiesInstances[] = $entityInstance;
173155
}
@@ -180,14 +162,30 @@ protected function buildEntitiesInstances(
180162
return $entitiesInstances;
181163
}
182164

165+
/** @param SplObjectStorage<object, Collection> $entities */
166+
private function tryHydration(SplObjectStorage $entities, object $sub, string $field, mixed &$v): void
167+
{
168+
$tableName = (string) $entities[$sub]->name;
169+
$primaryName = $this->style->identifier($tableName);
170+
171+
if (
172+
$tableName !== $this->style->remoteFromIdentifier($field)
173+
|| $this->entityFactory->get($sub, $primaryName) != $v
174+
) {
175+
return;
176+
}
177+
178+
$v = $sub;
179+
}
180+
183181
public function __get(string $name): Collection
184182
{
185183
if (isset($this->collections[$name])) {
186184
return $this->collections[$name];
187185
}
188186

189187
$coll = new Collection($name);
190-
$coll->setMapper($this);
188+
$coll->mapper = $this;
191189

192190
return $coll;
193191
}
@@ -197,17 +195,16 @@ public function __isset(string $alias): bool
197195
return isset($this->collections[$alias]);
198196
}
199197

200-
public function __set(string $alias, mixed $collection): void
198+
public function __set(string $alias, Collection $collection): void
201199
{
202-
assert($collection instanceof Collection);
203200
$this->registerCollection($alias, $collection);
204201
}
205202

206203
/** @param array<int, mixed> $children */
207204
public function __call(string $name, array $children): Collection
208205
{
209206
$collection = Collection::__callstatic($name, $children);
210-
$collection->setMapper($this);
207+
$collection->mapper = $this;
211208

212209
return $collection;
213210
}

src/CollectionIterator.php

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,28 @@ final class CollectionIterator extends RecursiveArrayIterator
1616
/** @var array<string, int> */
1717
protected array $namesCounts = [];
1818

19-
/** @param array<string, int> $namesCounts */
20-
public function __construct(mixed $target = [], array &$namesCounts = [])
19+
/**
20+
* @param Collection|array<Collection> $target
21+
* @param array<string, int> $namesCounts
22+
*/
23+
public function __construct(Collection|array $target = [], array &$namesCounts = [])
2124
{
2225
$this->namesCounts = &$namesCounts;
2326

24-
/** @var array<Collection> $items */
2527
$items = is_array($target) ? $target : [$target];
2628

2729
parent::__construct($items);
2830
}
2931

3032
/** @return RecursiveIteratorIterator<CollectionIterator> */
31-
public static function recursive(mixed $target): RecursiveIteratorIterator
33+
public static function recursive(Collection $target): RecursiveIteratorIterator
3234
{
3335
return new RecursiveIteratorIterator(new self($target), 1);
3436
}
3537

3638
public function key(): string
3739
{
38-
$name = $this->current()->getName() ?? '';
40+
$name = $this->current()->name ?? '';
3941

4042
if (isset($this->namesCounts[$name])) {
4143
return $name . ++$this->namesCounts[$name];
@@ -48,20 +50,15 @@ public function key(): string
4850

4951
public function hasChildren(): bool
5052
{
51-
return $this->current()->hasMore();
53+
return $this->current()->more;
5254
}
5355

5456
public function getChildren(): RecursiveArrayIterator
5557
{
5658
$c = $this->current();
57-
$pool = [];
58-
59-
if ($c->hasChildren()) {
60-
$pool = $c->getChildren();
61-
}
62-
63-
if ($c->hasNext()) {
64-
$pool[] = $c->getNext();
59+
$pool = $c->hasChildren ? $c->children : [];
60+
if ($c->next !== null) {
61+
$pool[] = $c->next;
6562
}
6663

6764
return new static($pool, $this->namesCounts);

0 commit comments

Comments
 (0)