Skip to content

Commit 59ec72d

Browse files
authored
Merge pull request #8756 from kenjis/fix-BaseConnection-escape-TypeError
fix: `BaseConnection::escape()` does not accept Stringable
2 parents 48be4ac + c1ec70f commit 59ec72d

File tree

4 files changed

+68
-25
lines changed

4 files changed

+68
-25
lines changed

system/Database/BaseConnection.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use CodeIgniter\Database\Exceptions\DatabaseException;
1818
use CodeIgniter\Events\Events;
1919
use stdClass;
20+
use Stringable;
2021
use Throwable;
2122

2223
/**
@@ -1309,12 +1310,15 @@ public function escape($str)
13091310
return array_map($this->escape(...), $str);
13101311
}
13111312

1312-
/** @psalm-suppress NoValue I don't know why ERROR. */
1313-
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
1313+
if ($str instanceof Stringable) {
13141314
if ($str instanceof RawSql) {
13151315
return $str->__toString();
13161316
}
13171317

1318+
$str = (string) $str;
1319+
}
1320+
1321+
if (is_string($str)) {
13181322
return "'" . $this->escapeString($str) . "'";
13191323
}
13201324

@@ -1328,8 +1332,8 @@ public function escape($str)
13281332
/**
13291333
* Escape String
13301334
*
1331-
* @param list<string>|string $str Input string
1332-
* @param bool $like Whether or not the string will be used in a LIKE condition
1335+
* @param list<string|Stringable>|string|Stringable $str Input string
1336+
* @param bool $like Whether the string will be used in a LIKE condition
13331337
*
13341338
* @return list<string>|string
13351339
*/
@@ -1343,6 +1347,14 @@ public function escapeString($str, bool $like = false)
13431347
return $str;
13441348
}
13451349

1350+
if ($str instanceof Stringable) {
1351+
if ($str instanceof RawSql) {
1352+
return $str->__toString();
1353+
}
1354+
1355+
$str = (string) $str;
1356+
}
1357+
13461358
$str = $this->_escapeString($str);
13471359

13481360
// escape LIKE condition wildcards
@@ -1371,7 +1383,7 @@ public function escapeString($str, bool $like = false)
13711383
* Calls the individual driver for platform
13721384
* specific escaping for LIKE conditions
13731385
*
1374-
* @param list<string>|string $str
1386+
* @param list<string|Stringable>|string|Stringable $str
13751387
*
13761388
* @return list<string>|string
13771389
*/

system/Database/Postgre/Connection.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use PgSql\Connection as PgSqlConnection;
2121
use PgSql\Result as PgSqlResult;
2222
use stdClass;
23+
use Stringable;
2324

2425
/**
2526
* Connection for Postgre
@@ -233,20 +234,22 @@ public function escape($str)
233234
$this->initialize();
234235
}
235236

236-
/** @psalm-suppress NoValue I don't know why ERROR. */
237-
if (is_string($str) || (is_object($str) && method_exists($str, '__toString'))) {
237+
if ($str instanceof Stringable) {
238238
if ($str instanceof RawSql) {
239239
return $str->__toString();
240240
}
241241

242+
$str = (string) $str;
243+
}
244+
245+
if (is_string($str)) {
242246
return pg_escape_literal($this->connID, $str);
243247
}
244248

245249
if (is_bool($str)) {
246250
return $str ? 'TRUE' : 'FALSE';
247251
}
248252

249-
/** @psalm-suppress NoValue I don't know why ERROR. */
250253
return parent::escape($str);
251254
}
252255

system/I18n/Time.php

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,34 @@
1414
namespace CodeIgniter\I18n;
1515

1616
use DateTimeImmutable;
17+
use Stringable;
1718

1819
/**
1920
* A localized date/time package inspired
2021
* by Nesbot/Carbon and CakePHP/Chronos.
2122
*
2223
* Requires the intl PHP extension.
2324
*
24-
* @property int $age read-only
25-
* @property string $day read-only
26-
* @property string $dayOfWeek read-only
27-
* @property string $dayOfYear read-only
28-
* @property bool $dst read-only
29-
* @property string $hour read-only
30-
* @property bool $local read-only
31-
* @property string $minute read-only
32-
* @property string $month read-only
33-
* @property string $quarter read-only
34-
* @property string $second read-only
35-
* @property int $timestamp read-only
36-
* @property bool $utc read-only
37-
* @property string $weekOfMonth read-only
38-
* @property string $weekOfYear read-only
39-
* @property string $year read-only
25+
* @property-read int $age
26+
* @property-read string $day
27+
* @property-read string $dayOfWeek
28+
* @property-read string $dayOfYear
29+
* @property-read bool $dst
30+
* @property-read string $hour
31+
* @property-read bool $local
32+
* @property-read string $minute
33+
* @property-read string $month
34+
* @property-read string $quarter
35+
* @property-read string $second
36+
* @property-read int $timestamp
37+
* @property-read bool $utc
38+
* @property-read string $weekOfMonth
39+
* @property-read string $weekOfYear
40+
* @property-read string $year
4041
*
4142
* @see \CodeIgniter\I18n\TimeTest
4243
*/
43-
class Time extends DateTimeImmutable
44+
class Time extends DateTimeImmutable implements Stringable
4445
{
4546
use TimeTrait;
4647
}

tests/system/Database/Live/EscapeTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace CodeIgniter\Database\Live;
1515

1616
use CodeIgniter\Database\RawSql;
17+
use CodeIgniter\I18n\Time;
1718
use CodeIgniter\Test\CIUnitTestCase;
1819
use CodeIgniter\Test\DatabaseTestTrait;
1920

@@ -54,6 +55,14 @@ public function testEscape(): void
5455
$this->assertSame($expected, $sql);
5556
}
5657

58+
public function testEscapeStringable(): void
59+
{
60+
$expected = "SELECT * FROM brands WHERE name = '2024-01-01 12:00:00'";
61+
$sql = 'SELECT * FROM brands WHERE name = ' . $this->db->escape(new Time('2024-01-01 12:00:00'));
62+
63+
$this->assertSame($expected, $sql);
64+
}
65+
5766
public function testEscapeString(): void
5867
{
5968
$expected = "SELECT * FROM brands WHERE name = 'O" . $this->char . "'Doules'";
@@ -62,6 +71,15 @@ public function testEscapeString(): void
6271
$this->assertSame($expected, $sql);
6372
}
6473

74+
public function testEscapeStringStringable(): void
75+
{
76+
$expected = "SELECT * FROM brands WHERE name = '2024-01-01 12:00:00'";
77+
$sql = "SELECT * FROM brands WHERE name = '"
78+
. $this->db->escapeString(new Time('2024-01-01 12:00:00')) . "'";
79+
80+
$this->assertSame($expected, $sql);
81+
}
82+
6583
public function testEscapeLikeString(): void
6684
{
6785
$expected = "SELECT * FROM brands WHERE column LIKE '%10!% more%' ESCAPE '!'";
@@ -70,6 +88,15 @@ public function testEscapeLikeString(): void
7088
$this->assertSame($expected, $sql);
7189
}
7290

91+
public function testEscapeLikeStringStringable(): void
92+
{
93+
$expected = "SELECT * FROM brands WHERE column LIKE '%2024-01-01 12:00:00%' ESCAPE '!'";
94+
$sql = "SELECT * FROM brands WHERE column LIKE '%"
95+
. $this->db->escapeLikeString(new Time('2024-01-01 12:00:00')) . "%' ESCAPE '!'";
96+
97+
$this->assertSame($expected, $sql);
98+
}
99+
73100
public function testEscapeLikeStringDirect(): void
74101
{
75102
if ($this->db->DBDriver === 'MySQLi') {

0 commit comments

Comments
 (0)