Passed
Push — 2.x ( 31e29e...5c8c20 )
by Aleksei
38:29 queued 18:23
created

TupleStorage.php$0 ➔ __destruct()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cycle\ORM\Transaction;
6
7
use Countable;
8
use IteratorAggregate;
9
10
/**
11
 * @internal
12
 * @implements IteratorAggregate<object, Tuple>
13
 */
14
final class TupleStorage implements IteratorAggregate, Countable
15
{
16
    /** @var array<int, Tuple> */
17
    private array $storage = [];
18
19
    private array $iterators = [];
20
21
    /**
22
     * @return \Traversable<object, Tuple>
23
     */
24
    public function getIterator(): \Traversable
25
    {
26
        $iterator = $this->storage;
27
        // When the generator is destroyed, the reference to the iterator is removed from the collection.
28
        $cleaner = new class () {
29
            public array $iterators;
30
            public function __destruct()
31
            {
32
                unset($this->iterators[\spl_object_id($this)]);
33
            }
34
        };
35
        /** @psalm-suppress UnsupportedPropertyReferenceUsage */
36
        $cleaner->iterators = &$this->iterators;
37
        $this->iterators[\spl_object_id($cleaner)] = &$iterator;
38
39
        while (\count($iterator) > 0) {
40
            $tuple = \current($iterator);
41
            unset($iterator[\key($iterator)]);
42
            yield $tuple->entity => $tuple;
43
        }
44
    }
45
46
    /**
47
     * Returns {@see Tuple} if exists, throws an exception otherwise.
48
     *
49
     * @throws \Throwable if the entity is not found in the storage
50
     */
51
    public function getTuple(object $entity): Tuple
52
    {
53
        return $this->storage[\spl_object_id($entity)] ?? throw new \RuntimeException('Tuple not found');
54
    }
55
56
    public function attach(Tuple $tuple): void
57
    {
58
        if ($this->contains($tuple->entity)) {
59
            return;
60
        }
61
62
        $this->storage[\spl_object_id($tuple->entity)] = $tuple;
63
        foreach ($this->iterators as &$collection) {
64
            $collection[\spl_object_id($tuple->entity)] = $tuple;
65
        }
66
    }
67
68
    public function contains(object $entity): bool
69
    {
70
        return \array_key_exists(\spl_object_id($entity), $this->storage);
71
    }
72
73
    public function detach(object $entity): void
74
    {
75
        $id = \spl_object_id($entity);
76
        unset($this->storage[$id]);
77
        foreach ($this->iterators as &$collection) {
78
            unset($collection[$id]);
79
        }
80
    }
81
82
    /**
83
     * @return int<0, max>
84
     */
85
    public function count(): int
86
    {
87
        return \count($this->storage);
88
    }
89
}
90