diff --git a/.github/workflows/reusable-phpunit-test.yml b/.github/workflows/reusable-phpunit-test.yml index c5ee92e7a70c..950babb7bd9c 100644 --- a/.github/workflows/reusable-phpunit-test.yml +++ b/.github/workflows/reusable-phpunit-test.yml @@ -138,7 +138,7 @@ jobs: steps: - name: Create database for MSSQL Server if: ${{ inputs.db-platform == 'SQLSRV' }} - run: sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q "CREATE DATABASE test" + run: sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q "CREATE DATABASE test COLLATE Latin1_General_100_CS_AS_SC_UTF8" - name: Install latest ImageMagick if: ${{ contains(inputs.extra-extensions, 'imagick') }} diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 7cb8e21eb180..0573b578a2bd 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -7759,12 +7759,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Log/Handlers/FileHandler.php', ]; -$ignoreErrors[] = [ - // identifier: identical.alwaysTrue - 'message' => '#^Strict comparison using \\=\\=\\= between true and true will always evaluate to true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Log/Handlers/FileHandler.php', -]; $ignoreErrors[] = [ // identifier: missingType.iterableValue 'message' => '#^Method CodeIgniter\\\\Log\\\\Logger\\:\\:determineFile\\(\\) return type has no value type specified in iterable type array\\.$#', diff --git a/rector.php b/rector.php index 6c24c66e5539..89647759b914 100644 --- a/rector.php +++ b/rector.php @@ -19,6 +19,7 @@ use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector; use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector; use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector; +use Rector\CodeQuality\Rector\Identical\SimplifyBoolIdenticalTrueRector; use Rector\CodeQuality\Rector\If_\CombineIfRector; use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector; use Rector\CodeQuality\Rector\If_\ShortenElseIfRector; @@ -211,9 +212,10 @@ AddMethodCallBasedStrictParamTypeRector::class, TypedPropertyFromAssignsRector::class, ClosureReturnTypeRector::class, + SimplifyBoolIdenticalTrueRector::class, ]) ->withConfiguredRule(StringClassNameToClassConstantRector::class, [ // keep '\\' prefix string on string '\Foo\Bar' StringClassNameToClassConstantRector::SHOULD_KEEP_PRE_SLASH => true, ]) - ->withCodeQualityLevel(14); + ->withCodeQualityLevel(15); diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index da79a256ef65..dc3dc7f0b899 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -514,7 +514,7 @@ public static function beep(int $num = 1) */ public static function wait(int $seconds, bool $countdown = false) { - if ($countdown === true) { + if ($countdown) { $time = $seconds; while ($time > 0) { diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index cf45a6544e27..a86a45e83d00 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -308,7 +308,7 @@ protected function deleteFiles(string $path, bool $delDir = false, bool $htdocs if ($filename !== '.' && $filename !== '..') { if (is_dir($path . DIRECTORY_SEPARATOR . $filename) && $filename[0] !== '.') { $this->deleteFiles($path . DIRECTORY_SEPARATOR . $filename, $delDir, $htdocs, $_level + 1); - } elseif ($htdocs !== true || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { + } elseif (! $htdocs || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { @unlink($path . DIRECTORY_SEPARATOR . $filename); } } @@ -316,7 +316,7 @@ protected function deleteFiles(string $path, bool $delDir = false, bool $htdocs closedir($currentDir); - return ($delDir === true && $_level > 0) ? @rmdir($path) : true; + return ($delDir && $_level > 0) ? @rmdir($path) : true; } /** diff --git a/system/Config/Services.php b/system/Config/Services.php index 1a8843fa39b4..28e521df3f0e 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -202,7 +202,7 @@ public static function csp(?CSPConfig $config = null, bool $getShared = true) */ public static function curlrequest(array $options = [], ?ResponseInterface $response = null, ?App $config = null, bool $getShared = true) { - if ($getShared === true) { + if ($getShared) { return static::getSharedInstance('curlrequest', $options, $response, $config); } diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 4863004effbe..21245275c835 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -584,7 +584,7 @@ public function distinct(bool $val = true) */ public function from($from, bool $overwrite = false): self { - if ($overwrite === true) { + if ($overwrite) { $this->QBFrom = []; $this->db->setAliasedTables([]); } @@ -774,7 +774,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type foreach ($keyValue as $k => $v) { $prefix = empty($this->{$qbKey}) ? $this->groupGetType('') : $this->groupGetType($type); - if ($rawSqlOnly === true) { + if ($rawSqlOnly) { $k = ''; $op = ''; } elseif ($v !== null) { @@ -1155,8 +1155,8 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri $keyValue = ! is_array($field) ? [$field => $match] : $field; foreach ($keyValue as $k => $v) { - if ($insensitiveSearch === true) { - $v = strtolower($v); + if ($insensitiveSearch) { + $v = mb_strtolower($v, 'UTF-8'); } $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); @@ -1192,7 +1192,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri */ protected function _like_statement(?string $prefix, string $column, ?string $not, string $bind, bool $insensitiveSearch = false): string { - if ($insensitiveSearch === true) { + if ($insensitiveSearch) { return "{$prefix} LOWER(" . $this->db->escapeIdentifiers($column) . ") {$not} LIKE :{$bind}:"; } @@ -1604,7 +1604,7 @@ public function getCompiledSelect(bool $reset = true): string { $select = $this->compileSelect(); - if ($reset === true) { + if ($reset) { $this->resetSelect(); } @@ -1648,7 +1648,7 @@ public function get(?int $limit = null, int $offset = 0, bool $reset = true) ? $this->getCompiledSelect($reset) : $this->db->query($this->compileSelect(), $this->binds, false); - if ($reset === true) { + if ($reset) { $this->resetSelect(); // Clear our binds so we don't eat up memory @@ -1683,7 +1683,7 @@ public function countAll(bool $reset = true) $query = $query->getRow(); - if ($reset === true) { + if ($reset) { $this->resetSelect(); } @@ -1732,7 +1732,7 @@ public function countAllResults(bool $reset = true) $result = $this->db->query($sql, $this->binds, false); - if ($reset === true) { + if ($reset) { $this->resetSelect(); } elseif (! isset($this->QBOrderBy)) { $this->QBOrderBy = $orderBy; @@ -1786,7 +1786,7 @@ public function getWhere($where = null, ?int $limit = null, ?int $offset = 0, bo ? $this->getCompiledSelect($reset) : $this->db->query($this->compileSelect(), $this->binds, false); - if ($reset === true) { + if ($reset) { $this->resetSelect(); // Clear our binds so we don't eat up memory @@ -2302,7 +2302,7 @@ public function getCompiledInsert(bool $reset = true) array_values($this->QBSet) ); - if ($reset === true) { + if ($reset) { $this->resetWrite(); } @@ -2471,7 +2471,7 @@ public function getCompiledUpdate(bool $reset = true) $sql = $this->_update($this->QBFrom[0], $this->QBSet); - if ($reset === true) { + if ($reset) { $this->resetWrite(); } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 8f5de35175d0..93b1f16e9e2f 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -852,7 +852,7 @@ public function transBegin(bool $testMode = false): bool // Reset the transaction failure flag. // If the $test_mode flag is set to TRUE transactions will be rolled back // even if the queries produce a successful result. - $this->transFailure = ($testMode === true); + $this->transFailure = $testMode; if ($this->_transBegin()) { $this->transDepth++; @@ -1143,7 +1143,7 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro $item = preg_replace('/^' . $this->swapPre . '(\S+?)/', $this->DBPrefix . '\\1', $item); } // Do we prefix an item with no segments? - elseif ($prefixSingle === true && ! str_starts_with($item, $this->DBPrefix)) { + elseif ($prefixSingle && ! str_starts_with($item, $this->DBPrefix)) { $item = $this->DBPrefix . $item; } } @@ -1166,7 +1166,7 @@ private function protectDotItem(string $item, string $alias, bool $protectIdenti // NOTE: The ! empty() condition prevents this method // from breaking when QB isn't enabled. if (! empty($this->aliasedTables) && in_array($parts[0], $this->aliasedTables, true)) { - if ($protectIdentifiers === true) { + if ($protectIdentifiers) { foreach ($parts as $key => $val) { if (! in_array($val, $this->reservedIdentifiers, true)) { $parts[$key] = $this->escapeIdentifiers($val); @@ -1217,7 +1217,7 @@ private function protectDotItem(string $item, string $alias, bool $protectIdenti $item = implode('.', $parts); } - if ($protectIdentifiers === true) { + if ($protectIdentifiers) { $item = $this->escapeIdentifiers($item); } @@ -1410,7 +1410,7 @@ public function escapeString($str, bool $like = false) $str = $this->_escapeString($str); // escape LIKE condition wildcards - if ($like === true) { + if ($like) { return str_replace( [ $this->likeEscapeChar, @@ -1539,7 +1539,7 @@ public function listTables(bool $constrainByPrefix = false) */ public function tableExists(string $tableName, bool $cached = true): bool { - if ($cached === true) { + if ($cached) { return in_array($this->protectIdentifiers($tableName, true, false, false), $this->listTables(), true); } diff --git a/system/Database/Forge.php b/system/Database/Forge.php index d1bc7993e65d..c4fc224eb58a 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -449,12 +449,12 @@ public function addForeignKey( */ public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool { - $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); + $keyName = $this->db->escapeIdentifiers(($prefixKeyName ? $this->db->DBPrefix : '') . $keyName); $table = $this->db->escapeIdentifiers($this->db->DBPrefix . $table); $dropKeyAsConstraint = $this->dropKeyAsConstraint($table, $keyName); - if ($dropKeyAsConstraint === true) { + if ($dropKeyAsConstraint) { $sql = sprintf( $this->dropConstraintStr, $table, @@ -559,7 +559,7 @@ public function createTable(string $table, bool $ifNotExists = false, array $att } // If table exists lets stop here - if ($ifNotExists === true && $this->db->tableExists($table, false)) { + if ($ifNotExists && $this->db->tableExists($table, false)) { $this->reset(); return true; @@ -895,7 +895,7 @@ protected function _processFields(bool $createTable = false): array $attributes = array_change_key_case($attributes, CASE_UPPER); - if ($createTable === true && empty($attributes['TYPE'])) { + if ($createTable && empty($attributes['TYPE'])) { continue; } @@ -942,7 +942,7 @@ protected function _processFields(bool $createTable = false): array } else { $field['null'] = ' NOT ' . $this->null; } - } elseif ($createTable === true) { + } elseif ($createTable) { $field['null'] = ' NOT ' . $this->null; } @@ -1085,7 +1085,7 @@ protected function _processPrimaryKeys(string $table, bool $asQuery = false): st } if (isset($this->primaryKeys['fields']) && $this->primaryKeys['fields'] !== []) { - if ($asQuery === true) { + if ($asQuery) { $sql .= 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $table) . ' ADD '; } else { $sql .= ",\n\t"; @@ -1229,7 +1229,7 @@ protected function _processForeignKeys(string $table, bool $asQuery = false): ar $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); - if ($asQuery === true) { + if ($asQuery) { $sqls[$index] .= 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $table) . ' ADD '; } else { $sqls[$index] .= ",\n\t"; diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index b20422d90aad..7e7020eafa41 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -107,7 +107,7 @@ public function connect(bool $persistent = false) $port = null; $socket = $this->hostname; } else { - $hostname = ($persistent === true) ? 'p:' . $this->hostname : $this->hostname; + $hostname = $persistent ? 'p:' . $this->hostname : $this->hostname; $port = empty($this->port) ? null : $this->port; $socket = ''; } @@ -414,7 +414,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n return $sql . ' LIKE ' . $this->escape($tableName); } - if ($prefixLimit !== false && $this->DBPrefix !== '') { + if ($prefixLimit && $this->DBPrefix !== '') { return $sql . " LIKE '" . $this->escapeLikeStringDirect($this->DBPrefix) . "%'"; } diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 132bde1258cc..3bde0c518daf 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -222,7 +222,7 @@ protected function _processIndexes(string $table, bool $asQuery = false): array implode('_', $this->keys[$i]['fields']) : $this->keys[$i]['keyName']); - if ($asQuery === true) { + if ($asQuery) { $sqls[$index] = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) . " ADD {$unique}KEY " . $keyName . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index e21519ea5259..53a5365bc90d 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -275,7 +275,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n return $sql . ' WHERE "TABLE_NAME" LIKE ' . $this->escape($tableName); } - if ($prefixLimit !== false && $this->DBPrefix !== '') { + if ($prefixLimit && $this->DBPrefix !== '') { return $sql . ' WHERE "TABLE_NAME" LIKE \'' . $this->escapeLikeString($this->DBPrefix) . "%' " . sprintf($this->likeEscapeStr, $this->likeEscapeChar); } diff --git a/system/Database/OCI8/Forge.php b/system/Database/OCI8/Forge.php index 5a10363be769..7d81cff8b506 100644 --- a/system/Database/OCI8/Forge.php +++ b/system/Database/OCI8/Forge.php @@ -135,7 +135,7 @@ protected function _alterTable(string $alterType, string $table, $processedField $wantToAddNull = ! str_contains($processedFields[$i]['null'], ' NOT'); $currentNullable = $nullableMap[$processedFields[$i]['name']]; - if ($wantToAddNull === true && $currentNullable === true) { + if ($wantToAddNull && $currentNullable === true) { $processedFields[$i]['null'] = ''; } elseif ($processedFields[$i]['null'] === '' && $currentNullable === false) { // Nullable by default @@ -293,7 +293,7 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade) { $sql = parent::_dropTable($table, $ifExists, $cascade); - if ($sql !== true && $cascade === true) { + if ($sql !== true && $cascade) { $sql .= ' CASCADE CONSTRAINTS PURGE'; } elseif ($sql !== true) { $sql .= ' PURGE'; diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index 196535729efe..38e34e060bee 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -293,7 +293,7 @@ protected function _truncate(string $table): string */ protected function _like_statement(?string $prefix, string $column, ?string $not, string $bind, bool $insensitiveSearch = false): string { - $op = $insensitiveSearch === true ? 'ILIKE' : 'LIKE'; + $op = $insensitiveSearch ? 'ILIKE' : 'LIKE'; return "{$prefix} {$column} {$not} {$op} :{$bind}:"; } diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index d687e30f7def..425b058932de 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -75,11 +75,11 @@ public function connect(bool $persistent = false) $this->convertDSN(); } - $this->connID = $persistent === true ? pg_pconnect($this->DSN) : pg_connect($this->DSN); + $this->connID = $persistent ? pg_pconnect($this->DSN) : pg_connect($this->DSN); if ($this->connID !== false) { if ( - $persistent === true + $persistent && pg_connection_status($this->connID) === PGSQL_CONNECTION_BAD && pg_ping($this->connID) === false ) { @@ -290,7 +290,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n return $sql . ' AND "table_name" LIKE ' . $this->escape($tableName); } - if ($prefixLimit !== false && $this->DBPrefix !== '') { + if ($prefixLimit && $this->DBPrefix !== '') { return $sql . ' AND "table_name" LIKE \'' . $this->escapeLikeString($this->DBPrefix) . "%' " . sprintf($this->likeEscapeStr, $this->likeEscapeChar); diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index 7a61bed5a57c..b516172737ae 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -118,7 +118,7 @@ protected function _alterTable(string $alterType, string $table, $processedField $nullable = false; } $sqls[] = $sql . ' ALTER COLUMN ' . $this->db->escapeIdentifiers($field['name']) - . ($nullable === true ? ' DROP' : ' SET') . ' NOT NULL'; + . ($nullable ? ' DROP' : ' SET') . ' NOT NULL'; if (! empty($field['new_name'])) { $sqls[] = $sql . ' RENAME COLUMN ' . $this->db->escapeIdentifiers($field['name']) @@ -195,7 +195,7 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str { $sql = parent::_dropTable($table, $ifExists, $cascade); - if ($cascade === true) { + if ($cascade) { $sql .= ' CASCADE'; } diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index fcc0b170084f..c1272cdcf326 100644 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -518,7 +518,7 @@ public function countAll(bool $reset = true) $query = $query->getRow(); - if ($reset === true) { + if ($reset) { $this->resetSelect(); } diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index 2a1abf620271..c5553a669262 100644 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -216,7 +216,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n return $sql .= ' AND [TABLE_NAME] LIKE ' . $this->escape($tableName); } - if ($prefixLimit === true && $this->DBPrefix !== '') { + if ($prefixLimit && $this->DBPrefix !== '') { $sql .= " AND [TABLE_NAME] LIKE '" . $this->escapeLikeString($this->DBPrefix) . "%' " . sprintf($this->likeEscapeStr, $this->likeEscapeChar); } diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index cae4eda2a4f5..d121560c9d47 100644 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -212,10 +212,10 @@ protected function _alterTable(string $alterType, string $table, $processedField $sql = <<db->escapeIdentifiers($field['name']) - . " {$field['type']}{$field['length']} " . ($nullable === true ? '' : 'NOT') . ' NULL'; + . " {$field['type']}{$field['length']} " . ($nullable ? '' : 'NOT') . ' NULL'; if (! empty($field['comment'])) { $sqls[] = 'EXEC sys.sp_addextendedproperty ' diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 03eb3ab130f7..d141805446a6 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -203,7 +203,7 @@ protected function _listTables(bool $prefixLimit = false, ?string $tableName = n return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\'' . ' AND "NAME" NOT LIKE \'sqlite!_%\' ESCAPE \'!\'' - . (($prefixLimit !== false && $this->DBPrefix !== '') + . (($prefixLimit && $this->DBPrefix !== '') ? ' AND "NAME" LIKE \'' . $this->escapeLikeString($this->DBPrefix) . '%\' ' . sprintf($this->likeEscapeStr, $this->likeEscapeChar) : ''); } @@ -372,7 +372,7 @@ protected function _indexData(string $table): array */ protected function _foreignKeyData(string $table): array { - if ($this->supportsForeignKeys() !== true) { + if (! $this->supportsForeignKeys()) { return []; } diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index 723c72b1ce98..6ef97170914e 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -95,9 +95,7 @@ public function __construct(App $config) */ public function getPath(): string { - $path = implode('/', $this->segments); - - return ($path === '') ? '' : $path; + return implode('/', $this->segments); } /** diff --git a/system/HTTP/DownloadResponse.php b/system/HTTP/DownloadResponse.php index 6b293fbca239..56953823693d 100644 --- a/system/HTTP/DownloadResponse.php +++ b/system/HTTP/DownloadResponse.php @@ -142,7 +142,7 @@ private function setContentTypeByMimeType(): void $mime = null; $charset = ''; - if ($this->setMime === true && ($lastDotPosition = strrpos($this->filename, '.')) !== false) { + if ($this->setMime && ($lastDotPosition = strrpos($this->filename, '.')) !== false) { $mime = Mimes::guessTypeFromExtension(substr($this->filename, $lastDotPosition + 1)); $charset = $this->charset; } diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index 2e5b9f7ca576..58cd828e3faa 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -582,7 +582,7 @@ function set_select(string $field, string $value = '', bool $default = false): s } if ($input === null) { - return ($default === true) ? ' selected="selected"' : ''; + return $default ? ' selected="selected"' : ''; } if (is_array($input)) { @@ -636,7 +636,7 @@ function set_checkbox(string $field, string $value = '', bool $default = false): return ($input === $value) ? ' checked="checked"' : ''; } - return ($default === true) ? ' checked="checked"' : ''; + return $default ? ' checked="checked"' : ''; } } @@ -673,7 +673,7 @@ function set_radio(string $field, string $value = '', bool $default = false): st return ((string) $input === $value) ? ' checked="checked"' : ''; } - return ($default === true) ? ' checked="checked"' : ''; + return $default ? ' checked="checked"' : ''; } } diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index b9e5e5c8ed0e..30733acd5175 100644 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -113,7 +113,7 @@ function img($src = '', bool $indexPage = false, $attributes = ''): string // Check for a relative URI if (! preg_match('#^([a-z]+:)?//#i', $src['src']) && ! str_starts_with($src['src'], 'data:')) { - if ($indexPage === true) { + if ($indexPage) { $img .= ' src="' . site_url($src['src']) . '"'; } else { $img .= ' src="' . slash_item('baseURL') . $src['src'] . '"'; @@ -207,7 +207,7 @@ function script_tag($src = '', bool $indexPage = false): string foreach ($src as $k => $v) { if ($k === 'src' && ! preg_match('#^([a-z]+:)?//#i', $v)) { - if ($indexPage === true) { + if ($indexPage) { $script .= 'src="' . site_url($v) . '" '; } else { $script .= 'src="' . slash_item('baseURL') . $v . '" '; @@ -302,7 +302,7 @@ function video($src, string $unsupportedMessage = '', string $attributes = '', a if (_has_protocol($src)) { $video .= ' src="' . $src . '"'; - } elseif ($indexPage === true) { + } elseif ($indexPage) { $video .= ' src="' . site_url($src) . '"'; } else { $video .= ' src="' . slash_item('baseURL') . $src . '"'; @@ -349,7 +349,7 @@ function audio($src, string $unsupportedMessage = '', string $attributes = '', a if (_has_protocol($src)) { $audio .= ' src="' . $src . '"'; - } elseif ($indexPage === true) { + } elseif ($indexPage) { $audio .= ' src="' . site_url($src) . '"'; } else { $audio .= ' src="' . slash_item('baseURL') . $src . '"'; @@ -422,7 +422,7 @@ function _media(string $name, array $types = [], string $unsupportedMessage = '' function source(string $src, string $type = 'unknown', string $attributes = '', bool $indexPage = false): string { if (! _has_protocol($src)) { - $src = $indexPage === true ? site_url($src) : slash_item('baseURL') . $src; + $src = $indexPage ? site_url($src) : slash_item('baseURL') . $src; } $source = 'width ?? 0) . 'x' . ($this->height ?? 0) . "{$escape}! \"" . $source . '" "' . $destination . '"'; diff --git a/system/Images/Image.php b/system/Images/Image.php index a2cf51436121..ec6d4b8fa5c0 100644 --- a/system/Images/Image.php +++ b/system/Images/Image.php @@ -116,7 +116,7 @@ public function getProperties(bool $return = false) $mime = 'image/' . ($types[$vals[2]] ?? 'jpg'); - if ($return === true) { + if ($return) { return [ 'width' => $vals[0], 'height' => $vals[1], diff --git a/system/Log/Handlers/FileHandler.php b/system/Log/Handlers/FileHandler.php index 42dd9ceefc0f..64d1485f0f7a 100644 --- a/system/Log/Handlers/FileHandler.php +++ b/system/Log/Handlers/FileHandler.php @@ -76,6 +76,7 @@ public function handle($level, $message): bool $msg = ''; + $newfile = false; if (! is_file($filepath)) { $newfile = true; @@ -117,7 +118,7 @@ public function handle($level, $message): bool flock($fp, LOCK_UN); fclose($fp); - if (isset($newfile) && $newfile === true) { + if ($newfile) { chmod($filepath, $this->filePermissions); } diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index af0e9accfaee..3bdc85388c18 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -288,7 +288,7 @@ public function getPageURI(?int $page = null, string $group = 'default', bool $r $uri->setQueryArray($query); } - return ($returnObject === true) + return $returnObject ? $uri : URI::createURIString( $uri->getScheme(), diff --git a/system/Router/AutoRouter.php b/system/Router/AutoRouter.php index 6e9f3248c86e..bb47bf96c89a 100644 --- a/system/Router/AutoRouter.php +++ b/system/Router/AutoRouter.php @@ -260,7 +260,7 @@ public function setDirectory(?string $dir = null, bool $append = false, bool $va } } - if ($append !== true || ($this->directory === null || $this->directory === '')) { + if (! $append || ($this->directory === null || $this->directory === '')) { $this->directory = trim($dir, '/') . '/'; } else { $this->directory .= trim($dir, '/') . '/'; diff --git a/system/Router/Router.php b/system/Router/Router.php index 247f0de6b6b8..853b251ac416 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -249,7 +249,7 @@ public function getFilters(): array */ public function controllerName() { - return $this->translateURIDashes + return $this->translateURIDashes && ! $this->controller instanceof Closure ? str_replace('-', '_', $this->controller) : $this->controller; } diff --git a/system/Typography/Typography.php b/system/Typography/Typography.php index 89687d72e2d1..c8ca5131171c 100644 --- a/system/Typography/Typography.php +++ b/system/Typography/Typography.php @@ -214,7 +214,7 @@ public function autoTypography(string $str, bool $reduceLinebreaks = false): str ]; // Do we need to reduce empty lines? - if ($reduceLinebreaks === true) { + if ($reduceLinebreaks) { $table['#

\n*

#'] = ''; } else { // If we have empty paragraph tags we add a non-breaking space diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index f036635058bc..71d96786c419 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -455,7 +455,7 @@ private function processPermitEmpty($value, array $rules, array $data) } } - if ($passed === true) { + if ($passed) { return true; } } diff --git a/system/View/Parser.php b/system/View/Parser.php index 6600b0178369..8a26cf825d3f 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -254,20 +254,39 @@ protected function parse(string $template, array $data = [], ?array $options = n // it can potentially modify any template between its tags. $template = $this->parsePlugins($template); - // loop over the data variables, replacing - // the content as we go. + // Parse stack for each parse type (Single and Pairs) + $replaceSingleStack = []; + $replacePairsStack = []; + + // loop over the data variables, saving regex and data + // for later replacement. foreach ($data as $key => $val) { $escape = true; if (is_array($val)) { - $escape = false; - $replace = $this->parsePair($key, $val, $template); + $escape = false; + $replacePairsStack[] = [ + 'replace' => $this->parsePair($key, $val, $template), + 'escape' => $escape, + ]; } else { - $replace = $this->parseSingle($key, (string) $val); + $replaceSingleStack[] = [ + 'replace' => $this->parseSingle($key, (string) $val), + 'escape' => $escape, + ]; } + } + + // Merge both stacks, pairs first + single stacks + // This allows for nested data with the same key to be replaced properly + $replace = array_merge($replacePairsStack, $replaceSingleStack); - foreach ($replace as $pattern => $content) { - $template = $this->replaceSingle($pattern, $content, $template, $escape); + // Loop over each replace array item which + // holds all the data to be replaced + foreach ($replace as $replaceItem) { + // Loop over the actual data to be replaced + foreach ($replaceItem['replace'] as $pattern => $content) { + $template = $this->replaceSingle($pattern, $content, $template, $replaceItem['escape']); } } diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index 1be92d1fe434..cf567ace96cf 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -92,6 +92,7 @@ public function up(): void if ($this->db->DBDriver === 'SQLSRV') { unset($dataTypeFields['type_timestamp']); + $dataTypeFields['type_text'] = ['type' => 'NVARCHAR(max)', 'null' => true]; } if ($this->db->DBDriver === 'Postgre' || $this->db->DBDriver === 'SQLSRV') { diff --git a/tests/_support/Database/Seeds/CITestSeeder.php b/tests/_support/Database/Seeds/CITestSeeder.php index f8582839cf05..45b70a7fdd19 100644 --- a/tests/_support/Database/Seeds/CITestSeeder.php +++ b/tests/_support/Database/Seeds/CITestSeeder.php @@ -86,6 +86,26 @@ public function run(): void 'key' => 'key', 'value' => 'value', ], + [ + 'key' => 'multibyte characters pl', + 'value' => 'śćźżłąęó', + ], + [ + 'key' => 'multibyte characters fa', + 'value' => 'خٌوب', + ], + [ + 'key' => 'multibyte characters bn', + 'value' => 'টাইপ', + ], + [ + 'key' => 'multibyte characters ko', + 'value' => '캐스팅', + ], + [ + 'key' => 'multibyte characters ml', + 'value' => 'ടൈപ്പ്', + ], ], 'type_test' => [ [ diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 53c6a2144819..ef3a1f3726da 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1615,9 +1615,15 @@ public function testDropKey(): void public function testAddTextColumnWithConstraint(): void { // some DBMS do not allow a constraint for type TEXT - $this->forge->addColumn('user', [ - 'text_with_constraint' => ['type' => 'text', 'constraint' => 255, 'default' => ''], - ]); + if ($this->db->DBDriver === 'SQLSRV') { + $this->forge->addColumn('user', [ + 'text_with_constraint' => ['type' => 'nvarchar(max)', 'default' => ''], + ]); + } else { + $this->forge->addColumn('user', [ + 'text_with_constraint' => ['type' => 'text', 'constraint' => 255, 'default' => ''], + ]); + } $this->assertTrue($this->db->fieldExists('text_with_constraint', 'user')); diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index 681af7344183..ce98ebf413e0 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -178,7 +178,7 @@ public function testGetFieldData(): void $this->assertSame('int', $typeTest[0]->type_name); // INTEGER AUTOINC $this->assertSame('varchar', $typeTest[1]->type_name); // VARCHAR $this->assertSame('char', $typeTest[2]->type_name); // CHAR - $this->assertSame('text', $typeTest[3]->type_name); // TEXT + $this->assertSame('nvarchar', $typeTest[3]->type_name); // TEXT $this->assertSame('smallint', $typeTest[4]->type_name); // SMALLINT $this->assertSame('int', $typeTest[5]->type_name); // INTEGER $this->assertSame('float', $typeTest[6]->type_name); // FLOAT diff --git a/tests/system/Database/Live/LikeTest.php b/tests/system/Database/Live/LikeTest.php index 5884f9d01220..9591eef72ea8 100644 --- a/tests/system/Database/Live/LikeTest.php +++ b/tests/system/Database/Live/LikeTest.php @@ -16,6 +16,7 @@ use CodeIgniter\Database\RawSql; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use Tests\Support\Database\Seeds\CITestSeeder; @@ -75,6 +76,29 @@ public function testLikeCaseInsensitive(): void $this->assertSame('Developer', $job->name); } + #[DataProvider('provideMultibyteCharacters')] + public function testLikeCaseInsensitiveWithMultibyteCharacter(string $match, string $result): void + { + $wai = $this->db->table('without_auto_increment')->like('value', $match, 'both', null, true)->get(); + $wai = $wai->getRow(); + + $this->assertSame($result, $wai->key); + } + + /** + * @return iterable + */ + public static function provideMultibyteCharacters(): iterable + { + yield from [ + 'polish' => ['ŁĄ', 'multibyte characters pl'], + 'farsi' => ['خٌوب', 'multibyte characters fa'], + 'bengali' => ['টাইপ', 'multibyte characters bn'], + 'korean' => ['캐스팅', 'multibyte characters ko'], + 'malayalam' => ['ടൈപ്പ്', 'multibyte characters ml'], + ]; + } + public function testOrLike(): void { $jobs = $this->db->table('job')->like('name', 'ian') diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index e21763b9dc8a..93f523da14af 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -13,6 +13,7 @@ namespace CodeIgniter\Router; +use Closure; use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\Exceptions\PageNotFoundException; @@ -77,6 +78,7 @@ private function createRouteCollection(?Routing $routingConfig = null): void 'posts/(:num)/edit' => 'Blog::edit/$1', 'books/(:num)/(:alpha)/(:num)' => 'Blog::show/$3/$1', 'closure/(:num)/(:alpha)' => static fn ($num, $str) => $num . '-' . $str, + 'closure-dash/(:num)/(:alpha)' => static fn ($num, $str) => $num . '-' . $str, '{locale}/pages' => 'App\Pages::list_all', 'test/(:any)/lang/{locale}' => 'App\Pages::list_all', 'admin/admins' => 'App\Admin\Admins::list_all', @@ -224,6 +226,22 @@ public function testClosures(): void $this->assertSame($expects, '123-alpha'); } + public function testClosuresWithTranslateURIDashes(): void + { + $router = new Router($this->collection, $this->request); + $router->setTranslateURIDashes(true); + + $router->handle('closure-dash/123/alpha'); + $closure = $router->controllerName(); + + $this->assertInstanceOf(Closure::class, $closure); + + $expects = $closure(...$router->params()); + + $this->assertIsCallable($router->controllerName()); + $this->assertSame($expects, '123-alpha'); + } + public function testAutoRouteFindsDefaultControllerAndMethod(): void { $this->collection->setAutoRoute(true); diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 9a9f1fd8d0ac..b3c99a2872ce 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -1061,4 +1061,44 @@ public function testChangeConditionalDelimitersWorkWithJavaScriptCode(): void EOL; $this->assertSame($expected, $this->parser->renderString($template)); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/9245 + */ + public function testParseSameArrayKeyName(): void + { + $data = [ + 'type' => 'Super Powers', + 'powers' => [ + [ + 'type' => 'invisibility', + ], + ], + ]; + + $template = '{type} like {powers}{type}{/powers}'; + + $this->parser->setData($data); + $this->assertSame('Super Powers like invisibility', $this->parser->renderString($template)); + } + + public function testParseSameArrayKeyNameNested(): void + { + $data = [ + 'title' => 'My title', + 'similar' => [ + ['items' => [ + [ + 'title' => 'My similar title', + ], + ], + ], + ], + ]; + + $template = '{title} with similar item {similar}{items}{title}{/items}{/similar}'; + + $this->parser->setData($data); + $this->assertSame('My title with similar item My similar title', $this->parser->renderString($template)); + } } diff --git a/user_guide_src/source/changelogs/v4.5.6.rst b/user_guide_src/source/changelogs/v4.5.6.rst index b982f54b38f7..2ea1f1ce46b7 100644 --- a/user_guide_src/source/changelogs/v4.5.6.rst +++ b/user_guide_src/source/changelogs/v4.5.6.rst @@ -32,6 +32,11 @@ Bugs Fixed - **Session Library:** The session initialization debug message now uses the correct log type "debug" instead of "info". - **Validation:** Fixed the `getValidated()` method that did not return valid data when validation rules used multiple asterisks. +- **Database:** Fixed the case insensitivity option in the ``like()`` method when dealing with accented characters. + +- **Parser:** Fixed bug that caused equal key names to be replaced by the key name defined first. + +- **Routing:** Fixed a TypeError in `str_replace()` when `Routing::$translateURIDashes` is set to `true` and a route is defined using a closure. See the repo's `CHANGELOG.md `_