ci4

Форк
0
/
BaseResult.php 
545 строк · 13.5 Кб
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Database;
15

16
use CodeIgniter\Entity\Entity;
17
use stdClass;
18

19
/**
20
 * @template TConnection
21
 * @template TResult
22
 *
23
 * @implements ResultInterface<TConnection, TResult>
24
 */
25
abstract class BaseResult implements ResultInterface
26
{
27
    /**
28
     * Connection ID
29
     *
30
     * @var         object|resource
31
     * @phpstan-var TConnection
32
     */
33
    public $connID;
34

35
    /**
36
     * Result ID
37
     *
38
     * @var         false|object|resource
39
     * @phpstan-var false|TResult
40
     */
41
    public $resultID;
42

43
    /**
44
     * Result Array
45
     *
46
     * @var list<array>
47
     */
48
    public $resultArray = [];
49

50
    /**
51
     * Result Object
52
     *
53
     * @var list<object>
54
     */
55
    public $resultObject = [];
56

57
    /**
58
     * Custom Result Object
59
     *
60
     * @var array
61
     */
62
    public $customResultObject = [];
63

64
    /**
65
     * Current Row index
66
     *
67
     * @var int
68
     */
69
    public $currentRow = 0;
70

71
    /**
72
     * The number of records in the query result
73
     *
74
     * @var int|null
75
     */
76
    protected $numRows;
77

78
    /**
79
     * Row data
80
     *
81
     * @var array|null
82
     */
83
    public $rowData;
84

85
    /**
86
     * Constructor
87
     *
88
     * @param         object|resource $connID
89
     * @param         object|resource $resultID
90
     * @phpstan-param TConnection     $connID
91
     * @phpstan-param TResult         $resultID
92
     */
93
    public function __construct(&$connID, &$resultID)
94
    {
95
        $this->connID   = $connID;
96
        $this->resultID = $resultID;
97
    }
98

99
    /**
100
     * Retrieve the results of the query. Typically an array of
101
     * individual data rows, which can be either an 'array', an
102
     * 'object', or a custom class name.
103
     *
104
     * @param string $type The row type. Either 'array', 'object', or a class name to use
105
     */
106
    public function getResult(string $type = 'object'): array
107
    {
108
        if ($type === 'array') {
109
            return $this->getResultArray();
110
        }
111

112
        if ($type === 'object') {
113
            return $this->getResultObject();
114
        }
115

116
        return $this->getCustomResultObject($type);
117
    }
118

119
    /**
120
     * Returns the results as an array of custom objects.
121
     *
122
     * @phpstan-param class-string $className
123
     *
124
     * @return array
125
     */
126
    public function getCustomResultObject(string $className)
127
    {
128
        if (isset($this->customResultObject[$className])) {
129
            return $this->customResultObject[$className];
130
        }
131

132
        if (! $this->isValidResultId()) {
133
            return [];
134
        }
135

136
        // Don't fetch the result set again if we already have it
137
        $_data = null;
138
        if (($c = count($this->resultArray)) > 0) {
139
            $_data = 'resultArray';
140
        } elseif (($c = count($this->resultObject)) > 0) {
141
            $_data = 'resultObject';
142
        }
143

144
        if ($_data !== null) {
145
            for ($i = 0; $i < $c; $i++) {
146
                $this->customResultObject[$className][$i] = new $className();
147

148
                foreach ($this->{$_data}[$i] as $key => $value) {
149
                    $this->customResultObject[$className][$i]->{$key} = $value;
150
                }
151
            }
152

153
            return $this->customResultObject[$className];
154
        }
155

156
        if ($this->rowData !== null) {
157
            $this->dataSeek();
158
        }
159
        $this->customResultObject[$className] = [];
160

161
        while ($row = $this->fetchObject($className)) {
162
            if (! is_subclass_of($row, Entity::class) && method_exists($row, 'syncOriginal')) {
163
                $row->syncOriginal();
164
            }
165

166
            $this->customResultObject[$className][] = $row;
167
        }
168

169
        return $this->customResultObject[$className];
170
    }
171

172
    /**
173
     * Returns the results as an array of arrays.
174
     *
175
     * If no results, an empty array is returned.
176
     */
177
    public function getResultArray(): array
178
    {
179
        if ($this->resultArray !== []) {
180
            return $this->resultArray;
181
        }
182

183
        // In the event that query caching is on, the result_id variable
184
        // will not be a valid resource so we'll simply return an empty
185
        // array.
186
        if (! $this->isValidResultId()) {
187
            return [];
188
        }
189

190
        if ($this->resultObject !== []) {
191
            foreach ($this->resultObject as $row) {
192
                $this->resultArray[] = (array) $row;
193
            }
194

195
            return $this->resultArray;
196
        }
197

198
        if ($this->rowData !== null) {
199
            $this->dataSeek();
200
        }
201

202
        while ($row = $this->fetchAssoc()) {
203
            $this->resultArray[] = $row;
204
        }
205

206
        return $this->resultArray;
207
    }
208

209
    /**
210
     * Returns the results as an array of objects.
211
     *
212
     * If no results, an empty array is returned.
213
     *
214
     * @return         array<int, stdClass>
215
     * @phpstan-return list<stdClass>
216
     */
217
    public function getResultObject(): array
218
    {
219
        if ($this->resultObject !== []) {
220
            return $this->resultObject;
221
        }
222

223
        // In the event that query caching is on, the result_id variable
224
        // will not be a valid resource so we'll simply return an empty
225
        // array.
226
        if (! $this->isValidResultId()) {
227
            return [];
228
        }
229

230
        if ($this->resultArray !== []) {
231
            foreach ($this->resultArray as $row) {
232
                $this->resultObject[] = (object) $row;
233
            }
234

235
            return $this->resultObject;
236
        }
237

238
        if ($this->rowData !== null) {
239
            $this->dataSeek();
240
        }
241

242
        while ($row = $this->fetchObject()) {
243
            if (! is_subclass_of($row, Entity::class) && method_exists($row, 'syncOriginal')) {
244
                $row->syncOriginal();
245
            }
246

247
            $this->resultObject[] = $row;
248
        }
249

250
        return $this->resultObject;
251
    }
252

253
    /**
254
     * Wrapper object to return a row as either an array, an object, or
255
     * a custom class.
256
     *
257
     * If the row doesn't exist, returns null.
258
     *
259
     * @template T of object
260
     *
261
     * @param         int|string                       $n    The index of the results to return, or column name.
262
     * @param         string                           $type The type of result object. 'array', 'object' or class name.
263
     * @phpstan-param class-string<T>|'array'|'object' $type
264
     *
265
     * @return         array|float|int|object|stdClass|string|null
266
     * @phpstan-return ($n is string ? float|int|string|null : ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : T|null)))
267
     */
268
    public function getRow($n = 0, string $type = 'object')
269
    {
270
        // $n is a column name.
271
        if (! is_numeric($n)) {
272
            // We cache the row data for subsequent uses
273
            if (! is_array($this->rowData)) {
274
                $this->rowData = $this->getRowArray();
275
            }
276

277
            // array_key_exists() instead of isset() to allow for NULL values
278
            if (empty($this->rowData) || ! array_key_exists($n, $this->rowData)) {
279
                return null;
280
            }
281

282
            return $this->rowData[$n];
283
        }
284

285
        if ($type === 'object') {
286
            return $this->getRowObject($n);
287
        }
288

289
        if ($type === 'array') {
290
            return $this->getRowArray($n);
291
        }
292

293
        return $this->getCustomRowObject($n, $type);
294
    }
295

296
    /**
297
     * Returns a row as a custom class instance.
298
     *
299
     * If the row doesn't exist, returns null.
300
     *
301
     * @template T of object
302
     *
303
     * @param         int             $n         The index of the results to return.
304
     * @phpstan-param class-string<T> $className
305
     *
306
     * @return         object|null
307
     * @phpstan-return T|null
308
     */
309
    public function getCustomRowObject(int $n, string $className)
310
    {
311
        if (! isset($this->customResultObject[$className])) {
312
            $this->getCustomResultObject($className);
313
        }
314

315
        if (empty($this->customResultObject[$className])) {
316
            return null;
317
        }
318

319
        if ($n !== $this->currentRow && isset($this->customResultObject[$className][$n])) {
320
            $this->currentRow = $n;
321
        }
322

323
        return $this->customResultObject[$className][$this->currentRow];
324
    }
325

326
    /**
327
     * Returns a single row from the results as an array.
328
     *
329
     * If row doesn't exist, returns null.
330
     *
331
     * @return array|null
332
     */
333
    public function getRowArray(int $n = 0)
334
    {
335
        $result = $this->getResultArray();
336
        if ($result === []) {
337
            return null;
338
        }
339

340
        if ($n !== $this->currentRow && isset($result[$n])) {
341
            $this->currentRow = $n;
342
        }
343

344
        return $result[$this->currentRow];
345
    }
346

347
    /**
348
     * Returns a single row from the results as an object.
349
     *
350
     * If row doesn't exist, returns null.
351
     *
352
     * @return object|stdClass|null
353
     */
354
    public function getRowObject(int $n = 0)
355
    {
356
        $result = $this->getResultObject();
357
        if ($result === []) {
358
            return null;
359
        }
360

361
        if ($n !== $this->customResultObject && isset($result[$n])) {
362
            $this->currentRow = $n;
363
        }
364

365
        return $result[$this->currentRow];
366
    }
367

368
    /**
369
     * Assigns an item into a particular column slot.
370
     *
371
     * @param array|string               $key
372
     * @param array|object|stdClass|null $value
373
     *
374
     * @return void
375
     */
376
    public function setRow($key, $value = null)
377
    {
378
        // We cache the row data for subsequent uses
379
        if (! is_array($this->rowData)) {
380
            $this->rowData = $this->getRowArray();
381
        }
382

383
        if (is_array($key)) {
384
            foreach ($key as $k => $v) {
385
                $this->rowData[$k] = $v;
386
            }
387

388
            return;
389
        }
390

391
        if ($key !== '' && $value !== null) {
392
            $this->rowData[$key] = $value;
393
        }
394
    }
395

396
    /**
397
     * Returns the "first" row of the current results.
398
     *
399
     * @return array|object|null
400
     */
401
    public function getFirstRow(string $type = 'object')
402
    {
403
        $result = $this->getResult($type);
404

405
        return ($result === []) ? null : $result[0];
406
    }
407

408
    /**
409
     * Returns the "last" row of the current results.
410
     *
411
     * @return array|object|null
412
     */
413
    public function getLastRow(string $type = 'object')
414
    {
415
        $result = $this->getResult($type);
416

417
        return ($result === []) ? null : $result[count($result) - 1];
418
    }
419

420
    /**
421
     * Returns the "next" row of the current results.
422
     *
423
     * @return array|object|null
424
     */
425
    public function getNextRow(string $type = 'object')
426
    {
427
        $result = $this->getResult($type);
428
        if ($result === []) {
429
            return null;
430
        }
431

432
        return isset($result[$this->currentRow + 1]) ? $result[++$this->currentRow] : null;
433
    }
434

435
    /**
436
     * Returns the "previous" row of the current results.
437
     *
438
     * @return array|object|null
439
     */
440
    public function getPreviousRow(string $type = 'object')
441
    {
442
        $result = $this->getResult($type);
443
        if ($result === []) {
444
            return null;
445
        }
446

447
        if (isset($result[$this->currentRow - 1])) {
448
            $this->currentRow--;
449
        }
450

451
        return $result[$this->currentRow];
452
    }
453

454
    /**
455
     * Returns an unbuffered row and move the pointer to the next row.
456
     *
457
     * @return array|object|null
458
     */
459
    public function getUnbufferedRow(string $type = 'object')
460
    {
461
        if ($type === 'array') {
462
            return $this->fetchAssoc();
463
        }
464

465
        if ($type === 'object') {
466
            return $this->fetchObject();
467
        }
468

469
        return $this->fetchObject($type);
470
    }
471

472
    /**
473
     * Number of rows in the result set; checks for previous count, falls
474
     * back on counting resultArray or resultObject, finally fetching resultArray
475
     * if nothing was previously fetched
476
     */
477
    public function getNumRows(): int
478
    {
479
        if (is_int($this->numRows)) {
480
            return $this->numRows;
481
        }
482
        if ($this->resultArray !== []) {
483
            return $this->numRows = count($this->resultArray);
484
        }
485
        if ($this->resultObject !== []) {
486
            return $this->numRows = count($this->resultObject);
487
        }
488

489
        return $this->numRows = count($this->getResultArray());
490
    }
491

492
    private function isValidResultId(): bool
493
    {
494
        return is_resource($this->resultID) || is_object($this->resultID);
495
    }
496

497
    /**
498
     * Gets the number of fields in the result set.
499
     */
500
    abstract public function getFieldCount(): int;
501

502
    /**
503
     * Generates an array of column names in the result set.
504
     */
505
    abstract public function getFieldNames(): array;
506

507
    /**
508
     * Generates an array of objects representing field meta-data.
509
     */
510
    abstract public function getFieldData(): array;
511

512
    /**
513
     * Frees the current result.
514
     *
515
     * @return void
516
     */
517
    abstract public function freeResult();
518

519
    /**
520
     * Moves the internal pointer to the desired offset. This is called
521
     * internally before fetching results to make sure the result set
522
     * starts at zero.
523
     *
524
     * @return bool
525
     */
526
    abstract public function dataSeek(int $n = 0);
527

528
    /**
529
     * Returns the result set as an array.
530
     *
531
     * Overridden by driver classes.
532
     *
533
     * @return array|false|null
534
     */
535
    abstract protected function fetchAssoc();
536

537
    /**
538
     * Returns the result set as an object.
539
     *
540
     * Overridden by child classes.
541
     *
542
     * @return Entity|false|object|stdClass
543
     */
544
    abstract protected function fetchObject(string $className = 'stdClass');
545
}
546

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.