Passed
Push — master ( d62147...276eed )
by Alexander
02:12
created

SelectDataReader::withSort()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 5
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\DataReader;
6
7
use Countable;
8
use Cycle\ORM\Select;
9
use InvalidArgumentException;
10
use IteratorAggregate;
11
use Spiral\Database\Query\SelectQuery;
12
use Spiral\Pagination\PaginableInterface;
13
use Traversable;
14
use Yiisoft\Data\Reader\CountableDataInterface;
15
use Yiisoft\Data\Reader\DataReaderInterface;
16
use Yiisoft\Data\Reader\OffsetableDataInterface;
17
use Yiisoft\Data\Reader\Sort;
18
use Yiisoft\Data\Reader\SortableDataInterface;
19
use Yiisoft\Yii\Cycle\DataReader\Cache\CachedCount;
20
use Yiisoft\Yii\Cycle\DataReader\Cache\CachedCollection;
21
22
final class SelectDataReader implements
23
    DataReaderInterface,
24
    OffsetableDataInterface,
25
    CountableDataInterface,
26
    SortableDataInterface,
27
    IteratorAggregate
28
{
29
    /** @var Select|SelectQuery */
30
    private $query;
31
    private ?int $limit = null;
32
    private ?int $offset = null;
33
    private ?Sort $sorting = null;
34
    private CachedCount $countCache;
35
    private CachedCollection $itemsCache;
36
37
    /**
38
     * @param Select|SelectQuery $query
39
     */
40
    public function __construct($query)
41
    {
42
        if (!$query instanceof Countable) {
0 ignored issues
show
introduced by
$query is always a sub-type of Countable.
Loading history...
43
            throw new InvalidArgumentException(sprintf('Query should implement %s interface', Countable::class));
44
        }
45
        if (!$query instanceof PaginableInterface) {
0 ignored issues
show
introduced by
$query is always a sub-type of Spiral\Pagination\PaginableInterface.
Loading history...
46
            throw new InvalidArgumentException(
47
                sprintf('Query should implement %s interface', PaginableInterface::class)
48
            );
49
        }
50
        $this->query = clone $query;
51
        $this->countCache = new CachedCount($this->query);
52
        $this->itemsCache = new CachedCollection();
53
    }
54
55
    public function getSort(): ?Sort
56
    {
57
        return $this->sorting;
58
    }
59
60
    public function withLimit(int $limit): self
61
    {
62
        $clone = clone $this;
63
        $clone->setLimit($limit);
64
        return $clone;
65
    }
66
67
    public function withOffset(int $offset): self
68
    {
69
        $clone = clone $this;
70
        $clone->setOffset($offset);
71
        return $clone;
72
    }
73
74
    public function withSort(?Sort $sorting): self
75
    {
76
        $clone = clone $this;
77
        $clone->setSort($sorting);
78
        return $clone;
79
    }
80
81
    public function count(): int
82
    {
83
        return $this->countCache->getCount();
84
    }
85
86
    public function read(): iterable
87
    {
88
        if ($this->itemsCache->getCollection() !== null) {
89
            return $this->itemsCache->getCollection();
90
        }
91
        $query = $this->buildQuery();
92
        $this->itemsCache->setCollection($query->fetchAll());
93
        return $this->itemsCache->getCollection();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->itemsCache->getCollection() targeting Yiisoft\Yii\Cycle\DataRe...ection::getCollection() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug Best Practice introduced by
The expression return $this->itemsCache->getCollection() returns the type null which is incompatible with the type-hinted return iterable.
Loading history...
94
    }
95
96
    private function setSort(?Sort $sorting): void
97
    {
98
        if ($this->sorting !== $sorting) {
99
            $this->sorting = $sorting;
100
            $this->itemsCache = new CachedCollection();
101
        }
102
    }
103
104
    private function setLimit(?int $limit): void
105
    {
106
        if ($this->limit !== $limit) {
107
            $this->limit = $limit;
108
            $this->itemsCache = new CachedCollection();
109
        }
110
    }
111
112
    private function setOffset(?int $offset): void
113
    {
114
        if ($this->offset !== $offset) {
115
            $this->offset = $offset;
116
            $this->itemsCache = new CachedCollection();
117
        }
118
    }
119
120
    /**
121
     * Get Iterator without caching
122
     * @return Traversable
123
     * @throws \Exception
124
     */
125
    public function getIterator(): Traversable
126
    {
127
        if ($this->itemsCache->getCollection() !== null) {
128
            yield from $this->itemsCache->getCollection();
129
        } else {
130
            yield from $this->buildQuery()->getIterator();
131
        }
132
    }
133
134
    /**
135
     * @return Select|SelectQuery
136
     */
137
    private function buildQuery()
138
    {
139
        $newQuery = clone $this->query;
140
        if ($this->offset !== null) {
141
            $newQuery->offset($this->offset);
142
        }
143
        if ($this->sorting !== null) {
144
            $newQuery->orderBy($this->sorting->getOrder());
145
        }
146
        if ($this->limit !== null) {
147
            $newQuery->limit($this->limit);
148
        }
149
        return $newQuery;
150
    }
151
}
152