Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 13 additions & 27 deletions src/AbstractMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ public function markTracked(object $entity, Collection $collection): bool

public function persist(object $object, Collection $onCollection): object
{
$next = $onCollection->next;
if ($onCollection instanceof Filtered && $next !== null) {
$this->persist($object, $next);
$connectsTo = $onCollection->connectsTo;
if ($onCollection instanceof Filtered && $connectsTo !== null) {
$this->persist($object, $connectsTo);

return $object;
}
Expand All @@ -103,6 +103,7 @@ public function persist(object $object, Collection $onCollection): object

$this->pending[$object] = 'insert';
$this->markTracked($object, $onCollection);
$this->registerInIdentityMap($object, $onCollection);

return $object;
}
Expand All @@ -123,21 +124,9 @@ public function isTracked(object $entity): bool
return $this->tracked->offsetExists($entity);
}

public function replaceTracked(object $old, object $new, Collection $onCollection): void
{
$op = $this->pending[$old] ?? 'update';
$this->tracked->offsetUnset($old);
$this->pending->offsetUnset($old);
$this->evictFromIdentityMap($old, $onCollection);

$this->markTracked($new, $onCollection);
$this->registerInIdentityMap($new, $onCollection);
$this->pending[$new] = $op;
}

public function registerCollection(string $alias, Collection $collection): void
{
$collection->mapper = $this;
$collection->bindMapper($this);
$this->collections[$alias] = $collection;
}

Expand Down Expand Up @@ -199,7 +188,7 @@ protected function evictFromIdentityMap(object $entity, Collection $coll): void

protected function findInIdentityMap(Collection $collection): object|null
{
if ($collection->name === null || !is_scalar($collection->condition) || $collection->more) {
if ($collection->name === null || !is_scalar($collection->condition) || $collection->hasMore) {
return null;
}

Expand Down Expand Up @@ -234,6 +223,8 @@ private function tryMergeWithIdentityMap(object $entity, Collection $coll): obje
$this->entityFactory->set($entity, $idName, $idValue);
}

$op = $this->pending[$existing] ?? 'update';

if ($this->entityFactory->isReadOnly($existing)) {
$merged = $this->entityFactory->mergeEntities($existing, $entity);

Expand All @@ -245,7 +236,7 @@ private function tryMergeWithIdentityMap(object $entity, Collection $coll): obje
$this->registerInIdentityMap($merged, $coll);
}

$this->pending[$merged] = 'update';
$this->pending[$merged] = $op;

return $merged;
}
Expand All @@ -258,7 +249,7 @@ private function tryMergeWithIdentityMap(object $entity, Collection $coll): obje
$this->markTracked($existing, $coll);
}

$this->pending[$existing] = 'update';
$this->pending[$existing] = $op;

return $existing;
}
Expand Down Expand Up @@ -290,9 +281,8 @@ public function __get(string $name): Collection
}

$coll = new Collection($name);
$coll->mapper = $this;

return $coll;
return $coll->bindMapper($this);
}

public function __isset(string $alias): bool
Expand All @@ -310,14 +300,10 @@ public function __call(string $name, array $arguments): Collection
{
if (isset($this->collections[$name])) {
$collection = clone $this->collections[$name];
$collection->mapper = $this;

return $collection->with(...$arguments);
return $collection->bindMapper($this)->with(...$arguments);
}

$collection = Collection::__callstatic($name, $arguments);
$collection->mapper = $this;

return $collection;
return Collection::__callstatic($name, $arguments)->bindMapper($this);
}
}
6 changes: 3 additions & 3 deletions src/CollectionIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ public function key(): string

public function hasChildren(): bool
{
return $this->current()->more;
return $this->current()->hasMore;
}

public function getChildren(): RecursiveArrayIterator
{
$c = $this->current();
$pool = $c->hasChildren ? $c->children : [];
if ($c->next !== null) {
$pool[] = $c->next;
if ($c->connectsTo !== null) {
$pool[] = $c->connectsTo;
}

return new static(
Expand Down
49 changes: 22 additions & 27 deletions src/Collections/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ class Collection implements ArrayAccess
{
public private(set) bool $required = true;

public AbstractMapper|null $mapper = null;
public private(set) AbstractMapper|null $mapper = null;

public Hydrator|null $hydrator = null;
public private(set) Hydrator|null $hydrator = null;

public private(set) Collection|null $parent = null;

public private(set) Collection|null $next = null;
public private(set) Collection|null $connectsTo = null;

private Collection|null $last = null;

Expand All @@ -29,7 +29,7 @@ class Collection implements ArrayAccess

public bool $hasChildren { get => !empty($this->children); }

public bool $more { get => $this->hasChildren || $this->next !== null; }
public bool $hasMore { get => $this->hasChildren || $this->connectsTo !== null; }

/** @var array<scalar, mixed>|scalar|null */
public private(set) array|int|float|string|bool|null $condition = [];
Expand All @@ -50,22 +50,9 @@ public function addChild(Collection $child): void
$this->children[] = $clone;
}

public function persist(object $object, mixed ...$changes): object
public function persist(object $object): object
{
$mapper = $this->resolveMapper();

if ($changes) {
$original = $object;
$object = $mapper->entityFactory->withChanges($original, ...$changes);

if ($mapper->isTracked($original)) {
$mapper->replaceTracked($original, $object, $this);

return $object;
}
}

return $mapper->persist($object, $this);
return $this->resolveMapper()->persist($object, $this);
}

public function remove(object $object): bool
Expand Down Expand Up @@ -106,6 +93,14 @@ public function offsetUnset(mixed $offset): void
// no-op
}

/** @internal Used by AbstractMapper to bind this collection */
public function bindMapper(AbstractMapper $mapper): static
{
$this->mapper = $mapper;

return $this;
}

public function hydrateFrom(Hydrator $hydrator): static
{
$this->hydrator = $hydrator;
Expand All @@ -116,7 +111,7 @@ public function hydrateFrom(Hydrator $hydrator): static
public function stack(Collection $collection): static
{
$tail = $this->last ?? $this;
$tail->setNext($collection);
$tail->setConnectsTo($collection);
$this->last = $collection->last ?? $collection;

return $this;
Expand Down Expand Up @@ -151,10 +146,10 @@ private function resolveMapper(): AbstractMapper
return $this->findMapper() ?? throw new CollectionNotBound($this->name);
}

private function setNext(Collection $collection): void
private function setConnectsTo(Collection $collection): void
{
$collection->parent = $this;
$this->next = $collection;
$this->connectsTo = $collection;
}

/** @param array<int, mixed> $arguments */
Expand Down Expand Up @@ -187,9 +182,9 @@ public function __call(string $name, array $children): static

public function __clone(): void
{
if ($this->next !== null) {
$this->next = clone $this->next;
$this->next->parent = $this;
if ($this->connectsTo !== null) {
$this->connectsTo = clone $this->connectsTo;
$this->connectsTo->parent = $this;
}

$clonedChildren = [];
Expand All @@ -209,8 +204,8 @@ public function __clone(): void

$node = $this;

while ($node->next !== null) {
$node = $node->next;
while ($node->connectsTo !== null) {
$node = $node->connectsTo;
}

$this->last = $node !== $this ? $node : null;
Expand Down
37 changes: 0 additions & 37 deletions src/EntityFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
use ReflectionUnionType;

use function array_key_exists;
use function array_keys;
use function class_exists;
use function implode;
use function is_array;
use function is_bool;
use function is_float;
Expand Down Expand Up @@ -124,41 +122,6 @@ public function create(string $class, mixed ...$properties): object
return $entity;
}

public function withChanges(object $entity, mixed ...$changes): object
{
$clone = $this->reflectClass($entity::class)->newInstanceWithoutConstructor();
$styledChanges = [];
foreach ($changes as $prop => $value) {
$styledChanges[$this->style->styledProperty((string) $prop)] = $value;
}

foreach ($this->reflectProperties($entity::class) as $name => $prop) {
if (array_key_exists($name, $styledChanges)) {
$value = $styledChanges[$name];
$coerced = $this->coerce($prop, $value);

if ($coerced === null && !($prop->getType()?->allowsNull() ?? false)) {
throw new DomainException(
'Invalid value for ' . $entity::class . '::$' . $name,
);
}

$prop->setValue($clone, $coerced);
unset($styledChanges[$name]);
} elseif ($prop->isInitialized($entity)) {
$prop->setValue($clone, $prop->getValue($entity));
}
}

if ($styledChanges) {
throw new DomainException(
'Unknown properties for ' . $entity::class . ': ' . implode(', ', array_keys($styledChanges)),
);
}

return $clone;
}

public function mergeEntities(object $base, object $overlay): object
{
if ($base::class !== $overlay::class) {
Expand Down
4 changes: 2 additions & 2 deletions src/Hydrators/Nested.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ private function hydrateNode(

$entities[$entity] = $collection;

if ($collection->next !== null) {
$this->hydrateChild($data, $collection->next, $entityFactory, $entities);
if ($collection->connectsTo !== null) {
$this->hydrateChild($data, $collection->connectsTo, $entityFactory, $entities);
}

foreach ($collection->children as $child) {
Expand Down
Loading
Loading