Merge pull request #9345 from codeigniter4/develop

4.5.6 Ready code
This commit is contained in:
John Paul E. Balandan, CPA 2024-12-29 02:21:40 +08:00 committed by GitHub
commit 51cdd7de22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
364 changed files with 17334 additions and 20047 deletions

View File

@ -159,11 +159,15 @@ jobs:
token: ${{ secrets.ACCESS_TOKEN }}
path: userguide
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Sphinx
run: |
sudo apt install python3-sphinx
sudo pip3 install sphinxcontrib-phpdomain
sudo pip3 install sphinx_rtd_theme
python -m pip install --upgrade pip
pip install -r ./source/user_guide_src/requirements.txt
- name: Chmod
run: chmod +x ./source/.github/scripts/deploy-userguide

View File

@ -33,11 +33,20 @@ jobs:
php-version: '8.1'
coverage: none
# Build the latest User Guide
- name: Build with Sphinx
uses: ammaraskar/sphinx-action@0.4
- name: Setup Python
uses: actions/setup-python@v5
with:
docs-folder: user_guide_src/
python-version: '3.12'
- name: Install Sphinx
run: |
python -m pip install --upgrade pip
pip install -r user_guide_src/requirements.txt
# Build the latest User Guide
- name: Build Docs with Sphinx
run: make html
working-directory: user_guide_src
- name: Add "Edit this page" links
run: |

View File

@ -13,6 +13,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -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') }}
@ -148,6 +148,12 @@ jobs:
sudo apt-get install -y gsfonts libmagickwand-dev imagemagick
sudo apt-get install --fix-broken
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -60,6 +60,12 @@ jobs:
sudo apt-get install -y imagemagick
sudo apt-get install --fix-broken
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -35,6 +35,12 @@ jobs:
name: Check normalized composer.json
runs-on: ubuntu-latest
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -32,6 +32,12 @@ jobs:
- '8.3'
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -36,6 +36,12 @@ jobs:
name: Architectural Inspection
runs-on: ubuntu-22.04
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -45,6 +45,12 @@ jobs:
strategy:
fail-fast: false
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -27,6 +27,12 @@ jobs:
if: (! contains(github.event.head_commit.message, '[ci skip]'))
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -47,6 +47,12 @@ jobs:
matrix:
php-versions: ['8.1', '8.3']
steps:
- name: Checkout base branch for PR
if: github.event_name == 'pull_request'
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}
- name: Checkout
uses: actions/checkout@v4

View File

@ -26,10 +26,19 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Sphinx
run: |
python -m pip install --upgrade pip
pip install -r user_guide_src/requirements.txt
- name: Detect usage of tabs in RST files
run: php utils/check_tabs_in_rst.php
- uses: ammaraskar/sphinx-action@0.4
with:
docs-folder: user_guide_src
build-command: 'make html SPHINXOPTS="-W --keep-going -w /tmp/sphinx-log"'
- name: Build Docs with Sphinx
run: make html SPHINXOPTS="-W --keep-going -w /tmp/sphinx-log"
working-directory: user_guide_src

View File

@ -26,6 +26,7 @@ $finder = Finder::create()
'_support/View/Cells/multiplier.php',
'_support/View/Cells/colors.php',
'_support/View/Cells/addition.php',
'system/Database/Live/PreparedQueryTest.php',
])
->notName('#Foobar.php$#');

View File

@ -1,5 +1,62 @@
# Changelog
## [v4.5.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.6) (2024-12-28)
[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.5...v4.5.6)
### Fixed Bugs
* fix: auto_link() converts invalid strings like `://codeigniter.com` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9180
* fix: change session start log level by @element-code in https://github.com/codeigniter4/CodeIgniter4/pull/9221
* fix: `getValidated()` when validation multiple asterisk by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9220
* fix: Parser - Equal key name replace conflict by @CosDiabos in https://github.com/codeigniter4/CodeIgniter4/pull/9246
* fix: case-insensitivity in the `like()` method when in use with accented characters by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9238
* fix: TypeError for routes when translateURIDashes is enabled by @maniaba in https://github.com/codeigniter4/CodeIgniter4/pull/9209
* fix: `fetchGlobal()` with numeric key by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9251
* fix: curl request crashes with params that give an int once hexed. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9198
* docs: allow boolean values in the model for PHPStan by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9276
* fix: respect complex language strings when using validation by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9201
* fix: `DownloadResponse` cache headers by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9237
* docs: fix `@param` `ResponseInterface::setJSON()` also accepts objects by @JulianAtkins in https://github.com/codeigniter4/CodeIgniter4/pull/9287
* fix: [CURLRequest] body contains "HTTP/1.0 200 Connection established" by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9285
* fix: `Postgre\Connection::reconnect()` `TypeError` in `pg_ping()` by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9279
* fix: primary key mapping in the model for the entity by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9307
* fix: check if defined `WRITEPATH` exists by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9317
* fix: handling binary data for prepared statement by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9337
### Refactoring
* refactor: enable TypedPropertyFromAssignsRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9184
* refactor: enable ClosureReturnTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9187
* refactor: remove unnecessary `is_countable()` check in `getMethodParams()` by @datamweb in https://github.com/codeigniter4/CodeIgniter4/pull/9206
* refactor: add more readonly property definitions on AutoRouteCollector and SiteURI by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9210
* refactor: starter key handling in SodiumHandler by @datamweb in https://github.com/codeigniter4/CodeIgniter4/pull/9207
* refactor: enable rector code quality level 14 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9232
* refactor: cleanup `DatabaseHandler::gc()` for session by @grimpirate in https://github.com/codeigniter4/CodeIgniter4/pull/9230
* refactor: enable rector code quality level 15 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9243
* refactor: enable SimplifyBoolIdenticalTrueRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9244
* refactor: enable FlipTypeControlToUseExclusiveTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9253
* refactor: flip assert and actual value position on tests by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9260
* perf: Improve call as `service()` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9248
* refactor: use compare empty array on Forge on keys property by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9267
* refactor: Fix `phpstan` errors related to `Autoloader` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9249
* refactor: use `Superglobals` in setting 'REQUEST_METHOD' in `FeatureT… by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9294
* refactor: use `baseURI` instead of `base_uri` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9296
* refactor: Apply code quality level 31 for rector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9303
* refactor: rename `stdclass` to `stdClass` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9312
* refactor: fix `phpDoc.parseError` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9313
* refactor: fix `method.nameCase` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9315
* refactor: rename `controller` to `Controller` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9314
* refactor: fix implicit array creation by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9316
* refactor: follow up implicit variable array by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9319
* refactor: split phpstan-baseline into smaller files by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9299
* refactor: upgrade to use phpstan 2 and rector 2 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9322
* refactor: fix `Forge::processIndexes()` for empty `$this->fields` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9330
* refactor: `Reflection*::setAccessible()` is now no-op in PHP 8.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9331
* refactor: add `@throws RedirectException` in `Controller::initController` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9327
* refactor: fix warning on new static usage by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9342
* refactor: fix used void return type by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9341
* refactor: enable instanceof and strictBooleans rector set by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9339
## [v4.5.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.5) (2024-09-07)
[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.4...v4.5.5)

View File

@ -12,6 +12,9 @@
- `4.y`: The next minor version. (e.g., `4.6`)
- `4.z`: The next next minor version. (e.g., `4.7`)
> [!NOTE]
> Copy this file, and replace the versions above with the actual versions.
## Merge `develop` branch into next minor version branch `4.y`
Before starting release process, if there are commits in `develop` branch that
@ -35,6 +38,26 @@ If you release a new minor version.
"Branch protection rules" to the next minor version. E.g. `4.5``4.6`
* [ ] Delete the merged `4.y` branch (This closes all PRs to the branch)
## Preparation
Work off direct clones of the repos so the release branches persist for a time.
* [ ] Clone both **codeigniter4/CodeIgniter4** and **codeigniter4/userguide** and
resolve any necessary PRs
```console
rm -rf CodeIgniter4.bk userguide.bk
mv CodeIgniter4 CodeIgniter4.bk
mv userguide userguide.bk
git clone git@github.com:codeigniter4/CodeIgniter4.git
git clone git@github.com:codeigniter4/userguide.git
```
* [ ] Vet the **admin/** folders for any removed hidden files (Action deploy scripts
*do not remove these*)
```console
cd CodeIgniter4
git diff --name-status origin/master admin/
```
## Changelog
When generating the changelog each Pull Request to be included must have one of
@ -65,33 +88,14 @@ the changelog.
Copy the resulting content into **CHANGELOG.md** and adjust the format to match
the existing content.
## Preparation
Work off direct clones of the repos so the release branches persist for a time.
* [ ] Clone both **codeigniter4/CodeIgniter4** and **codeigniter4/userguide** and
resolve any necessary PRs
```console
rm -rf CodeIgniter4.bk userguide.bk
mv CodeIgniter4 CodeIgniter4.bk
mv userguide userguide.bk
git clone git@github.com:codeigniter4/CodeIgniter4.git
git clone git@github.com:codeigniter4/userguide.git
```
* [ ] Vet the **admin/** folders for any removed hidden files (Action deploy scripts
*do not remove these*)
```console
cd CodeIgniter4
git diff --name-status origin/master admin/
```
* [ ] Merge any Security Advisory PRs in private forks
## Process
> **Note** Most changes that need noting in the User Guide and docs should have
> [!NOTE]
> Most changes that need noting in the User Guide and docs should have
> been included with their PR, so this process assumes you will not be
> generating much new content.
* [ ] Merge any Security Advisory PRs in private forks
* [ ] Replace **CHANGELOG.md** with the new version generated above
* [ ] Update **user_guide_src/source/changelogs/v4.x.x.rst**
* Remove the section titles that have no items

View File

@ -1,7 +1,6 @@
<?php
use CodeIgniter\Test\CIUnitTestCase;
use Config\Services;
/**
* @internal
@ -10,7 +9,7 @@ final class ExampleSessionTest extends CIUnitTestCase
{
public function testSessionSimple(): void
{
$session = Services::session();
$session = service('session');
$session->set('logged_in', 123);
$this->assertSame(123, $session->get('logged_in'));

View File

@ -2,7 +2,6 @@
use CodeIgniter\Test\CIUnitTestCase;
use Config\App;
use Config\Services;
use Tests\Support\Libraries\ConfigReader;
/**
@ -17,7 +16,7 @@ final class HealthTest extends CIUnitTestCase
public function testBaseUrlHasBeenSet(): void
{
$validation = Services::validation();
$validation = service('validation');
$env = false;

View File

@ -44,10 +44,10 @@ Events::on('pre_system', static function (): void {
*/
if (CI_DEBUG && ! is_cli()) {
Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
Services::toolbar()->respond();
service('toolbar')->respond();
// Hot Reload route - for framework use on the hot reloader.
if (ENVIRONMENT === 'development') {
Services::routes()->get('__hot-reload', static function (): void {
service('routes')->get('__hot-reload', static function (): void {
(new HotReloader())->run();
});
}

View File

@ -72,6 +72,6 @@ class Format extends BaseConfig
*/
public function getFormatter(string $mime)
{
return Services::format()->getFormatter($mime);
return service('format')->getFormatter($mime);
}
}

View File

@ -53,6 +53,6 @@ abstract class BaseController extends Controller
// Preload any models, libraries, etc, here.
// E.g.: $this->session = \Config\Services::session();
// E.g.: $this->session = service('session');
}
}

View File

@ -52,7 +52,7 @@ if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
$args = implode(', ', array_map(static fn ($value) => match (true) {
is_object($value) => 'Object(' . $value::class . ')',
is_array($value) => count($value) ? '[...]' : '[]',
is_array($value) => $value !== [] ? '[...]' : '[]',
$value === null => 'null', // return the lowercased version
default => var_export($value, true),
}, array_values($error['args'] ?? [])));

View File

@ -1,6 +1,5 @@
<?php
use CodeIgniter\HTTP\Header;
use Config\Services;
use CodeIgniter\CodeIgniter;
$errorId = uniqid('error', true);
@ -225,7 +224,7 @@ $errorId = uniqid('error', true);
<!-- Request -->
<div class="content" id="request">
<?php $request = Services::request(); ?>
<?php $request = service('request'); ?>
<table>
<tbody>
@ -343,7 +342,7 @@ $errorId = uniqid('error', true);
<!-- Response -->
<?php
$response = Services::response();
$response = service('response');
$response->setStatusCode(http_response_code());
?>
<div class="content" id="response">

View File

@ -17,18 +17,19 @@
"psr/log": "^3.0"
},
"require-dev": {
"codeigniter/phpstan-codeigniter": "^1.4",
"codeigniter/phpstan-codeigniter": "^1.5.1",
"fakerphp/faker": "^1.9",
"kint-php/kint": "^5.0.4",
"mikey179/vfsstream": "^1.6",
"nexusphp/tachycardia": "^2.0",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-strict-rules": "^1.6",
"phpstan/phpstan": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpcov": "^9.0.2 || ^10.0",
"phpunit/phpunit": "^10.5.16 || ^11.2",
"predis/predis": "^1.1 || ^2.0",
"rector/rector": "1.2.4"
"rector/rector": "2.0.4",
"shipmonk/phpstan-baseline-per-identifier": "^2.0"
},
"replace": {
"codeigniter4/framework": "self.version"
@ -80,7 +81,8 @@
},
"extra": {
"branch-alias": {
"dev-develop": "4.x-dev"
"dev-develop": "4.x-dev",
"dev-master": "4.x-dev"
}
},
"scripts": {
@ -110,7 +112,12 @@
"utils/vendor/bin/php-cs-fixer fix --ansi --verbose --diff"
],
"metrics": "utils/vendor/bin/phpmetrics --config=phpmetrics.json",
"phpstan:baseline": "vendor/bin/phpstan analyse --ansi --generate-baseline=phpstan-baseline.php",
"phpstan:baseline": [
"bash -c \"rm -rf utils/phpstan-baseline/*.neon\"",
"bash -c \"touch utils/phpstan-baseline/loader.neon\"",
"phpstan analyse --ansi --generate-baseline=utils/phpstan-baseline/loader.neon",
"split-phpstan-baseline utils/phpstan-baseline/loader.neon"
],
"phpstan:check": "vendor/bin/phpstan analyse --verbose --ansi",
"sa": "@analyze",
"style": "@cs-fix",

View File

@ -10,7 +10,7 @@
<output>api/build/</output>
<cache>api/cache/</cache>
</paths>
<version number="4.5.5">
<version number="4.5.6">
<api format="php">
<source dsn=".">
<path>system</path>

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,5 @@
services:
-
class: Utils\PHPStan\CheckUseStatementsAfterLicenseRule
tags:
- phpstan.rules.rule
includes:
- phpstan-baseline.php
- utils/phpstan-baseline/loader.neon
parameters:
phpVersion: 80100
@ -18,7 +12,6 @@ parameters:
- app
- system
- tests
- utils/src/PHPStan
excludePaths:
- app/Views/errors/cli/*
- app/Views/errors/html/*
@ -40,5 +33,10 @@ parameters:
allRules: false
disallowedLooseComparison: true
booleansInConditions: true
disallowedConstructs: true
disallowedBacktick: true
disallowedEmpty: true
disallowedImplicitArrayCreation: true
disallowedShortTernary: true
matchingInheritedMethodNames: true
shipmonkBaselinePerIdentifier:
directory: %currentWorkingDirectory%

View File

@ -12,22 +12,15 @@ declare(strict_types=1);
*/
use Rector\Caching\ValueObject\Storage\FileCacheStorage;
use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector;
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector;
use Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector;
use Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector;
use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
use Rector\CodeQuality\Rector\FuncCall\SimplifyStrposLowerRector;
use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector;
use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector;
use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector;
use Rector\CodeQuality\Rector\If_\CombineIfRector;
use Rector\CodeQuality\Rector\If_\ExplicitBoolCompareRector;
use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector;
use Rector\CodeQuality\Rector\If_\ShortenElseIfRector;
use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector;
use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector;
use Rector\CodeQuality\Rector\Ternary\TernaryEmptyArrayArrayDimFetchToCoalesceRector;
use Rector\CodeQuality\Rector\Ternary\UnnecessaryTernaryExpressionRector;
use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector;
use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector;
use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector;
@ -43,18 +36,18 @@ use Rector\EarlyReturn\Rector\Return_\PreparedValueToEarlyReturnRector;
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
use Rector\Php70\Rector\FuncCall\RandomFunctionRector;
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
use Rector\Php80\Rector\FunctionLike\MixedTypeRector;
use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector;
use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector;
use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector;
use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector;
use Rector\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
use Rector\TypeDeclaration\Rector\Closure\AddClosureVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\Closure\ClosureReturnTypeRector;
use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector;
use Rector\TypeDeclaration\Rector\Function_\AddFunctionVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector;
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;
use Utils\Rector\PassStrictParameterToFunctionParameterRector;
use Utils\Rector\RemoveErrorSuppressInTryCatchStmtsRector;
@ -62,11 +55,8 @@ use Utils\Rector\UnderscoreToCamelCaseVariableNameRector;
return RectorConfig::configure()
->withPhpSets(php81: true)
->withPreparedSets(deadCode: true)
->withSets([
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
PHPUnitSetList::PHPUNIT_100,
])
->withPreparedSets(deadCode: true, instanceOf: true, strictBooleans: true, phpunitCodeQuality: true)
->withComposerBased(phpunit: true)
->withParallel(120, 8, 10)
->withCache(
// Github action cache or local
@ -88,6 +78,7 @@ return RectorConfig::configure()
__DIR__ . '/phpstan.neon.dist',
__DIR__ . '/vendor/codeigniter/phpstan-codeigniter/extension.neon',
__DIR__ . '/vendor/phpstan/phpstan-strict-rules/rules.neon',
__DIR__ . '/vendor/shipmonk/phpstan-baseline-per-identifier/extension.neon',
])
// is there a file you need to skip?
->withSkip([
@ -156,7 +147,6 @@ return RectorConfig::configure()
__DIR__ . '/system/Security/Security.php',
__DIR__ . '/system/Session/Session.php',
],
MixedTypeRector::class,
ReturnNeverTypeRector::class => [
__DIR__ . '/system/Cache/Handlers/BaseHandler.php',
@ -176,6 +166,8 @@ return RectorConfig::configure()
// Unnecessary (string) is inserted
NullToStrictStringFuncCallArgRector::class,
CompactToVariablesRector::class,
])
// auto import fully qualified class names
->withImportNames(removeUnusedImports: true)
@ -188,35 +180,30 @@ return RectorConfig::configure()
CountArrayToEmptyArrayComparisonRector::class,
ChangeNestedForeachIfsToEarlyContinueRector::class,
ChangeIfElseValueAssignToEarlyReturnRector::class,
SimplifyStrposLowerRector::class,
CombineIfRector::class,
SimplifyIfReturnBoolRector::class,
InlineIfToExplicitIfRector::class,
PreparedValueToEarlyReturnRector::class,
ShortenElseIfRector::class,
SimplifyIfElseToTernaryRector::class,
UnusedForeachValueToArrayKeysRector::class,
ChangeArrayPushToArrayAssignRector::class,
UnnecessaryTernaryExpressionRector::class,
RemoveErrorSuppressInTryCatchStmtsRector::class,
FuncGetArgsToVariadicParamRector::class,
MakeInheritedMethodVisibilitySameAsParentRector::class,
SimplifyEmptyArrayCheckRector::class,
SimplifyEmptyCheckOnEmptyArrayRector::class,
TernaryEmptyArrayArrayDimFetchToCoalesceRector::class,
EmptyOnNullableObjectToInstanceOfRector::class,
DisallowedEmptyRuleFixerRector::class,
PrivatizeFinalClassPropertyRector::class,
CompleteDynamicPropertiesRector::class,
BooleanInIfConditionRuleFixerRector::class,
SingleInArrayToCompareRector::class,
VersionCompareFuncCallToConstantRector::class,
ExplicitBoolCompareRector::class,
AddClosureVoidReturnTypeWhereNoReturnRector::class,
AddFunctionVoidReturnTypeWhereNoReturnRector::class,
AddMethodCallBasedStrictParamTypeRector::class,
TypedPropertyFromAssignsRector::class,
ClosureReturnTypeRector::class,
FlipTypeControlToUseExclusiveTypeRector::class,
])
->withConfiguredRule(StringClassNameToClassConstantRector::class, [
// keep '\\' prefix string on string '\Foo\Bar'
StringClassNameToClassConstantRector::SHOULD_KEEP_PRE_SLASH => true,
]);
])
->withCodeQualityLevel(31);

View File

@ -19,7 +19,6 @@ use Composer\InstalledVersions;
use Config\Autoload;
use Config\Kint as KintConfig;
use Config\Modules;
use Config\Services;
use InvalidArgumentException;
use Kint;
use Kint\Renderer\CliRenderer;
@ -367,6 +366,9 @@ class Autoloader
return $cleanFilename;
}
/**
* @param array{only?: list<string>, exclude?: list<string>} $composerPackages
*/
private function loadComposerNamespaces(ClassLoader $composer, array $composerPackages): void
{
$namespacePaths = $composer->getPrefixesPsr4();
@ -380,7 +382,7 @@ class Autoloader
}
}
if (! method_exists(InstalledVersions::class, 'getAllRawData')) {
if (! method_exists(InstalledVersions::class, 'getAllRawData')) { // @phpstan-ignore function.alreadyNarrowedType
throw new RuntimeException(
'Your Composer version is too old.'
. ' Please update Composer (run `composer self-update`) to v2.0.14 or later'
@ -537,7 +539,7 @@ class Autoloader
Kint::$plugins = $config->plugins;
}
$csp = Services::csp();
$csp = service('csp');
if ($csp->enabled()) {
RichRenderer::$js_nonce = $csp->getScriptNonce();
RichRenderer::$css_nonce = $csp->getStyleNonce();

View File

@ -145,10 +145,11 @@ class FileLocator implements FileLocatorInterface
if ((isset($tokens[$i - 2][1]) && ($tokens[$i - 2][1] === 'phpnamespace' || $tokens[$i - 2][1] === 'namespace')) || ($dlm && $tokens[$i - 1][0] === T_NS_SEPARATOR && $token[0] === T_STRING)) {
if (! $dlm) {
$namespace = 0;
$namespace = '';
}
if (isset($token[1])) {
$namespace = $namespace ? $namespace . '\\' . $token[1] : $token[1];
$namespace = $namespace !== '' ? $namespace . '\\' . $token[1] : $token[1];
$dlm = true;
}
} elseif ($dlm && ($token[0] !== T_NS_SEPARATOR) && ($token[0] !== T_STRING)) {
@ -194,8 +195,9 @@ class FileLocator implements FileLocatorInterface
foreach ($this->getNamespaces() as $namespace) {
if (isset($namespace['path']) && is_file($namespace['path'] . $path)) {
$fullPath = $namespace['path'] . $path;
$fullPath = realpath($fullPath) ?: $fullPath;
$fullPath = $namespace['path'] . $path;
$resolvedPath = realpath($fullPath);
$fullPath = $resolvedPath !== false ? $resolvedPath : $fullPath;
if ($prioritizeApp) {
$foundPaths[] = $fullPath;
@ -272,14 +274,16 @@ class FileLocator implements FileLocatorInterface
*/
public function findQualifiedNameFromPath(string $path)
{
$path = realpath($path) ?: $path;
$resolvedPath = realpath($path);
$path = $resolvedPath !== false ? $resolvedPath : $path;
if (! is_file($path)) {
return false;
}
foreach ($this->getNamespaces() as $namespace) {
$namespace['path'] = realpath($namespace['path']) ?: $namespace['path'];
$resolvedNamespacePath = realpath($namespace['path']);
$namespace['path'] = $resolvedNamespacePath !== false ? $resolvedNamespacePath : $namespace['path'];
if ($namespace['path'] === '') {
continue;
@ -331,8 +335,9 @@ class FileLocator implements FileLocatorInterface
helper('filesystem');
foreach ($this->getNamespaces() as $namespace) {
$fullPath = $namespace['path'] . $path;
$fullPath = realpath($fullPath) ?: $fullPath;
$fullPath = $namespace['path'] . $path;
$resolvedPath = realpath($fullPath);
$fullPath = $resolvedPath !== false ? $resolvedPath : $fullPath;
if (! is_dir($fullPath)) {
continue;
@ -365,8 +370,9 @@ class FileLocator implements FileLocatorInterface
// autoloader->getNamespace($prefix) returns an array of paths for that namespace
foreach ($this->autoloader->getNamespace($prefix) as $namespacePath) {
$fullPath = rtrim($namespacePath, '/') . '/' . $path;
$fullPath = realpath($fullPath) ?: $fullPath;
$fullPath = rtrim($namespacePath, '/') . '/' . $path;
$resolvedPath = realpath($fullPath);
$fullPath = $resolvedPath !== false ? $resolvedPath : $fullPath;
if (! is_dir($fullPath)) {
continue;
@ -392,8 +398,9 @@ class FileLocator implements FileLocatorInterface
*/
protected function legacyLocate(string $file, ?string $folder = null)
{
$path = APPPATH . ($folder === null ? $file : $folder . '/' . $file);
$path = realpath($path) ?: $path;
$path = APPPATH . ($folder === null ? $file : $folder . '/' . $file);
$resolvedPath = realpath($path);
$path = $resolvedPath !== false ? $resolvedPath : $path;
if (is_file($path)) {
return $path;

View File

@ -36,6 +36,8 @@ final class FileLocatorCached implements FileLocatorInterface
* [
* 'search' => [$path => $foundPaths],
* ]
*
* @var array<string, array<string, mixed>>
*/
private array $cache = [];
@ -114,6 +116,9 @@ final class FileLocatorCached implements FileLocatorInterface
return $classname;
}
/**
* @return list<string>
*/
public function search(string $path, string $ext = 'php', bool $prioritizeApp = true): array
{
if (isset($this->cache['search'][$path][$ext][$prioritizeApp])) {

View File

@ -53,6 +53,8 @@ interface FileLocatorInterface
* 'app/Modules/foo/Config/Routes.php',
* 'app/Modules/bar/Config/Routes.php',
* ]
*
* @return list<string>
*/
public function search(string $path, string $ext = 'php', bool $prioritizeApp = true): array;

View File

@ -26,7 +26,6 @@ use CodeIgniter\I18n\Time;
use CodeIgniter\Pager\Pager;
use CodeIgniter\Validation\ValidationInterface;
use Config\Feature;
use Config\Services;
use InvalidArgumentException;
use ReflectionClass;
use ReflectionException;
@ -47,7 +46,7 @@ use stdClass;
* - process various callbacks
* - allow intermingling calls to the db connection
*
* @phpstan-type row_array array<int|string, float|int|null|object|string>
* @phpstan-type row_array array<int|string, float|int|null|object|string|bool>
* @phpstan-type event_data_beforeinsert array{data: row_array}
* @phpstan-type event_data_afterinsert array{id: int|string, data: row_array, result: bool}
* @phpstan-type event_data_beforefind array{id?: int|string, method: string, singleton: bool, limit?: int, offset?: int}
@ -571,8 +570,8 @@ abstract class BaseModel
* Loops over records in batches, allowing you to operate on them.
* This method works only with dbCalls.
*
* @param int $size Size
* @param Closure $userFunc Callback Function
* @param int $size Size
* @param Closure(array<string, string>|object): mixed $userFunc Callback Function
*
* @return void
*
@ -640,7 +639,7 @@ abstract class BaseModel
$resultSet = $this->doFindColumn($columnName);
return $resultSet ? array_column($resultSet, $columnName) : null;
return $resultSet !== null ? array_column($resultSet, $columnName) : null;
}
/**
@ -1138,7 +1137,7 @@ abstract class BaseModel
throw new InvalidArgumentException('delete(): argument #1 ($id) should not be boolean.');
}
if ($id && (is_numeric($id) || is_string($id))) {
if (! in_array($id, [null, 0, '0'], true) && (is_numeric($id) || is_string($id))) {
$id = [$id];
}
@ -1251,7 +1250,7 @@ abstract class BaseModel
}
// Do we have validation errors?
if (! $forceDB && ! $this->skipValidation && ($errors = $this->validation->getErrors())) {
if (! $forceDB && ! $this->skipValidation && ($errors = $this->validation->getErrors()) !== []) {
return $errors;
}
@ -1609,7 +1608,7 @@ abstract class BaseModel
protected function ensureValidation(): void
{
if ($this->validation === null) {
$this->validation = Services::validation(null, false);
$this->validation = service('validation', null, false);
}
}
@ -1800,8 +1799,6 @@ abstract class BaseModel
// Loop over each property,
// saving the name/value in a new array we can return.
foreach ($props as $prop) {
// Must make protected values accessible.
$prop->setAccessible(true);
$properties[$prop->getName()] = $prop->getValue($object);
}
}

View File

@ -196,7 +196,16 @@ class Boot
// The path to the writable directory.
if (! defined('WRITEPATH')) {
define('WRITEPATH', realpath(rtrim($paths->writableDirectory, '\\/ ')) . DIRECTORY_SEPARATOR);
$writePath = realpath(rtrim($paths->writableDirectory, '\\/ '));
if ($writePath === false) {
header('HTTP/1.1 503 Service Unavailable.', true, 503);
echo 'The WRITEPATH is not set correctly.';
// EXIT_ERROR is not yet defined
exit(1);
}
define('WRITEPATH', $writePath . DIRECTORY_SEPARATOR);
}
// The path to the tests directory
@ -246,12 +255,12 @@ class Boot
protected static function autoloadHelpers(): void
{
Services::autoloader()->loadHelpers();
service('autoloader')->loadHelpers();
}
protected static function setExceptionHandler(): void
{
Services::exceptions()->initialize();
service('exceptions')->initialize();
}
protected static function checkMissingExtensions(): void
@ -290,7 +299,7 @@ class Boot
protected static function initializeKint(): void
{
Services::autoloader()->initializeKint(CI_DEBUG);
service('autoloader')->initializeKint(CI_DEBUG);
}
protected static function loadConfigCache(): FactoriesCache
@ -308,7 +317,7 @@ class Boot
*/
protected static function initializeCodeIgniter(): CodeIgniter
{
$app = Config\Services::codeigniter();
$app = service('codeigniter');
$app->initialize();
$context = is_cli() ? 'php-cli' : 'web';
$app->setContext($context);

View File

@ -14,7 +14,6 @@ declare(strict_types=1);
namespace CodeIgniter\CLI;
use CodeIgniter\CLI\Exceptions\CLIException;
use Config\Services;
use InvalidArgumentException;
use Throwable;
@ -226,12 +225,12 @@ class CLI
$extraOutput = '';
$default = '';
if ($validation && ! is_array($validation) && ! is_string($validation)) {
if (isset($validation) && ! is_array($validation) && ! is_string($validation)) {
throw new InvalidArgumentException('$rules can only be of type string|array');
}
if (! is_array($validation)) {
$validation = $validation ? explode('|', $validation) : [];
$validation = ($validation !== null) ? explode('|', $validation) : [];
}
if (is_string($options)) {
@ -349,7 +348,7 @@ class CLI
// return the prompt again if $input contain(s) non-numeric character, except a comma.
// And if max from $options less than max from input,
// it means user tried to access null value in $options
if (! $pattern || $maxOptions < $maxInput) {
if ($pattern === 0 || $maxOptions < $maxInput) {
static::error('Please select correctly.');
CLI::newLine();
@ -416,7 +415,7 @@ class CLI
{
$label = $field;
$field = 'temp';
$validation = Services::validation(null, false);
$validation = service('validation', null, false);
$validation->setRules([
$field => [
'label' => $label,
@ -442,7 +441,7 @@ class CLI
*/
public static function print(string $text = '', ?string $foreground = null, ?string $background = null)
{
if ($foreground || $background) {
if ((string) $foreground !== '' || (string) $background !== '') {
$text = static::color($text, $foreground, $background);
}
@ -458,7 +457,7 @@ class CLI
*/
public static function write(string $text = '', ?string $foreground = null, ?string $background = null)
{
if ($foreground || $background) {
if ((string) $foreground !== '' || (string) $background !== '') {
$text = static::color($text, $foreground, $background);
}
@ -481,7 +480,7 @@ class CLI
$stdout = static::$isColored;
static::$isColored = static::hasColorSupport(STDERR);
if ($foreground || $background) {
if ($foreground !== '' || (string) $background !== '') {
$text = static::color($text, $foreground, $background);
}
@ -514,7 +513,7 @@ class CLI
*/
public static function wait(int $seconds, bool $countdown = false)
{
if ($countdown === true) {
if ($countdown) {
$time = $seconds;
while ($time > 0) {
@ -590,7 +589,7 @@ class CLI
throw CLIException::forInvalidColor('foreground', $foreground);
}
if ($background !== null && ! array_key_exists($background, static::$background_colors)) {
if ((string) $background !== '' && ! array_key_exists($background, static::$background_colors)) {
throw CLIException::forInvalidColor('background', $background);
}
@ -638,7 +637,7 @@ class CLI
{
$string = "\033[" . static::$foreground_colors[$foreground] . 'm';
if ($background !== null) {
if ((string) $background !== '') {
$string .= "\033[" . static::$background_colors[$background] . 'm';
}
@ -655,7 +654,7 @@ class CLI
*/
public static function strlen(?string $string): int
{
if ($string === null) {
if ((string) $string === '') {
return 0;
}
@ -769,7 +768,7 @@ class CLI
// Look for the next lines ending in ": <number>"
// Searching for "Columns:" or "Lines:" will fail on non-English locales
if ($return === 0 && $output && preg_match('/:\s*(\d+)\n[^:]+:\s*(\d+)\n/', implode("\n", $output), $matches)) {
if ($return === 0 && $output !== [] && preg_match('/:\s*(\d+)\n[^:]+:\s*(\d+)\n/', implode("\n", $output), $matches)) {
static::$height = (int) $matches[1];
static::$width = (int) $matches[2];
}
@ -836,7 +835,7 @@ class CLI
*/
public static function wrap(?string $string = null, int $max = 0, int $padLeft = 0): string
{
if ($string === null || $string === '') {
if ((string) $string === '') {
return '';
}

View File

@ -67,7 +67,7 @@ abstract class BaseHandler implements CacheInterface
}
$reserved = config(Cache::class)->reservedCharacters ?? self::RESERVED_CHARACTERS;
if ($reserved && strpbrk($key, $reserved) !== false) {
if ($reserved !== '' && strpbrk($key, $reserved) !== false) {
throw new InvalidArgumentException('Cache key contains reserved characters ' . $reserved);
}

View File

@ -308,7 +308,7 @@ class FileHandler extends BaseHandler
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) !== 1) {
@unlink($path . DIRECTORY_SEPARATOR . $filename);
}
}
@ -316,7 +316,7 @@ class FileHandler extends BaseHandler
closedir($currentDir);
return ($delDir === true && $_level > 0) ? @rmdir($path) : true;
return ($delDir && $_level > 0) ? @rmdir($path) : true;
}
/**
@ -337,13 +337,13 @@ class FileHandler extends BaseHandler
$relativePath = $sourceDir;
if ($fp = @opendir($sourceDir)) {
// reset the array and make sure $source_dir has a trailing slash on the initial call
// reset the array and make sure $sourceDir has a trailing slash on the initial call
if ($_recursion === false) {
$_filedata = [];
$sourceDir = rtrim(realpath($sourceDir) ?: $sourceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
// Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast
// Used to be foreach (scandir($sourceDir, 1) as $file), but scandir() is simply not as fast
while (false !== ($file = readdir($fp))) {
if (is_dir($sourceDir . $file) && $file[0] !== '.' && $topLevelOnly === false) {
$this->getDirFileInfo($sourceDir . $file . DIRECTORY_SEPARATOR, $topLevelOnly, true);

View File

@ -19,6 +19,7 @@ use Config\Cache;
use Exception;
use Predis\Client;
use Predis\Collection\Iterator\Keyspace;
use Predis\Response\Status;
/**
* Predis cache handler
@ -121,7 +122,7 @@ class PredisHandler extends BaseHandler
return false;
}
if (! $this->redis->hmset($key, ['__ci_type' => $dataType, '__ci_value' => $value])) {
if (! $this->redis->hmset($key, ['__ci_type' => $dataType, '__ci_value' => $value]) instanceof Status) {
return false;
}

View File

@ -108,7 +108,7 @@ class RedisHandler extends BaseHandler
public function get(string $key)
{
$key = static::validateKey($key, $this->prefix);
$data = $this->redis->hMGet($key, ['__ci_type', '__ci_value']);
$data = $this->redis->hMget($key, ['__ci_type', '__ci_value']);
if (! isset($data['__ci_type'], $data['__ci_value']) || $data['__ci_value'] === false) {
return null;
@ -147,7 +147,7 @@ class RedisHandler extends BaseHandler
return false;
}
if (! $this->redis->hMSet($key, ['__ci_type' => $dataType, '__ci_value' => $value])) {
if (! $this->redis->hMset($key, ['__ci_type' => $dataType, '__ci_value' => $value])) {
return false;
}

View File

@ -56,7 +56,7 @@ class CodeIgniter
/**
* The current version of CodeIgniter Framework
*/
public const CI_VERSION = '4.5.5';
public const CI_VERSION = '4.5.6';
/**
* App startup time.
@ -819,7 +819,7 @@ class CodeIgniter
{
$this->benchmark->start('routing');
if ($routes === null) {
if (! $routes instanceof RouteCollectionInterface) {
$routes = service('routes')->loadRoutes();
}

View File

@ -71,6 +71,8 @@ class ListCommands extends BaseCommand
/**
* Displays the help for the spark cli script itself.
*
* @return int
*/
public function run(array $params)
{
@ -78,7 +80,7 @@ class ListCommands extends BaseCommand
ksort($commands);
// Check for 'simple' format
return array_key_exists('simple', $params) || CLI::getOption('simple')
return array_key_exists('simple', $params) || CLI::getOption('simple') === true
? $this->listSimple($commands)
: $this->listFull($commands);
}
@ -86,7 +88,7 @@ class ListCommands extends BaseCommand
/**
* Lists the commands with accompanying info.
*
* @return void
* @return int
*/
protected function listFull(array $commands)
{
@ -124,17 +126,21 @@ class ListCommands extends BaseCommand
CLI::newLine();
}
}
return EXIT_SUCCESS;
}
/**
* Lists the commands only.
*
* @return void
* @return int
*/
protected function listSimple(array $commands)
{
foreach (array_keys($commands) as $title) {
CLI::write($title);
}
return EXIT_SUCCESS;
}
}

View File

@ -110,7 +110,7 @@ class Serve extends BaseCommand
// to ensure our environment is set and it simulates basic mod_rewrite.
passthru($php . ' -S ' . $host . ':' . $port . ' -t ' . $docroot . ' ' . $rewrite, $status);
if ($status && $this->portOffset < $this->tries) {
if ($status !== EXIT_SUCCESS && $this->portOffset < $this->tries) {
$this->portOffset++;
$this->run($params);

View File

@ -86,7 +86,7 @@ class Routes extends BaseCommand
$host = $params['host'] ?? null;
// Set HTTP_HOST
if ($host) {
if ($host !== null) {
$request = service('request');
$_SERVER = $request->getServer();
$_SERVER['HTTP_HOST'] = $host;
@ -96,7 +96,7 @@ class Routes extends BaseCommand
$collection = service('routes')->loadRoutes();
// Reset HTTP_HOST
if ($host) {
if ($host !== null) {
unset($_SERVER['HTTP_HOST']);
}
@ -139,7 +139,9 @@ class Routes extends BaseCommand
$autoRoutes = $autoRouteCollector->get();
// Check for Module Routes.
if ($routingConfig = config(Routing::class)) {
$routingConfig = config(Routing::class);
if ($routingConfig instanceof Routing) {
foreach ($routingConfig->moduleRoutes as $uri => $namespace) {
$autoRouteCollector = new AutoRouteCollectorImproved(
$namespace,
@ -188,7 +190,7 @@ class Routes extends BaseCommand
usort($tbody, static fn ($handler1, $handler2) => strcmp($handler1[3], $handler2[3]));
}
if ($host) {
if ($host !== null) {
CLI::write('Host: ' . $host);
}

View File

@ -36,7 +36,7 @@ final class AutoRouteCollector
private readonly string $defaultMethod,
private readonly array $httpMethods,
private readonly array $protectedControllers,
private string $prefix = ''
private readonly string $prefix = ''
) {
}
@ -122,8 +122,10 @@ final class AutoRouteCollector
$filtersShortest = $filterCollector->get($route['method'], $routePath . $sampleUri);
// Get common array elements
$filters['before'] = array_intersect($filtersLongest['before'], $filtersShortest['before']);
$filters['after'] = array_intersect($filtersLongest['after'], $filtersShortest['after']);
$filters = [
'before' => array_intersect($filtersLongest['before'], $filtersShortest['before']),
'after' => array_intersect($filtersLongest['after'], $filtersShortest['after']),
];
$route['before'] = implode(' ', array_map(class_basename(...), $filters['before']));
$route['after'] = implode(' ', array_map(class_basename(...), $filters['after']));

View File

@ -221,7 +221,7 @@ final class ControllerMethodReader
if ($classShortname === $defaultController) {
$pattern = '#' . preg_quote(lcfirst($defaultController), '#') . '\z#';
$routeWithoutController = rtrim(preg_replace($pattern, '', $uriByClass), '/');
$routeWithoutController = $routeWithoutController ?: '/';
$routeWithoutController = $routeWithoutController !== '' && $routeWithoutController !== '0' ? $routeWithoutController : '/';
[$params, $routeParams] = $this->getParameters($method);

View File

@ -161,7 +161,7 @@ final class ControllerMethodReader
$pattern = '#' . preg_quote(lcfirst($defaultController), '#') . '\z#';
$routeWithoutController = rtrim(preg_replace($pattern, '', $uriByClass), '/');
$routeWithoutController = $routeWithoutController ?: '/';
$routeWithoutController = $routeWithoutController !== '' && $routeWithoutController !== '0' ? $routeWithoutController : '/';
return [[
'route' => $routeWithoutController,

View File

@ -13,7 +13,6 @@ declare(strict_types=1);
namespace CodeIgniter\Commands\Utilities\Routes;
use CodeIgniter\Config\Services;
use CodeIgniter\Filters\Filters;
use CodeIgniter\HTTP\Method;
use CodeIgniter\HTTP\Request;
@ -68,7 +67,7 @@ final class FilterCollector
];
}
$request = Services::incomingrequest(null, false);
$request = service('incomingrequest', null, false);
$request->setMethod($method);
$router = $this->createRouter($request);
@ -86,7 +85,7 @@ final class FilterCollector
*/
public function getRequiredFilters(): array
{
$request = Services::incomingrequest(null, false);
$request = service('incomingrequest', null, false);
$request->setMethod(Method::GET);
$router = $this->createRouter($request);

View File

@ -441,7 +441,7 @@ if (! function_exists('esc')) {
$escaper = new Escaper($encoding);
}
if ($encoding && $escaper->getEncoding() !== $encoding) {
if ($encoding !== null && $escaper->getEncoding() !== $encoding) {
$escaper = new Escaper($encoding);
}
@ -580,8 +580,8 @@ if (! function_exists('helper')) {
foreach ($filenames as $filename) {
// Store our system and application helper
// versions so that we can control the load ordering.
$systemHelper = null;
$appHelper = null;
$systemHelper = '';
$appHelper = '';
$localIncludes = [];
if (! str_contains($filename, '_helper')) {
@ -598,7 +598,7 @@ if (! function_exists('helper')) {
if (str_contains($filename, '\\')) {
$path = $loader->locateFile($filename, 'Helpers');
if (empty($path)) {
if ($path !== '') {
throw FileNotFoundException::forFileNotFound($filename);
}
@ -620,7 +620,7 @@ if (! function_exists('helper')) {
}
// App-level helpers should override all others
if (! empty($appHelper)) {
if ($appHelper !== '') {
$includes[] = $appHelper;
$loaded[] = $filename;
}
@ -629,7 +629,7 @@ if (! function_exists('helper')) {
$includes = [...$includes, ...$localIncludes];
// And the system default one should be added in last.
if (! empty($systemHelper)) {
if ($systemHelper !== '') {
$includes[] = $systemHelper;
$loaded[] = $filename;
}
@ -739,13 +739,13 @@ if (! function_exists('lang')) {
// Get active locale
$activeLocale = $language->getLocale();
if ($locale && $locale !== $activeLocale) {
if ((string) $locale !== '' && $locale !== $activeLocale) {
$language->setLocale($locale);
}
$lines = $language->getLine($line, $args);
if ($locale && $locale !== $activeLocale) {
if ((string) $locale !== '' && $locale !== $activeLocale) {
// Reset to active locale
$language->setLocale($activeLocale);
}
@ -849,7 +849,7 @@ if (! function_exists('redirect')) {
{
$response = service('redirectresponse');
if ($route !== null) {
if ((string) $route !== '') {
return $response->route($route);
}
@ -869,7 +869,7 @@ if (! function_exists('_solidus')) {
{
static $docTypes = null;
if ($docTypesConfig !== null) {
if ($docTypesConfig instanceof DocTypes) {
$docTypes = $docTypesConfig;
}
@ -1092,7 +1092,7 @@ if (! function_exists('stringify_attributes')) {
{
$atts = '';
if (empty($attributes)) {
if ($attributes === '' || $attributes === [] || $attributes === null) {
return $atts;
}

View File

@ -94,7 +94,7 @@ class DotEnv
*/
protected function setVariable(string $name, string $value = '')
{
if (! getenv($name, true)) {
if (getenv($name, true) === false) {
putenv("{$name}={$value}");
}

View File

@ -37,7 +37,7 @@ final class Factories
*
* @var array<string, array<string, bool|string|null>>
*/
private static $options = [];
private static array $options = [];
/**
* Explicit options for the Config
@ -65,7 +65,7 @@ final class Factories
*
* @var array<string, array<string, class-string>>
*/
private static $aliases = [];
private static array $aliases = [];
/**
* Store for instances of any component that
@ -78,7 +78,7 @@ final class Factories
*
* @var array<string, array<class-string, object>>
*/
private static $instances = [];
private static array $instances = [];
/**
* Whether the component instances are updated?
@ -87,7 +87,7 @@ final class Factories
*
* @internal For caching only
*/
private static $updated = [];
private static array $updated = [];
/**
* Define the class to load. You can *override* the concrete class.
@ -162,7 +162,7 @@ final class Factories
}
// Try to locate the class
if (! $class = self::locateClass($options, $alias)) {
if (($class = self::locateClass($options, $alias)) === null) {
return null;
}
@ -213,7 +213,7 @@ final class Factories
}
// Try to locate the class
if (! $class = self::locateClass($options, $alias)) {
if (($class = self::locateClass($options, $alias)) === null) {
return null;
}
@ -310,7 +310,7 @@ final class Factories
}
// No namespace? Search for it
// Check all namespaces, prioritizing App and modules
elseif (! $files = $locator->search($options['path'] . DIRECTORY_SEPARATOR . $alias)) {
elseif (($files = $locator->search($options['path'] . DIRECTORY_SEPARATOR . $alias)) === []) {
return null;
}

View File

@ -202,7 +202,7 @@ class Services extends BaseService
*/
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);
}
@ -211,7 +211,7 @@ class Services extends BaseService
return new CURLRequest(
$config,
new URI($options['base_uri'] ?? null),
new URI($options['baseURI'] ?? null),
$response,
$options
);
@ -230,7 +230,7 @@ class Services extends BaseService
return static::getSharedInstance('email', $config);
}
if (empty($config) || ! (is_array($config) || $config instanceof EmailConfig)) {
if (empty($config) || (! is_array($config) && ! $config instanceof EmailConfig)) {
$config = config(EmailConfig::class);
}
@ -345,7 +345,7 @@ class Services extends BaseService
$config ??= config(Images::class);
assert($config instanceof Images);
$handler = $handler ?: $config->defaultHandler;
$handler = $handler !== null && $handler !== '' && $handler !== '0' ? $handler : $config->defaultHandler;
$class = $config->handlers[$handler];
return new $class($config);
@ -385,7 +385,7 @@ class Services extends BaseService
}
// Use '?:' for empty string check
$locale = $locale ?: $requestLocale;
$locale = $locale !== null && $locale !== '' && $locale !== '0' ? $locale : $requestLocale;
return new Language($locale);
}
@ -484,7 +484,7 @@ class Services extends BaseService
return static::getSharedInstance('parser', $viewPath, $config);
}
$viewPath = $viewPath ?: (new Paths())->viewDirectory;
$viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory;
$config ??= config(ViewConfig::class);
return new Parser($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
@ -503,7 +503,7 @@ class Services extends BaseService
return static::getSharedInstance('renderer', $viewPath, $config);
}
$viewPath = $viewPath ?: (new Paths())->viewDirectory;
$viewPath = $viewPath !== null && $viewPath !== '' && $viewPath !== '0' ? $viewPath : (new Paths())->viewDirectory;
$config ??= config(ViewConfig::class);
return new View($config, $viewPath, AppServices::get('locator'), CI_DEBUG, AppServices::get('logger'));
@ -705,7 +705,7 @@ class Services extends BaseService
// See https://www.php.net/manual/en/function.session-cache-limiter.php.
// The headers are not managed by CI's Response class.
// So, we remove CI's default Cache-Control header.
AppServices::response()->removeHeader('Cache-Control');
AppServices::get('response')->removeHeader('Cache-Control');
$session->start();
}

View File

@ -15,6 +15,7 @@ namespace CodeIgniter;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\Exceptions\HTTPException;
use CodeIgniter\HTTP\Exceptions\RedirectException;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
@ -77,7 +78,7 @@ class Controller
*
* @return void
*
* @throws HTTPException
* @throws HTTPException|RedirectException
*/
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
@ -105,7 +106,7 @@ class Controller
*
* @return void
*
* @throws HTTPException
* @throws HTTPException|RedirectException
*/
protected function forceHTTPS(int $duration = 31_536_000)
{

View File

@ -482,7 +482,7 @@ class Cookie implements ArrayAccess, CloneableCookieInterface
*/
public function withPath(?string $path)
{
$path = $path ?: self::$defaults['path'];
$path = $path !== null && $path !== '' && $path !== '0' ? $path : self::$defaults['path'];
$this->validatePrefix($this->prefix, $this->secure, $path, $this->domain);
$cookie = clone $this;

View File

@ -579,7 +579,7 @@ class BaseBuilder
*/
public function from($from, bool $overwrite = false): self
{
if ($overwrite === true) {
if ($overwrite) {
$this->QBFrom = [];
$this->db->setAliasedTables([]);
}
@ -769,7 +769,7 @@ class BaseBuilder
foreach ($keyValue as $k => $v) {
$prefix = empty($this->{$qbKey}) ? $this->groupGetType('') : $this->groupGetType($type);
if ($rawSqlOnly === true) {
if ($rawSqlOnly) {
$k = '';
$op = '';
} elseif ($v !== null) {
@ -836,7 +836,7 @@ class BaseBuilder
* Generates a WHERE field IN('item', 'item') SQL query,
* joined with 'AND' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -849,7 +849,7 @@ class BaseBuilder
* Generates a WHERE field IN('item', 'item') SQL query,
* joined with 'OR' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -862,7 +862,7 @@ class BaseBuilder
* Generates a WHERE field NOT IN('item', 'item') SQL query,
* joined with 'AND' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -875,7 +875,7 @@ class BaseBuilder
* Generates a WHERE field NOT IN('item', 'item') SQL query,
* joined with 'OR' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -888,7 +888,7 @@ class BaseBuilder
* Generates a HAVING field IN('item', 'item') SQL query,
* joined with 'AND' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -901,7 +901,7 @@ class BaseBuilder
* Generates a HAVING field IN('item', 'item') SQL query,
* joined with 'OR' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -914,7 +914,7 @@ class BaseBuilder
* Generates a HAVING field NOT IN('item', 'item') SQL query,
* joined with 'AND' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder):BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -927,7 +927,7 @@ class BaseBuilder
* Generates a HAVING field NOT IN('item', 'item') SQL query,
* joined with 'OR' if appropriate.
*
* @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*/
@ -942,8 +942,8 @@ class BaseBuilder
* @used-by whereNotIn()
* @used-by orWhereNotIn()
*
* @param non-empty-string|null $key
* @param array|BaseBuilder|Closure|null $values The values searched on, or anonymous function with subquery
* @param non-empty-string|null $key
* @param array|BaseBuilder|(Closure(BaseBuilder): BaseBuilder)|null $values The values searched on, or anonymous function with subquery
*
* @return $this
*
@ -1150,8 +1150,8 @@ class BaseBuilder
$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);
@ -1187,7 +1187,7 @@ class BaseBuilder
*/
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}:";
}
@ -1197,7 +1197,7 @@ class BaseBuilder
/**
* Add UNION statement
*
* @param BaseBuilder|Closure $union
* @param BaseBuilder|Closure(BaseBuilder): BaseBuilder $union
*
* @return $this
*/
@ -1209,7 +1209,7 @@ class BaseBuilder
/**
* Add UNION ALL statement
*
* @param BaseBuilder|Closure $union
* @param BaseBuilder|Closure(BaseBuilder): BaseBuilder $union
*
* @return $this
*/
@ -1222,7 +1222,7 @@ class BaseBuilder
* @used-by union()
* @used-by unionAll()
*
* @param BaseBuilder|Closure $union
* @param BaseBuilder|Closure(BaseBuilder): BaseBuilder $union
*
* @return $this
*/
@ -1599,7 +1599,7 @@ class BaseBuilder
{
$select = $this->compileSelect();
if ($reset === true) {
if ($reset) {
$this->resetSelect();
}
@ -1643,7 +1643,7 @@ class BaseBuilder
? $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
@ -1678,7 +1678,7 @@ class BaseBuilder
$query = $query->getRow();
if ($reset === true) {
if ($reset) {
$this->resetSelect();
}
@ -1727,7 +1727,7 @@ class BaseBuilder
$result = $this->db->query($sql, $this->binds, false);
if ($reset === true) {
if ($reset) {
$this->resetSelect();
} elseif (! isset($this->QBOrderBy)) {
$this->QBOrderBy = $orderBy;
@ -1736,7 +1736,7 @@ class BaseBuilder
// Restore the LIMIT setting
$this->QBLimit = $limit;
$row = ! $result instanceof ResultInterface ? null : $result->getRow();
$row = $result instanceof ResultInterface ? $result->getRow() : null;
if (empty($row)) {
return 0;
@ -1781,7 +1781,7 @@ class BaseBuilder
? $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
@ -2297,7 +2297,7 @@ class BaseBuilder
array_values($this->QBSet)
);
if ($reset === true) {
if ($reset) {
$this->resetWrite();
}
@ -2466,7 +2466,7 @@ class BaseBuilder
$sql = $this->_update($this->QBFrom[0], $this->QBSet);
if ($reset === true) {
if ($reset) {
$this->resetWrite();
}
@ -3167,11 +3167,11 @@ class BaseBuilder
$op = $this->getOperator($condition);
if (
$op === false
|| ! preg_match(
|| preg_match(
'/^(\(?)(.*)(' . preg_quote($op, '/') . ')\s*(.*(?<!\)))?(\)?)$/i',
$condition,
$matches
)
) !== 1
) {
continue;
}
@ -3558,9 +3558,9 @@ class BaseBuilder
}
/**
* @param BaseBuilder|Closure $builder
* @param bool $wrapped Wrap the subquery in brackets
* @param string $alias Subquery alias
* @param BaseBuilder|Closure(BaseBuilder): BaseBuilder $builder
* @param bool $wrapped Wrap the subquery in brackets
* @param string $alias Subquery alias
*/
protected function buildSubquery($builder, bool $wrapped = false, string $alias = ''): string
{

View File

@ -406,7 +406,7 @@ abstract class BaseConnection implements ConnectionInterface
/* If an established connection is available, then there's
* no need to connect and select the database.
*
* Depending on the database driver, conn_id can be either
* Depending on the database driver, connID can be either
* boolean TRUE, a resource or an object.
*/
if ($this->connID) {
@ -610,7 +610,7 @@ abstract class BaseConnection implements ConnectionInterface
*/
public function query(string $sql, $binds = null, bool $setEscapeFlags = true, string $queryClass = '')
{
$queryClass = $queryClass ?: $this->queryClass;
$queryClass = $queryClass !== '' && $queryClass !== '0' ? $queryClass : $this->queryClass;
if (empty($this->connID)) {
$this->initialize();
@ -684,7 +684,7 @@ abstract class BaseConnection implements ConnectionInterface
// Let others do something with this query.
Events::trigger('DBQuery', $query);
if ($exception !== null) {
if ($exception instanceof DatabaseException) {
throw new DatabaseException(
$exception->getMessage(),
$exception->getCode(),
@ -846,9 +846,9 @@ abstract class BaseConnection implements ConnectionInterface
}
// Reset the transaction failure flag.
// If the $test_mode flag is set to TRUE transactions will be rolled back
// If the $testMode 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++;
@ -959,6 +959,8 @@ abstract class BaseConnection implements ConnectionInterface
* ->get();
* })
*
* @param Closure(BaseConnection): mixed $func
*
* @return BasePreparedQuery|null
*/
public function prepare(Closure $func, array $options = [])
@ -1124,7 +1126,7 @@ abstract class BaseConnection implements ConnectionInterface
$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;
}
}
@ -1147,7 +1149,7 @@ abstract class BaseConnection implements ConnectionInterface
// 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);
@ -1198,7 +1200,7 @@ abstract class BaseConnection implements ConnectionInterface
$item = implode('.', $parts);
}
if ($protectIdentifiers === true) {
if ($protectIdentifiers) {
$item = $this->escapeIdentifiers($item);
}
@ -1372,7 +1374,7 @@ abstract class BaseConnection implements ConnectionInterface
$str = $this->_escapeString($str);
// escape LIKE condition wildcards
if ($like === true) {
if ($like) {
return str_replace(
[
$this->likeEscapeChar,
@ -1501,7 +1503,7 @@ abstract class BaseConnection implements ConnectionInterface
*/
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);
}

View File

@ -259,4 +259,12 @@ abstract class BasePreparedQuery implements PreparedQueryInterface
{
return $this->errorString;
}
/**
* Whether the input contain binary data.
*/
protected function isBinary(string $input): bool
{
return mb_detect_encoding($input, 'UTF-8', true) === false;
}
}

View File

@ -96,7 +96,7 @@ class Database
{
$dsn = parse_url($params['DSN']);
if (! $dsn) {
if ($dsn === 0 || $dsn === '' || $dsn === '0' || $dsn === [] || $dsn === false || $dsn === null) {
throw new InvalidArgumentException('Your DSN connection string is invalid.');
}

View File

@ -32,9 +32,9 @@ class Forge
protected $db;
/**
* List of fields.
* List of fields in the form `[name => attributes]`
*
* @var array<string, array|string> [name => attributes]
* @var array<string, array<string, bool|string>|string>
*/
protected $fields = [];
@ -449,12 +449,12 @@ class Forge
*/
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 @@ class Forge
}
// 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;
@ -573,7 +573,7 @@ class Forge
}
// Most databases don't support creating indexes from within the CREATE TABLE statement
if (! empty($this->keys)) {
if ($this->keys !== []) {
for ($i = 0, $sqls = $this->_processIndexes($table), $c = count($sqls); $i < $c; $i++) {
$this->db->query($sqls[$i]);
}
@ -650,7 +650,7 @@ class Forge
return false;
}
if ($this->db->DBPrefix && str_starts_with($tableName, $this->db->DBPrefix)) {
if ($this->db->DBPrefix !== '' && str_starts_with($tableName, $this->db->DBPrefix)) {
$tableName = substr($tableName, strlen($this->db->DBPrefix));
}
@ -895,7 +895,7 @@ class Forge
$attributes = array_change_key_case($attributes, CASE_UPPER);
if ($createTable === true && empty($attributes['TYPE'])) {
if ($createTable && empty($attributes['TYPE'])) {
continue;
}
@ -942,7 +942,7 @@ class Forge
} else {
$field['null'] = ' NOT ' . $this->null;
}
} elseif ($createTable === true) {
} elseif ($createTable) {
$field['null'] = ' NOT ' . $this->null;
}
@ -1085,7 +1085,7 @@ class Forge
}
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";
@ -1108,10 +1108,12 @@ class Forge
$fk = $this->foreignKeys;
if ($this->fields === []) {
$this->fields = array_flip(array_map(
static fn ($columnName) => $columnName->name,
$this->db->getFieldData($this->db->DBPrefix . $table)
));
$fieldData = $this->db->getFieldData($this->db->DBPrefix . $table);
$this->fields = array_combine(
array_map(static fn ($columnName) => $columnName->name, $fieldData),
array_fill(0, count($fieldData), [])
);
}
$fields = $this->fields;
@ -1229,7 +1231,7 @@ class Forge
$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";

View File

@ -45,7 +45,7 @@ abstract class Migration
{
if (isset($this->DBGroup)) {
$this->forge = Database::forge($this->DBGroup);
} elseif ($forge !== null) {
} elseif ($forge instanceof Forge) {
$this->forge = $forge;
} else {
$this->forge = Database::forge(config(Database::class)->defaultGroup);

View File

@ -19,7 +19,6 @@ use CodeIgniter\Exceptions\ConfigException;
use CodeIgniter\I18n\Time;
use Config\Database;
use Config\Migrations as MigrationsConfig;
use Config\Services;
use RuntimeException;
use stdClass;
@ -390,7 +389,7 @@ class MigrationRunner
*/
public function findMigrations(): array
{
$namespaces = $this->namespace ? [$this->namespace] : array_keys(Services::autoloader()->getNamespace());
$namespaces = $this->namespace !== null ? [$this->namespace] : array_keys(service('autoloader')->getNamespace());
$migrations = [];
foreach ($namespaces as $namespace) {
@ -415,7 +414,7 @@ class MigrationRunner
public function findNamespaceMigrations(string $namespace): array
{
$migrations = [];
$locator = Services::locator(true);
$locator = service('locator', true);
if (! empty($this->path)) {
helper('filesystem');
@ -451,11 +450,11 @@ class MigrationRunner
$filename = basename($path, '.php');
if (! preg_match($this->regex, $filename)) {
if (preg_match($this->regex, $filename) !== 1) {
return false;
}
$locator = Services::locator(true);
$locator = service('locator', true);
$migration = new stdClass();
@ -525,7 +524,7 @@ class MigrationRunner
{
preg_match($this->regex, $migration, $matches);
return count($matches) ? $matches[1] : '0';
return $matches !== [] ? $matches[1] : '0';
}
/**
@ -540,7 +539,7 @@ class MigrationRunner
{
preg_match($this->regex, $migration, $matches);
return count($matches) ? $matches[2] : '';
return $matches !== [] ? $matches[2] : '';
}
/**
@ -646,7 +645,7 @@ class MigrationRunner
}
// If a namespace was specified then use it
if ($this->namespace) {
if ($this->namespace !== null) {
$builder->where('namespace', $this->namespace);
}
@ -701,7 +700,7 @@ class MigrationRunner
->get()
->getResultObject();
$batch = is_array($batch) && count($batch)
$batch = is_array($batch) && $batch !== []
? end($batch)->batch
: 0;
@ -726,7 +725,7 @@ class MigrationRunner
->get()
->getResultObject();
return count($migration) ? $migration[0]->version : '0';
return $migration !== [] ? $migration[0]->version : '0';
}
/**

View File

@ -57,7 +57,7 @@ class Connection extends BaseConnection
/**
* MySQLi object
*
* Has to be preserved without being assigned to $conn_id.
* Has to be preserved without being assigned to $connId.
*
* @var false|mysqli
*/
@ -96,7 +96,7 @@ class Connection extends BaseConnection
$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 = '';
}
@ -193,7 +193,7 @@ class Connection extends BaseConnection
$clientFlags
)) {
// Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails
if (($clientFlags & MYSQLI_CLIENT_SSL) && version_compare($this->mysqli->client_info, 'mysqlnd 5.7.3', '<=')
if (($clientFlags & MYSQLI_CLIENT_SSL) !== 0 && version_compare($this->mysqli->client_info, 'mysqlnd 5.7.3', '<=')
&& empty($this->mysqli->query("SHOW STATUS LIKE 'ssl_cipher'")->fetch_object()->Value)
) {
$this->mysqli->close();
@ -297,7 +297,7 @@ class Connection extends BaseConnection
/**
* Executes the query against the database.
*
* @return false|mysqli_result;
* @return false|mysqli_result
*/
protected function execute(string $sql)
{
@ -395,11 +395,11 @@ class Connection extends BaseConnection
{
$sql = 'SHOW TABLES FROM ' . $this->escapeIdentifier($this->database);
if ($tableName !== null) {
if ((string) $tableName !== '') {
return $sql . ' LIKE ' . $this->escape($tableName);
}
if ($prefixLimit !== false && $this->DBPrefix !== '') {
if ($prefixLimit && $this->DBPrefix !== '') {
return $sql . " LIKE '" . $this->escapeLikeStringDirect($this->DBPrefix) . "%'";
}
@ -462,7 +462,9 @@ class Connection extends BaseConnection
throw new DatabaseException(lang('Database.failGetIndexData'));
}
if (! $indexes = $query->getResultArray()) {
$indexes = $query->getResultArray();
if ($indexes === []) {
return [];
}

View File

@ -116,11 +116,11 @@ class Forge extends BaseForge
}
}
if ($this->db->charset !== '' && ! strpos($sql, 'CHARACTER SET') && ! strpos($sql, 'CHARSET')) {
if ($this->db->charset !== '' && ! str_contains($sql, 'CHARACTER SET') && ! str_contains($sql, 'CHARSET')) {
$sql .= ' DEFAULT CHARACTER SET = ' . $this->db->escapeString($this->db->charset);
}
if ($this->db->DBCollat !== '' && ! strpos($sql, 'COLLATE')) {
if ($this->db->DBCollat !== '' && ! str_contains($sql, 'COLLATE')) {
$sql .= ' COLLATE = ' . $this->db->escapeString($this->db->DBCollat);
}
@ -222,7 +222,7 @@ class Forge extends BaseForge
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'])) . ')';

View File

@ -66,15 +66,19 @@ class PreparedQuery extends BasePreparedQuery
throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.');
}
// First off -bind the parameters
$bindTypes = '';
// First off - bind the parameters
$bindTypes = '';
$binaryData = [];
// Determine the type string
foreach ($data as $item) {
foreach ($data as $key => $item) {
if (is_int($item)) {
$bindTypes .= 'i';
} elseif (is_numeric($item)) {
$bindTypes .= 'd';
} elseif (is_string($item) && $this->isBinary($item)) {
$bindTypes .= 'b';
$binaryData[$key] = $item;
} else {
$bindTypes .= 's';
}
@ -83,6 +87,11 @@ class PreparedQuery extends BasePreparedQuery
// Bind it
$this->statement->bind_param($bindTypes, ...$data);
// Stream binary data
foreach ($binaryData as $key => $value) {
$this->statement->send_long_data($key, $value);
}
try {
return $this->statement->execute();
} catch (mysqli_sql_exception $e) {

View File

@ -109,12 +109,12 @@ class Builder extends BaseBuilder
{
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '"'), $keys);
$uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
$uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY') && $hasAllFields;
});
$replaceableFields = array_filter($keys, static function ($columnName) use ($uniqueIndexes) {
$replaceableFields = array_filter($keys, static function ($columnName) use ($uniqueIndexes): bool {
foreach ($uniqueIndexes as $index) {
if (in_array(trim($columnName, '"'), $index->fields, true)) {
return false;
@ -344,7 +344,7 @@ class Builder extends BaseBuilder
if (empty($constraints)) {
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '"'), $keys);
$uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
$uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields;

View File

@ -274,7 +274,7 @@ class Connection extends BaseConnection
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);
}

View File

@ -135,7 +135,7 @@ class Forge extends BaseForge
$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 @@ class Forge extends BaseForge
{
$sql = parent::_dropTable($table, $ifExists, $cascade);
if ($sql !== true && $cascade === true) {
if ($sql !== true && $cascade) {
$sql .= ' CASCADE CONSTRAINTS PURGE';
} elseif ($sql !== true) {
$sql .= ' PURGE';

View File

@ -16,6 +16,7 @@ namespace CodeIgniter\Database\OCI8;
use BadMethodCallException;
use CodeIgniter\Database\BasePreparedQuery;
use CodeIgniter\Database\Exceptions\DatabaseException;
use OCILob;
/**
* Prepared query for OCI8
@ -73,12 +74,24 @@ class PreparedQuery extends BasePreparedQuery
throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.');
}
$binaryData = null;
foreach (array_keys($data) as $key) {
oci_bind_by_name($this->statement, ':' . $key, $data[$key]);
if (is_string($data[$key]) && $this->isBinary($data[$key])) {
$binaryData = oci_new_descriptor($this->db->connID, OCI_D_LOB);
$binaryData->writeTemporary($data[$key], OCI_TEMP_BLOB);
oci_bind_by_name($this->statement, ':' . $key, $binaryData, -1, OCI_B_BLOB);
} else {
oci_bind_by_name($this->statement, ':' . $key, $data[$key]);
}
}
$result = oci_execute($this->statement, $this->db->commitMode);
if ($binaryData instanceof OCILob) {
$binaryData->free();
}
if ($result && $this->lastInsertTableName !== '') {
$this->db->lastInsertedTableName = $this->lastInsertTableName;
}
@ -113,7 +126,7 @@ class PreparedQuery extends BasePreparedQuery
// Track our current value
$count = 0;
return preg_replace_callback('/\?/', static function ($matches) use (&$count) {
return preg_replace_callback('/\?/', static function ($matches) use (&$count): string {
return ':' . ($count++);
}, $sql);
}

View File

@ -293,7 +293,7 @@ class Builder extends BaseBuilder
*/
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}:";
}
@ -368,7 +368,7 @@ class Builder extends BaseBuilder
$sql .= 'WHERE ' . implode(
' AND ',
array_map(
static function ($key, $value) use ($table, $alias, $that) {
static function ($key, $value) use ($table, $alias, $that): string|RawSql {
if ($value instanceof RawSql && is_string($key)) {
return $table . '.' . $key . ' = ' . $value;
}
@ -463,7 +463,7 @@ class Builder extends BaseBuilder
$constraints = $this->QBOptions['constraints'] ?? [];
if (empty($constraints)) {
$allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
$allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'UNIQUE' || $index->type === 'PRIMARY') && $hasAllFields;
@ -575,7 +575,7 @@ class Builder extends BaseBuilder
$sql .= 'WHERE ' . implode(
' AND ',
array_map(
static function ($key, $value) use ($table, $alias, $that) {
static function ($key, $value) use ($table, $alias, $that): RawSql|string {
if ($value instanceof RawSql) {
return $value;
}

View File

@ -74,11 +74,11 @@ class Connection extends BaseConnection
$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
) {
@ -149,8 +149,9 @@ class Connection extends BaseConnection
*/
public function reconnect()
{
if (pg_ping($this->connID) === false) {
$this->connID = false;
if ($this->connID === false || pg_ping($this->connID) === false) {
$this->close();
$this->initialize();
}
}
@ -289,7 +290,7 @@ class Connection extends BaseConnection
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);
@ -462,7 +463,7 @@ class Connection extends BaseConnection
{
return [
'code' => '',
'message' => pg_last_error($this->connID) ?: '',
'message' => pg_last_error($this->connID),
];
}

View File

@ -118,7 +118,7 @@ class Forge extends BaseForge
$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'])
@ -173,6 +173,10 @@ class Forge extends BaseForge
$attributes['TYPE'] = 'TIMESTAMP';
break;
case 'BLOB':
$attributes['TYPE'] = 'BYTEA';
break;
default:
break;
}
@ -195,7 +199,7 @@ class Forge extends BaseForge
{
$sql = parent::_dropTable($table, $ifExists, $cascade);
if ($cascade === true) {
if ($cascade) {
$sql .= ' CASCADE';
}

View File

@ -87,6 +87,12 @@ class PreparedQuery extends BasePreparedQuery
throw new BadMethodCallException('You must call prepare before trying to execute a prepared statement.');
}
foreach ($data as &$item) {
if (is_string($item) && $this->isBinary($item)) {
$item = pg_escape_bytea($this->db->connID, $item);
}
}
$this->result = pg_execute($this->db->connID, $this->name, $data);
return (bool) $this->result;
@ -119,7 +125,7 @@ class PreparedQuery extends BasePreparedQuery
// Track our current value
$count = 0;
return preg_replace_callback('/\?/', static function () use (&$count) {
return preg_replace_callback('/\?/', static function () use (&$count): string {
$count++;
return "\${$count}";

View File

@ -518,7 +518,7 @@ class Builder extends BaseBuilder
$query = $query->getRow();
if ($reset === true) {
if ($reset) {
$this->resetSelect();
}
@ -699,7 +699,7 @@ class Builder extends BaseBuilder
if (empty($constraints)) {
$tableIndexes = $this->db->getIndexData($table);
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return $index->type === 'PRIMARY' && $hasAllFields;
@ -707,7 +707,7 @@ class Builder extends BaseBuilder
// if no primary found then look for unique - since indexes have no order
if ($uniqueIndexes === []) {
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames) {
$uniqueIndexes = array_filter($tableIndexes, static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return $index->type === 'UNIQUE' && $hasAllFields;

View File

@ -215,7 +215,7 @@ class Connection extends BaseConnection
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);
}
@ -368,7 +368,11 @@ class Connection extends BaseConnection
$retVal[$i]->max_length = $query[$i]->CHARACTER_MAXIMUM_LENGTH > 0
? $query[$i]->CHARACTER_MAXIMUM_LENGTH
: $query[$i]->NUMERIC_PRECISION;
: (
$query[$i]->CHARACTER_MAXIMUM_LENGTH === -1
? 'max'
: $query[$i]->NUMERIC_PRECISION
);
$retVal[$i]->nullable = $query[$i]->IS_NULLABLE !== 'NO';
$retVal[$i]->default = $query[$i]->COLUMN_DEFAULT;

View File

@ -212,10 +212,10 @@ class Forge extends BaseForge
$sql = <<<SQL
SELECT name
FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID('{$fullTable}')
AND PARENT_COLUMN_ID IN (
SELECT column_id FROM sys.columns WHERE NAME IN ({$fields}) AND object_id = OBJECT_ID(N'{$fullTable}')
FROM sys.default_constraints
WHERE parent_object_id = OBJECT_ID('{$fullTable}')
AND parent_column_id IN (
SELECT column_id FROM sys.columns WHERE name IN ({$fields}) AND object_id = OBJECT_ID(N'{$fullTable}')
)
SQL;
@ -263,7 +263,7 @@ class Forge extends BaseForge
$nullable = false;
}
$sqls[] = $sql . ' ALTER COLUMN ' . $this->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 '
@ -397,6 +397,11 @@ class Forge extends BaseForge
$attributes['TYPE'] = 'BIT';
break;
case 'BLOB':
$attributes['TYPE'] = 'VARBINARY';
$attributes['CONSTRAINT'] ??= 'MAX';
break;
default:
break;
}

View File

@ -59,7 +59,7 @@ class PreparedQuery extends BasePreparedQuery
// Prepare parameters for the query
$queryString = $this->getQueryString();
$parameters = $this->parameterize($queryString);
$parameters = $this->parameterize($queryString, $options);
// Prepare the query
$this->statement = sqlsrv_prepare($this->db->connID, $sql, $parameters);
@ -120,8 +120,10 @@ class PreparedQuery extends BasePreparedQuery
/**
* Handle parameters.
*
* @param array<int, mixed> $options
*/
protected function parameterize(string $queryString): array
protected function parameterize(string $queryString, array $options): array
{
$numberOfVariables = substr_count($queryString, '?');
@ -129,7 +131,11 @@ class PreparedQuery extends BasePreparedQuery
for ($c = 0; $c < $numberOfVariables; $c++) {
$this->parameters[$c] = null;
$params[] = &$this->parameters[$c];
if (isset($options[$c])) {
$params[] = [&$this->parameters[$c], SQLSRV_PARAM_IN, $options[$c]];
} else {
$params[] = &$this->parameters[$c];
}
}
return $params;

View File

@ -145,7 +145,7 @@ class Builder extends BaseBuilder
if (empty($constraints)) {
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '`'), $keys);
$allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
$allIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames): bool {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);
return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields;

View File

@ -89,7 +89,7 @@ class Connection extends BaseConnection
$this->database = WRITEPATH . $this->database;
}
$sqlite = (! $this->password)
$sqlite = (! isset($this->password) || $this->password !== '')
? new SQLite3($this->database)
: new SQLite3($this->database, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, $this->password);
@ -194,7 +194,7 @@ class Connection extends BaseConnection
*/
protected function _listTables(bool $prefixLimit = false, ?string $tableName = null): string
{
if ($tableName !== null) {
if ((string) $tableName !== '') {
return 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''
. ' AND "NAME" NOT LIKE \'sqlite!_%\' ESCAPE \'!\''
. ' AND "NAME" LIKE ' . $this->escape($tableName);
@ -202,7 +202,7 @@ class Connection extends BaseConnection
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)
: '');
}
@ -359,7 +359,7 @@ class Connection extends BaseConnection
*/
protected function _foreignKeyData(string $table): array
{
if ($this->supportsForeignKeys() !== true) {
if (! $this->supportsForeignKeys()) {
return [];
}

View File

@ -75,6 +75,8 @@ class PreparedQuery extends BasePreparedQuery
$bindType = SQLITE3_INTEGER;
} elseif (is_float($item)) {
$bindType = SQLITE3_FLOAT;
} elseif (is_string($item) && $this->isBinary($item)) {
$bindType = SQLITE3_BLOB;
} else {
$bindType = SQLITE3_TEXT;
}

View File

@ -105,7 +105,7 @@ class Seeder
*/
public static function faker(): ?Generator
{
if (self::$faker === null && class_exists(Factory::class)) {
if (! self::$faker instanceof Generator && class_exists(Factory::class)) {
self::$faker = Factory::create();
}

View File

@ -22,7 +22,6 @@ use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Exceptions as ExceptionsConfig;
use Config\Paths;
use Config\Services;
use ErrorException;
use Psr\Log\LogLevel;
use Throwable;
@ -126,7 +125,7 @@ class Exceptions
[$statusCode, $exitCode] = $this->determineCodes($exception);
$this->request = Services::request();
$this->request = service('request');
if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) {
$uri = $this->request->getPath() === '' ? '/' : $this->request->getPath();
@ -155,7 +154,7 @@ class Exceptions
}
}
$this->response = Services::response();
$this->response = service('response');
if (method_exists($this->config, 'handler')) {
// Use new ExceptionHandler

View File

@ -25,7 +25,6 @@ use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\I18n\Time;
use Config\Services;
use Config\Toolbar as ToolbarConfig;
use Kint\Kint;
@ -386,7 +385,7 @@ class Toolbar
return;
}
$toolbar = Services::toolbar(config(ToolbarConfig::class));
$toolbar = service('toolbar', config(ToolbarConfig::class));
$stats = $app->getPerformanceStats();
$data = $toolbar->run(
$stats['startTime'],
@ -529,7 +528,7 @@ class Toolbar
case 'html':
$data['styles'] = [];
extract($data);
$parser = Services::parser($this->config->viewsPath, null, false);
$parser = service('parser', $this->config->viewsPath, null, false);
ob_start();
include $this->config->viewsPath . 'toolbar.tpl.php';
$output = ob_get_clean();

View File

@ -148,7 +148,7 @@ class Database extends BaseCollector
public function display(): array
{
$data = [];
$data['queries'] = array_map(static function (array $query) {
$data['queries'] = array_map(static function (array $query): array {
$isDuplicate = $query['duplicate'] === true;
$firstNonSystemLine = '';

View File

@ -13,8 +13,6 @@ declare(strict_types=1);
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\Services;
/**
* Loags collector
*/
@ -92,6 +90,6 @@ class Logs extends BaseCollector
return $this->data;
}
return $this->data = Services::logger(true)->logCache ?? [];
return $this->data = service('logger', true)->logCache ?? [];
}
}

View File

@ -14,7 +14,6 @@ declare(strict_types=1);
namespace CodeIgniter\Debug\Toolbar\Collectors;
use CodeIgniter\Router\DefinedRouteCollector;
use Config\Services;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
@ -74,8 +73,8 @@ class Routes extends BaseCollector
*/
public function display(): array
{
$rawRoutes = Services::routes(true);
$router = Services::router(null, null, true);
$rawRoutes = service('routes', true);
$router = service('router', null, null, true);
// Get our parameters
// Closure routes
@ -153,7 +152,7 @@ class Routes extends BaseCollector
*/
public function getBadgeValue(): int
{
$rawRoutes = Services::routes(true);
$rawRoutes = service('routes', true);
return count($rawRoutes->getRoutes());
}

View File

@ -13,8 +13,6 @@ declare(strict_types=1);
namespace CodeIgniter\Debug\Toolbar\Collectors;
use Config\Services;
/**
* Timers collector
*/
@ -52,7 +50,7 @@ class Timers extends BaseCollector
{
$data = [];
$benchmark = Services::timer(true);
$benchmark = service('timer', true);
$rows = $benchmark->getTimers(6);
foreach ($rows as $name => $info) {

View File

@ -485,7 +485,7 @@ class Email
if ($this->validate) {
$this->validateEmail($this->stringToArray($from));
if ($returnPath) {
if ($returnPath !== null) {
$this->validateEmail($this->stringToArray($returnPath));
}
}
@ -495,7 +495,7 @@ class Email
if ($name !== '') {
// only use Q encoding if there are characters that would require it
if (! preg_match('/[\200-\377]/', $name)) {
if (preg_match('/[\200-\377]/', $name) !== 1) {
$name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"';
} else {
$name = $this->prepQEncoding($name);
@ -532,7 +532,7 @@ class Email
$this->tmpArchive['replyName'] = $name;
// only use Q encoding if there are characters that would require it
if (! preg_match('/[\200-\377]/', $name)) {
if (preg_match('/[\200-\377]/', $name) !== 1) {
$name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"';
} else {
$name = $this->prepQEncoding($name);
@ -1233,7 +1233,9 @@ class Email
$this->headerStr .= $hdr;
}
static::strlen($body) && $body .= $this->newline . $this->newline;
if (static::strlen($body) > 0) {
$body .= $this->newline . $this->newline;
}
$body .= $this->getMimeMessage() . $this->newline . $this->newline
. '--' . $lastBoundary . $this->newline

View File

@ -82,7 +82,7 @@ class OpenSSLHandler extends BaseHandler
public function encrypt($data, $params = null)
{
// Allow key override
if ($params) {
if ($params !== null) {
$this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params;
}
@ -118,7 +118,7 @@ class OpenSSLHandler extends BaseHandler
public function decrypt($data, $params = null)
{
// Allow key override
if ($params) {
if ($params !== null) {
$this->key = is_array($params) && isset($params['key']) ? $params['key'] : $params;
}

View File

@ -26,7 +26,7 @@ class SodiumHandler extends BaseHandler
/**
* Starter key
*
* @var string
* @var string|null Null is used for buffer cleanup.
*/
protected $key = '';

View File

@ -84,7 +84,7 @@ class Events
$files = service('locator')->search('Config/Events.php');
}
$files = array_filter(array_map(static function (string $file) {
$files = array_filter(array_map(static function (string $file): false|string {
if (is_file($file)) {
return realpath($file) ?: $file;
}

View File

@ -47,6 +47,8 @@ class DownloadException extends RuntimeException implements ExceptionInterface
}
/**
* @deprecated Since v4.5.6
*
* @return static
*/
public static function forCannotSetCache()

View File

@ -13,7 +13,6 @@ declare(strict_types=1);
namespace CodeIgniter\Exceptions;
use Config\Services;
use OutOfBoundsException;
class PageNotFoundException extends OutOfBoundsException implements ExceptionInterface, HTTPExceptionInterface
@ -78,7 +77,7 @@ class PageNotFoundException extends OutOfBoundsException implements ExceptionInt
*/
private static function lang(string $line, array $args = []): string
{
$lang = Services::language(null, false);
$lang = service('language', null, false);
return $lang->getLine($line, $args);
}

View File

@ -557,7 +557,7 @@ class Filters
*/
public function getArguments(?string $key = null)
{
return $key === null ? $this->arguments : $this->arguments[$key];
return ((string) $key === '') ? $this->arguments : $this->arguments[$key];
}
// --------------------------------------------------------------------
@ -674,7 +674,7 @@ class Filters
*/
protected function processFilters(?string $uri = null)
{
if (! isset($this->config->filters) || ! $this->config->filters) {
if (! isset($this->config->filters) || $this->config->filters === []) {
return;
}

View File

@ -17,7 +17,6 @@ use CodeIgniter\Honeypot\Exceptions\HoneypotException;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Services;
/**
* Honeypot filter
@ -40,7 +39,7 @@ class Honeypot implements FilterInterface
return;
}
if (Services::honeypot()->hasContent($request)) {
if (service('honeypot')->hasContent($request)) {
throw HoneypotException::isBot();
}
}

View File

@ -95,9 +95,7 @@ class CLIRequest extends Request
*/
public function getPath(): string
{
$path = implode('/', $this->segments);
return ($path === '') ? '' : $path;
return implode('/', $this->segments);
}
/**

View File

@ -389,7 +389,7 @@ class CURLRequest extends OutgoingRequest
$output = substr($output, strpos($output, $breakString) + 4);
}
if (str_starts_with($output, 'HTTP/1.1 200 Connection established')) {
if (preg_match('/HTTP\/\d\.\d 200 Connection established/i', $output)) {
$output = substr($output, strpos($output, $breakString) + 4);
}

View File

@ -356,9 +356,9 @@ class ContentSecurityPolicy
}
/**
* Adds a new base_uri value. Can be either a URI class or a simple string.
* Adds a new baseURI value. Can be either a URI class or a simple string.
*
* base_uri restricts the URLs that can appear in a page's <base> element.
* baseURI restricts the URLs that can appear in a page's <base> element.
*
* @see http://www.w3.org/TR/CSP/#directive-base-uri
*
@ -713,7 +713,7 @@ class ContentSecurityPolicy
$pattern = '/(' . preg_quote($this->styleNonceTag, '/')
. '|' . preg_quote($this->scriptNonceTag, '/') . ')/';
$body = preg_replace_callback($pattern, function ($match) {
$body = preg_replace_callback($pattern, function ($match): string {
$nonce = $match[0] === $this->styleNonceTag ? $this->getStyleNonce() : $this->getScriptNonce();
return "nonce=\"{$nonce}\"";

View File

@ -85,7 +85,7 @@ class DownloadResponse extends Response
*/
public function setBinary(string $binary)
{
if ($this->file !== null) {
if ($this->file instanceof File) {
throw DownloadException::forCannotSetBinary();
}
@ -142,7 +142,7 @@ class DownloadResponse extends Response
$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;
}
@ -242,16 +242,6 @@ class DownloadResponse extends Response
return $this;
}
/**
* Disables cache configuration.
*
* @throws DownloadException
*/
public function setCache(array $options = [])
{
throw DownloadException::forCannotSetCache();
}
/**
* {@inheritDoc}
*
@ -290,10 +280,8 @@ class DownloadResponse extends Response
$this->setHeader('Content-Disposition', $this->getContentDisposition());
}
$this->setHeader('Expires-Disposition', '0');
$this->setHeader('Content-Transfer-Encoding', 'binary');
$this->setHeader('Content-Length', (string) $this->getContentLength());
$this->noCache();
}
/**
@ -309,7 +297,7 @@ class DownloadResponse extends Response
return $this->sendBodyByBinary();
}
if ($this->file !== null) {
if ($this->file instanceof File) {
return $this->sendBodyByFilePath();
}

View File

@ -69,7 +69,7 @@ class RedirectException extends Exception implements ResponsableInterface, HTTPE
public function getResponse(): ResponseInterface
{
if (null === $this->response) {
if (! $this->response instanceof ResponseInterface) {
$this->response = service('response')
->redirect(base_url($this->getMessage()), 'auto', $this->getCode());
}

View File

@ -253,7 +253,7 @@ class FileCollection
{
$currentIndex = array_shift($index);
if (isset($currentIndex) && is_array($index) && $index && is_array($value[$currentIndex]) && $value[$currentIndex]) {
if (isset($currentIndex) && is_array($index) && $index !== [] && array_key_exists($currentIndex, $value) && is_array($value[$currentIndex])) {
return $this->getValueDotNotationSyntax($index, $value[$currentIndex]);
}

View File

@ -302,7 +302,9 @@ class UploadedFile extends File implements UploadedFileInterface
*/
public function getExtension(): string
{
return $this->guessExtension() ?: $this->getClientExtension();
$guessExtension = $this->guessExtension();
return $guessExtension !== '' ? $guessExtension : $this->getClientExtension();
}
/**

View File

@ -39,7 +39,7 @@ class Negotiate
*/
public function __construct(?RequestInterface $request = null)
{
if ($request !== null) {
if ($request instanceof RequestInterface) {
assert($request instanceof IncomingRequest);
$this->request = $request;
@ -233,7 +233,7 @@ class Negotiate
}
// Sort to get the highest results first
usort($results, static function ($a, $b) {
usort($results, static function ($a, $b): int {
if ($a['q'] === $b['q']) {
$aAst = substr_count($a['value'], '*');
$bAst = substr_count($b['value'], '*');

Some files were not shown because too many files have changed in this diff Show More