Passed
Push — master ( 9302c9...f08430 )
by Dawid
02:34
created

Cursor::hydrateWith()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Igni\Storage\Driver\Pdo;
4
5
use Igni\Storage\Driver\MemorySavingCursor;
6
use Igni\Storage\Hydration\MemorySavingHydrator;
7
use Igni\Storage\EntityManager;
8
use Igni\Storage\Storable;
9
use Igni\Storage\Exception\CursorException;
10
use Igni\Storage\Hydration\ObjectHydrator;
11
use IteratorIterator;
12
13
class Cursor implements MemorySavingCursor
14
{
15
    /** @var Connection  */
16
    private $connection;
17
    /** @var string */
18
    private $query;
19
    /** @var array */
20
    private $params;
21
    /** @var ObjectHydrator */
22
    private $hydrator;
23
    /** @var \PDOStatement */
24
    private $baseCursor;
25
    /** @var Storable|array|null */
26
    private $current = null;
27
    /** @var  IteratorIterator */
28
    private $iterator;
29
30 25
    public function __construct(
31
        Connection $connection,
32
        string $query,
33
        array $params = null
34
    ) {
35 25
        $this->connection = $connection;
36 25
        $this->query = $query;
37 25
        $this->params = $params;
38 25
    }
39
40
    public function getBaseCursor(): \PDOStatement
41
    {
42
        $this->open();
43
        return $this->baseCursor;
44
    }
45
46
    public function getConnection(): \Igni\Storage\Driver\Connection
47
    {
48
        return $this->connection;
49
    }
50
51 13
    public function hydrateWith(ObjectHydrator $hydrator): void
52
    {
53 13
        $this->hydrator = $hydrator;
54 13
    }
55
56
    public function saveMemory(bool $save = true): void
57
    {
58
        if ($this->hydrator instanceof MemorySavingHydrator) {
59
            $this->hydrator->saveMemory($save);
60
        }
61
    }
62
63 22
    public function current()
64
    {
65 22
        $this->open();
66 22
        return $this->current;
67
    }
68
69 10
    public function next(): void
70
    {
71 10
        $this->open();
72 10
        $this->iterator->next();
73 10
        $this->current = $this->fetch();
74 10
    }
75
76 6
    public function key(): int
77
    {
78 6
        $this->open();
79 6
        return $this->iterator->key();
80
    }
81
82 13
    public function valid(): bool
83
    {
84 13
        $this->open();
85 13
        return $this->iterator->valid();
86
    }
87
88 7
    public function rewind(): void
89
    {
90 7
        $this->close();
91 7
        $this->open();
92 7
    }
93
94 25
    public function close(): void
95
    {
96 25
        $this->current = null;
97 25
        if ($this->baseCursor) {
98 22
            $this->baseCursor = null;
99 22
            $this->iterator = null;
100
        }
101 25
    }
102
103 6
    public function execute(): void
104
    {
105 6
        $this->open();
106 6
        $this->close();
107 6
    }
108
109 22
    public function open(): void
110
    {
111 22
        if ($this->iterator) {
112 12
            return;
113
        }
114
        try {
115 22
            $this->baseCursor = $this->connection
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->connection->getBa...->prepare($this->query) can also be of type boolean. However, the property $baseCursor is declared as type PDOStatement. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
116 22
                ->getBaseConnection()
117 22
                ->prepare($this->query);
118 22
            $this->baseCursor->setFetchMode(\PDO::FETCH_ASSOC);
119 22
            $this->baseCursor->execute($this->params);
120 22
            $this->iterator = new IteratorIterator($this->baseCursor);
0 ignored issues
show
Bug introduced by
It seems like $this->baseCursor can also be of type boolean; however, parameter $iterator of IteratorIterator::__construct() does only seem to accept Traversable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
            $this->iterator = new IteratorIterator(/** @scrutinizer ignore-type */ $this->baseCursor);
Loading history...
121 22
            $this->iterator->rewind();
122 22
            $this->current = $this->fetch();
123
        } catch (\Exception $e) {
124
            throw CursorException::forExecutionFailure($this, $e->getMessage());
125
        }
126 22
    }
127
128
    public function toArray(): array
129
    {
130
        return iterator_to_array($this);
131
    }
132
133 22
    private function fetch()
134
    {
135 22
        $fetched = $this->iterator->current();
136 22
        if ($this->hydrator && $fetched !== null) {
137 10
            $fetched = $this->hydrator->hydrate($fetched);
138
        }
139
140 22
        return $fetched;
141
    }
142
143 25
    public function __destruct()
144
    {
145 25
        $this->close();
146 25
    }
147
}
148