Skip to content

Commit 5c7fca7

Browse files
committed
fix: use currentRow instead of customResultObject in getRowObject and add null fallback
1 parent 784ba45 commit 5c7fca7

2 files changed

Lines changed: 252 additions & 3 deletions

File tree

system/Database/BaseResult.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ public function getRowArray(int $n = 0)
333333
$this->currentRow = $n;
334334
}
335335

336-
return $result[$this->currentRow];
336+
return $result[$this->currentRow] ?? null;
337337
}
338338

339339
/**
@@ -350,11 +350,11 @@ public function getRowObject(int $n = 0)
350350
return null;
351351
}
352352

353-
if ($n !== $this->customResultObject && isset($result[$n])) {
353+
if ($n !== $this->currentRow && isset($result[$n])) {
354354
$this->currentRow = $n;
355355
}
356356

357-
return $result[$this->currentRow];
357+
return $result[$this->currentRow] ?? null;
358358
}
359359

360360
/**
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
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\Test\CIUnitTestCase;
17+
use PHPUnit\Framework\Attributes\Group;
18+
use stdClass;
19+
20+
/**
21+
* @internal
22+
*/
23+
#[Group('Database')]
24+
final class BaseResultTest extends CIUnitTestCase
25+
{
26+
/**
27+
* Create a minimal concrete implementation of BaseResult for testing.
28+
*/
29+
private function createResultDouble(array $resultArray, array $resultObject): BaseResult
30+
{
31+
return new class ($resultArray, $resultObject) extends BaseResult {
32+
public function __construct(array $resultArray, array $resultObject)
33+
{
34+
$this->resultArray = $resultArray;
35+
$this->resultObject = $resultObject;
36+
$this->currentRow = 0;
37+
38+
$connId = null;
39+
$resultId = null;
40+
parent::__construct($connId, $resultId);
41+
}
42+
43+
public function getFieldCount(): int
44+
{
45+
return 0;
46+
}
47+
48+
public function getFieldNames(): array
49+
{
50+
return [];
51+
}
52+
53+
public function getFieldData(): array
54+
{
55+
return [];
56+
}
57+
58+
public function freeResult(): void
59+
{
60+
}
61+
62+
public function dataSeek(int $n = 0): bool
63+
{
64+
return true;
65+
}
66+
67+
protected function fetchAssoc()
68+
{
69+
return false;
70+
}
71+
72+
protected function fetchObject(string $className = stdClass::class)
73+
{
74+
return false;
75+
}
76+
};
77+
}
78+
79+
// --------------------------------------------------------------------
80+
// getRowArray()
81+
// --------------------------------------------------------------------
82+
83+
public function testGetRowArrayReturnsRow(): void
84+
{
85+
$result = $this->createResultDouble(
86+
[
87+
['id' => 1, 'name' => 'John'],
88+
['id' => 2, 'name' => 'Jane'],
89+
],
90+
[],
91+
);
92+
93+
$this->assertSame(['id' => 1, 'name' => 'John'], $result->getRowArray(0));
94+
$this->assertSame(['id' => 2, 'name' => 'Jane'], $result->getRowArray(1));
95+
}
96+
97+
public function testGetRowArrayReturnsNullForEmptyResult(): void
98+
{
99+
$result = $this->createResultDouble([], []);
100+
101+
$this->assertNull($result->getRowArray(0));
102+
}
103+
104+
public function testGetRowArrayReturnsFirstRowByDefault(): void
105+
{
106+
$result = $this->createResultDouble(
107+
[
108+
['id' => 1, 'name' => 'John'],
109+
['id' => 2, 'name' => 'Jane'],
110+
],
111+
[],
112+
);
113+
114+
$this->assertSame(['id' => 1, 'name' => 'John'], $result->getRowArray());
115+
}
116+
117+
// --------------------------------------------------------------------
118+
// getRowObject()
119+
// --------------------------------------------------------------------
120+
121+
public function testGetRowObjectReturnsObject(): void
122+
{
123+
$row1 = new stdClass();
124+
$row1->id = 1;
125+
$row1->name = 'John';
126+
$row2 = new stdClass();
127+
$row2->id = 2;
128+
$row2->name = 'Jane';
129+
130+
$result = $this->createResultDouble([], [$row1, $row2]);
131+
132+
$this->assertEquals($row1, $result->getRowObject(0));
133+
$this->assertEquals($row2, $result->getRowObject(1));
134+
}
135+
136+
public function testGetRowObjectReturnsNullForEmptyResult(): void
137+
{
138+
$result = $this->createResultDouble([], []);
139+
140+
$this->assertNull($result->getRowObject(0));
141+
}
142+
143+
public function testGetRowObjectReturnsFirstRowByDefault(): void
144+
{
145+
$row1 = new stdClass();
146+
$row1->id = 1;
147+
$row1->name = 'John';
148+
149+
$result = $this->createResultDouble([], [$row1]);
150+
151+
$this->assertEquals($row1, $result->getRowObject());
152+
}
153+
154+
public function testGetRowObjectAndGetRowArrayShareCurrentRow(): void
155+
{
156+
$row1 = new stdClass();
157+
$row1->id = 1;
158+
$row1->name = 'John';
159+
$row2 = new stdClass();
160+
$row2->id = 2;
161+
$row2->name = 'Jane';
162+
163+
$result = $this->createResultDouble(
164+
[
165+
['id' => 1, 'name' => 'John'],
166+
['id' => 2, 'name' => 'Jane'],
167+
],
168+
[$row1, $row2],
169+
);
170+
171+
// getRowObject(1) should advance currentRow to 1 (same as getRowArray would)
172+
$result->getRowObject(1);
173+
$this->assertSame(['id' => 2, 'name' => 'Jane'], $result->getRowArray(1));
174+
}
175+
176+
public function testGetRowObjectUsesCurrentRowLikeGetRowArray(): void
177+
{
178+
$row1 = new stdClass();
179+
$row1->id = 1;
180+
$row1->name = 'John';
181+
$row2 = new stdClass();
182+
$row2->id = 2;
183+
$row2->name = 'Jane';
184+
185+
$result = $this->createResultDouble(
186+
[
187+
['id' => 1, 'name' => 'John'],
188+
['id' => 2, 'name' => 'Jane'],
189+
],
190+
[$row1, $row2],
191+
);
192+
193+
// Both methods should advance currentRow consistently
194+
$result->getRowObject(1);
195+
$result->getRowArray();
196+
$this->assertEquals($row1, $result->getRowObject());
197+
}
198+
199+
// --------------------------------------------------------------------
200+
// getRow() — convenience wrapper
201+
// --------------------------------------------------------------------
202+
203+
public function testGetRowWithInvalidIndexReturnsFirstRow(): void
204+
{
205+
$result = $this->createResultDouble(
206+
[['id' => 1, 'name' => 'John']],
207+
[],
208+
);
209+
210+
$this->assertSame(['id' => 1, 'name' => 'John'], $result->getRow(999, 'array'));
211+
}
212+
213+
public function testGetRowObjectWithInvalidIndexReturnsFirstRow(): void
214+
{
215+
$row1 = new stdClass();
216+
$row1->id = 1;
217+
$row1->name = 'John';
218+
219+
$result = $this->createResultDouble([], [$row1]);
220+
221+
$this->assertEquals($row1, $result->getRow(999, 'object'));
222+
}
223+
224+
public function testGetRowNullForColumnNameNotFound(): void
225+
{
226+
$result = $this->createResultDouble(
227+
[['id' => 1, 'name' => 'John']],
228+
[],
229+
);
230+
231+
$this->assertNull($result->getRow('nonexistent', 'array'));
232+
}
233+
234+
// --------------------------------------------------------------------
235+
// Custom Result Object
236+
// --------------------------------------------------------------------
237+
238+
public function testGetCustomRowObjectReturnsNullForOutOfBounds(): void
239+
{
240+
$row = new stdClass();
241+
$row->id = 1;
242+
$row->name = 'John';
243+
244+
$result = $this->createResultDouble([], [$row]);
245+
$result->getCustomResultObject(stdClass::class);
246+
247+
$this->assertNull($result->getCustomRowObject(999, stdClass::class));
248+
}
249+
}

0 commit comments

Comments
 (0)