Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
Table
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
13 / 13
48
100.00% covered (success)
100.00%
1 / 1
 getNumberOfRows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getRows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasRows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 rows
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 select
100.00% covered (success)
100.00%
37 / 37
100.00% covered (success)
100.00%
1 / 1
23
 insert
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
4
 insertRows
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
5
 update
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
5
 delete
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 setRows
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIterator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Db\Gateway;
16
17use Pop\Db\Db;
18use Pop\Db\Sql\Parser;
19use ArrayIterator;
20
21/**
22 * Table gateway class
23 *
24 * @category   Pop
25 * @package    Pop\Db
26 * @author     Nick Sagona, III <nick@popphp.org>
27 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
28 * @license    https://www.popphp.org/license     New BSD License
29 * @version    7.0.0
30 */
31class Table extends AbstractGateway implements \Countable, \IteratorAggregate
32{
33
34    /**
35     * Result rows
36     * @var array
37     */
38    protected array $rows = [];
39
40    /**
41     * Get the number of result rows
42     *
43     * @return int
44     */
45    public function getNumberOfRows(): int
46    {
47        return count($this->rows);
48    }
49
50    /**
51     * Get the result rows
52     *
53     * @return array
54     */
55    public function getRows(): array
56    {
57        return $this->rows;
58    }
59
60    /**
61     * Has rows
62     *
63     * @return bool
64     */
65    public function hasRows(): bool
66    {
67        return (count($this->rows) > 0);
68    }
69
70    /**
71     * Get the result rows (alias method)
72     *
73     * @return array
74     */
75    public function rows(): array
76    {
77        return $this->rows;
78    }
79
80    /**
81     * Method to convert table gateway to an array (alias method)
82     *
83     * @return array
84     */
85    public function toArray(): array
86    {
87        return $this->rows;
88    }
89
90    /**
91     * Select rows from the table
92     *
93     * @param  ?array $columns
94     * @param  mixed  $where
95     * @param  ?array $parameters
96     * @param  ?array $options
97     * @return array
98     */
99    public function select(?array $columns = null, mixed $where = null, ?array $parameters = null, ?array $options = null): array
100    {
101        $this->rows = [];
102
103        $this->checkOptions($options);
104
105        $db  = Db::getDb($this->table);
106        $sql = $db->createSql();
107
108        if ($columns === null) {
109            $columns = [$this->table . '.*'];
110        }
111
112        $sql->select($columns)->from($this->table);
113
114        if ($where !== null) {
115            $sql->select()->where($where);
116        }
117
118        if (($options !== null) && isset($options['limit'])) {
119            $sql->select()->limit((int)$options['limit']);
120        }
121
122        if (($options !== null) && isset($options['offset'])) {
123            $sql->select()->offset((int)$options['offset']);
124        }
125
126        if (($options !== null) && isset($options['join'])) {
127            $joins = (is_array($options['join']) && isset($options['join']['table'])) ?
128                [$options['join']] : $options['join'];
129
130            foreach ($joins as $join) {
131                if (isset($join['type']) && method_exists($sql->select(), $join['type'])) {
132                    $joinMethod = $join['type'];
133                    $sql->select()->{$joinMethod}($join['table'], $join['columns']);
134                } else {
135                    $sql->select()->leftJoin($join['table'], $join['columns']);
136                }
137            }
138        }
139
140        if (($options !== null) && isset($options['order'])) {
141            if (!is_array($options['order'])) {
142                $orders = (strpos($options['order'], ',') !== false) ?
143                    explode(',', $options['order']) : [$options['order']];
144            } else {
145                $orders = $options['order'];
146            }
147            foreach ($orders as $order) {
148                $ord = Parser\Order::parse(trim($order));
149                $sql->select()->orderBy($ord['by'], $db->escape($ord['order']));
150            }
151        }
152
153        if (($options !== null) && isset($options['group'])) {
154            $sql->select()->groupBy($options['group']);
155        }
156
157        $db->prepare((string)$sql);
158
159        if (($parameters !== null) && (count($parameters) > 0)) {
160            $db->bindParams($parameters);
161        }
162
163        $db->execute();
164
165        $this->rows = $db->fetchAll();
166
167        return $this->rows;
168    }
169
170    /**
171     * Insert a row of values into the table
172     *
173     * @param  array $columns
174     * @return Table
175     */
176    public function insert(array $columns): Table
177    {
178        $this->rows = [];
179
180        $db     = Db::getDb($this->table);
181        $sql    = $db->createSql();
182        $values = [];
183        $params = [];
184        $i      = 1;
185
186        foreach ($columns as $column => $value) {
187            $placeholder = $sql->getPlaceholder();
188
189            if ($placeholder == ':') {
190                $placeholder .= $column;
191            } else if ($placeholder == '$') {
192                $placeholder .= $i;
193            }
194            $values[$column] = $placeholder;
195            $params[$column] = $value;
196            $i++;
197        }
198
199        $sql->insert($this->table)->values($values);
200
201        $db->prepare((string)$sql)
202           ->bindParams($params)
203           ->execute();
204
205        return $this;
206    }
207
208    /**
209     * Insert rows of values into the table
210     *
211     * @param  array $values
212     * @return Table
213     */
214    public function insertRows(array $values): Table
215    {
216        $this->rows   = [];
217        $db           = Db::getDb($this->table);
218        $sql          = $db->createSql();
219        $placeholders = [];
220        $columns      = array_keys($values[0]);
221
222        foreach ($columns as $i => $column) {
223            $placeholder = $sql->getPlaceholder();
224
225            if ($placeholder == ':') {
226                $placeholder .= $column;
227            } else if ($placeholder == '$') {
228                $placeholder .= ($i + 1);
229            }
230            $placeholders[$column] = $placeholder;
231        }
232
233        $sql->insert($this->table)->values($placeholders);
234        $db->prepare((string)$sql);
235
236        foreach ($values as $rowValues) {
237            $db->bindParams($rowValues)->execute();
238        }
239
240        return $this;
241    }
242
243    /**
244     * Update a table
245     *
246     * @param  array  $columns
247     * @param  mixed  $where
248     * @param  ?array $parameters
249     * @return Table
250     */
251    public function update(array $columns, mixed $where = null, ?array $parameters = []): Table
252    {
253        $this->rows = [];
254
255        $db     = Db::getDb($this->table);
256        $sql    = $db->createSql();
257        $values = [];
258        $params = [];
259        $i      = 1;
260
261        foreach ($columns as $column => $value) {
262            $placeholder = $sql->getPlaceholder();
263
264            if ($placeholder == ':') {
265                $placeholder .= $column;
266            } else if ($placeholder == '$') {
267                $placeholder .= $i;
268            }
269            $values[$column] = $placeholder;
270            $params[$column] = $value;
271            $i++;
272        }
273
274        $sql->update($this->table)->values($values);
275
276        if ($where !== null) {
277            $sql->update()->where($where);
278        }
279
280        $db->prepare((string)$sql)
281           ->bindParams($params + $parameters)
282           ->execute();
283
284        return $this;
285    }
286
287    /**
288     * Delete from a table
289     *
290     * @param  mixed $where
291     * @param  array $parameters
292     * @return Table
293     */
294    public function delete(mixed $where = null, array $parameters = []): Table
295    {
296        $this->rows = [];
297
298        $db  = Db::getDb($this->table);
299        $sql = $db->createSql();
300
301        $sql->delete($this->table);
302
303        if ($where !== null) {
304            $sql->delete()->where($where);
305        }
306
307        $db->prepare((string)$sql);
308
309        if (count($parameters) > 0) {
310            $db->bindParams($parameters);
311        }
312
313        $db->execute();
314
315        return $this;
316    }
317
318    /**
319     * Set all the table rows at once
320     *
321     * @param  array  $rows
322     * @return Table
323     */
324    public function setRows(array $rows = []): Table
325    {
326        $this->rows = $rows;
327        return $this;
328    }
329
330    /**
331     * Method to get the count of items in the collection
332     *
333     * @return int
334     */
335    public function count(): int
336    {
337        return count($this->rows);
338    }
339
340    /**
341     * Method to iterate over the table rows
342     *
343     * @return ArrayIterator
344     */
345    public function getIterator(): ArrayIterator
346    {
347        return new ArrayIterator($this->rows);
348    }
349
350}