Passed
Push — master ( be06f7...c027e3 )
by Wilmer
08:58 queued 06:59
created

DataReaderProvider::getModels()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Data;
6
7
use Yiisoft\Db\Connection\ConnectionInterface;
8
use Yiisoft\Data\Reader\CountableDataInterface;
9
use Yiisoft\Db\Query\Query;
10
use Yiisoft\Data\Reader\Sort;
11
12
class DataReaderProvider implements CountableDataInterface
13
{
14
    private ?ConnectionInterface $db = null;
15
    private ?string $sql = null;
16
    private array $params = [];
17
    private bool $pagination = false;
18
    private array $models = [];
19
    private array $keys = [];
20
    private ?Sort $sort = null;
21
22
    /**
23
     * @var string the column that is used as the key of the data models. This can be either a column name.
24
     *
25
     * If this is not set, the keys of the {@see models} array will be used.
26
     */
27
    private ?string $key = null;
28
29
    /**
30
     * Returns the data models in the current page.
31
     *
32
     * @return array the list of data models in the current page.
33
     */
34 3
    public function getModels(): array
35
    {
36 3
        $this->prepare();
37
38 3
        return $this->models;
39
    }
40
41
    /**
42
     * Returns the number of data models in the current page.
43
     *
44
     * @return int the number of data models in the current page.
45
     */
46 2
    public function count(): int
47
    {
48 2
        return \count($this->getModels());
49
    }
50
51
    /**
52
     * Returns the total number of data models.
53
     *
54
     * When {@see pagination} is false, this returns the same value as {@see count}, otherwise, it will call
55
     * {@see prepareTotalCount()} to get the count.
56
     *
57
     * @return int total number of possible data models.
58
     */
59 2
    public function getTotalCount()
60
    {
61 2
        if ($this->getPagination() === false) {
62 2
            return $this->count();
63
        } else {
64
            return $this->prepareTotalCount();
65
        }
66
    }
67
68 3
    public function getSort(): ?Sort
69
    {
70 3
        return $this->sort;
71
    }
72
73 3
    public function getPagination(): bool
74
    {
75 3
        return $this->pagination;
76
    }
77
78
    /**
79
     * Set the DB connection the application.
80
     *
81
     * @param ConnectionInterface $value
82
     *
83
     * @return self
84
     */
85 3
    public function db(ConnectionInterface $value): self
86
    {
87 3
        $this->db = $value;
88
89 3
        return $this;
90
    }
91
92
    /**
93
     * Set the SQL statement to be used for fetching data rows.
94
     *
95
     * @param string $sql
96
     *
97
     * @return self
98
     */
99 3
    public function sql(string $value): self
100
    {
101 3
        $this->sql = $value;
102
103 3
        return $this;
104
    }
105
106
    /**
107
     * Set parameters (name=>value) to be bound to the SQL statement.
108
     *
109
     * @param array $params
110
     *
111
     * @return self
112
     */
113 1
    public function params(array $value): self
114
    {
115 1
        $this->params = $value;
116
117 1
        return $this;
118
    }
119
120
    /**
121
     * Set the value of pagination.
122
     *
123
     * @param bool $value
124
     *
125
     * @return self
126
     */
127
    public function setPagination(bool $value): self
128
    {
129
        $this->pagination = $value;
130
131
        return $this;
132
    }
133
134
    /**
135
     * Prepares the data models and keys.
136
     *
137
     * This method will prepare the data models and keys that can be retrieved via {@see getModels()} and
138
     * {@see getKeys()}.
139
     *
140
     * This method will be implicitly called by {@see getModels()} and {@see getKeys()} if it has not been called
141
     * before.
142
     *
143
     * @param bool $forcePrepare whether to force data preparation even if it has been done before.
144
     */
145 3
    private function prepare()
146
    {
147 3
        $this->models = $this->prepareModels();
148 3
        $this->keys = $this->prepareKeys($this->models);
149 3
    }
150
151 3
    private function prepareModels()
152
    {
153 3
        if ($this->getPagination() === false && $this->getSort() === null) {
154 3
            return $this->db->createCommand($this->sql, $this->params)->queryAll();
0 ignored issues
show
Bug introduced by
The method createCommand() does not exist on null. ( Ignorable by Annotation )

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

154
            return $this->db->/** @scrutinizer ignore-call */ createCommand($this->sql, $this->params)->queryAll();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
155
        }
156
157
        $sql = $this->sql;
158
        $orders = [];
159
        $limit = $offset = null;
160
161
        $sql = $this->db->getQueryBuilder()->buildOrderByAndLimit($sql, $orders, $limit, $offset);
0 ignored issues
show
Bug introduced by
The method getQueryBuilder() does not exist on Yiisoft\Db\Connection\ConnectionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Yiisoft\Db\Connection\ConnectionInterface. ( Ignorable by Annotation )

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

161
        $sql = $this->db->/** @scrutinizer ignore-call */ getQueryBuilder()->buildOrderByAndLimit($sql, $orders, $limit, $offset);
Loading history...
162
163
        return $this->db->createCommand($sql, $this->params)->queryAll();
164
    }
165
166 3
    private function prepareKeys(array $models)
167
    {
168 3
        $keys = [];
169
170 3
        if ($this->key !== null) {
171
            foreach ($models as $model) {
172
                if (\is_string($this->key)) {
173
                    $keys[] = $model[$this->key];
174
                } else {
175
                    $keys[] = \call_user_func($this->key, $model);
176
                }
177
            }
178
179
            return $keys;
180
        }
181
182 3
        return \array_keys($models);
183
    }
184
185
    private function prepareTotalCount(): int
186
    {
187
        return (new Query($this->db))->from(['sub' => "({$this->sql})"])->params($this->params)->count('*');
0 ignored issues
show
Bug Best Practice introduced by
The expression return new Yiisoft\Db\Qu...is->params)->count('*') could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
Bug introduced by
It seems like $this->db can also be of type null; however, parameter $db of Yiisoft\Db\Query\Query::__construct() does only seem to accept Yiisoft\Db\Connection\ConnectionInterface, 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

187
        return (new Query(/** @scrutinizer ignore-type */ $this->db))->from(['sub' => "({$this->sql})"])->params($this->params)->count('*');
Loading history...
188
    }
189
}
190