From 3a04112ba3a030a78111ad92827fe8f3657a16e4 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 20 Jan 2025 03:16:22 +0800 Subject: [PATCH 01/83] chore: update release process (#9421) --- admin/RELEASE.md | 75 +++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/admin/RELEASE.md b/admin/RELEASE.md index 9ed91e55c183..697af85ff712 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -3,6 +3,7 @@ > Documentation guide based on the releases of `4.0.5` and `4.1.0` on January 31, 2021. > > Updated for `4.5.0` on April 7, 2024. +> Updated for `4.6.0` on January 19, 2025. > > -MGatner, kenjis @@ -33,10 +34,12 @@ git push upstream HEAD If you release a new minor version. -* [ ] Create PR to merge `4.y` into `develop` and merge it +* [ ] Create PR to merge `4.y` into `develop`: + * Title: `4.y.0 Merge code` + * Description: blank * [ ] Rename the current minor version (e.g., `4.5`) in Setting > Branches > - "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) + "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 @@ -60,7 +63,7 @@ Work off direct clones of the repos so the release branches persist for a time. ## Changelog -When generating the changelog each Pull Request to be included must have one of +When generating the changelog, each pull request to be included must have one of the following [labels](https://github.com/codeigniter4/CodeIgniter4/labels): - **bug** ... PRs that fix bugs - **enhancement** ... PRs to improve existing functionalities @@ -72,11 +75,11 @@ PRs with breaking changes must have the following additional label: ### Generate Changelog -To auto-generate, navigate to the +To auto-generate the changelog, navigate to the [Releases](https://github.com/codeigniter4/CodeIgniter4/releases) page, click the "Draft a new release" button. -* Tag: `v4.x.x` (Create new tag) +* Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish) * Target: `develop` Click the "Generate release notes" button. @@ -85,7 +88,7 @@ Check the resulting content. If there are items in the *Others* section which should be included in the changelog, add a label to the PR and regenerate the changelog. -Copy the resulting content into **CHANGELOG.md** and adjust the format to match +Copy the resulting contents into **CHANGELOG.md** and adjust the format to match the existing content. ## Process @@ -95,23 +98,27 @@ the existing content. > 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 +* [ ] Merge any security advisory PRs in private forks. +* [ ] Add the current version to **CHANGELOG.md** with the contents generated above. * [ ] Update **user_guide_src/source/changelogs/v4.x.x.rst** * Remove the section titles that have no items * [ ] Update **user_guide_src/source/installation/upgrade_4xx.rst** - * [ ] fill in the "All Changes" section, and add it to **upgrade_4xx.rst** - * git diff --name-status origin/master -- . ':!system' ':!tests' ':!user_guide_src' - * Note: `tests/` is not used for distribution repos. See `admin/starter/tests/` + * [ ] fill in the "All Changes" section using the following command, and add it to **upgrade_4xx.rst**: + ``` + git diff --name-status origin/master -- . ':!.github/' ':!admin/' ':!system/' ':!tests/' \ + ':!user_guide_src/' ':!utils/' ':!*.json' ':!*.xml' ':!*.dist' ':!rector.php' \ + ':!phpstan*' ':!psalm*' ':!.php-cs-fixer.*' ':!LICENSE' ':!CHANGELOG.md' + ``` + * Note: `tests/` is not used for distribution repos. See `admin/starter/tests/`. * [ ] Remove the section titles that have no items - * [ ] [Minor version only] Update the "from" version in the title. E.g., `from 4.3.x` → `from 4.3.8` -* [ ] Run `php admin/prepare-release.php 4.x.x` and push to origin + * [ ] [Minor version only] Update the "from" version in the title, (e.g., `from 4.3.x` → `from 4.3.8`). +* [ ] Run `php admin/prepare-release.php 4.x.x` and push to origin. * The above command does the following: * Create a new branch `release-4.x.x` * Update **system/CodeIgniter.php** with the new version number: `const CI_VERSION = '4.x.x';` - * Update **user_guide_src/source/conf.py** with the new `version = '4.x'` (if applicable) - and `release = '4.x.x'` + * Update **user_guide_src/source/conf.py** with the new `version = '4.x'` (if releasing + the minor version) and `release = '4.x.x'`. * Update **user_guide_src/source/changelogs/{version}.rst** * Set the date to format `Release Date: January 31, 2021` * Update **phpdoc.dist.xml** with the new `CodeIgniter v4.x API` @@ -126,15 +133,17 @@ the existing content. Previous version: #xxxx Release Code: TODO New Changelog: TODO - ``` + (plus checklist) -* [ ] Let all tests run, then review and merge the PR + ``` + +* [ ] Let all tests run, then review and merge the PR. * [ ] Create a new PR from `develop` to `master`: * Title: `4.x.x Ready code` * Description: blank * [ ] Merge the PR and wait for all tests. * [ ] Create a new Release: - * Tag: `v4.x.x` (Create new tag) + * Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish) * Target: `master` * Title: `CodeIgniter 4.x.x` * Description: @@ -167,31 +176,31 @@ the existing content. created when v4.3.8 was released. * [ ] Fast-forward `develop` branch to catch the merge commit from `master` ```console - git fetch origin + git fetch upstream git checkout develop - git merge origin/develop - git merge origin/master - git push origin HEAD + git merge upstream/develop + git merge upstream/master + git push upstream HEAD ``` * [ ] Update the next minor version branch `4.y`: ```console - git fetch origin - git checkout 4.y - git merge origin/4.y - git merge origin/develop - git push origin HEAD + git fetch upstream + git switch 4.y + git merge upstream/4.y + git merge upstream/develop + git push upstream HEAD ``` * [ ] [Minor version only] Create the new next minor version branch `4.z`: ```console - git fetch origin + git fetch upstream git switch develop git switch -c 4.z - git push origin HEAD + git push upstream HEAD ``` -* [ ] Request CVEs and Publish any Security Advisories that were resolved from private forks - (note: publishing is restricted to administrators): +* [ ] Request CVEs and publish any security advisories that were resolved from private forks + (note: publishing is restricted to administrators). * [ ] Announce the release on the forums and Slack channel - (note: this forum is restricted to administrators): + (note: this forum is restricted to administrators). * Make a new topic in the "News & Discussion" forums: https://forum.codeigniter.com/forum-2.html * The content is somewhat organic, but should include any major features and From d9686083cd6906e28086ed2dff986a733d963e2c Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 20 Jan 2025 20:32:05 +0800 Subject: [PATCH 02/83] docs: add changelog and upgrade for v4.6.1 (#9425) --- user_guide_src/source/changelogs/index.rst | 1 + user_guide_src/source/changelogs/v4.6.1.rst | 35 ++++++++++++ .../source/installation/upgrade_461.rst | 55 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 4 files changed, 92 insertions(+) create mode 100644 user_guide_src/source/changelogs/v4.6.1.rst create mode 100644 user_guide_src/source/installation/upgrade_461.rst diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index d15b5d11b831..ee417164aa87 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,6 +12,7 @@ See all the changes. .. toctree:: :titlesonly: + v4.6.1 v4.6.0 v4.5.8 v4.5.7 diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst new file mode 100644 index 000000000000..ca3d601c61c0 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -0,0 +1,35 @@ +############# +Version 4.6.1 +############# + +Release Date: Unreleased + +**4.6.1 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 3 + +******** +BREAKING +******** + +*************** +Message Changes +*************** + +******* +Changes +******* + +************ +Deprecations +************ + +********** +Bugs Fixed +********** + +See the repo's +`CHANGELOG.md `_ +for a complete list of bugs fixed. diff --git a/user_guide_src/source/installation/upgrade_461.rst b/user_guide_src/source/installation/upgrade_461.rst new file mode 100644 index 000000000000..0ddfa2e32e45 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_461.rst @@ -0,0 +1,55 @@ +############################# +Upgrading from 4.6.0 to 4.6.1 +############################# + +Please refer to the upgrade instructions corresponding to your installation method. + +- :ref:`Composer Installation App Starter Upgrading ` +- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` +- :ref:`Manual Installation Upgrading ` + +.. contents:: + :local: + :depth: 2 + +********************** +Mandatory File Changes +********************** + +**************** +Breaking Changes +**************** + +********************* +Breaking Enhancements +********************* + +************* +Project Files +************* + +Some files in the **project space** (root, app, public, writable) received updates. Due to +these files being outside of the **system** scope they will not be changed without your intervention. + +.. note:: There are some third-party CodeIgniter modules available to assist + with merging changes to the project space: + `Explore on Packagist `_. + +Content Changes +=============== + +The following files received significant changes (including deprecations or visual adjustments) +and it is recommended that you merge the updated versions with your application: + +Config +------ + +- @TODO + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +- @TODO diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 4e291f8c6f1f..a2125cba81a3 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -16,6 +16,7 @@ See also :doc:`./backward_compatibility_notes`. backward_compatibility_notes + upgrade_461 upgrade_460 upgrade_458 upgrade_457 From 9727f104c8b7d1520e95d816857cd8a6c3f9ab8f Mon Sep 17 00:00:00 2001 From: Nalaka Samarasinghe <30935025+nalakapws@users.noreply.github.com> Date: Wed, 22 Jan 2025 04:06:06 +0530 Subject: [PATCH 03/83] chore: Fix Netbeans IDE related entries in two gitignore files under framework admin dir (#9428) * Fix Netbeans IDE related entries in the framework/admin/starter gitignore file. * Fix Netbeans IDE related entries in the framework/admin/framework gitignore file. --- admin/framework/.gitignore | 18 +++++++++--------- admin/starter/.gitignore | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/admin/framework/.gitignore b/admin/framework/.gitignore index 8071bd3d07f8..e24e7ce497d1 100644 --- a/admin/framework/.gitignore +++ b/admin/framework/.gitignore @@ -100,15 +100,15 @@ _modules/* .idea/ *.iml -# Netbeans -nbproject/ -build/ -nbbuild/ -dist/ -nbdist/ -nbactions.xml -nb-configuration.xml -.nb-gradle/ +# NetBeans +/nbproject/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/nbactions.xml +/nb-configuration.xml +/.nb-gradle/ # Sublime Text *.tmlanguage.cache diff --git a/admin/starter/.gitignore b/admin/starter/.gitignore index 8071bd3d07f8..e24e7ce497d1 100644 --- a/admin/starter/.gitignore +++ b/admin/starter/.gitignore @@ -100,15 +100,15 @@ _modules/* .idea/ *.iml -# Netbeans -nbproject/ -build/ -nbbuild/ -dist/ -nbdist/ -nbactions.xml -nb-configuration.xml -.nb-gradle/ +# NetBeans +/nbproject/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/nbactions.xml +/nb-configuration.xml +/.nb-gradle/ # Sublime Text *.tmlanguage.cache From 909e9b0a1a7c5581e9ce84439d9d68cece871679 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 23 Jan 2025 14:28:25 +1300 Subject: [PATCH 04/83] fix(CURLRequest): multiple header sections after redirects (#9426) * fix: strip out multiple header sections for redirect * test: add test for stripping out multiple redirect header sections * docs: changelog for fixing returning multiple header sections after redirects * Added a non-standard http redirect code test * apply cs-fix for test * Moved redirect header loop to a separate function * Updated changelog to be clearer --- system/HTTP/CURLRequest.php | 30 +++++++++ tests/system/HTTP/CURLRequestTest.php | 68 +++++++++++++++++++++ user_guide_src/source/changelogs/v4.6.1.rst | 2 + 3 files changed, 100 insertions(+) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index e9e2d89d9481..742da9f18d08 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -385,6 +385,10 @@ public function send(string $method, string $url) // Set the string we want to break our response from $breakString = "\r\n\r\n"; + if (isset($this->config['allow_redirects']) && $this->config['allow_redirects'] !== false) { + $output = $this->handleRedirectHeaders($output, $breakString); + } + while (str_starts_with($output, 'HTTP/1.1 100 Continue')) { $output = substr($output, strpos($output, $breakString) + 4); } @@ -713,4 +717,30 @@ protected function sendRequest(array $curlOptions = []): string return $output; } + + private function handleRedirectHeaders(string $output, string $breakString): string + { + // Strip out multiple redirect header sections + while (preg_match('/^HTTP\/\d(?:\.\d)? 3\d\d/', $output)) { + $breakStringPos = strpos($output, $breakString); + $redirectHeaderSection = substr($output, 0, $breakStringPos); + $redirectHeaders = explode("\n", $redirectHeaderSection); + $locationHeaderFound = false; + + foreach ($redirectHeaders as $header) { + if (str_starts_with(strtolower($header), 'location:')) { + $locationHeaderFound = true; + break; + } + } + + if ($locationHeaderFound) { + $output = substr($output, $breakStringPos + 4); + } else { + break; + } + } + + return $output; + } } diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 138b7eaa7cb2..94c2b7dbbb24 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -1313,4 +1313,72 @@ public function testHTTPversionAsString(): void $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options); $this->assertSame(CURL_HTTP_VERSION_2_0, $options[CURLOPT_HTTP_VERSION]); } + + public function testRemoveMultipleRedirectHeaderSections(): void + { + $testBody = 'Hello world'; + + $output = "HTTP/1.1 301 Moved Permanently +content-type: text/html; charset=utf-8 +content-length: 211 +location: http://example.com +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\nHTTP/1.1 302 Found +content-type: text/html; charset=utf-8 +content-length: 211 +location: http://example.com +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\nHTTP/1.1 399 Custom Redirect +content-type: text/html; charset=utf-8 +content-length: 211 +location: http://example.com +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\nHTTP/2 308 +content-type: text/html; charset=utf-8 +content-length: 211 +location: http://example.com +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\nHTTP/1.1 200 OK +content-type: text/html; charset=utf-8 +content-length: 211 +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\n" . $testBody; + + $this->request->setOutput($output); + + $response = $this->request->request('GET', 'http://example.com', [ + 'allow_redirects' => true, + ]); + + $this->assertSame(200, $response->getStatusCode()); + + $this->assertSame($testBody, $response->getBody()); + } + + public function testNotRemoveMultipleRedirectHeaderSectionsWithoutLocationHeader(): void + { + $testBody = 'Hello world'; + + $output = "HTTP/1.1 301 Moved Permanently +content-type: text/html; charset=utf-8 +content-length: 211 +date: Mon, 20 Jan 2025 11:46:34 GMT +server: nginx/1.21.6 +vary: Origin\r\n\r\n" . $testBody; + + $this->request->setOutput($output); + + $response = $this->request->request('GET', 'http://example.com', [ + 'allow_redirects' => true, + ]); + + $this->assertSame(301, $response->getStatusCode()); + + $this->assertSame($testBody, $response->getBody()); + } } diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index ca3d601c61c0..c230ee6d32b9 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -30,6 +30,8 @@ Deprecations Bugs Fixed ********** +- **CURLRequest:** Fixed an issue where multiple header sections appeared in the CURL response body during multiple redirects from the target server. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. From 897980a1c82587ba1a9109565954430c19bcc48c Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 24 Jan 2025 23:13:59 +0800 Subject: [PATCH 05/83] chore: update phpstan baseline count of errors --- utils/phpstan-baseline/argument.type.neon | 7 +------ utils/phpstan-baseline/assign.propertyType.neon | 2 +- .../phpstan-baseline/codeigniter.cacheHandlerInstance.neon | 2 +- utils/phpstan-baseline/codeigniter.getReassignArray.neon | 2 +- utils/phpstan-baseline/codeigniter.superglobalAccess.neon | 2 +- .../codeigniter.superglobalAccessAssign.neon | 2 +- .../phpstan-baseline/codeigniter.unknownServiceMethod.neon | 2 +- utils/phpstan-baseline/empty.notAllowed.neon | 2 +- utils/phpstan-baseline/method.alreadyNarrowedType.neon | 2 +- utils/phpstan-baseline/method.childReturnType.neon | 2 +- utils/phpstan-baseline/method.notFound.neon | 2 +- utils/phpstan-baseline/missingType.iterableValue.neon | 2 +- utils/phpstan-baseline/missingType.property.neon | 2 +- utils/phpstan-baseline/nullCoalesce.property.neon | 2 +- utils/phpstan-baseline/offsetAccess.notFound.neon | 2 +- utils/phpstan-baseline/property.nonObject.neon | 2 +- utils/phpstan-baseline/property.notFound.neon | 2 +- utils/phpstan-baseline/property.protected.neon | 2 +- .../property.readOnlyByPhpDocAssignOutOfClass.neon | 2 +- .../property.readOnlyByPhpDocDefaultValue.neon | 2 +- utils/phpstan-baseline/staticMethod.notFound.neon | 2 +- utils/phpstan-baseline/ternary.shortNotAllowed.neon | 2 +- utils/phpstan-baseline/varTag.type.neon | 2 +- utils/phpstan-baseline/variable.undefined.neon | 2 +- 24 files changed, 24 insertions(+), 29 deletions(-) diff --git a/utils/phpstan-baseline/argument.type.neon b/utils/phpstan-baseline/argument.type.neon index 6e4bc79f0f9c..2f2e9f3baa38 100644 --- a/utils/phpstan-baseline/argument.type.neon +++ b/utils/phpstan-baseline/argument.type.neon @@ -1,4 +1,4 @@ -# total 73 errors +# total 147 errors parameters: ignoreErrors: @@ -122,11 +122,6 @@ parameters: count: 1 path: ../../tests/system/Database/Live/SQLite3/AlterTableTest.php - - - message: '#^Parameter \#2 \$forge of class CodeIgniter\\Database\\SQLite3\\Table constructor expects CodeIgniter\\Database\\SQLite3\\Forge, CodeIgniter\\Database\\Forge given\.$#' - count: 1 - path: ../../tests/system/Database/Live/SQLite3/AlterTableTest.php - - message: '#^Parameter \#1 \$set of method CodeIgniter\\Database\\BaseBuilder\:\:updateFields\(\) expects list\\|string, array\{0\: ''country'', updated_at\: CodeIgniter\\Database\\RawSql\} given\.$#' count: 2 diff --git a/utils/phpstan-baseline/assign.propertyType.neon b/utils/phpstan-baseline/assign.propertyType.neon index 4d21e95d87b1..76c1a55f3756 100644 --- a/utils/phpstan-baseline/assign.propertyType.neon +++ b/utils/phpstan-baseline/assign.propertyType.neon @@ -1,4 +1,4 @@ -# total 20 errors +# total 29 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/codeigniter.cacheHandlerInstance.neon b/utils/phpstan-baseline/codeigniter.cacheHandlerInstance.neon index 7ec98d64cc7a..f9225bcfb5dd 100644 --- a/utils/phpstan-baseline/codeigniter.cacheHandlerInstance.neon +++ b/utils/phpstan-baseline/codeigniter.cacheHandlerInstance.neon @@ -1,4 +1,4 @@ -# total 6 errors +# total 14 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/codeigniter.getReassignArray.neon b/utils/phpstan-baseline/codeigniter.getReassignArray.neon index ae2b6c2cb27f..e02f1107c29c 100644 --- a/utils/phpstan-baseline/codeigniter.getReassignArray.neon +++ b/utils/phpstan-baseline/codeigniter.getReassignArray.neon @@ -1,4 +1,4 @@ -# total 13 errors +# total 22 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/codeigniter.superglobalAccess.neon b/utils/phpstan-baseline/codeigniter.superglobalAccess.neon index 4610e9fa2258..a12ee94e1fff 100644 --- a/utils/phpstan-baseline/codeigniter.superglobalAccess.neon +++ b/utils/phpstan-baseline/codeigniter.superglobalAccess.neon @@ -1,4 +1,4 @@ -# total 53 errors +# total 83 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon index 7071f868984a..365455768963 100644 --- a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon +++ b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon @@ -1,4 +1,4 @@ -# total 260 errors +# total 582 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/codeigniter.unknownServiceMethod.neon b/utils/phpstan-baseline/codeigniter.unknownServiceMethod.neon index 9972ab0a370b..2053fa0f2bbd 100644 --- a/utils/phpstan-baseline/codeigniter.unknownServiceMethod.neon +++ b/utils/phpstan-baseline/codeigniter.unknownServiceMethod.neon @@ -1,4 +1,4 @@ -# total 6 errors +# total 9 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/empty.notAllowed.neon b/utils/phpstan-baseline/empty.notAllowed.neon index e191dd27e5cc..ad029ff92d04 100644 --- a/utils/phpstan-baseline/empty.notAllowed.neon +++ b/utils/phpstan-baseline/empty.notAllowed.neon @@ -1,4 +1,4 @@ -# total 77 errors +# total 271 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/method.alreadyNarrowedType.neon b/utils/phpstan-baseline/method.alreadyNarrowedType.neon index 855a53be253c..ed9ef85490e3 100644 --- a/utils/phpstan-baseline/method.alreadyNarrowedType.neon +++ b/utils/phpstan-baseline/method.alreadyNarrowedType.neon @@ -1,4 +1,4 @@ -# total 16 errors +# total 22 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/method.childReturnType.neon b/utils/phpstan-baseline/method.childReturnType.neon index 4ad4f256f858..e2fcf04827da 100644 --- a/utils/phpstan-baseline/method.childReturnType.neon +++ b/utils/phpstan-baseline/method.childReturnType.neon @@ -1,4 +1,4 @@ -# total 39 errors +# total 40 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/method.notFound.neon b/utils/phpstan-baseline/method.notFound.neon index 4d94dfbba7e4..71e25c746678 100644 --- a/utils/phpstan-baseline/method.notFound.neon +++ b/utils/phpstan-baseline/method.notFound.neon @@ -1,4 +1,4 @@ -# total 40 errors +# total 83 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index 8a99113f5f0f..a5207361901e 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1665 errors +# total 1672 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/missingType.property.neon b/utils/phpstan-baseline/missingType.property.neon index f9d34b635d94..b4e0a4992eb9 100644 --- a/utils/phpstan-baseline/missingType.property.neon +++ b/utils/phpstan-baseline/missingType.property.neon @@ -1,4 +1,4 @@ -# total 127 errors +# total 130 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/nullCoalesce.property.neon b/utils/phpstan-baseline/nullCoalesce.property.neon index 4491bbf08a8b..fb447e22e1c2 100644 --- a/utils/phpstan-baseline/nullCoalesce.property.neon +++ b/utils/phpstan-baseline/nullCoalesce.property.neon @@ -1,4 +1,4 @@ -# total 15 errors +# total 22 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/offsetAccess.notFound.neon b/utils/phpstan-baseline/offsetAccess.notFound.neon index 6a1a134232f6..e96706dc1bb5 100644 --- a/utils/phpstan-baseline/offsetAccess.notFound.neon +++ b/utils/phpstan-baseline/offsetAccess.notFound.neon @@ -1,4 +1,4 @@ -# total 6 errors +# total 19 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/property.nonObject.neon b/utils/phpstan-baseline/property.nonObject.neon index 65d1006d02ca..ccb1a0cb3f42 100644 --- a/utils/phpstan-baseline/property.nonObject.neon +++ b/utils/phpstan-baseline/property.nonObject.neon @@ -1,4 +1,4 @@ -# total 25 errors +# total 54 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/property.notFound.neon b/utils/phpstan-baseline/property.notFound.neon index 079d6a122e7c..4d31a18bf6b7 100644 --- a/utils/phpstan-baseline/property.notFound.neon +++ b/utils/phpstan-baseline/property.notFound.neon @@ -1,4 +1,4 @@ -# total 30 errors +# total 58 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/property.protected.neon b/utils/phpstan-baseline/property.protected.neon index a9e65666816a..04b9a637fcbc 100644 --- a/utils/phpstan-baseline/property.protected.neon +++ b/utils/phpstan-baseline/property.protected.neon @@ -1,4 +1,4 @@ -# total 9 errors +# total 15 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/property.readOnlyByPhpDocAssignOutOfClass.neon b/utils/phpstan-baseline/property.readOnlyByPhpDocAssignOutOfClass.neon index 45048a1b949f..b26204669407 100644 --- a/utils/phpstan-baseline/property.readOnlyByPhpDocAssignOutOfClass.neon +++ b/utils/phpstan-baseline/property.readOnlyByPhpDocAssignOutOfClass.neon @@ -1,4 +1,4 @@ -# total 16 errors +# total 33 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/property.readOnlyByPhpDocDefaultValue.neon b/utils/phpstan-baseline/property.readOnlyByPhpDocDefaultValue.neon index 6eab9222e367..6bd85ccd63d8 100644 --- a/utils/phpstan-baseline/property.readOnlyByPhpDocDefaultValue.neon +++ b/utils/phpstan-baseline/property.readOnlyByPhpDocDefaultValue.neon @@ -1,4 +1,4 @@ -# total 7 errors +# total 20 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/staticMethod.notFound.neon b/utils/phpstan-baseline/staticMethod.notFound.neon index 223177bb3ef9..e8bc56bf5968 100644 --- a/utils/phpstan-baseline/staticMethod.notFound.neon +++ b/utils/phpstan-baseline/staticMethod.notFound.neon @@ -1,4 +1,4 @@ -# total 7 errors +# total 20 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/ternary.shortNotAllowed.neon b/utils/phpstan-baseline/ternary.shortNotAllowed.neon index a3dfc431cd94..59dca6cac690 100644 --- a/utils/phpstan-baseline/ternary.shortNotAllowed.neon +++ b/utils/phpstan-baseline/ternary.shortNotAllowed.neon @@ -1,4 +1,4 @@ -# total 27 errors +# total 38 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/varTag.type.neon b/utils/phpstan-baseline/varTag.type.neon index d2c028d9230b..8edeb6f38113 100644 --- a/utils/phpstan-baseline/varTag.type.neon +++ b/utils/phpstan-baseline/varTag.type.neon @@ -1,4 +1,4 @@ -# total 8 errors +# total 9 errors parameters: ignoreErrors: diff --git a/utils/phpstan-baseline/variable.undefined.neon b/utils/phpstan-baseline/variable.undefined.neon index e9e6a7a59275..00aea3030994 100644 --- a/utils/phpstan-baseline/variable.undefined.neon +++ b/utils/phpstan-baseline/variable.undefined.neon @@ -1,4 +1,4 @@ -# total 15 errors +# total 21 errors parameters: ignoreErrors: From b5e9715518186a9f4a98deeac1587b1131d01f8b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 25 Jan 2025 00:43:15 +0800 Subject: [PATCH 06/83] refactor: fix rector change on RedirectException (#9433) --- composer.json | 2 +- system/HTTP/Exceptions/RedirectException.php | 20 ++++++++++++------- .../ternary.shortNotAllowed.neon | 7 +------ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index c762845f9a7e..a0e5f0b5d081 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.3", - "rector/rector": "2.0.6", + "rector/rector": "2.0.7", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { diff --git a/system/HTTP/Exceptions/RedirectException.php b/system/HTTP/Exceptions/RedirectException.php index 792ffe921d70..abb9be1e9e35 100644 --- a/system/HTTP/Exceptions/RedirectException.php +++ b/system/HTTP/Exceptions/RedirectException.php @@ -51,7 +51,8 @@ public function __construct($message = '', int $code = 0, ?Throwable $previous = if ($message instanceof ResponseInterface) { $this->response = $message; - $message = ''; + + $message = ''; if ($this->response->getHeaderLine('Location') === '' && $this->response->getHeaderLine('Refresh') === '') { throw new LogicException( @@ -70,14 +71,19 @@ public function __construct($message = '', int $code = 0, ?Throwable $previous = public function getResponse(): ResponseInterface { if (! $this->response instanceof ResponseInterface) { - $this->response = service('response') - ->redirect(base_url($this->getMessage()), 'auto', $this->getCode()); + $this->response = service('response')->redirect( + base_url($this->getMessage()), + 'auto', + $this->getCode(), + ); } - service('logger')->info( - 'REDIRECTED ROUTE at ' - . ($this->response->getHeaderLine('Location') ?: substr($this->response->getHeaderLine('Refresh'), 6)), - ); + $location = $this->response->getHeaderLine('Location'); + + service(('logger'))->info(sprintf( + 'REDIRECTED ROUTE at %s', + $location !== '' ? $location : substr($this->response->getHeaderLine('Refresh'), 6), + )); return $this->response; } diff --git a/utils/phpstan-baseline/ternary.shortNotAllowed.neon b/utils/phpstan-baseline/ternary.shortNotAllowed.neon index 59dca6cac690..8fbe74a182db 100644 --- a/utils/phpstan-baseline/ternary.shortNotAllowed.neon +++ b/utils/phpstan-baseline/ternary.shortNotAllowed.neon @@ -1,4 +1,4 @@ -# total 38 errors +# total 37 errors parameters: ignoreErrors: @@ -47,11 +47,6 @@ parameters: count: 1 path: ../../system/HTTP/CURLRequest.php - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../system/HTTP/Exceptions/RedirectException.php - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 2 From 47e36c96748cbec25dfa1fc076f2aa4943010553 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 25 Jan 2025 03:05:06 +0800 Subject: [PATCH 07/83] chore: try a universal branch alias --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index a0e5f0b5d081..f7d990bfa189 100644 --- a/composer.json +++ b/composer.json @@ -81,8 +81,7 @@ }, "extra": { "branch-alias": { - "dev-develop": "4.x-dev", - "dev-master": "4.x-dev" + "dev-*": "4.6.x-dev" } }, "scripts": { From faeedb5a7eeaedc5e85be29ec8ecaf8faba6ce1f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 25 Jan 2025 03:18:52 +0700 Subject: [PATCH 08/83] chore: try using codeigniter/phpstan-codeigniter:1.x-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f7d990bfa189..9aea9b1d9e6f 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "psr/log": "^3.0" }, "require-dev": { - "codeigniter/phpstan-codeigniter": "^1.5.1", + "codeigniter/phpstan-codeigniter": "1.x-dev", "fakerphp/faker": "^1.24", "kint-php/kint": "^6.0", "mikey179/vfsstream": "^1.6.12", From 3276808f5bd5ea1edcac252985e6fc4de56ef9f4 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 26 Jan 2025 14:58:03 +0800 Subject: [PATCH 09/83] chore: greet new PR contributors using mergeable (#9434) --- .github/mergeable.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 95766c23fcee..ef4a92260c78 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -32,3 +32,40 @@ mergeable: Sincerely, the mergeable bot 🤖 - do: close + + - when: pull_request.opened, pull_request.ready_for_review + filter: + - do: payload + pull_request: + draft: + match: false + author_association: + must_include: + regex: ^NONE|FIRST_TIME_CONTRIBUTOR|FIRST_TIMER$ + validate: [] + pass: + - do: comment + payload: + body: | + Hi there, @@author! :wave: + + Thank you for sending this PR! + + We expect the following in all Pull Requests (PRs). + - PRs must be sent to the [appropriate branch](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#branching) + - All git commits must be [GPG-signed](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#signing) + - Must follow our [style guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#php-style) + - Be [commented](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#comments) in the PHP source file + - Be documented in the [user guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#user-guide) + - Be [unit tested](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#unit-testing) + - Pass all checks in GitHub Actions + + > [!IMPORTANT] + > We expect all code changes or bug-fixes to be accompanied by one or more tests added to our test suite to prove the code works. + + If pull requests do not comply with the above, they will likely be closed. Since we are a team of volunteers, we don't have any more time to work + on the framework than you do. Please make it as painless for your contributions to be included as possible. + + See https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md + + Sincerely, the mergeable bot 🤖 From e3d19a183bbafd2db136fd6a86ef82e103679741 Mon Sep 17 00:00:00 2001 From: Nalaka Samarasinghe <30935025+nalakapws@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:47:45 +0530 Subject: [PATCH 10/83] style: Update Cache to fix some formatting (#9438) --- app/Config/Cache.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 9ae2e843ac91..e6efa3acf6f5 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -108,6 +108,7 @@ class Cache extends BaseConfig * ------------------------------------------------------------------------- * Redis settings * ------------------------------------------------------------------------- + * * Your Redis server can be specified below, if you are using * the Redis or Predis drivers. * From 74a78610fddf251650793c689c4decd1b53eeb34 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 30 Jan 2025 18:18:20 +0800 Subject: [PATCH 11/83] chore: remove draft condition in mergeable (#9439) --- .github/mergeable.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index ef4a92260c78..d20aa796f5d0 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -37,8 +37,6 @@ mergeable: filter: - do: payload pull_request: - draft: - match: false author_association: must_include: regex: ^NONE|FIRST_TIME_CONTRIBUTOR|FIRST_TIMER$ From 3eae99070b207b34dd29f9ade8569c37e1ff1dad Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 4 Feb 2025 09:00:10 +0700 Subject: [PATCH 12/83] refactor: use assertNotInstanceOf over assertNull on nullable object return and flip actual/expect on constant check --- tests/system/Cache/ResponseCacheTest.php | 10 +++++----- tests/system/Filters/CorsTest.php | 2 +- tests/system/HTTP/Files/FileCollectionTest.php | 4 ++-- tests/system/HTTP/ResponseTest.php | 2 +- tests/system/Images/GDHandlerTest.php | 4 ++-- tests/system/Images/ImageMagickHandlerTest.php | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index d22f2a7683f4..11c82db71247 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -128,7 +128,7 @@ public function testCachePageIncomingRequest(): void $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); - $this->assertNull($cachedResponse); + $this->assertNotInstanceOf(ResponseInterface::class, $cachedResponse); } public function testCachePageIncomingRequestWithCacheQueryString(): void @@ -159,14 +159,14 @@ public function testCachePageIncomingRequestWithCacheQueryString(): void $request = $this->createIncomingRequest('foo/bar', ['xfoo' => 'bar', 'bar' => 'baz']); $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); - $this->assertNull($cachedResponse); + $this->assertNotInstanceOf(ResponseInterface::class, $cachedResponse); // Check cache with another request with the different URI path. $request = $this->createIncomingRequest('another'); $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); - $this->assertNull($cachedResponse); + $this->assertNotInstanceOf(ResponseInterface::class, $cachedResponse); } public function testCachePageIncomingRequestWithHttpMethods(): void @@ -186,7 +186,7 @@ public function testCachePageIncomingRequestWithHttpMethods(): void $request = $this->createIncomingRequest('foo/bar')->withMethod('POST'); $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); - $this->assertNull($cachedResponse); + $this->assertNotInstanceOf(ResponseInterface::class, $cachedResponse); } public function testCachePageCLIRequest(): void @@ -214,7 +214,7 @@ public function testCachePageCLIRequest(): void $cachedResponse = $pageCache->get($request, new Response($this->appConfig)); - $this->assertNull($cachedResponse); + $this->assertNotInstanceOf(ResponseInterface::class, $cachedResponse); } public function testUnserializeError(): void diff --git a/tests/system/Filters/CorsTest.php b/tests/system/Filters/CorsTest.php index 5e25af0572f2..1cbf4718212f 100644 --- a/tests/system/Filters/CorsTest.php +++ b/tests/system/Filters/CorsTest.php @@ -102,7 +102,7 @@ public function testBeforeDoesNothingWhenCliRequest(): void $return = $this->cors->before($cliRequest); - $this->assertNull($return); + $this->assertNotInstanceOf(ResponseInterface::class, $return); } private function assertHeader(string $name, string $value): void diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 3e502f7afec4..7be7fcfe546e 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -524,7 +524,7 @@ public function testFileNoExistSingleFile(): void $collection = new FileCollection(); $file = $collection->getFile('fileuser'); - $this->assertNull($file); + $this->assertNotInstanceOf(UploadedFile::class, $file); } public function testFileReturnValidMultipleFiles(): void @@ -686,7 +686,7 @@ public function testDoesntHaveFile(): void $collection = new FileCollection(); $this->assertFalse($collection->hasFile('my-form.detailz.avatars.0')); - $this->assertNull($collection->getFile('my-form.detailz.avatars.0')); + $this->assertNotInstanceOf(UploadedFile::class, $collection->getFile('my-form.detailz.avatars.0')); } public function testGetFileMultipleHasNoFile(): void diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index eeac917c7c64..bea0944599d8 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -495,7 +495,7 @@ public function testVagueDownload(): void $actual = $response->download(); - $this->assertNull($actual); + $this->assertNotInstanceOf(DownloadResponse::class, $actual); } public function testPretendMode(): void diff --git a/tests/system/Images/GDHandlerTest.php b/tests/system/Images/GDHandlerTest.php index 836f4f2cf05d..121ce040904a 100644 --- a/tests/system/Images/GDHandlerTest.php +++ b/tests/system/Images/GDHandlerTest.php @@ -411,7 +411,7 @@ public function testImageConvert(): void $this->handler->withFile($this->origin . 'ci-logo.jpeg'); $this->handler->convert(IMAGETYPE_PNG); $this->handler->save($this->start . 'work/ci-logo.png'); - $this->assertSame(exif_imagetype($this->start . 'work/ci-logo.png'), IMAGETYPE_PNG); + $this->assertSame(IMAGETYPE_PNG, exif_imagetype($this->start . 'work/ci-logo.png')); } public function testImageConvertPngToWebp(): void @@ -420,7 +420,7 @@ public function testImageConvertPngToWebp(): void $this->handler->convert(IMAGETYPE_WEBP); $saved = $this->start . 'work/rocket.webp'; $this->handler->save($saved); - $this->assertSame(exif_imagetype($saved), IMAGETYPE_WEBP); + $this->assertSame(IMAGETYPE_WEBP, exif_imagetype($saved)); } public function testImageReorientLandscape(): void diff --git a/tests/system/Images/ImageMagickHandlerTest.php b/tests/system/Images/ImageMagickHandlerTest.php index c189929dedb7..14cb4bc57980 100644 --- a/tests/system/Images/ImageMagickHandlerTest.php +++ b/tests/system/Images/ImageMagickHandlerTest.php @@ -447,7 +447,7 @@ public function testImageConvert(): void $this->handler->withFile($this->origin . 'ci-logo.jpeg'); $this->handler->convert(IMAGETYPE_PNG); $this->handler->save($this->root . 'ci-logo.png'); - $this->assertSame(exif_imagetype($this->root . 'ci-logo.png'), IMAGETYPE_PNG); + $this->assertSame(IMAGETYPE_PNG, exif_imagetype($this->root . 'ci-logo.png')); } public function testImageReorientLandscape(): void From aa90aab952b63ae6a5daad9cdb6cdeb4882bb372 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:24:09 +0000 Subject: [PATCH 13/83] chore(deps-dev): update rector/rector requirement from 2.0.7 to 2.0.8 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/2.0.7...2.0.8) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9aea9b1d9e6f..8797584457ea 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.3", - "rector/rector": "2.0.7", + "rector/rector": "2.0.8", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { From 73d5d3f813647037efd6ec26f87b199cdb2122da Mon Sep 17 00:00:00 2001 From: grimpirate Date: Fri, 7 Feb 2025 12:46:08 -0500 Subject: [PATCH 14/83] Typo fix, classname misspelled (#9444) --- user_guide_src/source/outgoing/localization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index dfbc6d3130ac..77d7abefc5bb 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -120,7 +120,7 @@ Language Locale --------------- The ``Language`` class used in the :php:func:`lang()` function also has the current -locale. This is set to the ``IncommingRequest`` locale during instantiating. +locale. This is set to the ``IncomingRequest`` locale during instantiating. If you want to change the locale after instantiating the language class, use the ``Language::setLocale()`` method. From efcabb3fdfafd6156ba12ab050d0dbf2bd2fceef Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Fri, 7 Feb 2025 20:47:32 +0300 Subject: [PATCH 15/83] docs: Add info about `Router::getMatchedRouteOptions()` (#9441) * docs: Add info about `Router::getMatchedRouteOptions()` * fix: Apply suggestions --- user_guide_src/source/incoming/routing.rst | 9 ++++++++ .../source/incoming/routing/074.php | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 user_guide_src/source/incoming/routing/074.php diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index c2f5977384a2..a1bb81726b14 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -1044,3 +1044,12 @@ This method returns a list of filters that are currently active for the route be .. note:: The ``getFilters()`` method returns only the filters defined for the specific route. It does not include global filters or those specified in the **app/Config/Filters.php** file. +Getting Matched Route Options for the Current Route +=================================================== + +When we're defining routes, they may have optional parameters: ``filter``, ``namespace``, ``hostname``, ``subdomain``, ``offset``, ``priority``, ``as``. All of them were described earlier above. +Additionally, if we use ``addRedirect()`` we can also expect the ``redirect`` key. +To access the values of these parameters, we can call ``Router::getMatchedRouteOptions()``. Here is an example of the returned array: + +.. literalinclude:: routing/074.php + diff --git a/user_guide_src/source/incoming/routing/074.php b/user_guide_src/source/incoming/routing/074.php new file mode 100644 index 000000000000..74eaeaf7e353 --- /dev/null +++ b/user_guide_src/source/incoming/routing/074.php @@ -0,0 +1,23 @@ +getMatchedRouteOptions(); + +echo 'Route name: ' . $options['as']; + +print_r($options); + +// Route name: api:auth +// +// Array +// ( +// [filter] => api-auth +// [namespace] => App\API\v1 +// [hostname] => example.com +// [subdomain] => api +// [offset] => 1 +// [priority] => 1 +// [as] => api:auth +// ) From c430f347200ec3a505cb48233f577edef5a1de5c Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Sat, 8 Feb 2025 19:43:28 +0100 Subject: [PATCH 16/83] fix: set headers for CORS (#9437) * fix: set everything in the before filter for CORS * fix append vary header * cors: apply response headers in the after filter only if they are not already set * cs fix --- system/Filters/Cors.php | 38 +++++++++++------ system/HTTP/Cors.php | 20 +++++++++ tests/system/Filters/CorsTest.php | 45 +++++++++++++++++++++ tests/system/HTTP/CorsTest.php | 37 +++++++++++++++++ user_guide_src/source/changelogs/v4.6.1.rst | 1 + 5 files changed, 128 insertions(+), 13 deletions(-) diff --git a/system/Filters/Cors.php b/system/Filters/Cors.php index 9a9bbb208152..c070d72925e5 100644 --- a/system/Filters/Cors.php +++ b/system/Filters/Cors.php @@ -58,22 +58,32 @@ public function before(RequestInterface $request, $arguments = null) $this->createCorsService($arguments); - if (! $this->cors->isPreflightRequest($request)) { - return null; - } - /** @var ResponseInterface $response */ $response = service('response'); - $response = $this->cors->handlePreflightRequest($request, $response); + if ($this->cors->isPreflightRequest($request)) { + $response = $this->cors->handlePreflightRequest($request, $response); - // Always adds `Vary: Access-Control-Request-Method` header for cacheability. - // If there is an intermediate cache server such as a CDN, if a plain - // OPTIONS request is sent, it may be cached. But valid preflight requests - // have this header, so it will be cached separately. - $response->appendHeader('Vary', 'Access-Control-Request-Method'); + // Always adds `Vary: Access-Control-Request-Method` header for cacheability. + // If there is an intermediate cache server such as a CDN, if a plain + // OPTIONS request is sent, it may be cached. But valid preflight requests + // have this header, so it will be cached separately. + $response->appendHeader('Vary', 'Access-Control-Request-Method'); + + return $response; + } - return $response; + if ($request->is('OPTIONS')) { + // Always adds `Vary: Access-Control-Request-Method` header for cacheability. + // If there is an intermediate cache server such as a CDN, if a plain + // OPTIONS request is sent, it may be cached. But valid preflight requests + // have this header, so it will be cached separately. + $response->appendHeader('Vary', 'Access-Control-Request-Method'); + } + + $this->cors->addResponseHeaders($request, $response); + + return null; } /** @@ -87,8 +97,6 @@ private function createCorsService(?array $arguments): void /** * @param list|null $arguments - * - * @return ResponseInterface|null */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { @@ -98,6 +106,10 @@ public function after(RequestInterface $request, ResponseInterface $response, $a $this->createCorsService($arguments); + if ($this->cors->hasResponseHeaders($request, $response)) { + return null; + } + // Always adds `Vary: Access-Control-Request-Method` header for cacheability. // If there is an intermediate cache server such as a CDN, if a plain // OPTIONS request is sent, it may be cached. But valid preflight requests diff --git a/system/HTTP/Cors.php b/system/HTTP/Cors.php index 2f151a738344..270b344abb8b 100644 --- a/system/HTTP/Cors.php +++ b/system/HTTP/Cors.php @@ -227,4 +227,24 @@ private function setExposeHeaders(ResponseInterface $response): void ); } } + + /** + * Check if response headers were set + */ + public function hasResponseHeaders(RequestInterface $request, ResponseInterface $response): bool + { + if (! $response->hasHeader('Access-Control-Allow-Origin')) { + return false; + } + + if ($this->config['supportsCredentials'] + && ! $response->hasHeader('Access-Control-Allow-Credentials')) { + return false; + } + + return ! ($this->config['exposedHeaders'] !== [] && (! $response->hasHeader('Access-Control-Expose-Headers') || ! str_contains( + $response->getHeaderLine('Access-Control-Expose-Headers'), + implode(', ', $this->config['exposedHeaders']), + ))); + } } diff --git a/tests/system/Filters/CorsTest.php b/tests/system/Filters/CorsTest.php index 1cbf4718212f..38389f25c213 100644 --- a/tests/system/Filters/CorsTest.php +++ b/tests/system/Filters/CorsTest.php @@ -16,6 +16,7 @@ use CodeIgniter\Exceptions\ConfigException; use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\SiteURI; @@ -154,6 +155,25 @@ private function handle(RequestInterface $request): ResponseInterface return $response; } + private function handleRedirect(RequestInterface $request): ResponseInterface + { + $response = $this->cors->before($request); + if ($response instanceof ResponseInterface) { + $this->response = $response; + + return $response; + } + + $response = service('redirectresponse'); + + $response = $this->cors->after($request, $response); + $response ??= service('redirectresponse'); + + $this->response = $response; + + return $response; + } + public function testItDoesModifyOnARequestWithSameOrigin(): void { $this->cors = $this->createCors(['allowedOrigins' => ['*']]); @@ -461,4 +481,29 @@ public function testItAddsVaryAccessControlRequestMethodHeaderEvenIfItIsNormalOp // Always adds `Vary: Access-Control-Request-Method` header. $this->assertHeader('Vary', 'Access-Control-Request-Method'); } + + public function testItReturnsAllowOriginHeaderOnValidActualRequestWithRedirect(): void + { + $this->cors = $this->createCors(); + $request = $this->createValidActualRequest(); + + $response = $this->handleRedirect($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertTrue($response->hasHeader('Access-Control-Allow-Origin')); + $this->assertHeader('Access-Control-Allow-Origin', 'http://localhost'); + } + + public function testItReturnsAllowOriginHeaderOnAllowAllOriginRequestWithRedirect(): void + { + $this->cors = $this->createCors(['allowedOrigins' => ['*']]); + $request = $this->createRequest(); + $request->setHeader('Origin', 'http://localhost'); + + $response = $this->handleRedirect($request); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertTrue($response->hasHeader('Access-Control-Allow-Origin')); + $this->assertHeader('Access-Control-Allow-Origin', '*'); + } } diff --git a/tests/system/HTTP/CorsTest.php b/tests/system/HTTP/CorsTest.php index 1002c557d313..5373959746ac 100644 --- a/tests/system/HTTP/CorsTest.php +++ b/tests/system/HTTP/CorsTest.php @@ -521,4 +521,41 @@ public function testAddResponseHeadersMultipleAllowedOriginsNotAllowed(): void $response->hasHeader('Access-Control-Allow-Methods'), ); } + + public function testHasResponseHeadersFalse(): void + { + $config = $this->getDefaultConfig(); + $config['allowedOrigins'] = ['http://localhost:8080']; + $config['allowedMethods'] = ['GET', 'POST', 'PUT']; + $cors = $this->createCors($config); + + $request = $this->createRequest() + ->withMethod('GET') + ->setHeader('Origin', 'http://localhost:8080'); + + $response = service('redirectresponse', null, false); + + $this->assertFalse( + $cors->hasResponseHeaders($request, $response), + ); + } + + public function testHasResponseHeadersTrue(): void + { + $config = $this->getDefaultConfig(); + $config['allowedOrigins'] = ['http://localhost:8080']; + $config['allowedMethods'] = ['GET', 'POST']; + $cors = $this->createCors($config); + + $request = $this->createRequest() + ->withMethod('GET') + ->setHeader('Origin', 'http://localhost:8080'); + + $response = service('redirectresponse', null, false); + $response = $cors->addResponseHeaders($request, $response); + + $this->assertTrue( + $cors->hasResponseHeaders($request, $response), + ); + } } diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index c230ee6d32b9..9a3ccfe76490 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -31,6 +31,7 @@ Bugs Fixed ********** - **CURLRequest:** Fixed an issue where multiple header sections appeared in the CURL response body during multiple redirects from the target server. +- **Cors:** Fixed a bug in the Cors filter that caused the appropriate headers to not be added when another filter returned a response object in the ``before`` filter. See the repo's `CHANGELOG.md `_ From 1dc2f7c918d40c086479c23a58af7d1cf3bdf34d Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Sun, 9 Feb 2025 23:06:54 +0300 Subject: [PATCH 17/83] refactor: Add phpDoc for Filters --- system/Config/Filters.php | 2 ++ utils/phpstan-baseline/missingType.iterableValue.neon | 7 +------ utils/phpstan-baseline/property.phpDocType.neon | 7 +------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/system/Config/Filters.php b/system/Config/Filters.php index 562eae8a26ef..7eddc721bff6 100644 --- a/system/Config/Filters.php +++ b/system/Config/Filters.php @@ -113,6 +113,8 @@ class Filters extends BaseConfig * * Example: * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']] + * + * @var array>> */ public array $filters = []; } diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index a5207361901e..1dc74c4561e9 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1672 errors +# total 1671 errors parameters: ignoreErrors: @@ -792,11 +792,6 @@ parameters: count: 1 path: ../../system/Config/Factory.php - - - message: '#^Property CodeIgniter\\Config\\Filters\:\:\$filters type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Config/Filters.php - - message: '#^Method CodeIgniter\\Config\\Services\:\:curlrequest\(\) has parameter \$options with no value type specified in iterable type array\.$#' count: 1 diff --git a/utils/phpstan-baseline/property.phpDocType.neon b/utils/phpstan-baseline/property.phpDocType.neon index f186ad067cb0..dda215c49436 100644 --- a/utils/phpstan-baseline/property.phpDocType.neon +++ b/utils/phpstan-baseline/property.phpDocType.neon @@ -1,12 +1,7 @@ -# total 47 errors +# total 46 errors parameters: ignoreErrors: - - - message: '#^PHPDoc type array\\>\> of property Config\\Filters\:\:\$filters is not the same as PHPDoc type array of overridden property CodeIgniter\\Config\\Filters\:\:\$filters\.$#' - count: 1 - path: ../../app/Config/Filters.php - - message: '#^PHPDoc type string of property CodeIgniter\\Database\\MySQLi\\Connection\:\:\$escapeChar is not the same as PHPDoc type array\|string of overridden property CodeIgniter\\Database\\BaseConnection\\:\:\$escapeChar\.$#' count: 1 From 1955a33b992823a3bec5eb5dd2b8716dc3819636 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:15:28 +0000 Subject: [PATCH 18/83] chore(deps-dev): update rector/rector requirement from 2.0.8 to 2.0.9 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/2.0.8...2.0.9) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8797584457ea..96a555a20562 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.3", - "rector/rector": "2.0.8", + "rector/rector": "2.0.9", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { From 65b71e963b1cb6f36b284ae0e5be13faabe33ff4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 10 Feb 2025 22:37:03 +0700 Subject: [PATCH 19/83] refactor: re-run rector --- tests/system/Database/Live/ForgeTest.php | 6 +++--- tests/system/Database/Live/GetTest.php | 2 +- tests/system/Log/LoggerTest.php | 2 +- tests/system/Models/FindModelTest.php | 2 +- tests/system/View/ViewTest.php | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index ab5b17bec174..6c43c246cf7e 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1292,7 +1292,7 @@ public function testSetKeyNames(): void $this->forge->dropKey('forge_test_1', $index, false); $this->forge->dropKey('forge_test_1', $uniqueIndex, false); - $this->assertCount(0, $this->db->getIndexData('forge_test_1')); + $this->assertEmpty($this->db->getIndexData('forge_test_1')); $this->forge->dropTable('forge_test_1', true); } @@ -1500,7 +1500,7 @@ public function testDropTableSuccess(): void $this->assertFalse($this->db->tableExists('dropTest')); if ($this->db->DBDriver === 'SQLite3') { - $this->assertCount(0, $this->db->getIndexData('droptest')); + $this->assertEmpty($this->db->getIndexData('droptest')); } } @@ -1668,7 +1668,7 @@ public function testDropPrimaryKey(): void $indexes = $this->db->getIndexData('forge_test_users'); - $this->assertCount(0, $indexes); + $this->assertEmpty($indexes); $this->forge->dropTable('forge_test_users', true); } diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index ce98ebf413e0..3bfa417f9127 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -58,7 +58,7 @@ public function testGetWithLimitZero(): void $jobs = $this->db->table('job')->limit(0)->get()->getResult(); - $this->assertCount(0, $jobs); + $this->assertEmpty($jobs); } public function testGetWithLimitZeroAsAll(): void diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 569de4dbd33d..497ff9fe47a0 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -103,7 +103,7 @@ public function testLogDoesnotLogUnhandledLevels(): void $logs = TestHandler::getLogs(); - $this->assertCount(0, $logs); + $this->assertEmpty($logs); } public function testLogInterpolatesMessage(): void diff --git a/tests/system/Models/FindModelTest.php b/tests/system/Models/FindModelTest.php index 43fb96d76b53..cd62f2dec107 100644 --- a/tests/system/Models/FindModelTest.php +++ b/tests/system/Models/FindModelTest.php @@ -130,7 +130,7 @@ public function testFindClearsBinds(): void // Binds should be reset to 0 after each one $binds = $this->model->builder()->getBinds(); - $this->assertCount(0, $binds); + $this->assertEmpty($binds); $query = $this->model->getLastQuery(); $this->assertCount(1, $this->getPrivateProperty($query, 'binds')); diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index b15e603408d8..c1fc85ede201 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -250,7 +250,7 @@ public function testPerformanceLogging(): void { // Make sure debugging is on for our view $view = new View($this->config, $this->viewsDir, $this->loader, true); - $this->assertCount(0, $view->getPerformanceData()); + $this->assertEmpty($view->getPerformanceData()); $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; @@ -262,12 +262,12 @@ public function testPerformanceNonLogging(): void { // Make sure debugging is on for our view $view = new View($this->config, $this->viewsDir, $this->loader, false); - $this->assertCount(0, $view->getPerformanceData()); + $this->assertEmpty($view->getPerformanceData()); $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; $this->assertSame($expected, $view->renderString('

', [], true)); - $this->assertCount(0, $view->getPerformanceData()); + $this->assertEmpty($view->getPerformanceData()); } public function testRenderLayoutExtendsCorrectly(): void From 1925f692bcc60deb81b103e8814687fd6e53094e Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 11 Feb 2025 14:30:12 +0700 Subject: [PATCH 20/83] fix Revert "refactor: re-run rector" This reverts commit 65b71e963b1cb6f36b284ae0e5be13faabe33ff4. fix: skip rector.php --- rector.php | 3 +++ tests/system/Database/Live/ForgeTest.php | 6 +++--- tests/system/Database/Live/GetTest.php | 2 +- tests/system/Log/LoggerTest.php | 2 +- tests/system/Models/FindModelTest.php | 2 +- tests/system/View/ViewTest.php | 6 +++--- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rector.php b/rector.php index ffa21b4e663e..7adec00da4bd 100644 --- a/rector.php +++ b/rector.php @@ -37,6 +37,7 @@ use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; +use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector; @@ -168,6 +169,8 @@ NullToStrictStringFuncCallArgRector::class, CompactToVariablesRector::class, + + AssertCountWithZeroToAssertEmptyRector::class, ]) // auto import fully qualified class names ->withImportNames(removeUnusedImports: true) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 6c43c246cf7e..ab5b17bec174 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1292,7 +1292,7 @@ public function testSetKeyNames(): void $this->forge->dropKey('forge_test_1', $index, false); $this->forge->dropKey('forge_test_1', $uniqueIndex, false); - $this->assertEmpty($this->db->getIndexData('forge_test_1')); + $this->assertCount(0, $this->db->getIndexData('forge_test_1')); $this->forge->dropTable('forge_test_1', true); } @@ -1500,7 +1500,7 @@ public function testDropTableSuccess(): void $this->assertFalse($this->db->tableExists('dropTest')); if ($this->db->DBDriver === 'SQLite3') { - $this->assertEmpty($this->db->getIndexData('droptest')); + $this->assertCount(0, $this->db->getIndexData('droptest')); } } @@ -1668,7 +1668,7 @@ public function testDropPrimaryKey(): void $indexes = $this->db->getIndexData('forge_test_users'); - $this->assertEmpty($indexes); + $this->assertCount(0, $indexes); $this->forge->dropTable('forge_test_users', true); } diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index 3bfa417f9127..ce98ebf413e0 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -58,7 +58,7 @@ public function testGetWithLimitZero(): void $jobs = $this->db->table('job')->limit(0)->get()->getResult(); - $this->assertEmpty($jobs); + $this->assertCount(0, $jobs); } public function testGetWithLimitZeroAsAll(): void diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 497ff9fe47a0..569de4dbd33d 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -103,7 +103,7 @@ public function testLogDoesnotLogUnhandledLevels(): void $logs = TestHandler::getLogs(); - $this->assertEmpty($logs); + $this->assertCount(0, $logs); } public function testLogInterpolatesMessage(): void diff --git a/tests/system/Models/FindModelTest.php b/tests/system/Models/FindModelTest.php index cd62f2dec107..43fb96d76b53 100644 --- a/tests/system/Models/FindModelTest.php +++ b/tests/system/Models/FindModelTest.php @@ -130,7 +130,7 @@ public function testFindClearsBinds(): void // Binds should be reset to 0 after each one $binds = $this->model->builder()->getBinds(); - $this->assertEmpty($binds); + $this->assertCount(0, $binds); $query = $this->model->getLastQuery(); $this->assertCount(1, $this->getPrivateProperty($query, 'binds')); diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index c1fc85ede201..b15e603408d8 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -250,7 +250,7 @@ public function testPerformanceLogging(): void { // Make sure debugging is on for our view $view = new View($this->config, $this->viewsDir, $this->loader, true); - $this->assertEmpty($view->getPerformanceData()); + $this->assertCount(0, $view->getPerformanceData()); $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; @@ -262,12 +262,12 @@ public function testPerformanceNonLogging(): void { // Make sure debugging is on for our view $view = new View($this->config, $this->viewsDir, $this->loader, false); - $this->assertEmpty($view->getPerformanceData()); + $this->assertCount(0, $view->getPerformanceData()); $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; $this->assertSame($expected, $view->renderString('

', [], true)); - $this->assertEmpty($view->getPerformanceData()); + $this->assertCount(0, $view->getPerformanceData()); } public function testRenderLayoutExtendsCorrectly(): void From d2bf2099e2b5465c5c43ee3737b6906791fbaf34 Mon Sep 17 00:00:00 2001 From: Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:36:53 +0700 Subject: [PATCH 21/83] refactor: get upper first protocol only one call in Email --- system/Email/Email.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/system/Email/Email.php b/system/Email/Email.php index 17b24c9de575..24c3af4cd376 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -1689,8 +1689,9 @@ protected function removeNLCallback($matches) protected function spoolEmail() { $this->unwrapSpecials(); - $protocol = $this->getProtocol(); - $method = 'sendWith' . ucfirst($protocol); + $protocol = $this->getProtocol(); + $upperFirstProtocol = ucfirst($protocol); + $method = 'sendWith' . $upperFirstProtocol; try { $success = $this->{$method}(); @@ -1700,7 +1701,7 @@ protected function spoolEmail() } if (! $success) { - $message = lang('Email.sendFailure' . ($protocol === 'mail' ? 'PHPMail' : ucfirst($protocol))); + $message = lang('Email.sendFailure' . ($protocol === 'mail' ? 'PHPMail' : $upperFirstProtocol)); log_message('error', 'Email: ' . $message); log_message('error', $this->printDebuggerRaw()); From da85d9f523b9636a1a8515c8aa6a4d43f81b24b0 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 15 Feb 2025 12:03:25 +0100 Subject: [PATCH 22/83] chore: update gpg key for phpdocumentor workflow --- .github/workflows/deploy-apidocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index fb9665327578..ca77c6a08c26 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -49,7 +49,7 @@ jobs: - name: Download latest phpDocumentor working-directory: source - run: phive --no-progress install --trust-gpg-keys 8AC0BAA79732DD42 phpDocumentor + run: phive --no-progress install --trust-gpg-keys 6DA3ACC4991FFAE5 phpDocumentor - name: Prepare API repo working-directory: api From 0ee6adefc2a50a8d0716d8d12feea9b2450090e4 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 23 Feb 2025 23:40:41 +0800 Subject: [PATCH 23/83] chore: bump to laminas-escaper v2.16 (#9458) --- system/ThirdParty/Escaper/Escaper.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/system/ThirdParty/Escaper/Escaper.php b/system/ThirdParty/Escaper/Escaper.php index 1e5bc7f9fad9..4fce36bd0c6c 100644 --- a/system/ThirdParty/Escaper/Escaper.php +++ b/system/ThirdParty/Escaper/Escaper.php @@ -4,11 +4,13 @@ namespace Laminas\Escaper; +use function assert; use function bin2hex; use function ctype_digit; use function hexdec; use function htmlspecialchars; use function in_array; +use function is_string; use function mb_convert_encoding; use function ord; use function preg_match; @@ -207,6 +209,8 @@ public function escapeHtmlAttr(string $string) } $result = preg_replace_callback('/[^a-z0-9,\.\-_]/iSu', $this->htmlAttrMatcher, $string); + assert(is_string($result)); + return $this->fromUtf8($result); } @@ -229,6 +233,8 @@ public function escapeJs(string $string) } $result = preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string); + assert(is_string($result)); + return $this->fromUtf8($result); } @@ -258,6 +264,8 @@ public function escapeCss(string $string) } $result = preg_replace_callback('/[^a-z0-9]/iSu', $this->cssMatcher, $string); + assert(is_string($result)); + return $this->fromUtf8($result); } From d8be763306faca266b5b8a4a191f90031da2f8f6 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Sun, 23 Feb 2025 16:57:04 +0100 Subject: [PATCH 24/83] docs: improved description of beforeDelete and afterDelete model events (#9459) --- user_guide_src/source/models/model.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 1a08519ca55d..53664b5db1a8 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -1016,9 +1016,9 @@ beforeFind The name of the calling **method**, whether a **singleton** wa - ``findAll()`` **limit** = the number of rows to find. **offset** = the number of rows to skip during the search. afterFind Same as **beforeFind** but including the resulting row(s) of data, or null if no result found. -beforeDelete **id** = primary key of row being passed to the ``delete()`` method. +beforeDelete **id** = an array of primary key rows being passed to the ``delete()`` method. **purge** = boolean whether soft-delete rows should be hard deleted. -afterDelete **id** = primary key of row being passed to the ``delete()`` method. +afterDelete **id** = an array of primary key rows being passed to the ``delete()`` method. **purge** = boolean whether soft-delete rows should be hard deleted. **result** = the result of the ``delete()`` call on the Query Builder. **data** = unused. From b21343a219eb00dbf8f582e31e4a84b288afcecc Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Sat, 1 Mar 2025 18:09:42 +0330 Subject: [PATCH 25/83] docs: use source code for plugin example (#9470) --- .../source/outgoing/view_parser.rst | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index dc2a702fe000..ad3e6bf5103c 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -464,23 +464,23 @@ Provided Plugins The following plugins are available when using the parser: -================== ========================= ============================================ ================================================================ +================== ========================= ============================================ =================================================================== Plugin Arguments Description Example -================== ========================= ============================================ ================================================================ -current_url Alias for the current_url helper function. {+ current_url +} -previous_url Alias for the previous_url helper function. {+ previous_url +} -siteURL Alias for the site_url helper function. {+ siteURL "login" +} -mailto email, title, attributes Alias for the mailto helper function. {+ mailto email=foo@example.com title="Stranger Things" +} -safe_mailto email, title, attributes Alias for the safe_mailto helper function. {+ safe_mailto email=foo@example.com title="Stranger Things" +} -lang language string Alias for the lang helper function. {+ lang number.terabyteAbbr +} -validation_errors fieldname(optional) Returns either error string for the field {+ validation_errors +} , {+ validation_errors field="email" +} +================== ========================= ============================================ =================================================================== +current_url Alias for the current_url helper function. ``{+ current_url +}`` +previous_url Alias for the previous_url helper function. ``{+ previous_url +}`` +siteURL Alias for the site_url helper function. ``{+ siteURL "login" +}`` +mailto email, title, attributes Alias for the mailto helper function. ``{+ mailto email=foo@example.com title="Stranger Things" +}`` +safe_mailto email, title, attributes Alias for the safe_mailto helper function. ``{+ safe_mailto email=foo@example.com title="Stranger Things" +}`` +lang language string Alias for the lang helper function. ``{+ lang number.terabyteAbbr +}`` +validation_errors fieldname(optional) Returns either error string for the field ``{+ validation_errors +} , {+ validation_errors field="email" +}`` (if specified) or all validation errors. -route route name Alias for the route_to helper function. {+ route "login" +} -csp_script_nonce Alias for the csp_script_nonce helper {+ csp_script_nonce +} +route route name Alias for the route_to helper function. ``{+ route "login" +}`` +csp_script_nonce Alias for the csp_script_nonce helper ``{+ csp_script_nonce +}`` function. -csp_style_nonce Alias for the csp_style_nonce helper {+ csp_style_nonce +} +csp_style_nonce Alias for the csp_style_nonce helper ``{+ csp_style_nonce +}`` function. -================== ========================= ============================================ ================================================================ +================== ========================= ============================================ =================================================================== Registering a Plugin -------------------- From 288345e1e77ac089902bd9818307528b8b80b21a Mon Sep 17 00:00:00 2001 From: Aselsan Date: Tue, 4 Mar 2025 15:42:19 +0700 Subject: [PATCH 26/83] fix: [DebugBar] make debug bar more user-friendly on mobile (#9473) --- admin/css/debug-toolbar/toolbar.scss | 25 +++++++++++++++++++++++++ system/Debug/Toolbar/Views/toolbar.css | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index eec3d25546e3..65f4b802e22c 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -457,6 +457,31 @@ } } +@media screen and (max-width: 768px) { + #debug-bar { + table { + display: block; + overflow-x: auto; + font-size: 12px; + margin: 5px 5px 10px 5px; + + td, + th { + padding: 4px 6px; + } + } + + .timeline { + display: block; + white-space: nowrap; + font-size: 12px; + } + + .toolbar { + overflow-x: auto; + } + } + } // THEMES // ========================================================================== */ diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index b9f13c51ff2e..abf61e9cca93 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -332,6 +332,26 @@ display: none !important; } } +@media screen and (max-width: 768px) { + #debug-bar table { + display: block; + overflow-x: auto; + font-size: 12px; + margin: 5px 5px 10px 5px; + } + #debug-bar table td, + #debug-bar table th { + padding: 4px 6px; + } + #debug-bar .timeline { + display: block; + white-space: nowrap; + font-size: 12px; + } + #debug-bar .toolbar { + overflow-x: auto; + } +} #debug-icon { background-color: #FFFFFF; box-shadow: 0 0 4px #DFDFDF; From fe925ab5fa49e24843fc444e69df7087d05b30a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 15:50:04 +0000 Subject: [PATCH 27/83] chore(deps-dev): update rector/rector requirement from 2.0.9 to 2.0.10 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/2.0.9...2.0.10) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 96a555a20562..50371dc14671 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.3", - "rector/rector": "2.0.9", + "rector/rector": "2.0.10", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { From 6acd5b904a93eb6af7f9c3ff4f8ff09129edb32f Mon Sep 17 00:00:00 2001 From: Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:33:18 +0700 Subject: [PATCH 28/83] refactor: PHPDocs in env() (#9468) --- system/Common.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Common.php b/system/Common.php index 7fb4c5964254..fafaccd31921 100644 --- a/system/Common.php +++ b/system/Common.php @@ -371,9 +371,9 @@ function db_connect($db = null, bool $getShared = true) * retrieving values set from the .env file for * use in config files. * - * @param string|null $default + * @param array|bool|float|int|object|string|null $default * - * @return bool|string|null + * @return array|bool|float|int|object|string|null */ function env(string $key, $default = null) { From 236dca3cd6634c003ea94040aef15e230a299394 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Fri, 7 Mar 2025 15:42:42 +0300 Subject: [PATCH 29/83] refactor: Update Toolbar tests (#9479) --- tests/system/Filters/DebugToolbarTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/system/Filters/DebugToolbarTest.php b/tests/system/Filters/DebugToolbarTest.php index 0826a04afca8..4968cede04f0 100644 --- a/tests/system/Filters/DebugToolbarTest.php +++ b/tests/system/Filters/DebugToolbarTest.php @@ -17,6 +17,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\Test\CIUnitTestCase; use Config\Filters as FilterConfig; use PHPUnit\Framework\Attributes\BackupGlobals; @@ -60,11 +61,13 @@ public function testDebugToolbarFilter(): void $expectedAfter = $this->response; // nothing should change here, since we have no before logic - $filter->before($this->request); + $result = $filter->before($this->request); $this->assertSame($expectedBefore, $this->request); + $this->assertNull($result); // nothing should change here, since we are running in the CLI - $filter->after($this->request, $this->response); + $result = $filter->after($this->request, $this->response); $this->assertSame($expectedAfter, $this->response); + $this->assertNotInstanceOf(ResponseInterface::class, $result); } } From 686e9ae2b077c1372d60034e3cf8ecc209e42615 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Mon, 10 Mar 2025 06:56:00 +0100 Subject: [PATCH 30/83] fix: upsert with composite unique index (#9454) * fix: upsert with composite unique index * cs fix * update tests * docs: handling constraints for databases other than MySQL --- system/Database/Postgre/Builder.php | 5 ++- system/Database/SQLite3/Builder.php | 4 +-- .../20160428212500_Create_test_tables.php | 9 ++++++ .../_support/Database/Seeds/CITestSeeder.php | 14 ++++++++ tests/system/Database/Live/MetadataTest.php | 1 + tests/system/Database/Live/UpsertTest.php | 32 ++++++++++++++++++- user_guide_src/source/changelogs/v4.6.1.rst | 1 + .../source/database/query_builder.rst | 4 +++ 8 files changed, 64 insertions(+), 6 deletions(-) diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index 27a72b58c333..8d0d569d5e28 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -469,9 +469,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri return ($index->type === 'UNIQUE' || $index->type === 'PRIMARY') && $hasAllFields; }); - foreach (array_map(static fn ($index) => $index->fields, $allIndexes) as $index) { - $constraints[] = current($index); - // only one index can be used? + foreach ($allIndexes as $index) { + $constraints = $index->fields; break; } diff --git a/system/Database/SQLite3/Builder.php b/system/Database/SQLite3/Builder.php index 6e62907ac1aa..3aa13edeb96a 100644 --- a/system/Database/SQLite3/Builder.php +++ b/system/Database/SQLite3/Builder.php @@ -151,8 +151,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields; }); - foreach (array_map(static fn ($index) => $index->fields, $allIndexes) as $index) { - $constraints[] = current($index); + foreach ($allIndexes as $index) { + $constraints = $index->fields; break; } diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index 8a7cb5b7d11c..6af55fa7c9c9 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -47,6 +47,15 @@ public function up(): void 'value' => ['type' => 'VARCHAR', 'constraint' => 400, 'null' => true], ])->addKey('id', true)->createTable('misc', true); + // Team members Table (composite key) + $this->forge->addField([ + 'team_id' => ['type' => 'INTEGER', 'constraint' => 3], + 'person_id' => ['type' => 'INTEGER', 'constraint' => 3], + 'role' => ['type' => 'VARCHAR', 'constraint' => 40], + 'status' => ['type' => 'VARCHAR', 'constraint' => 40], + 'created_at' => ['type' => 'DATETIME', 'null' => true], + ])->addUniqueKey(['team_id', 'person_id'])->createTable('team_members', true); + // Database Type test table // missing types: // TINYINT,MEDIUMINT,BIT,YEAR,BINARY,VARBINARY,TINYTEXT,LONGTEXT, diff --git a/tests/_support/Database/Seeds/CITestSeeder.php b/tests/_support/Database/Seeds/CITestSeeder.php index 9ce0bce4f1c3..09dba65f155b 100644 --- a/tests/_support/Database/Seeds/CITestSeeder.php +++ b/tests/_support/Database/Seeds/CITestSeeder.php @@ -107,6 +107,20 @@ public function run(): void 'value' => 'ടൈപ്പ്', ], ], + 'team_members' => [ + [ + 'team_id' => 1, + 'person_id' => 22, + 'role' => 'member', + 'status' => 'active', + ], + [ + 'team_id' => 1, + 'person_id' => 33, + 'role' => 'mentor', + 'status' => 'active', + ], + ], 'type_test' => [ [ 'type_varchar' => 'test', diff --git a/tests/system/Database/Live/MetadataTest.php b/tests/system/Database/Live/MetadataTest.php index 0488dd2f4a51..643d0689fdad 100644 --- a/tests/system/Database/Live/MetadataTest.php +++ b/tests/system/Database/Live/MetadataTest.php @@ -47,6 +47,7 @@ protected function setUp(): void $prefix . 'user', $prefix . 'job', $prefix . 'misc', + $prefix . 'team_members', $prefix . 'type_test', $prefix . 'empty', $prefix . 'secondary', diff --git a/tests/system/Database/Live/UpsertTest.php b/tests/system/Database/Live/UpsertTest.php index a702ff5e1b8d..000fa6fec7cb 100644 --- a/tests/system/Database/Live/UpsertTest.php +++ b/tests/system/Database/Live/UpsertTest.php @@ -448,7 +448,7 @@ public function testUpsertBatchWithOnConflictAndUpdateFields(): void $this->assertSame('El Salvador', $data[4]->country); } - public function testUpsertWithMatchingDataOnUniqueIndexandPrimaryKey(): void + public function testUpsertWithMatchingDataOnUniqueIndexAndPrimaryKey(): void { $data = [ 'id' => 6, @@ -607,6 +607,36 @@ public function testUpsertBatchMultipleConstraints(): void } } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/9450 + */ + public function testUpsertBatchCompositeUniqueIndex(): void + { + $data = [ + [ + 'team_id' => 1, + 'person_id' => 22, + 'role' => 'leader', + 'status' => 'active', + ], + [ + 'team_id' => 1, + 'person_id' => 33, + 'role' => 'member', + 'status' => 'active', + ], + ]; + + // uses (team_id, person_id) - composite unique index + $this->db->table('team_members')->upsertBatch($data); + + $this->seeInDatabase('team_members', ['team_id' => 1, 'person_id' => 22, 'role' => 'leader']); + $this->dontSeeInDatabase('team_members', ['team_id' => 1, 'person_id' => 22, 'role' => 'member']); + + $this->seeInDatabase('team_members', ['team_id' => 1, 'person_id' => 33, 'role' => 'member']); + $this->dontSeeInDatabase('team_members', ['team_id' => 1, 'person_id' => 33, 'role' => 'mentor']); + } + public function testSetBatchOneRow(): void { $data = [ diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index 9a3ccfe76490..9a5ea391d4f3 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -32,6 +32,7 @@ Bugs Fixed - **CURLRequest:** Fixed an issue where multiple header sections appeared in the CURL response body during multiple redirects from the target server. - **Cors:** Fixed a bug in the Cors filter that caused the appropriate headers to not be added when another filter returned a response object in the ``before`` filter. +- **Database:** Fixed a bug in ``Postgre`` and ``SQLite3`` handlers where composite unique keys were not fully taken into account for ``upsert`` type of queries. See the repo's `CHANGELOG.md `_ diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 6e4b1359c898..31515768d530 100644 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -937,6 +937,10 @@ constraint by default. Here is an example using an array: .. literalinclude:: query_builder/112.php +.. note:: For databases other than MySQL, if a table has multiple keys (primary or unique), + the primary key will be prioritized by default when handling constraints. If you prefer + to use a different unique key instead of the primary key, use the ``onConstraint()`` method. + The first parameter is an associative array of values. Here is an example using an object: From 770e067e291cd1f11f28f804a6184dfce2a4a113 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Tue, 11 Mar 2025 14:48:28 +0300 Subject: [PATCH 31/83] refactor: Fix phpstan `varTag.type` errors (#9480) * refactor: Update return types `ReflectionHelper` * refactor: Update types in RedisHandler::deleteMatching() * refactor: Remove unnecessary hints * refactor: TimeTrait::$timezone can be a string * refactor: Refresh phpstan baseline --- system/Cache/Handlers/RedisHandler.php | 2 +- .../Generators/MigrationGenerator.php | 5 +-- system/HTTP/CURLRequest.php | 4 +-- system/I18n/TimeTrait.php | 2 +- system/Test/ReflectionHelper.php | 3 +- .../Commands/Utilities/ConfigCheckTest.php | 8 +++-- utils/phpstan-baseline/varTag.type.neon | 32 +------------------ 7 files changed, 12 insertions(+), 44 deletions(-) diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index 6cd43506bdb5..80c21e8559e8 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -181,7 +181,7 @@ public function deleteMatching(string $pattern) $iterator = null; do { - /** @var false|list|Redis $keys */ + /** @var false|list $keys */ $keys = $this->redis->scan($iterator, $pattern); if (is_array($keys)) { diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php index b7d7d585e945..b5e64ec1bce1 100644 --- a/system/Commands/Generators/MigrationGenerator.php +++ b/system/Commands/Generators/MigrationGenerator.php @@ -112,10 +112,7 @@ protected function prepare(string $class): string $data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default'; $data['DBDriver'] = config(Database::class)->{$data['DBGroup']}['DBDriver']; - /** @var SessionConfig|null $session */ - $session = config(SessionConfig::class); - - $data['matchIP'] = $session->matchIP; + $data['matchIP'] = config(SessionConfig::class)->matchIP; } return $this->parseTemplate($class, [], [], $data); diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 742da9f18d08..8a21d77262a0 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -125,9 +125,7 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response $this->baseURI = $uri->useRawQueryString(); $this->defaultOptions = $options; - /** @var ConfigCURLRequest|null $configCURLRequest */ - $configCURLRequest = config(ConfigCURLRequest::class); - $this->shareOptions = $configCURLRequest->shareOptions ?? true; + $this->shareOptions = config(ConfigCURLRequest::class)->shareOptions ?? true; $this->config = $this->defaultConfig; $this->parseOptions($options); diff --git a/system/I18n/TimeTrait.php b/system/I18n/TimeTrait.php index 5e908bef5c2e..42278c960c43 100644 --- a/system/I18n/TimeTrait.php +++ b/system/I18n/TimeTrait.php @@ -32,7 +32,7 @@ trait TimeTrait { /** - * @var DateTimeZone + * @var DateTimeZone|string */ protected $timezone; diff --git a/system/Test/ReflectionHelper.php b/system/Test/ReflectionHelper.php index 988fe949004c..47e85f4a8903 100644 --- a/system/Test/ReflectionHelper.php +++ b/system/Test/ReflectionHelper.php @@ -31,8 +31,7 @@ trait ReflectionHelper * @param object|string $obj object or class name * @param string $method method name * - * @return Closure - * @phpstan-return Closure(mixed ...$args): mixed + * @return Closure(mixed ...$args): mixed * * @throws ReflectionException */ diff --git a/tests/system/Commands/Utilities/ConfigCheckTest.php b/tests/system/Commands/Utilities/ConfigCheckTest.php index e49a8170ec08..dcd001b0c323 100644 --- a/tests/system/Commands/Utilities/ConfigCheckTest.php +++ b/tests/system/Commands/Utilities/ConfigCheckTest.php @@ -89,7 +89,9 @@ public function testCommandConfigCheckNonexistentClass(): void public function testConfigCheckWithKintEnabledUsesKintD(): void { - /** @var Closure(object): string $command */ + /** + * @var Closure(mixed...): string + */ $command = $this->getPrivateMethodInvoker( new ConfigCheck(service('logger'), service('commands')), 'getKintD', @@ -105,7 +107,9 @@ public function testConfigCheckWithKintEnabledUsesKintD(): void public function testConfigCheckWithKintDisabledUsesVarDump(): void { - /** @var Closure(object): string $command */ + /** + * @var Closure(mixed...): string + */ $command = $this->getPrivateMethodInvoker( new ConfigCheck(service('logger'), service('commands')), 'getVarDump', diff --git a/utils/phpstan-baseline/varTag.type.neon b/utils/phpstan-baseline/varTag.type.neon index 8edeb6f38113..4be1089ace00 100644 --- a/utils/phpstan-baseline/varTag.type.neon +++ b/utils/phpstan-baseline/varTag.type.neon @@ -1,37 +1,7 @@ -# total 9 errors +# total 2 errors parameters: ignoreErrors: - - - message: '#^PHPDoc tag @var with type list\\|Redis\|false is not subtype of type array\\|false\.$#' - count: 1 - path: ../../system/Cache/Handlers/RedisHandler.php - - - - message: '#^PHPDoc tag @var with type Config\\Session\|null is not subtype of type Config\\Session\.$#' - count: 1 - path: ../../system/Commands/Generators/MigrationGenerator.php - - - - message: '#^PHPDoc tag @var with type Config\\CURLRequest\|null is not subtype of type Config\\CURLRequest\.$#' - count: 1 - path: ../../system/HTTP/CURLRequest.php - - - - message: '#^PHPDoc tag @var with type string is not subtype of type DateTimeZone\.$#' - count: 1 - path: ../../system/I18n/Time.php - - - - message: '#^PHPDoc tag @var with type string is not subtype of type DateTimeZone\.$#' - count: 1 - path: ../../system/I18n/TimeLegacy.php - - - - message: '#^PHPDoc tag @var with type Closure\(object\)\: string is not subtype of type Closure\(mixed \.\.\.\)\: mixed\.$#' - count: 2 - path: ../../tests/system/Commands/Utilities/ConfigCheckTest.php - - message: '#^PHPDoc tag @var with type Tests\\Support\\Entity\\UserWithCasts is not subtype of type list\\|null\.$#' count: 1 From 436f8cd9b6fafd1d9dd658272b0f171b60012008 Mon Sep 17 00:00:00 2001 From: Aselsan Date: Tue, 11 Mar 2025 18:48:49 +0700 Subject: [PATCH 32/83] fix: [Views] adjust panel top spacing (#9477) * fix: panel top spacing * change brand primary color with the actual color code * update environment panel to top --- app/Views/errors/html/debug.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Views/errors/html/debug.css b/app/Views/errors/html/debug.css index b20f36a53ce2..b8539a420221 100644 --- a/app/Views/errors/html/debug.css +++ b/app/Views/errors/html/debug.css @@ -3,7 +3,7 @@ --main-text-color: #555; --dark-text-color: #222; --light-text-color: #c7c7c7; - --brand-primary-color: #E06E3F; + --brand-primary-color: #DC4814; --light-bg-color: #ededee; --dark-bg-color: #404040; } @@ -71,7 +71,7 @@ p.lead { text-align: center; padding: calc(4px + 0.2083vw); width: 100%; - margin-top: -2.14rem; + top: 0; position: fixed; } From 884412caead75b464a81b8f1d3cec710e851d2ef Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Tue, 11 Mar 2025 14:49:35 +0300 Subject: [PATCH 33/83] fix: Time tests for arab locale (#9481) --- tests/system/I18n/TimeLegacyTest.php | 6 +++--- tests/system/I18n/TimeTest.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/system/I18n/TimeLegacyTest.php b/tests/system/I18n/TimeLegacyTest.php index c53b4ce3bda3..8fbd359fbfd5 100644 --- a/tests/system/I18n/TimeLegacyTest.php +++ b/tests/system/I18n/TimeLegacyTest.php @@ -1091,11 +1091,11 @@ public function testHumanizeWithArLocale(): void $this->resetServices(); $currentLocale = Locale::getDefault(); - Locale::setDefault('ar'); + Locale::setDefault('ar-SA'); $config = new App(); - $config->supportedLocales = ['ar']; - $config->defaultLocale = 'ar'; + $config->supportedLocales = ['ar-SA']; + $config->defaultLocale = 'ar-SA'; Factories::injectMock('config', 'App', $config); TimeLegacy::setTestNow('2022-06-14 12:00', 'America/Chicago'); diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 4dd49d9a5388..af45abcbe4b8 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -1176,11 +1176,11 @@ public function testHumanizeWithArLocale(): void $this->resetServices(); $currentLocale = Locale::getDefault(); - Locale::setDefault('ar'); + Locale::setDefault('ar-SA'); $config = new App(); - $config->supportedLocales = ['ar']; - $config->defaultLocale = 'ar'; + $config->supportedLocales = ['ar-SA']; + $config->defaultLocale = 'ar-SA'; Factories::injectMock('config', 'App', $config); Time::setTestNow('2022-06-14 12:00', 'America/Chicago'); From 38c1c79459d734b34f7a11ac84f9dcc52f70fb82 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Tue, 11 Mar 2025 14:57:52 +0300 Subject: [PATCH 34/83] refactor: Fix phpstan errors `offsetAccess.notFound` (#9486) --- .../system/Models/DataConverterModelTest.php | 24 +++++++------- tests/system/Models/TimestampModelTest.php | 28 +++++++++++----- utils/phpstan-baseline/loader.neon | 1 - .../offsetAccess.notFound.neon | 33 ------------------- 4 files changed, 33 insertions(+), 53 deletions(-) delete mode 100644 utils/phpstan-baseline/offsetAccess.notFound.neon diff --git a/tests/system/Models/DataConverterModelTest.php b/tests/system/Models/DataConverterModelTest.php index f243871526f3..7d647790d62b 100644 --- a/tests/system/Models/DataConverterModelTest.php +++ b/tests/system/Models/DataConverterModelTest.php @@ -36,7 +36,7 @@ public function testFindAsArray(): void $user = $this->model->find($id); - $this->assertIsInt($user['id']); + $this->assertIsInt($user['id']); // @phpstan-ignore offsetAccess.notFound $this->assertInstanceOf(Time::class, $user['created_at']); $this->assertSame('John Smith', $user['name']); // `name` is cast by custom CastBase64 handler. @@ -128,9 +128,9 @@ public function testFindAllAsArray(): void $users = $this->model->findAll(); - $this->assertIsInt($users[0]['id']); + $this->assertIsInt($users[0]['id']); // @phpstan-ignore offsetAccess.notFound $this->assertInstanceOf(Time::class, $users[0]['created_at']); - $this->assertIsInt($users[1]['id']); + $this->assertIsInt($users[1]['id']); // @phpstan-ignore offsetAccess.notFound $this->assertInstanceOf(Time::class, $users[1]['created_at']); } @@ -208,7 +208,7 @@ public function testFirstAsArray(): void $user = $this->model->first(); - $this->assertIsInt($user['id']); + $this->assertIsInt($user['id']); // @phpstan-ignore offsetAccess.notFound $this->assertInstanceOf(Time::class, $user['created_at']); } @@ -264,7 +264,8 @@ public function testInsertArray(): void $id = $this->model->insert($data, true); $user = $this->model->find($id); - $this->assertSame(['joe@example.com'], $user['email']); + + $this->assertSame(['joe@example.com'], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testInsertObject(): void @@ -279,7 +280,8 @@ public function testInsertObject(): void $id = $this->model->insert($data, true); $user = $this->model->find($id); - $this->assertSame(['joe@example.com'], $user['email']); + + $this->assertSame(['joe@example.com'], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testUpdateArray(): void @@ -288,14 +290,14 @@ public function testUpdateArray(): void $user = $this->model->find($id); $user['email'][] = 'private@example.org'; - $this->model->update($user['id'], $user); + $this->model->update($user['id'], $user); // @phpstan-ignore offsetAccess.notFound $user = $this->model->find($id); $this->assertSame([ 'john@example.com', 'private@example.org', - ], $user['email']); + ], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testUpdateObject(): void @@ -311,7 +313,7 @@ public function testUpdateObject(): void $this->assertSame([ 'john@example.com', 'private@example.org', - ], $user['email']); + ], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testUpdateCustomObject(): void @@ -363,7 +365,7 @@ public function testSaveArray(): void $this->assertSame([ 'john@example.com', 'private@example.org', - ], $user['email']); + ], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testSaveObject(): void @@ -379,7 +381,7 @@ public function testSaveObject(): void $this->assertSame([ 'john@example.com', 'private@example.org', - ], $user['email']); + ], $user['email']); // @phpstan-ignore offsetAccess.notFound } public function testSaveCustomObject(): void diff --git a/tests/system/Models/TimestampModelTest.php b/tests/system/Models/TimestampModelTest.php index 8736691b2d4a..ce2675a2d89d 100644 --- a/tests/system/Models/TimestampModelTest.php +++ b/tests/system/Models/TimestampModelTest.php @@ -93,10 +93,12 @@ public function testDoNotAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void $user = $this->model->find($id); $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } @@ -116,10 +118,12 @@ public function testDoNotAllowDatesInsertArrayWithDatesSetsTimestamp(): void $user = $this->model->find($id); $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } @@ -139,15 +143,17 @@ public function testDoNotAllowDatesUpdateArrayUpdatesUpdatedAt(): void $user = $this->model->find($id); $user['country'] = 'CA'; - $this->model->update($user['id'], $user); + $this->model->update($user['id'], $user); // @phpstan-ignore offsetAccess.notFound $user = $this->model->find($id); $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } @@ -197,10 +203,12 @@ public function testAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void $user = $this->model->find($id); $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } @@ -224,10 +232,12 @@ public function testAllowDatesInsertArrayWithDatesSetsTimestamp(): void $user = $this->model->find($id); $expected = '2000-01-01 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } @@ -251,15 +261,17 @@ public function testAllowDatesUpdateArrayUpdatesUpdatedAt(): void $user = $this->model->find($id); $user['country'] = 'CA'; - $this->model->update($user['id'], $user); + $this->model->update($user['id'], $user); // @phpstan-ignore offsetAccess.notFound $user = $this->model->find($id); $expected = '2000-01-01 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { $expected .= '.000'; } - $this->assertSame($expected, $user['created_at']); + + $this->assertSame($expected, $user['created_at']); // @phpstan-ignore offsetAccess.notFound $this->assertSame($expected, $user['updated_at']); } diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 61b40215f4f2..24fe8aba136f 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -26,7 +26,6 @@ includes: - notIdentical.alwaysTrue.neon - nullCoalesce.property.neon - nullCoalesce.variable.neon - - offsetAccess.notFound.neon - parameterByRef.unusedType.neon - property.defaultValue.neon - property.nonObject.neon diff --git a/utils/phpstan-baseline/offsetAccess.notFound.neon b/utils/phpstan-baseline/offsetAccess.notFound.neon deleted file mode 100644 index e96706dc1bb5..000000000000 --- a/utils/phpstan-baseline/offsetAccess.notFound.neon +++ /dev/null @@ -1,33 +0,0 @@ -# total 19 errors - -parameters: - ignoreErrors: - - - message: '#^Offset ''email'' does not exist on array\{\}\.$#' - count: 4 - path: ../../tests/system/Models/DataConverterModelTest.php - - - - message: '#^Offset ''email'' does not exist on list\\.$#' - count: 2 - path: ../../tests/system/Models/DataConverterModelTest.php - - - - message: '#^Offset ''id'' does not exist on array\{email\: array\{''private@example\.org''\}\}\.$#' - count: 1 - path: ../../tests/system/Models/DataConverterModelTest.php - - - - message: '#^Offset ''id'' does not exist on array\{\}\.$#' - count: 4 - path: ../../tests/system/Models/DataConverterModelTest.php - - - - message: '#^Offset ''created_at'' does not exist on array\{\}\.$#' - count: 6 - path: ../../tests/system/Models/TimestampModelTest.php - - - - message: '#^Offset ''id'' does not exist on array\{country\: ''CA''\}\.$#' - count: 2 - path: ../../tests/system/Models/TimestampModelTest.php From 4b77fd35e9d94335317d438cc6e5542d394d33f1 Mon Sep 17 00:00:00 2001 From: Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:07:00 +0700 Subject: [PATCH 35/83] refactor: lowercase event name calling unnecessarily (#9483) --- system/Events/Events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Events/Events.php b/system/Events/Events.php index 97f4e81d0369..ebe13d8682c1 100644 --- a/system/Events/Events.php +++ b/system/Events/Events.php @@ -158,7 +158,7 @@ public static function trigger($eventName, ...$arguments): bool static::$performanceLog[] = [ 'start' => $start, 'end' => microtime(true), - 'event' => strtolower($eventName), + 'event' => $eventName, ]; } From 99be15154096793c5e21b0853adac3c72af81267 Mon Sep 17 00:00:00 2001 From: Ilia Chernykh Date: Wed, 12 Mar 2025 13:09:13 +0500 Subject: [PATCH 36/83] Fix variable name according to the example (#9485) --- user_guide_src/source/models/model.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 53664b5db1a8..bfef42f86d32 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -487,7 +487,7 @@ Returns null or an indexed array of column values: .. literalinclude:: model/008.php -``$column_name`` should be a name of single column else you will get the ``DataException``. +``$columnName`` should be a name of single column else you will get the ``DataException``. findAll() --------- From 249b88a68cec051924b2eb96d5658b91561cd8c2 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Wed, 12 Mar 2025 09:10:28 +0100 Subject: [PATCH 37/83] fix: `getVersion()` for OCI8 and SQLSRV drivers (#9471) * fix: getVersion() for OCI8 driver when no connection is established * phpstan - regenerate baseline * fix: SQLSRV getVersion() when no connection is established --- system/Database/OCI8/Connection.php | 7 ++++++- system/Database/SQLSRV/Connection.php | 8 ++++++-- tests/system/Database/Live/GetVersionTest.php | 6 ++++++ user_guide_src/source/changelogs/v4.6.1.rst | 1 + utils/phpstan-baseline/property.notFound.neon | 7 ++++++- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index b6078febd030..67921d2c13f8 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -193,9 +193,14 @@ public function getVersion(): string return $this->dataCache['version']; } - if (! $this->connID || ($versionString = oci_server_version($this->connID)) === false) { + if ($this->connID === false) { + $this->initialize(); + } + + if (($versionString = oci_server_version($this->connID)) === false) { return ''; } + if (preg_match('#Release\s(\d+(?:\.\d+)+)#', $versionString, $match)) { return $this->dataCache['version'] = $match[1]; } diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index c8e1e3fbee12..7ef4f31901d1 100644 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -561,11 +561,15 @@ public function getVersion(): string return $this->dataCache['version']; } - if (! $this->connID || ($info = sqlsrv_server_info($this->connID)) === []) { + if (! $this->connID) { $this->initialize(); } - return isset($info['SQLServerVersion']) ? $this->dataCache['version'] = $info['SQLServerVersion'] : false; + if (($info = sqlsrv_server_info($this->connID)) === []) { + return ''; + } + + return isset($info['SQLServerVersion']) ? $this->dataCache['version'] = $info['SQLServerVersion'] : ''; } /** diff --git a/tests/system/Database/Live/GetVersionTest.php b/tests/system/Database/Live/GetVersionTest.php index 73da7c07071d..93678e3b8356 100644 --- a/tests/system/Database/Live/GetVersionTest.php +++ b/tests/system/Database/Live/GetVersionTest.php @@ -29,6 +29,12 @@ final class GetVersionTest extends CIUnitTestCase public function testGetVersion(): void { + if ($this->db->DBDriver === 'MySQLi') { + $this->db->mysqli = false; + } + + $this->db->connID = false; + $version = $this->db->getVersion(); $this->assertMatchesRegularExpression('/\A\d+(\.\d+)*\z/', $version); diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index 9a5ea391d4f3..7b35ad9faabc 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -33,6 +33,7 @@ Bugs Fixed - **CURLRequest:** Fixed an issue where multiple header sections appeared in the CURL response body during multiple redirects from the target server. - **Cors:** Fixed a bug in the Cors filter that caused the appropriate headers to not be added when another filter returned a response object in the ``before`` filter. - **Database:** Fixed a bug in ``Postgre`` and ``SQLite3`` handlers where composite unique keys were not fully taken into account for ``upsert`` type of queries. +- **Database:** Fixed a bug in the ``OCI8`` and ``SQLSRV`` drivers where ``getVersion()`` returned an empty string when the database connection was not yet established. See the repo's `CHANGELOG.md `_ diff --git a/utils/phpstan-baseline/property.notFound.neon b/utils/phpstan-baseline/property.notFound.neon index 4d31a18bf6b7..9c0dfe2005a3 100644 --- a/utils/phpstan-baseline/property.notFound.neon +++ b/utils/phpstan-baseline/property.notFound.neon @@ -1,4 +1,4 @@ -# total 58 errors +# total 59 errors parameters: ignoreErrors: @@ -42,6 +42,11 @@ parameters: count: 2 path: ../../tests/system/Database/BaseConnectionTest.php + - + message: '#^Access to an undefined property CodeIgniter\\Database\\BaseConnection\:\:\$mysqli\.$#' + count: 1 + path: ../../tests/system/Database/Live/GetVersionTest.php + - message: '#^Access to an undefined property CodeIgniter\\Database\\BaseConnection\:\:\$foundRows\.$#' count: 2 From 9b9d42710325f3d6b8c1c7d0ea4bdb46148986a3 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Sat, 15 Mar 2025 15:40:34 +0300 Subject: [PATCH 38/83] fix: Update hint vars in userguide (#9489) --- user_guide_src/source/database/results.rst | 4 ++-- user_guide_src/source/dbmgmt/forge.rst | 10 +++++----- user_guide_src/source/general/common_functions.rst | 4 ++-- user_guide_src/source/libraries/typography.rst | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst index 85e57c3be70e..846bca15bc9f 100644 --- a/user_guide_src/source/database/results.rst +++ b/user_guide_src/source/database/results.rst @@ -287,9 +287,9 @@ Class Reference Usage: see `Getting an Array of stdClass`_. - .. php:method:: getCustomResultObject($class_name) + .. php:method:: getCustomResultObject($className) - :param string $class_name: Class name for the resulting rows + :param string $className: Class name for the resulting rows :returns: Array containing the fetched rows :rtype: array diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index 00915a5dae81..ed31afdebcc3 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -493,10 +493,10 @@ Class Reference Creates a new table. Usage: See `Creating a Table`_. - .. php:method:: dropColumn($table, $column_name) + .. php:method:: dropColumn($table, $columnNames) :param string $table: Table name - :param mixed $column_names: Comma-delimited string or an array of column names + :param mixed $columnNames: Comma-delimited string or an array of column names :returns: true on success, false on failure :rtype: bool @@ -563,10 +563,10 @@ Class Reference Modifies a table column. Usage: See `Modifying a Field in a Table`_. - .. php:method:: renameTable($table_name, $new_table_name) + .. php:method:: renameTable($tableName, $newTableName) - :param string $table: Current of the table - :param string $new_table_name: New name of the table + :param string $tableName: Current of the table + :param string $newTableName: New name of the table :returns: Query object on success, false on failure :rtype: mixed diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index d0a23758e348..1745b0e732e1 100644 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -293,9 +293,9 @@ Miscellaneous Functions .. note:: This function is also used when you set ``Config\App:$forceGlobalSecureRequests`` to true. -.. php:function:: function_usable($function_name) +.. php:function:: function_usable($functionName) - :param string $function_name: Function to check for + :param string $functionName: Function to check for :returns: true if the function exists and is safe to call, false otherwise. :rtype: bool diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst index 111287d0c366..9e8755ed69c5 100644 --- a/user_guide_src/source/libraries/typography.rst +++ b/user_guide_src/source/libraries/typography.rst @@ -24,10 +24,10 @@ Available static functions The following functions are available: -.. php:function:: autoTypography($str[, $reduce_linebreaks = false]) +.. php:function:: autoTypography($str[, $reduceLinebreaks = false]) :param string $str: Input string - :param bool $reduce_linebreaks: Whether to reduce multiple instances of double newlines to two + :param bool $reduceLinebreaks: Whether to reduce multiple instances of double newlines to two :returns: HTML-formatted typography-safe string :rtype: string From 0e0a5ad8b285fb59a0dbb2b99d0507238a5596c8 Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Sat, 15 Mar 2025 16:54:23 +0300 Subject: [PATCH 39/83] refactor: Typing commands (#9488) * refactor: Improve typing in the Command area * tests: Check the case when CLI option is `null` * chore: Update phpstan baseline --- system/Autoloader/FileLocator.php | 8 +-- system/Autoloader/FileLocatorInterface.php | 2 +- system/CLI/CLI.php | 8 ++- system/CLI/Commands.php | 24 +++++-- system/CLI/Console.php | 7 ++- system/Common.php | 6 +- system/Config/BaseConfig.php | 2 + system/Config/Factories.php | 2 + system/Publisher/Publisher.php | 3 +- tests/system/CLI/CLITest.php | 1 + tests/system/CLI/ConsoleTest.php | 2 +- tests/system/Commands/CommandTest.php | 11 +++- .../codeigniter.superglobalAccessAssign.neon | 2 +- .../missingType.iterableValue.neon | 62 +------------------ 14 files changed, 53 insertions(+), 87 deletions(-) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 844ac7fc4cc9..13ecb817a56c 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -266,12 +266,6 @@ protected function getNamespaces() return array_merge($namespaces, $system); } - /** - * Find the qualified name of a file according to - * the namespace of the first matched namespace path. - * - * @return false|string The qualified name or false if the path is not found - */ public function findQualifiedNameFromPath(string $path) { $resolvedPath = realpath($path); @@ -299,7 +293,9 @@ public function findQualifiedNameFromPath(string $path) ), '\\', ); + // Remove the file extension (.php) + /** @var class-string */ $className = mb_substr($className, 0, -4); if (in_array($className, $this->invalidClassnames, true)) { diff --git a/system/Autoloader/FileLocatorInterface.php b/system/Autoloader/FileLocatorInterface.php index 3a1112dd480e..8f6129abee17 100644 --- a/system/Autoloader/FileLocatorInterface.php +++ b/system/Autoloader/FileLocatorInterface.php @@ -62,7 +62,7 @@ public function search(string $path, string $ext = 'php', bool $prioritizeApp = * Find the qualified name of a file according to * the namespace of the first matched namespace path. * - * @return false|string The qualified name or false if the path is not found + * @return class-string|false The qualified name or false if the path is not found */ public function findQualifiedNameFromPath(string $path); diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index a21996507d55..b8ea4714f39b 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -107,12 +107,12 @@ class CLI /** * List of array segments. * - * @var array + * @var list */ protected static $segments = []; /** - * @var array + * @var array */ protected static $options = []; @@ -944,6 +944,8 @@ public static function getSegment(int $index) /** * Returns the raw array of segments found. + * + * @return list */ public static function getSegments(): array { @@ -971,6 +973,8 @@ public static function getOption(string $name) /** * Returns the raw array of options found. + * + * @return array */ public static function getOptions(): array { diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php index 732cb370382d..aecd22c3f348 100644 --- a/system/CLI/Commands.php +++ b/system/CLI/Commands.php @@ -21,13 +21,15 @@ /** * Core functionality for running, listing, etc commands. + * + * @phpstan-type commands_list array, 'file': string, 'group': string,'description': string}> */ class Commands { /** * The found commands. * - * @var array + * @var commands_list */ protected $commands = []; @@ -52,6 +54,8 @@ public function __construct($logger = null) /** * Runs a command given * + * @param array $params + * * @return int Exit code */ public function run(string $command, array $params) @@ -77,7 +81,7 @@ public function run(string $command, array $params) /** * Provide access to the list of commands. * - * @return array + * @return commands_list */ public function getCommands() { @@ -96,7 +100,7 @@ public function discoverCommands() return; } - /** @var FileLocatorInterface $locator */ + /** @var FileLocatorInterface */ $locator = service('locator'); $files = $locator->listFiles('Commands/'); @@ -109,6 +113,7 @@ public function discoverCommands() // Loop over each file checking to see if a command with that // alias exists in the class. foreach ($files as $file) { + /** @var class-string|false */ $className = $locator->findQualifiedNameFromPath($file); if ($className === false || ! class_exists($className)) { @@ -122,7 +127,6 @@ public function discoverCommands() continue; } - /** @var BaseCommand $class */ $class = new $className($this->logger, $this); if (isset($class->group) && ! isset($this->commands[$class->name])) { @@ -146,6 +150,8 @@ public function discoverCommands() /** * Verifies if the command being sought is found * in the commands list. + * + * @param commands_list $commands */ public function verifyCommand(string $command, array $commands): bool { @@ -153,9 +159,9 @@ public function verifyCommand(string $command, array $commands): bool return true; } - $message = lang('CLI.commandNotFound', [$command]); - + $message = lang('CLI.commandNotFound', [$command]); $alternatives = $this->getCommandAlternatives($command, $commands); + if ($alternatives !== []) { if (count($alternatives) === 1) { $message .= "\n\n" . lang('CLI.altCommandSingular') . "\n "; @@ -175,11 +181,17 @@ public function verifyCommand(string $command, array $commands): bool /** * Finds alternative of `$name` among collection * of commands. + * + * @param commands_list $collection + * + * @return list */ protected function getCommandAlternatives(string $name, array $collection): array { + /** @var array */ $alternatives = []; + /** @var string $commandName */ foreach (array_keys($collection) as $commandName) { $lev = levenshtein($name, $commandName); diff --git a/system/CLI/Console.php b/system/CLI/Console.php index 5cb8b57a0ad3..325eaa7b455c 100644 --- a/system/CLI/Console.php +++ b/system/CLI/Console.php @@ -38,14 +38,13 @@ public function run() $appConfig = config(App::class); Services::createRequest($appConfig, true); // Load Routes - Services::routes()->loadRoutes(); + service('routes')->loadRoutes(); - $runner = Services::commands(); $params = array_merge(CLI::getSegments(), CLI::getOptions()); $params = $this->parseParamsForHelpOption($params); $command = array_shift($params) ?? 'list'; - return $runner->run($command, $params); + return service('commands')->run($command, $params); } /** @@ -75,6 +74,8 @@ public function showHeader(bool $suppress = false) * If present, it will be found as `['help' => null]`. * We'll remove that as an option from `$params` and * unshift it as argument instead. + * + * @param array $params */ private function parseParamsForHelpOption(array $params): array { diff --git a/system/Common.php b/system/Common.php index fafaccd31921..910ec9b1cc28 100644 --- a/system/Common.php +++ b/system/Common.php @@ -124,7 +124,6 @@ function clean_path(string $path): string */ function command(string $command) { - $runner = service('commands'); $regexString = '([^\s]+?)(?:\s|(? */ $params = []; + $command = array_shift($args); $optionValue = false; foreach ($args as $i => $arg) { @@ -187,7 +187,7 @@ function command(string $command) } ob_start(); - $runner->run($command, $params); + service('commands')->run($command, $params); return ob_get_clean(); } diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index e056664e24be..ce6594d45d36 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Config; +use CodeIgniter\Autoloader\FileLocatorInterface; use CodeIgniter\Exceptions\ConfigException; use CodeIgniter\Exceptions\RuntimeException; use Config\Encryption; @@ -252,6 +253,7 @@ protected function registerProperties() static::$discovering = true; + /** @var FileLocatorInterface */ $locator = service('locator'); $registrarsFiles = $locator->search('Config/Registrar.php'); diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 797f9fd9c7de..dc74c45e76f7 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -13,6 +13,7 @@ namespace CodeIgniter\Config; +use CodeIgniter\Autoloader\FileLocatorInterface; use CodeIgniter\Database\ConnectionInterface; use CodeIgniter\Exceptions\InvalidArgumentException; use CodeIgniter\Model; @@ -299,6 +300,7 @@ class_exists($alias, false) } // Have to do this the hard way... + /** @var FileLocatorInterface */ $locator = service('locator'); // Check if the class alias was namespaced diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index d65765947db1..8d9f6b72327a 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -109,7 +109,7 @@ final public static function discover(string $directory = 'Publishers', string $ self::$discovered[$key] = []; - /** @var FileLocatorInterface $locator */ + /** @var FileLocatorInterface */ $locator = service('locator'); $files = $namespace === '' @@ -125,6 +125,7 @@ final public static function discover(string $directory = 'Publishers', string $ $className = $locator->findQualifiedNameFromPath($file); if ($className !== false && class_exists($className) && is_a($className, self::class, true)) { + /** @var class-string $className */ self::$discovered[$key][] = new $className(); } } diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 5c17fd820044..b29ef7bfc12f 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -539,6 +539,7 @@ public function testParseCommandMultipleOptions(): void $this->assertSame(['parm' => 'pvalue', 'p2' => null, 'p3' => 'value 3'], CLI::getOptions()); $this->assertSame('pvalue', CLI::getOption('parm')); + $this->assertTrue(CLI::getOption('p2')); $this->assertSame('-parm pvalue -p2 -p3 "value 3" ', CLI::getOptionString()); $this->assertSame('-parm pvalue -p2 -p3 "value 3"', CLI::getOptionString(false, true)); $this->assertSame('--parm pvalue --p2 --p3 "value 3" ', CLI::getOptionString(true)); diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index 5962f3a9b21e..4d66a48447b4 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -169,7 +169,7 @@ public function testHelpArgumentAndHelpOptionCombined(): void } /** - * @param array $command + * @param string ...$command */ protected function initCLI(...$command): void { diff --git a/tests/system/Commands/CommandTest.php b/tests/system/Commands/CommandTest.php index 84fa6ecac993..1c6e81033e63 100644 --- a/tests/system/Commands/CommandTest.php +++ b/tests/system/Commands/CommandTest.php @@ -19,6 +19,7 @@ use CodeIgniter\Test\StreamFilterTrait; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; +use Tests\Support\Commands\AppInfo; use Tests\Support\Commands\ParamsReveal; /** @@ -74,9 +75,12 @@ public function testShowError(): void { command('app:info'); $commands = $this->commands->getCommands(); - $command = new $commands['app:info']['class']($this->logger, $this->commands); + + /** @var AppInfo */ + $command = new $commands['app:info']['class']($this->logger, $this->commands); $command->helpme(); + $this->assertStringContainsString('Displays basic usage information.', $this->getBuffer()); } @@ -84,9 +88,12 @@ public function testCommandCall(): void { command('app:info'); $commands = $this->commands->getCommands(); - $command = new $commands['app:info']['class']($this->logger, $this->commands); + + /** @var AppInfo */ + $command = new $commands['app:info']['class']($this->logger, $this->commands); $command->bomb(); + $this->assertStringContainsString('Invalid "background" color:', $this->getBuffer()); } diff --git a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon index 365455768963..665b2a986ce5 100644 --- a/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon +++ b/utils/phpstan-baseline/codeigniter.superglobalAccessAssign.neon @@ -58,7 +58,7 @@ parameters: path: ../../tests/system/CLI/ConsoleTest.php - - message: '#^Assigning non\-empty\-array\ directly on offset ''argv'' of \$_SERVER is discouraged\.$#' + message: '#^Assigning non\-empty\-array\ directly on offset ''argv'' of \$_SERVER is discouraged\.$#' count: 1 path: ../../tests/system/CLI/ConsoleTest.php diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index 1dc74c4561e9..9f19deb6ea78 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1671 errors +# total 1659 errors parameters: ignoreErrors: @@ -182,16 +182,6 @@ parameters: count: 1 path: ../../system/BaseModel.php - - - message: '#^Method CodeIgniter\\CLI\\CLI\:\:getOptions\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Method CodeIgniter\\CLI\\CLI\:\:getSegments\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - message: '#^Method CodeIgniter\\CLI\\CLI\:\:isZeroOptions\(\) has parameter \$options with no value type specified in iterable type array\.$#' count: 1 @@ -247,51 +237,6 @@ parameters: count: 1 path: ../../system/CLI/CLI.php - - - message: '#^Property CodeIgniter\\CLI\\CLI\:\:\$options type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Property CodeIgniter\\CLI\\CLI\:\:\$segments type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/CLI.php - - - - message: '#^Method CodeIgniter\\CLI\\Commands\:\:getCommandAlternatives\(\) has parameter \$collection with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Method CodeIgniter\\CLI\\Commands\:\:getCommandAlternatives\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Method CodeIgniter\\CLI\\Commands\:\:getCommands\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Method CodeIgniter\\CLI\\Commands\:\:run\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Method CodeIgniter\\CLI\\Commands\:\:verifyCommand\(\) has parameter \$commands with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Property CodeIgniter\\CLI\\Commands\:\:\$commands type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Commands.php - - - - message: '#^Method CodeIgniter\\CLI\\Console\:\:parseParamsForHelpOption\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/CLI/Console.php - - message: '#^Method CodeIgniter\\CLI\\Console\:\:parseParamsForHelpOption\(\) return type has no value type specified in iterable type array\.$#' count: 1 @@ -6652,11 +6597,6 @@ parameters: count: 1 path: ../../tests/system/CLI/CLITest.php - - - message: '#^Method CodeIgniter\\CLI\\ConsoleTest\:\:initCLI\(\) has parameter \$command with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/system/CLI/ConsoleTest.php - - message: '#^Method CodeIgniter\\Cache\\Handlers\\BaseHandlerTest\:\:provideValidateKeyInvalidType\(\) return type has no value type specified in iterable type iterable\.$#' count: 1 From 0611c355e2835c78ad486bd7cc8fb0129efc70b9 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 15 Mar 2025 23:35:24 +0800 Subject: [PATCH 40/83] refactor: call `getPrivateMethodInvoker()` statically (#9490) --- tests/system/API/ResponseTraitTest.php | 2 +- tests/system/Autoloader/AutoloaderTest.php | 6 +++--- tests/system/CodeIgniterTest.php | 6 +++--- .../Translation/LocalizationSyncTest.php | 2 +- .../Commands/Utilities/ConfigCheckTest.php | 4 ++-- .../system/Commands/Utilities/NamespacesTest.php | 2 +- tests/system/Config/BaseConfigTest.php | 4 ++-- tests/system/ControllerTest.php | 16 ++++++++-------- tests/system/Database/ConfigTest.php | 4 ++-- tests/system/Database/Live/ForgeTest.php | 2 +- .../system/Database/Live/OCI8/ConnectionTest.php | 2 +- .../Database/Migrations/MigrationRunnerTest.php | 12 ++++++------ tests/system/Debug/ExceptionHandlerTest.php | 16 ++++++++-------- tests/system/Debug/ExceptionsTest.php | 10 +++++----- tests/system/Files/FileCollectionTest.php | 12 ++++++------ tests/system/HTTP/CURLRequestTest.php | 2 +- tests/system/Models/MiscellaneousModelTest.php | 4 ++-- .../Models/ValidationModelRuleGroupTest.php | 6 +++--- tests/system/Models/ValidationModelTest.php | 6 +++--- tests/system/Publisher/PublisherSupportTest.php | 4 ++-- tests/system/RESTful/ResourceControllerTest.php | 2 +- tests/system/Security/SecurityTest.php | 10 +++++----- .../Database/AbstractHandlerTestCase.php | 4 ++-- tests/system/Test/FabricatorTest.php | 12 ++++++------ tests/system/Test/ReflectionHelperTest.php | 4 ++-- tests/system/Validation/ValidationTest.php | 10 +++++----- user_guide_src/source/testing/overview/013.php | 2 +- 27 files changed, 83 insertions(+), 83 deletions(-) diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 6a6da58cf3db..978513b74c50 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -661,7 +661,7 @@ public function testXMLResponseFormat(): void private function invoke(object $controller, string $method, array $args = []) { - $method = $this->getPrivateMethodInvoker($controller, $method); + $method = self::getPrivateMethodInvoker($controller, $method); return $method(...$args); } diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 5b11df6f7efb..af5340400160 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -64,7 +64,7 @@ protected function setUp(): void $this->loader = new Autoloader(); $this->loader->initialize($config, $modules)->register(); - $this->classLoader = $this->getPrivateMethodInvoker($this->loader, 'loadInNamespace'); + $this->classLoader = self::getPrivateMethodInvoker($this->loader, 'loadInNamespace'); } protected function tearDown(): void @@ -111,7 +111,7 @@ public function testInitializeTwice(): void public function testServiceAutoLoaderFromShareInstances(): void { - $classLoader = $this->getPrivateMethodInvoker(service('autoloader'), 'loadInNamespace'); + $classLoader = self::getPrivateMethodInvoker(service('autoloader'), 'loadInNamespace'); // look for Home controller, as that should be in base repo $actual = $classLoader(Home::class); @@ -129,7 +129,7 @@ public function testServiceAutoLoader(): void $autoloader->initialize(new Autoload(), new Modules()); $autoloader->register(); - $classLoader = $this->getPrivateMethodInvoker($autoloader, 'loadInNamespace'); + $classLoader = self::getPrivateMethodInvoker($autoloader, 'loadInNamespace'); // look for Home controller, as that should be in base repo $actual = $classLoader(Home::class); diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index bbd895e177f4..ca7819306e62 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -460,8 +460,8 @@ public function testRunForceSecure(): void $codeigniter = new MockCodeIgniter($config); $codeigniter->setContext('web'); - $this->getPrivateMethodInvoker($codeigniter, 'getRequestObject')(); - $this->getPrivateMethodInvoker($codeigniter, 'getResponseObject')(); + self::getPrivateMethodInvoker($codeigniter, 'getRequestObject')(); + self::getPrivateMethodInvoker($codeigniter, 'getResponseObject')(); $response = $this->getPrivateProperty($codeigniter, 'response'); $this->assertNull($response->header('Location')); @@ -949,7 +949,7 @@ public function testStartControllerPermitsInvoke(): void { $this->setPrivateProperty($this->codeigniter, 'benchmark', new Timer()); $this->setPrivateProperty($this->codeigniter, 'controller', '\\' . Home::class); - $startController = $this->getPrivateMethodInvoker($this->codeigniter, 'startController'); + $startController = self::getPrivateMethodInvoker($this->codeigniter, 'startController'); $this->setPrivateProperty($this->codeigniter, 'method', '__invoke'); $startController(); diff --git a/tests/system/Commands/Translation/LocalizationSyncTest.php b/tests/system/Commands/Translation/LocalizationSyncTest.php index 88d7dc6f3bd6..f6dc00764eac 100644 --- a/tests/system/Commands/Translation/LocalizationSyncTest.php +++ b/tests/system/Commands/Translation/LocalizationSyncTest.php @@ -212,7 +212,7 @@ public function testProcessWithInvalidOption(): void $langPath = SUPPORTPATH . 'Language'; $command = new LocalizationSync(service('logger'), service('commands')); $this->setPrivateProperty($command, 'languagePath', $langPath); - $runner = $this->getPrivateMethodInvoker($command, 'process'); + $runner = self::getPrivateMethodInvoker($command, 'process'); $status = $runner('de', 'jp'); diff --git a/tests/system/Commands/Utilities/ConfigCheckTest.php b/tests/system/Commands/Utilities/ConfigCheckTest.php index dcd001b0c323..22d0e3d1f1d3 100644 --- a/tests/system/Commands/Utilities/ConfigCheckTest.php +++ b/tests/system/Commands/Utilities/ConfigCheckTest.php @@ -92,7 +92,7 @@ public function testConfigCheckWithKintEnabledUsesKintD(): void /** * @var Closure(mixed...): string */ - $command = $this->getPrivateMethodInvoker( + $command = self::getPrivateMethodInvoker( new ConfigCheck(service('logger'), service('commands')), 'getKintD', ); @@ -110,7 +110,7 @@ public function testConfigCheckWithKintDisabledUsesVarDump(): void /** * @var Closure(mixed...): string */ - $command = $this->getPrivateMethodInvoker( + $command = self::getPrivateMethodInvoker( new ConfigCheck(service('logger'), service('commands')), 'getVarDump', ); diff --git a/tests/system/Commands/Utilities/NamespacesTest.php b/tests/system/Commands/Utilities/NamespacesTest.php index 35c1e3eed998..eea619e1b229 100644 --- a/tests/system/Commands/Utilities/NamespacesTest.php +++ b/tests/system/Commands/Utilities/NamespacesTest.php @@ -90,7 +90,7 @@ public function testNamespacesCommandAllNamespaces(): void public function testTruncateNamespaces(): void { $commandObject = new Namespaces(service('logger'), service('commands')); - $truncateRunner = $this->getPrivateMethodInvoker($commandObject, 'truncate'); + $truncateRunner = self::getPrivateMethodInvoker($commandObject, 'truncate'); $this->assertSame('App\Controllers\...', $truncateRunner('App\Controllers\Admin', 19)); // multibyte namespace diff --git a/tests/system/Config/BaseConfigTest.php b/tests/system/Config/BaseConfigTest.php index a46551ae8bb4..0ba70346de4c 100644 --- a/tests/system/Config/BaseConfigTest.php +++ b/tests/system/Config/BaseConfigTest.php @@ -257,7 +257,7 @@ public function testRegistrars(): void $config = new RegistrarConfig(); $config::$registrars = [TestRegistrar::class]; $this->setPrivateProperty($config, 'didDiscovery', true); - $method = $this->getPrivateMethodInvoker($config, 'registerProperties'); + $method = self::getPrivateMethodInvoker($config, 'registerProperties'); $method(); // no change to unmodified property @@ -274,7 +274,7 @@ public function testBadRegistrar(): void $this->setPrivateProperty($config, 'didDiscovery', true); $this->expectException(RuntimeException::class); - $method = $this->getPrivateMethodInvoker($config, 'registerProperties'); + $method = self::getPrivateMethodInvoker($config, 'registerProperties'); $method(); $this->assertSame('bar', $config->foo); diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 733705725258..6bf50ba0bd76 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -94,7 +94,7 @@ public function testCachePage(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'cachePage'); + $method = self::getPrivateMethodInvoker($this->controller, 'cachePage'); $this->assertNull($method(10)); } @@ -105,7 +105,7 @@ public function testValidate(): void $this->controller->initController($this->request, $this->response, $this->logger); // and that we can attempt validation, with no rules - $method = $this->getPrivateMethodInvoker($this->controller, 'validate'); + $method = self::getPrivateMethodInvoker($this->controller, 'validate'); $this->assertFalse($method([])); } @@ -117,7 +117,7 @@ public function testValidateWithStringRulesNotFound(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validate'); + $method = self::getPrivateMethodInvoker($this->controller, 'validate'); $this->assertFalse($method('signup')); } @@ -146,7 +146,7 @@ public function testValidateWithStringRulesFoundReadMessagesFromValidationConfig $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validate'); + $method = self::getPrivateMethodInvoker($this->controller, 'validate'); $this->assertFalse($method('signup')); $this->assertSame('You must choose a username.', service('validation')->getError('username')); } @@ -167,7 +167,7 @@ public function testValidateWithStringRulesFoundUseMessagesParameter(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validate'); + $method = self::getPrivateMethodInvoker($this->controller, 'validate'); $this->assertFalse($method('signup', [ 'username' => [ 'required' => 'You must choose a username.', @@ -182,7 +182,7 @@ public function testValidateData(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validateData'); + $method = self::getPrivateMethodInvoker($this->controller, 'validateData'); $data = [ 'username' => 'mike', @@ -205,7 +205,7 @@ public function testValidateDataWithCustomErrorMessage(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validateData'); + $method = self::getPrivateMethodInvoker($this->controller, 'validateData'); $data = [ 'username' => 'a', @@ -238,7 +238,7 @@ public function testValidateDataWithCustomErrorMessageLabeledStyle(): void $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); - $method = $this->getPrivateMethodInvoker($this->controller, 'validateData'); + $method = self::getPrivateMethodInvoker($this->controller, 'validateData'); $data = [ 'username' => 'a', diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index 882301692352..f64434e561bc 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -167,7 +167,7 @@ public function testConnectionGroupWithDSNPostgre(): void $this->assertSame('5', $this->getPrivateProperty($conn, 'connect_timeout')); $this->assertSame('1', $this->getPrivateProperty($conn, 'sslmode')); - $method = $this->getPrivateMethodInvoker($conn, 'buildDSN'); + $method = self::getPrivateMethodInvoker($conn, 'buildDSN'); $method(); $expected = "host=localhost port=5432 user=user password='pass' dbname=dbname connect_timeout='5' sslmode='1'"; @@ -207,7 +207,7 @@ public function testConvertDSN(string $input, string $expected): void $conn = Config::connect($this->dsnGroupPostgreNative, false); $this->assertInstanceOf(BaseConnection::class, $conn); - $method = $this->getPrivateMethodInvoker($conn, 'convertDSN'); + $method = self::getPrivateMethodInvoker($conn, 'convertDSN'); $method(); $this->assertSame($expected, $this->getPrivateProperty($conn, 'DSN')); diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index ab5b17bec174..d36a0e558685 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -371,7 +371,7 @@ public function testCreateTableWithNullableFieldsGivesNullDataType(): void ], ]); - $createTable = $this->getPrivateMethodInvoker($this->forge, '_createTable'); + $createTable = self::getPrivateMethodInvoker($this->forge, '_createTable'); $sql = $createTable('forge_nullable_table', false, []); diff --git a/tests/system/Database/Live/OCI8/ConnectionTest.php b/tests/system/Database/Live/OCI8/ConnectionTest.php index caf97ed632fd..6fe89302337f 100644 --- a/tests/system/Database/Live/OCI8/ConnectionTest.php +++ b/tests/system/Database/Live/OCI8/ConnectionTest.php @@ -47,7 +47,7 @@ public function testIsValidDSN(string $dsn): void $db = new Connection($this->settings); - $isValidDSN = $this->getPrivateMethodInvoker($db, 'isValidDSN'); + $isValidDSN = self::getPrivateMethodInvoker($db, 'isValidDSN'); $this->assertTrue($isValidDSN()); } diff --git a/tests/system/Database/Migrations/MigrationRunnerTest.php b/tests/system/Database/Migrations/MigrationRunnerTest.php index 61517d9f7521..fbe7cbca05f5 100644 --- a/tests/system/Database/Migrations/MigrationRunnerTest.php +++ b/tests/system/Database/Migrations/MigrationRunnerTest.php @@ -156,7 +156,7 @@ public function testGetMigrationNumberAllDigits(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationNumber'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationNumber'); $this->assertSame('20190806235100', $method('20190806235100_Foo')); } @@ -165,7 +165,7 @@ public function testGetMigrationNumberDashes(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationNumber'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationNumber'); $this->assertSame('2019-08-06-235100', $method('2019-08-06-235100_Foo')); } @@ -174,7 +174,7 @@ public function testGetMigrationNumberUnderscores(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationNumber'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationNumber'); $this->assertSame('2019_08_06_235100', $method('2019_08_06_235100_Foo')); } @@ -183,7 +183,7 @@ public function testGetMigrationNumberReturnsZeroIfNoneFound(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationNumber'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationNumber'); $this->assertSame('0', $method('Foo')); } @@ -192,7 +192,7 @@ public function testGetMigrationNameDashes(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationName'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationName'); $this->assertSame('Foo_bar', $method('2019-08-06-235100_Foo_bar')); } @@ -201,7 +201,7 @@ public function testGetMigrationNameUnderscores(): void { $runner = new MigrationRunner($this->config); - $method = $this->getPrivateMethodInvoker($runner, 'getMigrationName'); + $method = self::getPrivateMethodInvoker($runner, 'getMigrationName'); $this->assertSame('Foo_bar', $method('2019_08_06_235100_Foo_bar')); } diff --git a/tests/system/Debug/ExceptionHandlerTest.php b/tests/system/Debug/ExceptionHandlerTest.php index 37beae999886..36279dd58f80 100644 --- a/tests/system/Debug/ExceptionHandlerTest.php +++ b/tests/system/Debug/ExceptionHandlerTest.php @@ -43,7 +43,7 @@ protected function setUp(): void public function testDetermineViewsPageNotFoundException(): void { - $determineView = $this->getPrivateMethodInvoker($this->handler, 'determineView'); + $determineView = self::getPrivateMethodInvoker($this->handler, 'determineView'); $exception = PageNotFoundException::forControllerNotFound('Foo', 'bar'); $templatePath = APPPATH . 'Views/errors/html'; @@ -54,7 +54,7 @@ public function testDetermineViewsPageNotFoundException(): void public function testDetermineViewsRuntimeException(): void { - $determineView = $this->getPrivateMethodInvoker($this->handler, 'determineView'); + $determineView = self::getPrivateMethodInvoker($this->handler, 'determineView'); $exception = new RuntimeException('Exception'); $templatePath = APPPATH . 'Views/errors/html'; @@ -65,7 +65,7 @@ public function testDetermineViewsRuntimeException(): void public function testDetermineViewsRuntimeExceptionCode404(): void { - $determineView = $this->getPrivateMethodInvoker($this->handler, 'determineView'); + $determineView = self::getPrivateMethodInvoker($this->handler, 'determineView'); $exception = new RuntimeException('foo', 404); $templatePath = APPPATH . 'Views/errors/html'; @@ -78,7 +78,7 @@ public function testDetermineViewsDisplayErrorsOffRuntimeException(): void { ini_set('display_errors', '0'); - $determineView = $this->getPrivateMethodInvoker($this->handler, 'determineView'); + $determineView = self::getPrivateMethodInvoker($this->handler, 'determineView'); $exception = new RuntimeException('Exception'); $templatePath = APPPATH . 'Views/errors/html'; @@ -91,7 +91,7 @@ public function testDetermineViewsDisplayErrorsOffRuntimeException(): void public function testCollectVars(): void { - $collectVars = $this->getPrivateMethodInvoker($this->handler, 'collectVars'); + $collectVars = self::getPrivateMethodInvoker($this->handler, 'collectVars'); $vars = $collectVars(new RuntimeException('This.'), 404); @@ -163,7 +163,7 @@ public function testHandleCLIPageNotFoundException(): void public function testMaskSensitiveData(): void { - $maskSensitiveData = $this->getPrivateMethodInvoker($this->handler, 'maskSensitiveData'); + $maskSensitiveData = self::getPrivateMethodInvoker($this->handler, 'maskSensitiveData'); $trace = [ 0 => [ @@ -212,7 +212,7 @@ public function testMaskSensitiveData(): void public function testMaskSensitiveDataTraceDataKey(): void { - $maskSensitiveData = $this->getPrivateMethodInvoker($this->handler, 'maskSensitiveData'); + $maskSensitiveData = self::getPrivateMethodInvoker($this->handler, 'maskSensitiveData'); $trace = [ 0 => [ @@ -248,7 +248,7 @@ public function testHighlightFile(): void 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string', ]); - $highlightFile = $this->getPrivateMethodInvoker($this->handler, 'highlightFile'); + $highlightFile = self::getPrivateMethodInvoker($this->handler, 'highlightFile'); $result = $highlightFile(SUPPORTPATH . 'Controllers' . DIRECTORY_SEPARATOR . 'Hello.php', 16); $resultFile = match (true) { diff --git a/tests/system/Debug/ExceptionsTest.php b/tests/system/Debug/ExceptionsTest.php index 965bb1df78dd..6ce2fda06c88 100644 --- a/tests/system/Debug/ExceptionsTest.php +++ b/tests/system/Debug/ExceptionsTest.php @@ -96,7 +96,7 @@ public function testSuppressedDeprecationsAreLogged(): void public function testDetermineViews(): void { - $determineView = $this->getPrivateMethodInvoker($this->exception, 'determineView'); + $determineView = self::getPrivateMethodInvoker($this->exception, 'determineView'); $this->assertSame('error_404.php', $determineView(PageNotFoundException::forControllerNotFound('Foo', 'bar'), '')); $this->assertSame('error_exception.php', $determineView(new RuntimeException('Exception'), '')); @@ -105,7 +105,7 @@ public function testDetermineViews(): void public function testCollectVars(): void { - $vars = $this->getPrivateMethodInvoker($this->exception, 'collectVars')(new RuntimeException('This.'), 404); + $vars = self::getPrivateMethodInvoker($this->exception, 'collectVars')(new RuntimeException('This.'), 404); $this->assertIsArray($vars); $this->assertCount(7, $vars); @@ -117,7 +117,7 @@ public function testCollectVars(): void public function testDetermineCodes(): void { - $determineCodes = $this->getPrivateMethodInvoker($this->exception, 'determineCodes'); + $determineCodes = self::getPrivateMethodInvoker($this->exception, 'determineCodes'); $this->assertSame([500, EXIT_ERROR], $determineCodes(new RuntimeException('This.'))); $this->assertSame([500, EXIT_ERROR], $determineCodes(new RuntimeException('That.', 600))); @@ -146,7 +146,7 @@ public function testRenderBacktrace(): void public function testMaskSensitiveData(): void { - $maskSensitiveData = $this->getPrivateMethodInvoker($this->exception, 'maskSensitiveData'); + $maskSensitiveData = self::getPrivateMethodInvoker($this->exception, 'maskSensitiveData'); $trace = [ 0 => [ @@ -195,7 +195,7 @@ public function testMaskSensitiveData(): void public function testMaskSensitiveDataTraceDataKey(): void { - $maskSensitiveData = $this->getPrivateMethodInvoker($this->exception, 'maskSensitiveData'); + $maskSensitiveData = self::getPrivateMethodInvoker($this->exception, 'maskSensitiveData'); $trace = [ 0 => [ diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php index 44a1acf54dab..7bb402eaa4af 100644 --- a/tests/system/Files/FileCollectionTest.php +++ b/tests/system/Files/FileCollectionTest.php @@ -47,14 +47,14 @@ public static function setUpBeforeClass(): void public function testResolveDirectoryDirectory(): void { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); $this->assertSame($this->directory, $method($this->directory)); } public function testResolveDirectoryFile(): void { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); $this->expectException(FileException::class); $this->expectExceptionMessage(lang('Files.expectedDirectory', ['invokeArgs'])); @@ -68,7 +68,7 @@ public function testResolveDirectorySymlink(): void $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); symlink($this->directory, $link); - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); $this->assertSame($this->directory, $method($link)); @@ -77,7 +77,7 @@ public function testResolveDirectorySymlink(): void public function testResolveFileFile(): void { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); $this->assertSame($this->file, $method($this->file)); } @@ -88,7 +88,7 @@ public function testResolveFileSymlink(): void $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); symlink($this->file, $link); - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); $this->assertSame($this->file, $method($link)); @@ -97,7 +97,7 @@ public function testResolveFileSymlink(): void public function testResolveFileDirectory(): void { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + $method = self::getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); $this->expectException(FileException::class); $this->expectExceptionMessage(lang('Files.expectedFile', ['invokeArgs'])); diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 94c2b7dbbb24..e72a1d37d17c 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -66,7 +66,7 @@ public function testPrepareURLIgnoresAppConfig(): void $request = $this->getRequest(['baseURI' => 'http://example.com/v1/']); - $method = $this->getPrivateMethodInvoker($request, 'prepareURL'); + $method = self::getPrivateMethodInvoker($request, 'prepareURL'); $this->assertSame('http://example.com/v1/bananas', $method('bananas')); } diff --git a/tests/system/Models/MiscellaneousModelTest.php b/tests/system/Models/MiscellaneousModelTest.php index 74cbf95479e1..556c1b441c18 100644 --- a/tests/system/Models/MiscellaneousModelTest.php +++ b/tests/system/Models/MiscellaneousModelTest.php @@ -109,7 +109,7 @@ public function testUndefinedTypeInTransformDataToArray(): void $this->expectExceptionMessage('Invalid type "whatever" used upon transforming data to array.'); $this->createModel(JobModel::class); - $method = $this->getPrivateMethodInvoker($this->model, 'transformDataToArray'); + $method = self::getPrivateMethodInvoker($this->model, 'transformDataToArray'); $method([], 'whatever'); } @@ -119,7 +119,7 @@ public function testEmptyDataInTransformDataToArray(): void $this->expectExceptionMessage('There is no data to insert.'); $this->createModel(JobModel::class); - $method = $this->getPrivateMethodInvoker($this->model, 'transformDataToArray'); + $method = self::getPrivateMethodInvoker($this->model, 'transformDataToArray'); $method([], 'insert'); } } diff --git a/tests/system/Models/ValidationModelRuleGroupTest.php b/tests/system/Models/ValidationModelRuleGroupTest.php index b2ab45eb5693..eb50406ab62b 100644 --- a/tests/system/Models/ValidationModelRuleGroupTest.php +++ b/tests/system/Models/ValidationModelRuleGroupTest.php @@ -194,7 +194,7 @@ public function testSkipValidation(): void public function testCleanValidationRemovesAllWhenNoDataProvided(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', @@ -207,7 +207,7 @@ public function testCleanValidationRemovesAllWhenNoDataProvided(): void public function testCleanValidationRemovesOnlyForFieldsNotProvided(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', @@ -225,7 +225,7 @@ public function testCleanValidationRemovesOnlyForFieldsNotProvided(): void public function testCleanValidationReturnsAllWhenAllExist(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', diff --git a/tests/system/Models/ValidationModelTest.php b/tests/system/Models/ValidationModelTest.php index 9257c5eb8e74..4a99d8fae5bb 100644 --- a/tests/system/Models/ValidationModelTest.php +++ b/tests/system/Models/ValidationModelTest.php @@ -182,7 +182,7 @@ public function testSkipValidation(): void public function testCleanValidationRemovesAllWhenNoDataProvided(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', @@ -195,7 +195,7 @@ public function testCleanValidationRemovesAllWhenNoDataProvided(): void public function testCleanValidationRemovesOnlyForFieldsNotProvided(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', @@ -213,7 +213,7 @@ public function testCleanValidationRemovesOnlyForFieldsNotProvided(): void public function testCleanValidationReturnsAllWhenAllExist(): void { - $cleaner = $this->getPrivateMethodInvoker($this->model, 'cleanValidationRules'); + $cleaner = self::getPrivateMethodInvoker($this->model, 'cleanValidationRules'); $rules = [ 'name' => 'required', diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index e92bdd0c69c3..7e6e21e430d4 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -141,7 +141,7 @@ public function testWipeDirectory(): void mkdir($directory, 0700); $this->assertDirectoryExists($directory); - $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method = self::getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); $method($directory); $this->assertDirectoryDoesNotExist($directory); @@ -149,7 +149,7 @@ public function testWipeDirectory(): void public function testWipeIgnoresFiles(): void { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method = self::getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); $method($this->file); $this->assertFileExists($this->file); diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index 580909cdff76..e51e6c41f694 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -369,7 +369,7 @@ public function testXMLFormatOutput(): void private function invoke(object $controller, string $method, array $args = []) { - $method = $this->getPrivateMethodInvoker($controller, $method); + $method = self::getPrivateMethodInvoker($controller, $method); return $method(...$args); } diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 2f3aea06470b..6bc975d16c22 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -319,7 +319,7 @@ public function testGetPostedTokenReturnsTokenFromPost(): void { $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $request = $this->createIncomingRequest(); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $method = self::getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } @@ -328,7 +328,7 @@ public function testGetPostedTokenReturnsTokenFromHeader(): void { $_POST = []; $request = $this->createIncomingRequest()->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $method = self::getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } @@ -338,7 +338,7 @@ public function testGetPostedTokenReturnsTokenFromJsonBody(): void $_POST = []; $jsonBody = json_encode(['csrf_test_name' => '8b9218a55906f9dcc1dc263dce7f005a']); $request = $this->createIncomingRequest()->setBody($jsonBody); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $method = self::getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } @@ -348,7 +348,7 @@ public function testGetPostedTokenReturnsTokenFromFormBody(): void $_POST = []; $formBody = 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a'; $request = $this->createIncomingRequest()->setBody($formBody); - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $method = self::getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $method($request)); } @@ -356,7 +356,7 @@ public function testGetPostedTokenReturnsTokenFromFormBody(): void #[DataProvider('provideGetPostedTokenReturnsNullForInvalidInputs')] public function testGetPostedTokenReturnsNullForInvalidInputs(string $case, IncomingRequest $request): void { - $method = $this->getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); + $method = self::getPrivateMethodInvoker($this->createMockSecurity(), 'getPostedToken'); $this->assertNull( $method($request), diff --git a/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php index 4f6143493479..ad27d88bfb76 100644 --- a/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php +++ b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php @@ -97,13 +97,13 @@ public function testWriteUpdate(): void $this->setPrivateProperty($handler, 'sessionID', '1f5o06b43phsnnf8if6bo33b635e4p2o'); $this->setPrivateProperty($handler, 'rowExists', true); - $lockSession = $this->getPrivateMethodInvoker($handler, 'lockSession'); + $lockSession = self::getPrivateMethodInvoker($handler, 'lockSession'); $lockSession('1f5o06b43phsnnf8if6bo33b635e4p2o'); $data = '__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";'; $this->assertTrue($handler->write('1f5o06b43phsnnf8if6bo33b635e4p2o', $data)); - $releaseLock = $this->getPrivateMethodInvoker($handler, 'releaseLock'); + $releaseLock = self::getPrivateMethodInvoker($handler, 'releaseLock'); $releaseLock(); $row = $this->db->table('ci_sessions') diff --git a/tests/system/Test/FabricatorTest.php b/tests/system/Test/FabricatorTest.php index a05f9e10a7ec..041dea518485 100644 --- a/tests/system/Test/FabricatorTest.php +++ b/tests/system/Test/FabricatorTest.php @@ -157,7 +157,7 @@ public function testDetectFormattersDetectsFormatters(): void $formatters = ['boo' => 'hiss']; $fabricator = new Fabricator(UserModel::class, $formatters); - $method = $this->getPrivateMethodInvoker($fabricator, 'detectFormatters'); + $method = self::getPrivateMethodInvoker($fabricator, 'detectFormatters'); $method(); @@ -200,7 +200,7 @@ public function testGuessFormattersReturnsActual(): void { $fabricator = new Fabricator(UserModel::class); - $method = $this->getPrivateMethodInvoker($fabricator, 'guessFormatter'); + $method = self::getPrivateMethodInvoker($fabricator, 'guessFormatter'); $field = 'catchPhrase'; $formatter = $method($field); @@ -212,7 +212,7 @@ public function testGuessFormattersFieldReturnsDateFormat(): void { $fabricator = new Fabricator(UserModel::class); - $method = $this->getPrivateMethodInvoker($fabricator, 'guessFormatter'); + $method = self::getPrivateMethodInvoker($fabricator, 'guessFormatter'); $field = 'created_at'; $formatter = $method($field); @@ -224,7 +224,7 @@ public function testGuessFormattersPrimaryReturnsNumberBetween(): void { $fabricator = new Fabricator(UserModel::class); - $method = $this->getPrivateMethodInvoker($fabricator, 'guessFormatter'); + $method = self::getPrivateMethodInvoker($fabricator, 'guessFormatter'); $field = 'id'; $formatter = $method($field); @@ -236,7 +236,7 @@ public function testGuessFormattersMatchesPartial(): void { $fabricator = new Fabricator(UserModel::class); - $method = $this->getPrivateMethodInvoker($fabricator, 'guessFormatter'); + $method = self::getPrivateMethodInvoker($fabricator, 'guessFormatter'); $field = 'business_email'; $formatter = $method($field); @@ -248,7 +248,7 @@ public function testGuessFormattersFallback(): void { $fabricator = new Fabricator(UserModel::class); - $method = $this->getPrivateMethodInvoker($fabricator, 'guessFormatter'); + $method = self::getPrivateMethodInvoker($fabricator, 'guessFormatter'); $field = 'zaboomafoo'; $formatter = $method($field); diff --git a/tests/system/Test/ReflectionHelperTest.php b/tests/system/Test/ReflectionHelperTest.php index 8e4eda219485..e110a4820422 100644 --- a/tests/system/Test/ReflectionHelperTest.php +++ b/tests/system/Test/ReflectionHelperTest.php @@ -72,7 +72,7 @@ public function testSetPrivatePropertyWithStatic(): void public function testGetPrivateMethodInvokerWithObject(): void { $obj = new TestForReflectionHelper(); - $method = $this->getPrivateMethodInvoker( + $method = self::getPrivateMethodInvoker( $obj, 'privateMethod', ); @@ -84,7 +84,7 @@ public function testGetPrivateMethodInvokerWithObject(): void public function testGetPrivateMethodInvokerWithStatic(): void { - $method = $this->getPrivateMethodInvoker( + $method = self::getPrivateMethodInvoker( TestForReflectionHelper::class, 'privateStaticMethod', ); diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 413ea1e0c518..621b20e1103f 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -1078,14 +1078,14 @@ public function testSplitRulesFalse(): void */ public function testSplitNotRegex(): void { - $method = $this->getPrivateMethodInvoker($this->validation, 'splitRules'); + $method = self::getPrivateMethodInvoker($this->validation, 'splitRules'); $result = $method('uploaded[avatar]|max_size[avatar,1024]'); $this->assertSame('uploaded[avatar]', $result[0]); } public function testSplitRegex(): void { - $method = $this->getPrivateMethodInvoker($this->validation, 'splitRules'); + $method = self::getPrivateMethodInvoker($this->validation, 'splitRules'); $result = $method('required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]'); $this->assertSame('regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', $result[1]); } @@ -1531,7 +1531,7 @@ public static function provideValidationOfArrayData(): iterable #[DataProvider('provideSplittingOfComplexStringRules')] public function testSplittingOfComplexStringRules(string $input, array $expected): void { - $splitter = $this->getPrivateMethodInvoker($this->validation, 'splitRules'); + $splitter = self::getPrivateMethodInvoker($this->validation, 'splitRules'); $this->assertSame($expected, $splitter($input)); } @@ -1597,10 +1597,10 @@ protected function placeholderReplacementResultDetermination(string $placeholder $data = [$placeholder => '12']; } - $validationRules = $this->getPrivateMethodInvoker($this->validation, 'fillPlaceholders')($this->validation->getRules(), $data); + $validationRules = self::getPrivateMethodInvoker($this->validation, 'fillPlaceholders')($this->validation->getRules(), $data); $fieldRules = $validationRules['foo']['rules'] ?? $validationRules['foo']; if (is_string($fieldRules)) { - $fieldRules = $this->getPrivateMethodInvoker($this->validation, 'splitRules')($fieldRules); + $fieldRules = self::getPrivateMethodInvoker($this->validation, 'splitRules')($fieldRules); } // loop all rules for this field diff --git a/user_guide_src/source/testing/overview/013.php b/user_guide_src/source/testing/overview/013.php index bca1a8513f67..3eedfa9e1144 100644 --- a/user_guide_src/source/testing/overview/013.php +++ b/user_guide_src/source/testing/overview/013.php @@ -6,7 +6,7 @@ $obj = new Foo(); // Get the invoker for the 'privateMethod' method. -$method = $this->getPrivateMethodInvoker($obj, 'privateMethod'); +$method = self::getPrivateMethodInvoker($obj, 'privateMethod'); // Test the results $this->assertEquals('bar', $method('param1', 'param2')); From 453ec563b2f4850e05dd3792abeef503741c098e Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 19 Mar 2025 01:47:54 +0800 Subject: [PATCH 41/83] refactor: fix tests after smarter `getPrivateMethodInvoker()` return (#9491) --- tests/system/ControllerTest.php | 8 ++++++-- tests/system/Database/ConfigTest.php | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 6bf50ba0bd76..113b02c14deb 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -89,13 +89,17 @@ public function testConstructorHTTPS(): void $_SERVER = $original; // restore so code coverage doesn't break } - public function testCachePage(): void + public function testCachePageSetsTtl(): void { $this->controller = new Controller(); $this->controller->initController($this->request, $this->response, $this->logger); $method = self::getPrivateMethodInvoker($this->controller, 'cachePage'); - $this->assertNull($method(10)); + + $this->assertSame(0, self::getPrivateProperty(service('responsecache'), 'ttl')); + + $method(10); + $this->assertSame(10, self::getPrivateProperty(service('responsecache'), 'ttl')); } public function testValidate(): void diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index f64434e561bc..1d2482e0ad87 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -13,6 +13,7 @@ namespace CodeIgniter\Database; +use CodeIgniter\Database\Postgre\Connection as PostgreConnection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\ReflectionHelper; use PHPUnit\Framework\Attributes\DataProvider; @@ -149,7 +150,7 @@ public function testConnectionGroupWithDSN(): void public function testConnectionGroupWithDSNPostgre(): void { $conn = Config::connect($this->dsnGroupPostgre, false); - $this->assertInstanceOf(BaseConnection::class, $conn); + $this->assertInstanceOf(PostgreConnection::class, $conn); $this->assertSame('', $this->getPrivateProperty($conn, 'DSN')); $this->assertSame('localhost', $this->getPrivateProperty($conn, 'hostname')); @@ -205,7 +206,7 @@ public function testConvertDSN(string $input, string $expected): void // Should deprecate? $this->dsnGroupPostgreNative['DSN'] = $input; $conn = Config::connect($this->dsnGroupPostgreNative, false); - $this->assertInstanceOf(BaseConnection::class, $conn); + $this->assertInstanceOf(PostgreConnection::class, $conn); $method = self::getPrivateMethodInvoker($conn, 'convertDSN'); $method(); From 5d1d53a2178f1a4890cbca3bf04e6dae5de1dc61 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 19 Mar 2025 01:53:13 +0800 Subject: [PATCH 42/83] refactor: relax objects allowed in `model()` (#9493) --- phpstan.neon.dist | 1 + .../codeigniter.modelArgumentInstanceof.neon | 13 ------------- utils/phpstan-baseline/loader.neon | 1 - 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 utils/phpstan-baseline/codeigniter.modelArgumentInstanceof.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 999972f556b8..43d658c22c35 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -41,5 +41,6 @@ parameters: codeigniter: additionalServices: - AfterAutoloadModule\Config\Services + checkArgumentTypeOfModel: false shipmonkBaselinePerIdentifier: directory: %currentWorkingDirectory% diff --git a/utils/phpstan-baseline/codeigniter.modelArgumentInstanceof.neon b/utils/phpstan-baseline/codeigniter.modelArgumentInstanceof.neon deleted file mode 100644 index 8d709df14603..000000000000 --- a/utils/phpstan-baseline/codeigniter.modelArgumentInstanceof.neon +++ /dev/null @@ -1,13 +0,0 @@ -# total 2 errors - -parameters: - ignoreErrors: - - - message: '#^Argument \#1 \$name \(class\-string\) passed to function model does not extend CodeIgniter\\\\Model\.$#' - count: 1 - path: ../../system/RESTful/BaseResource.php - - - - message: '#^Argument \#1 \$name \(''CodeIgniter\\\\UnexsistenceClass''\) passed to function model does not extend CodeIgniter\\\\Model\.$#' - count: 1 - path: ../../tests/system/CommonFunctionsTest.php diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 24fe8aba136f..9cac99c53599 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -3,7 +3,6 @@ includes: - assign.propertyType.neon - codeigniter.cacheHandlerInstance.neon - codeigniter.getReassignArray.neon - - codeigniter.modelArgumentInstanceof.neon - codeigniter.modelArgumentType.neon - codeigniter.superglobalAccess.neon - codeigniter.superglobalAccessAssign.neon From 1cfe68cc1de1946553dbb0943740926fd854c69a Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Tue, 18 Mar 2025 21:49:34 +0300 Subject: [PATCH 43/83] refactor: Fix phpstan errors `parameterByRef.unusedType` (#9487) --- system/Log/Handlers/ChromeLoggerHandler.php | 2 ++ tests/_support/Validation/TestRules.php | 3 +++ utils/phpstan-baseline/loader.neon | 1 - .../phpstan-baseline/parameterByRef.unusedType.neon | 13 ------------- 4 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 utils/phpstan-baseline/parameterByRef.unusedType.neon diff --git a/system/Log/Handlers/ChromeLoggerHandler.php b/system/Log/Handlers/ChromeLoggerHandler.php index eedea60a1558..5813f338b389 100644 --- a/system/Log/Handlers/ChromeLoggerHandler.php +++ b/system/Log/Handlers/ChromeLoggerHandler.php @@ -151,6 +151,8 @@ protected function format($object) /** * Attaches the header and the content to the passed in request object. * + * @param-out ResponseInterface $response + * * @return void */ public function sendLogs(?ResponseInterface &$response = null) diff --git a/tests/_support/Validation/TestRules.php b/tests/_support/Validation/TestRules.php index 41f765fe14a7..cb6cde9d4584 100644 --- a/tests/_support/Validation/TestRules.php +++ b/tests/_support/Validation/TestRules.php @@ -15,6 +15,9 @@ class TestRules { + /** + * @param-out string $error + */ public function customError(string $str, ?string &$error = null) { $error = 'My lovely error'; diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 9cac99c53599..a2989fec1d0d 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -25,7 +25,6 @@ includes: - notIdentical.alwaysTrue.neon - nullCoalesce.property.neon - nullCoalesce.variable.neon - - parameterByRef.unusedType.neon - property.defaultValue.neon - property.nonObject.neon - property.notFound.neon diff --git a/utils/phpstan-baseline/parameterByRef.unusedType.neon b/utils/phpstan-baseline/parameterByRef.unusedType.neon deleted file mode 100644 index a750c89a492e..000000000000 --- a/utils/phpstan-baseline/parameterByRef.unusedType.neon +++ /dev/null @@ -1,13 +0,0 @@ -# total 2 errors - -parameters: - ignoreErrors: - - - message: '#^Method CodeIgniter\\Log\\Handlers\\ChromeLoggerHandler\:\:sendLogs\(\) never assigns null to &\$response so it can be removed from the by\-ref type\.$#' - count: 1 - path: ../../system/Log/Handlers/ChromeLoggerHandler.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:customError\(\) never assigns null to &\$error so it can be removed from the by\-ref type\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php From c5e1c8bc8a4ac8ab5ca4d965170d9c164c972514 Mon Sep 17 00:00:00 2001 From: Aselsan Date: Wed, 19 Mar 2025 21:26:56 +0700 Subject: [PATCH 44/83] fix: Inconsistent directives value between Default and OPCache groups (#9476) * fix: Inconsistent directives value between default and OPCache groups * improve remark message * Apply suggestions from code review Co-authored-by: John Paul E. Balandan, CPA --------- Co-authored-by: John Paul E. Balandan, CPA --- system/Security/CheckPhpIni.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Security/CheckPhpIni.php b/system/Security/CheckPhpIni.php index e2ff075678cd..35431c35af57 100644 --- a/system/Security/CheckPhpIni.php +++ b/system/Security/CheckPhpIni.php @@ -135,7 +135,7 @@ public static function checkIni(?string $argument = null): array 'date.timezone' => ['recommended' => 'UTC'], 'mbstring.language' => ['recommended' => 'neutral'], 'opcache.enable' => ['recommended' => '1'], - 'opcache.enable_cli' => ['recommended' => '1'], + 'opcache.enable_cli' => ['recommended' => '0', 'remark' => 'Enable when you are using queues or running repetitive CLI tasks'], 'opcache.jit' => ['recommended' => 'tracing'], 'opcache.jit_buffer_size' => ['recommended' => '128', 'remark' => 'Adjust with your free space of memory'], 'zend.assertions' => ['recommended' => '-1'], @@ -144,7 +144,7 @@ public static function checkIni(?string $argument = null): array if ($argument === 'opcache') { $items = [ 'opcache.enable' => ['recommended' => '1'], - 'opcache.enable_cli' => ['recommended' => '0', 'remark' => 'Enable when you using CLI'], + 'opcache.enable_cli' => ['recommended' => '0', 'remark' => 'Enable when you are using queues or running repetitive CLI tasks'], 'opcache.jit' => ['recommended' => 'tracing', 'remark' => 'Disable when you used third-party extensions'], 'opcache.jit_buffer_size' => ['recommended' => '128', 'remark' => 'Adjust with your free space of memory'], 'opcache.memory_consumption' => ['recommended' => '128', 'remark' => 'Adjust with your free space of memory'], From 7a177dd32b6983a2b5f30db59d63f4008ff552af Mon Sep 17 00:00:00 2001 From: Ilia Chernykh Date: Sat, 22 Mar 2025 01:56:25 +0500 Subject: [PATCH 45/83] Fix the description of $protectFields property (#9495) --- system/BaseModel.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index b0be872050c6..cf8df09998f3 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -121,9 +121,13 @@ abstract class BaseModel protected ?DataConverter $converter = null; /** - * If this model should use "softDeletes" and - * simply set a date when rows are deleted, or - * do hard deletes. + * Determines whether the model should protect field names during + * mass assignment operations such as insert() and update(). + * + * When set to true, only the fields explicitly defined in the $allowedFields + * property will be allowed for mass assignment. This helps prevent + * unintended modification of database fields and improves security + * by avoiding mass assignment vulnerabilities. * * @var bool */ From c7e479860301e300daf605c11e6d0f99850f4849 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Thu, 27 Mar 2025 09:23:53 +0100 Subject: [PATCH 46/83] refactor: OCI8 `limit()` method (#9472) * refactor: OCI8 limit() method * remove the unused class property and method * phpstan - regenerate baseline --- system/Database/OCI8/Builder.php | 33 +++---------------- .../phpstan-baseline/missingType.return.neon | 7 +--- 2 files changed, 5 insertions(+), 35 deletions(-) diff --git a/system/Database/OCI8/Builder.php b/system/Database/OCI8/Builder.php index 5b586761e2c0..2e62b3121cbd 100644 --- a/system/Database/OCI8/Builder.php +++ b/system/Database/OCI8/Builder.php @@ -48,16 +48,6 @@ class Builder extends BaseBuilder */ protected $countString = 'SELECT COUNT(1) '; - /** - * Limit used flag - * - * If we use LIMIT, we'll add a field that will - * throw off num_fields later. - * - * @var bool - */ - protected $limitUsed = false; - /** * A reference to the database connection. * @@ -214,28 +204,13 @@ protected function _update(string $table, array $values): string protected function _limit(string $sql, bool $offsetIgnore = false): string { $offset = (int) ($offsetIgnore === false ? $this->QBOffset : 0); - if (version_compare($this->db->getVersion(), '12.1', '>=')) { - // OFFSET-FETCH can be used only with the ORDER BY clause - if (empty($this->QBOrderBy)) { - $sql .= ' ORDER BY 1'; - } - return $sql . ' OFFSET ' . $offset . ' ROWS FETCH NEXT ' . $this->QBLimit . ' ROWS ONLY'; + // OFFSET-FETCH can be used only with the ORDER BY clause + if (empty($this->QBOrderBy)) { + $sql .= ' ORDER BY 1'; } - $this->limitUsed = true; - $limitTemplateQuery = 'SELECT * FROM (SELECT INNER_QUERY.*, ROWNUM RNUM FROM (%s) INNER_QUERY WHERE ROWNUM < %d)' . ($offset !== 0 ? ' WHERE RNUM >= %d' : ''); - - return sprintf($limitTemplateQuery, $sql, $offset + $this->QBLimit + 1, $offset); - } - - /** - * Resets the query builder values. Called by the get() function - */ - protected function resetSelect() - { - $this->limitUsed = false; - parent::resetSelect(); + return $sql . ' OFFSET ' . $offset . ' ROWS FETCH NEXT ' . $this->QBLimit . ' ROWS ONLY'; } /** diff --git a/utils/phpstan-baseline/missingType.return.neon b/utils/phpstan-baseline/missingType.return.neon index baddb8644505..838443fab4f0 100644 --- a/utils/phpstan-baseline/missingType.return.neon +++ b/utils/phpstan-baseline/missingType.return.neon @@ -1,4 +1,4 @@ -# total 201 errors +# total 200 errors parameters: ignoreErrors: @@ -112,11 +112,6 @@ parameters: count: 1 path: ../../system/Database/MigrationRunner.php - - - message: '#^Method CodeIgniter\\Database\\OCI8\\Builder\:\:resetSelect\(\) has no return type specified\.$#' - count: 1 - path: ../../system/Database/OCI8/Builder.php - - message: '#^Method CodeIgniter\\Database\\Postgre\\Connection\:\:buildDSN\(\) has no return type specified\.$#' count: 1 From c377646e8cb42d80e59d17b19b4155c476442879 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Thu, 27 Mar 2025 14:32:11 +0100 Subject: [PATCH 47/83] refactor: update PHPStan baseline and fix Rector (#9498) * refactor: update PHPStan baseline * fix Rector --- system/HTTP/UserAgent.php | 2 +- utils/phpstan-baseline/loader.neon | 2 ++ .../phpstan-baseline/method.alreadyNarrowedType.neon | 12 +++++++++++- utils/phpstan-baseline/offsetAccess.notFound.neon | 8 ++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 utils/phpstan-baseline/offsetAccess.notFound.neon diff --git a/system/HTTP/UserAgent.php b/system/HTTP/UserAgent.php index ec4d17438284..5e8eece63659 100644 --- a/system/HTTP/UserAgent.php +++ b/system/HTTP/UserAgent.php @@ -278,7 +278,7 @@ protected function compileData() $this->setPlatform(); foreach (['setRobot', 'setBrowser', 'setMobile'] as $function) { - if ($this->{$function}() === true) { + if ($this->{$function}()) { break; } } diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index a2989fec1d0d..f795aabb7fb5 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,3 +1,4 @@ +# total 3759 errors includes: - argument.type.neon - assign.propertyType.neon @@ -25,6 +26,7 @@ includes: - notIdentical.alwaysTrue.neon - nullCoalesce.property.neon - nullCoalesce.variable.neon + - offsetAccess.notFound.neon - property.defaultValue.neon - property.nonObject.neon - property.notFound.neon diff --git a/utils/phpstan-baseline/method.alreadyNarrowedType.neon b/utils/phpstan-baseline/method.alreadyNarrowedType.neon index ed9ef85490e3..23132319175b 100644 --- a/utils/phpstan-baseline/method.alreadyNarrowedType.neon +++ b/utils/phpstan-baseline/method.alreadyNarrowedType.neon @@ -1,7 +1,17 @@ -# total 22 errors +# total 24 errors parameters: ignoreErrors: + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with bool will always evaluate to true\.$#' + count: 1 + path: ../../admin/starter/tests/unit/HealthTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with bool will always evaluate to true\.$#' + count: 1 + path: ../../tests/system/Autoloader/AutoloaderTest.php + - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertIsBool\(\) with bool will always evaluate to true\.$#' count: 1 diff --git a/utils/phpstan-baseline/offsetAccess.notFound.neon b/utils/phpstan-baseline/offsetAccess.notFound.neon new file mode 100644 index 000000000000..ba50b4d14f96 --- /dev/null +++ b/utils/phpstan-baseline/offsetAccess.notFound.neon @@ -0,0 +1,8 @@ +# total 2 errors + +parameters: + ignoreErrors: + - + message: '#^Offset ''_ci_old_input'' does not exist on array\{\}\.$#' + count: 2 + path: ../../tests/system/HTTP/RedirectResponseTest.php From 80d767a05f32ea5e88ded1237606cd0aff3d6076 Mon Sep 17 00:00:00 2001 From: michalsn Date: Mon, 7 Apr 2025 10:13:19 +0200 Subject: [PATCH 48/83] chore: update rector to 2.0.11 --- composer.json | 2 +- rector.php | 7 ----- tests/system/CodeIgniterTest.php | 5 ++++ .../Database/Live/OCI8/LastInsertIDTest.php | 2 ++ .../system/HTTP/Files/FileCollectionTest.php | 8 +++++ tests/system/HTTP/Files/FileMovingTest.php | 3 ++ tests/system/Pager/PagerRendererTest.php | 30 +++++++++---------- tests/system/Test/ControllerTestTraitTest.php | 2 ++ tests/system/Throttle/ThrottleTest.php | 18 +++++------ 9 files changed, 45 insertions(+), 32 deletions(-) diff --git a/composer.json b/composer.json index 50371dc14671..902c2bd11065 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpcov": "^9.0.2 || ^10.0", "phpunit/phpunit": "^10.5.16 || ^11.2", "predis/predis": "^1.1 || ^2.3", - "rector/rector": "2.0.10", + "rector/rector": "2.0.11", "shipmonk/phpstan-baseline-per-identifier": "^2.0" }, "replace": { diff --git a/rector.php b/rector.php index 7adec00da4bd..6e9a1ef5def2 100644 --- a/rector.php +++ b/rector.php @@ -18,7 +18,6 @@ use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector; use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector; use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector; -use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector; use Rector\CodeQuality\Rector\Ternary\TernaryEmptyArrayArrayDimFetchToCoalesceRector; use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector; use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; @@ -37,7 +36,6 @@ use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; -use Rector\PHPUnit\CodeQuality\Rector\MethodCall\AssertCountWithZeroToAssertEmptyRector; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector; @@ -46,7 +44,6 @@ 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; @@ -169,8 +166,6 @@ NullToStrictStringFuncCallArgRector::class, CompactToVariablesRector::class, - - AssertCountWithZeroToAssertEmptyRector::class, ]) // auto import fully qualified class names ->withImportNames(removeUnusedImports: true) @@ -192,7 +187,6 @@ MakeInheritedMethodVisibilitySameAsParentRector::class, SimplifyEmptyCheckOnEmptyArrayRector::class, TernaryEmptyArrayArrayDimFetchToCoalesceRector::class, - EmptyOnNullableObjectToInstanceOfRector::class, DisallowedEmptyRuleFixerRector::class, PrivatizeFinalClassPropertyRector::class, BooleanInIfConditionRuleFixerRector::class, @@ -202,7 +196,6 @@ AddMethodCallBasedStrictParamTypeRector::class, TypedPropertyFromAssignsRector::class, ClosureReturnTypeRector::class, - FlipTypeControlToUseExclusiveTypeRector::class, AddArrowFunctionReturnTypeRector::class, ]) ->withConfiguredRule(StringClassNameToClassConstantRector::class, [ diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index ca7819306e62..ed6ba957f90c 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -13,6 +13,7 @@ namespace CodeIgniter; +use CodeIgniter\HTTP\ResponseInterface; use App\Controllers\Home; use CodeIgniter\Config\Services; use CodeIgniter\Debug\Timer; @@ -95,6 +96,7 @@ public function testRunEmptyDefaultRouteReturnResponse(): void $_SERVER['argc'] = 1; $response = $this->codeigniter->run(null, true); + $this->assertInstanceof(ResponseInterface::class, $response); $this->assertStringContainsString('Welcome to CodeIgniter', $response->getBody()); } @@ -159,6 +161,7 @@ public function testRun404OverrideControllerReturnsResponse(): void Services::injectMock('router', $router); $response = $this->codeigniter->run($routes, true); + $this->assertInstanceof(ResponseInterface::class, $response); $this->assertStringContainsString('Oops', $response->getBody()); $this->assertSame(567, $response->getStatusCode()); @@ -177,6 +180,7 @@ public function testRun404OverrideReturnResponse(): void Services::injectMock('router', $router); $response = $this->codeigniter->run($routes, true); + $this->assertInstanceof(ResponseInterface::class, $response); $this->assertStringContainsString('Oops', $response->getBody()); } @@ -467,6 +471,7 @@ public function testRunForceSecure(): void $this->assertNull($response->header('Location')); $response = $codeigniter->run(null, true); + $this->assertInstanceof(ResponseInterface::class, $response); $this->assertSame('https://example.com/index.php/', $response->header('Location')->getValue()); } diff --git a/tests/system/Database/Live/OCI8/LastInsertIDTest.php b/tests/system/Database/Live/OCI8/LastInsertIDTest.php index 33945cf7d276..525ab0456408 100644 --- a/tests/system/Database/Live/OCI8/LastInsertIDTest.php +++ b/tests/system/Database/Live/OCI8/LastInsertIDTest.php @@ -13,6 +13,7 @@ namespace CodeIgniter\Database\Live\OCI8; +use CodeIgniter\Database\BasePreparedQuery; use CodeIgniter\Database\Query; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; @@ -83,6 +84,7 @@ public function testGetInsertIDWithPreparedQuery(): void return (new Query($db))->setQuery($sql); }); + $this->assertInstanceof(BasePreparedQuery::class, $query); $query->execute('foo', 'bar'); $actual = $this->db->insertID(); diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 7be7fcfe546e..c611edbcbf9e 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -359,6 +359,7 @@ public function testErrorString(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -379,6 +380,7 @@ public function testErrorStringWithUnknownError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -398,6 +400,7 @@ public function testErrorStringWithNoError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -416,6 +419,7 @@ public function testError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame(UPLOAD_ERR_INI_SIZE, $file->getError()); } @@ -433,6 +437,7 @@ public function testErrorWithUnknownError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame(0, $file->getError()); } @@ -451,6 +456,7 @@ public function testErrorWithNoError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame(UPLOAD_ERR_OK, $file->getError()); } @@ -469,6 +475,7 @@ public function testClientPathReturnsValidFullPath(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertSame('someDir/someFile.txt', $file->getClientPath()); } @@ -486,6 +493,7 @@ public function testClientPathReturnsNullWhenFullPathIsNull(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $this->assertNull($file->getClientPath()); } diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index 9624ecd78a06..05a5096fba2a 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -264,6 +264,7 @@ public function testInvalidFile(): void $this->expectException(HTTPException::class); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } @@ -290,6 +291,7 @@ public function testFailedMoveBecauseOfWarning(): void $this->expectException(HTTPException::class); $file = $collection->getFile('userfile'); + $this->assertInstanceof(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } @@ -321,6 +323,7 @@ public function testFailedMoveBecauseOfFalseReturned(): void $this->expectExceptionMessage('move_uploaded_file() returned false'); $file = $collection->getFile('userfile1'); + $this->assertInstanceof(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } } diff --git a/tests/system/Pager/PagerRendererTest.php b/tests/system/Pager/PagerRendererTest.php index d06a040a7925..d29539c3ed67 100644 --- a/tests/system/Pager/PagerRendererTest.php +++ b/tests/system/Pager/PagerRendererTest.php @@ -643,59 +643,59 @@ public static function providePageStartEnd(): iterable return [ 'first page' => [ - 'details' => [ + [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 1, 'perPage' => 10, ], - 'pageStart' => 1, - 'pageEnd' => 10, + 1, + 10, ], 'second page' => [ - 'details' => [ + [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 2, 'perPage' => 10, ], - 'pageStart' => 11, - 'pageEnd' => 20, + 11, + 20, ], 'last page' => [ - 'details' => [ + [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 3, 'perPage' => 10, ], - 'pageStart' => 21, - 'pageEnd' => 25, + 21, + 25, ], 'current greater last page' => [ - 'details' => [ + [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 5, 'perPage' => 10, ], - 'pageStart' => 41, - 'pageEnd' => 50, + 41, + 50, ], 'current equal last page' => [ - 'details' => [ + [ 'uri' => $uri, 'pageCount' => 1, 'total' => 10, 'currentPage' => 1, 'perPage' => 10, ], - 'pageStart' => 1, - 'pageEnd' => 10, + 1, + 10, ], ]; } diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index aa130ba85cab..4e81e35925ad 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -13,6 +13,7 @@ namespace CodeIgniter\Test; +use CodeIgniter\HTTP\RequestInterface; use App\Controllers\Home; use App\Controllers\NeverHeardOfIt; use CodeIgniter\Controller; @@ -161,6 +162,7 @@ public function testRequestPassthrough(): void ->execute('popper'); $req = $result->request(); + $this->assertInstanceof(RequestInterface::class, $req); $this->assertSame('GET', $req->getMethod()); } diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 655cc21dfcfa..a5a71631c594 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -213,9 +213,9 @@ public static function provideTokenTimeCalculationUCs(): iterable { return [ '2 capacity / 200 seconds (100s refresh, 0.01 tokens/s) -> 5 checks, 1 cost each' => [ - 'capacity' => 2, - 'seconds' => 200, - 'checkInputs' => [ + 2, + 200, + [ [ // 2 -> 1 'testTime' => 0, 'cost' => 1, @@ -255,9 +255,9 @@ public static function provideTokenTimeCalculationUCs(): iterable ], ], '1 capacity / 3600 seconds (3600s refresh, 2.77e-4 tokens/s) -> 2 checks with 1 cost each' => [ - 'capacity' => 1, - 'seconds' => 3600, - 'checkInputs' => [ + 1, + 3600, + [ [ // 1 -> 0 'testTime' => 0, 'cost' => 1, @@ -273,9 +273,9 @@ public static function provideTokenTimeCalculationUCs(): iterable ], ], '10 capacity / 200 seconds (20s refresh, 0.05 tokens/s) -> 7 checks with different costs (RNG)' => [ - 'capacity' => 10, - 'seconds' => 200, - 'checkInputs' => [ + 10, + 200, + [ [ // -2t / 10 -> 8 'testTime' => 0, 'cost' => 2, From 9cc2a5e93749b48c47a14dc27dcbbaa956e82f27 Mon Sep 17 00:00:00 2001 From: michalsn Date: Mon, 7 Apr 2025 10:16:00 +0200 Subject: [PATCH 49/83] cs-fix --- tests/system/CodeIgniterTest.php | 2 +- tests/system/Test/ControllerTestTraitTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index ed6ba957f90c..a240726132c8 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -13,13 +13,13 @@ namespace CodeIgniter; -use CodeIgniter\HTTP\ResponseInterface; use App\Controllers\Home; use CodeIgniter\Config\Services; use CodeIgniter\Debug\Timer; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\Method; use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Filters\CITestStreamFilter; diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index 4e81e35925ad..671b477bd001 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -13,12 +13,12 @@ namespace CodeIgniter\Test; -use CodeIgniter\HTTP\RequestInterface; use App\Controllers\Home; use App\Controllers\NeverHeardOfIt; use CodeIgniter\Controller; use CodeIgniter\Exceptions\InvalidArgumentException; use CodeIgniter\Exceptions\RuntimeException; +use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\Log\Logger; use CodeIgniter\Test\Mock\MockLogger as LoggerConfig; use Config\App; From 896bc2b7ad39a7f15c07b9d2744cb5e6e4758009 Mon Sep 17 00:00:00 2001 From: michalsn Date: Mon, 7 Apr 2025 10:27:21 +0200 Subject: [PATCH 50/83] fix phpstan --- tests/system/CodeIgniterTest.php | 8 ++++---- .../Database/Live/OCI8/LastInsertIDTest.php | 2 +- tests/system/HTTP/Files/FileCollectionTest.php | 16 ++++++++-------- tests/system/HTTP/Files/FileMovingTest.php | 6 +++--- tests/system/Pager/PagerRendererTest.php | 2 +- tests/system/Test/ControllerTestTraitTest.php | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index a240726132c8..df2f217eb68a 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -96,7 +96,7 @@ public function testRunEmptyDefaultRouteReturnResponse(): void $_SERVER['argc'] = 1; $response = $this->codeigniter->run(null, true); - $this->assertInstanceof(ResponseInterface::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertStringContainsString('Welcome to CodeIgniter', $response->getBody()); } @@ -161,7 +161,7 @@ public function testRun404OverrideControllerReturnsResponse(): void Services::injectMock('router', $router); $response = $this->codeigniter->run($routes, true); - $this->assertInstanceof(ResponseInterface::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertStringContainsString('Oops', $response->getBody()); $this->assertSame(567, $response->getStatusCode()); @@ -180,7 +180,7 @@ public function testRun404OverrideReturnResponse(): void Services::injectMock('router', $router); $response = $this->codeigniter->run($routes, true); - $this->assertInstanceof(ResponseInterface::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertStringContainsString('Oops', $response->getBody()); } @@ -471,7 +471,7 @@ public function testRunForceSecure(): void $this->assertNull($response->header('Location')); $response = $codeigniter->run(null, true); - $this->assertInstanceof(ResponseInterface::class, $response); + $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame('https://example.com/index.php/', $response->header('Location')->getValue()); } diff --git a/tests/system/Database/Live/OCI8/LastInsertIDTest.php b/tests/system/Database/Live/OCI8/LastInsertIDTest.php index 525ab0456408..716cef2ff09d 100644 --- a/tests/system/Database/Live/OCI8/LastInsertIDTest.php +++ b/tests/system/Database/Live/OCI8/LastInsertIDTest.php @@ -84,7 +84,7 @@ public function testGetInsertIDWithPreparedQuery(): void return (new Query($db))->setQuery($sql); }); - $this->assertInstanceof(BasePreparedQuery::class, $query); + $this->assertInstanceOf(BasePreparedQuery::class, $query); $query->execute('foo', 'bar'); $actual = $this->db->insertID(); diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index c611edbcbf9e..daebf98fc314 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -359,7 +359,7 @@ public function testErrorString(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -380,7 +380,7 @@ public function testErrorStringWithUnknownError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -400,7 +400,7 @@ public function testErrorStringWithNoError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame($expected, $file->getErrorString()); } @@ -419,7 +419,7 @@ public function testError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame(UPLOAD_ERR_INI_SIZE, $file->getError()); } @@ -437,7 +437,7 @@ public function testErrorWithUnknownError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame(0, $file->getError()); } @@ -456,7 +456,7 @@ public function testErrorWithNoError(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame(UPLOAD_ERR_OK, $file->getError()); } @@ -475,7 +475,7 @@ public function testClientPathReturnsValidFullPath(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame('someDir/someFile.txt', $file->getClientPath()); } @@ -493,7 +493,7 @@ public function testClientPathReturnsNullWhenFullPathIsNull(): void $collection = new FileCollection(); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $this->assertNull($file->getClientPath()); } diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index 05a5096fba2a..2d43c775f949 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -264,7 +264,7 @@ public function testInvalidFile(): void $this->expectException(HTTPException::class); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } @@ -291,7 +291,7 @@ public function testFailedMoveBecauseOfWarning(): void $this->expectException(HTTPException::class); $file = $collection->getFile('userfile'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } @@ -323,7 +323,7 @@ public function testFailedMoveBecauseOfFalseReturned(): void $this->expectExceptionMessage('move_uploaded_file() returned false'); $file = $collection->getFile('userfile1'); - $this->assertInstanceof(UploadedFile::class, $file); + $this->assertInstanceOf(UploadedFile::class, $file); $file->move($destination, $file->getName(), false); } } diff --git a/tests/system/Pager/PagerRendererTest.php b/tests/system/Pager/PagerRendererTest.php index d29539c3ed67..7d9d94e49303 100644 --- a/tests/system/Pager/PagerRendererTest.php +++ b/tests/system/Pager/PagerRendererTest.php @@ -635,7 +635,7 @@ public function testPageStartEnd(array $details, int $pageStart, int $pageEnd): } /** - * @return array> $details + * @return array|int>> $details */ public static function providePageStartEnd(): iterable { diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index 671b477bd001..44301afa376d 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -162,7 +162,7 @@ public function testRequestPassthrough(): void ->execute('popper'); $req = $result->request(); - $this->assertInstanceof(RequestInterface::class, $req); + $this->assertInstanceOf(RequestInterface::class, $req); $this->assertSame('GET', $req->getMethod()); } From 8b30ca32a2665b429ebba95526e010c3daa057ce Mon Sep 17 00:00:00 2001 From: michalsn Date: Mon, 7 Apr 2025 10:56:25 +0200 Subject: [PATCH 51/83] skip rector rule RemoveDataProviderParamKeysRector --- rector.php | 3 +++ tests/system/Pager/PagerRendererTest.php | 32 ++++++++++++------------ tests/system/Throttle/ThrottleTest.php | 18 ++++++------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/rector.php b/rector.php index 6e9a1ef5def2..b8b5e1ccc73f 100644 --- a/rector.php +++ b/rector.php @@ -35,6 +35,7 @@ use Rector\Php70\Rector\FuncCall\RandomFunctionRector; use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector; use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector; +use Rector\PHPUnit\CodeQuality\Rector\Class_\RemoveDataProviderParamKeysRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; @@ -166,6 +167,8 @@ NullToStrictStringFuncCallArgRector::class, CompactToVariablesRector::class, + + RemoveDataProviderParamKeysRector::class, ]) // auto import fully qualified class names ->withImportNames(removeUnusedImports: true) diff --git a/tests/system/Pager/PagerRendererTest.php b/tests/system/Pager/PagerRendererTest.php index 7d9d94e49303..d06a040a7925 100644 --- a/tests/system/Pager/PagerRendererTest.php +++ b/tests/system/Pager/PagerRendererTest.php @@ -635,7 +635,7 @@ public function testPageStartEnd(array $details, int $pageStart, int $pageEnd): } /** - * @return array|int>> $details + * @return array> $details */ public static function providePageStartEnd(): iterable { @@ -643,59 +643,59 @@ public static function providePageStartEnd(): iterable return [ 'first page' => [ - [ + 'details' => [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 1, 'perPage' => 10, ], - 1, - 10, + 'pageStart' => 1, + 'pageEnd' => 10, ], 'second page' => [ - [ + 'details' => [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 2, 'perPage' => 10, ], - 11, - 20, + 'pageStart' => 11, + 'pageEnd' => 20, ], 'last page' => [ - [ + 'details' => [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 3, 'perPage' => 10, ], - 21, - 25, + 'pageStart' => 21, + 'pageEnd' => 25, ], 'current greater last page' => [ - [ + 'details' => [ 'uri' => $uri, 'pageCount' => 3, 'total' => 25, 'currentPage' => 5, 'perPage' => 10, ], - 41, - 50, + 'pageStart' => 41, + 'pageEnd' => 50, ], 'current equal last page' => [ - [ + 'details' => [ 'uri' => $uri, 'pageCount' => 1, 'total' => 10, 'currentPage' => 1, 'perPage' => 10, ], - 1, - 10, + 'pageStart' => 1, + 'pageEnd' => 10, ], ]; } diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index a5a71631c594..655cc21dfcfa 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -213,9 +213,9 @@ public static function provideTokenTimeCalculationUCs(): iterable { return [ '2 capacity / 200 seconds (100s refresh, 0.01 tokens/s) -> 5 checks, 1 cost each' => [ - 2, - 200, - [ + 'capacity' => 2, + 'seconds' => 200, + 'checkInputs' => [ [ // 2 -> 1 'testTime' => 0, 'cost' => 1, @@ -255,9 +255,9 @@ public static function provideTokenTimeCalculationUCs(): iterable ], ], '1 capacity / 3600 seconds (3600s refresh, 2.77e-4 tokens/s) -> 2 checks with 1 cost each' => [ - 1, - 3600, - [ + 'capacity' => 1, + 'seconds' => 3600, + 'checkInputs' => [ [ // 1 -> 0 'testTime' => 0, 'cost' => 1, @@ -273,9 +273,9 @@ public static function provideTokenTimeCalculationUCs(): iterable ], ], '10 capacity / 200 seconds (20s refresh, 0.05 tokens/s) -> 7 checks with different costs (RNG)' => [ - 10, - 200, - [ + 'capacity' => 10, + 'seconds' => 200, + 'checkInputs' => [ [ // -2t / 10 -> 8 'testTime' => 0, 'cost' => 2, From 92d69b46be2928cee1136bb62c0130e0ee33ae3a Mon Sep 17 00:00:00 2001 From: Ilia Chernykh <25124661+Elias-Black@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:05:43 +0500 Subject: [PATCH 52/83] docs: Add description of conflicts between named and unnamed routes (#9499) --- user_guide_src/source/incoming/routing.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a1bb81726b14..6a48e95fe7a2 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -543,6 +543,14 @@ with the name of the route: This has the added benefit of making the views more readable, too. +.. note:: By default, all defined routes have names matching their paths, with placeholders replaced by their corresponding + regular expressions. For example, if you define a route like ``$routes->get('edit/(:num)', 'PostController::edit/$1');``, + you can generate the corresponding URL using ``route_to('edit/([0-9]+)', 12)``. + +.. warning:: According to :ref:`routing-priority`, if a not-named route is defined first (e.g., ``$routes->get('edit', 'PostController::edit');``) + and another named route is defined later with the same name as the path of the first route (e.g., ``$routes->get('edit/(:num)', 'PostController::edit/$1', ['as' => 'edit']);``), + the second route will not be registered because its name will conflict with the automatically assigned name of the first route. + Grouping Routes *************** From 6fbf60143b672955559148e1d88e53340c7fce92 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Tue, 8 Apr 2025 08:06:10 +0200 Subject: [PATCH 53/83] fix: Logger - allow variable {line} to be used without variable {file} when logging message (#9502) * fix: allow Logger variable {line} to be used without variable {file} * add changelog * phpstan baseline update --- system/Log/Logger.php | 2 +- tests/system/Log/LoggerTest.php | 17 +++++++++++++++++ user_guide_src/source/changelogs/v4.6.1.rst | 1 + utils/phpstan-baseline/argument.type.neon | 4 ++-- utils/phpstan-baseline/loader.neon | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/system/Log/Logger.php b/system/Log/Logger.php index 6762e3380ecf..7c14fcdaeb5b 100644 --- a/system/Log/Logger.php +++ b/system/Log/Logger.php @@ -341,7 +341,7 @@ protected function interpolate($message, array $context = []) $replace['{env}'] = ENVIRONMENT; // Allow us to log the file/line that we are logging from - if (str_contains($message, '{file}')) { + if (str_contains($message, '{file}') || str_contains($message, '{line}')) { [$file, $line] = $this->determineFile(); $replace['{file}'] = $file; diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 569de4dbd33d..695e99fa3ef1 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -236,6 +236,23 @@ public function testLogInterpolatesFileAndLine(): void $this->assertGreaterThan(1, strpos($logs[0], $expected)); } + public function testLogInterpolatesLineOnly(): void + { + $config = new LoggerConfig(); + + $logger = new Logger($config); + + $_ENV['foo'] = 'bar'; + + $logger->log('debug', 'Test message Sample {line}'); + $line = __LINE__ - 1; + $expected = "Sample {$line}"; + + $logs = TestHandler::getLogs(); + + $this->assertGreaterThan(1, strpos($logs[0], $expected)); + } + public function testLogInterpolatesExceptions(): void { $config = new LoggerConfig(); diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index 7b35ad9faabc..77fa4799e37e 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -34,6 +34,7 @@ Bugs Fixed - **Cors:** Fixed a bug in the Cors filter that caused the appropriate headers to not be added when another filter returned a response object in the ``before`` filter. - **Database:** Fixed a bug in ``Postgre`` and ``SQLite3`` handlers where composite unique keys were not fully taken into account for ``upsert`` type of queries. - **Database:** Fixed a bug in the ``OCI8`` and ``SQLSRV`` drivers where ``getVersion()`` returned an empty string when the database connection was not yet established. +- **Logger:** Fixed a bug where the ``{line}`` variable couldn't be used without specifying the ``{file}`` variable when logging the message. See the repo's `CHANGELOG.md `_ diff --git a/utils/phpstan-baseline/argument.type.neon b/utils/phpstan-baseline/argument.type.neon index 2f2e9f3baa38..011377a40084 100644 --- a/utils/phpstan-baseline/argument.type.neon +++ b/utils/phpstan-baseline/argument.type.neon @@ -1,4 +1,4 @@ -# total 147 errors +# total 148 errors parameters: ignoreErrors: @@ -229,7 +229,7 @@ parameters: - message: '#^Parameter \#1 \$config of class CodeIgniter\\Log\\Logger constructor expects Config\\Logger, CodeIgniter\\Test\\Mock\\MockLogger given\.$#' - count: 24 + count: 25 path: ../../tests/system/Log/LoggerTest.php - diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index f795aabb7fb5..11c2852f5c57 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3759 errors +# total 3760 errors includes: - argument.type.neon - assign.propertyType.neon From 73718f4c87d84f25f620929fe0ae799c05342afa Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Thu, 10 Apr 2025 07:18:45 +0200 Subject: [PATCH 54/83] fix: Toolbar when `maxHistory` is set to `0` (#9506) * fix: debugbar when maxHistory is set to 0 * apply code suggestion - make use of the historyLoad variable --- system/Debug/Toolbar.php | 2 +- system/Debug/Toolbar/Views/toolbar.js | 39 +++++++++++---------- user_guide_src/source/changelogs/v4.6.1.rst | 2 ++ 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 9a884b60f5b3..7900c7c780c5 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -512,7 +512,7 @@ protected function format(string $data, string $format = 'html'): string { $data = json_decode($data, true); - if ($this->config->maxHistory !== 0 && preg_match('/\d+\.\d{6}/s', (string) service('request')->getGet('debugbar_time'), $debugbarTime)) { + if (preg_match('/\d+\.\d{6}/s', (string) service('request')->getGet('debugbar_time'), $debugbarTime)) { $history = new History(); $history->setFiles( $debugbarTime[0], diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 54fe3d69f106..ddaa2386f260 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -27,22 +27,25 @@ var ciDebugBar = { .getElementById("debug-icon-link") .addEventListener("click", ciDebugBar.toggleToolbar, true); - // Allows to highlight the row of the current history request - var btn = this.toolbar.querySelector( - 'button[data-time="' + localStorage.getItem("debugbar-time") + '"]' - ); - ciDebugBar.addClass(btn.parentNode.parentNode, "current"); - historyLoad = this.toolbar.getElementsByClassName("ci-history-load"); - for (var i = 0; i < historyLoad.length; i++) { - historyLoad[i].addEventListener( - "click", - function () { - loadDoc(this.getAttribute("data-time")); - }, - true + if (historyLoad.length) { + // Allows highlighting the row of the current history request + var btn = this.toolbar.querySelector( + 'button[data-time="' + localStorage.getItem("debugbar-time-new") + '"]' ); + ciDebugBar.addClass(btn.parentNode.parentNode, "current"); + + + for (var i = 0; i < historyLoad.length; i++) { + historyLoad[i].addEventListener( + "click", + function () { + loadDoc(this.getAttribute("data-time")); + }, + true + ); + } } // Display the active Tab on page load @@ -77,14 +80,14 @@ var ciDebugBar = { links[i].addEventListener("click", function() { ciDebugBar.toggleDataTable(datatable) }, true); - + } else if (toggleData === "childrows") { let child = links[i].getAttribute("data-child"); links[i].addEventListener("click", function() { ciDebugBar.toggleChildRows(child) }, true); - + } else { links[i].addEventListener("click", ciDebugBar.toggleRows, true); } @@ -174,10 +177,10 @@ var ciDebugBar = { ); if (target.classList.contains("debug-bar-ndisplay")) { - ciDebugBar.switchClass(target, "debug-bar-ndisplay", "debug-bar-dtableRow"); + ciDebugBar.switchClass(target, "debug-bar-ndisplay", "debug-bar-dtableRow"); } else { ciDebugBar.switchClass(target, "debug-bar-dtableRow", "debug-bar-ndisplay"); - } + } } }, @@ -261,7 +264,7 @@ var ciDebugBar = { } else { ciDebugBar.switchClass(ciDebugBar.icon, "debug-bar-dinlineBlock", "debug-bar-ndisplay"); ciDebugBar.switchClass(ciDebugBar.toolbar, "debug-bar-ndisplay", "debug-bar-dinlineBlock"); - } + } }, toggleViewsHints: function () { diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index 77fa4799e37e..495fcd1b3af5 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -35,6 +35,8 @@ Bugs Fixed - **Database:** Fixed a bug in ``Postgre`` and ``SQLite3`` handlers where composite unique keys were not fully taken into account for ``upsert`` type of queries. - **Database:** Fixed a bug in the ``OCI8`` and ``SQLSRV`` drivers where ``getVersion()`` returned an empty string when the database connection was not yet established. - **Logger:** Fixed a bug where the ``{line}`` variable couldn't be used without specifying the ``{file}`` variable when logging the message. +- **Toolbar:** Fixed a bug where setting ``maxHistory`` to ``0`` would produce a JavaScript error in the Debug Toolbar. +- **Toolbar:** Fixed a bug where setting ``maxHistory`` to ``0`` prevented log files from being properly cleared. See the repo's `CHANGELOG.md `_ From 49a56dac5a9937650a245a2bbd9ae605297407dc Mon Sep 17 00:00:00 2001 From: neznaika0 Date: Sat, 12 Apr 2025 16:37:17 +0300 Subject: [PATCH 55/83] docs: Notes about switching types in session (#9508) * docs: Note about switching types in session * docs: Apply suggestion * docs:Grammar fix --- user_guide_src/source/libraries/sessions.rst | 7 ++++++ .../source/libraries/sessions/045.php | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 user_guide_src/source/libraries/sessions/045.php diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 03c2bbe81fc2..a89e12df32c0 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -344,6 +344,13 @@ intend to reuse that same key in the same request, you'd want to use .. literalinclude:: sessions/036.php +Changing the Session Key Type +============================= + +Since session data values like Flashdata and Tempdata are differentiated only by internal flags, you can change a value's type without rewriting its data. + +.. literalinclude:: sessions/045.php + Closing a Session ================= diff --git a/user_guide_src/source/libraries/sessions/045.php b/user_guide_src/source/libraries/sessions/045.php new file mode 100644 index 000000000000..b9327e133172 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/045.php @@ -0,0 +1,25 @@ +setFlashdata('alerts', 'Operation successful!'); + +/* + * Get flash value 'Operation successful!' in another controller. + * + * echo session()->getFlashdata('alerts'); + */ + +// You can switch the session key type from Flashdata to Tempdata like this: +session()->markAsTempdata('alerts'); + +// Or simply rewrite it directly +session()->setTempdata('alerts', 'Operation successful!'); + +/* + * Get temp value 'Operation successful!' in another controller. + * + * echo session()->getTempdata('alerts'); + * + * But flash value will be empty 'null'. + * + * echo session()->getFlashdata('alerts'); + */ From bd60f5052cd933ed3452962c7317dbec4812632d Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 12 Apr 2025 21:53:21 +0800 Subject: [PATCH 56/83] refactor: deprecate redundant `FileHandler` cache methods (#9511) --- system/Cache/Handlers/FileHandler.php | 16 +++++++++++++--- user_guide_src/source/changelogs/v4.6.1.rst | 5 +++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index 0a97a89f4862..8f63c93acb20 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -63,6 +63,8 @@ public function __construct(Cache $config) $this->mode = $config->file['mode'] ?? 0640; $this->prefix = $config->prefix; + + helper('filesystem'); } /** @@ -96,7 +98,7 @@ public function save(string $key, $value, int $ttl = 60) 'data' => $value, ]; - if ($this->writeFile($this->path . $key, serialize($contents))) { + if (write_file($this->path . $key, serialize($contents))) { try { chmod($this->path . $key, $this->mode); @@ -176,7 +178,7 @@ public function decrement(string $key, int $offset = 1) */ public function clean() { - return $this->deleteFiles($this->path, false, true); + return delete_files($this->path, false, true); } /** @@ -184,7 +186,7 @@ public function clean() */ public function getCacheInfo() { - return $this->getDirFileInfo($this->path); + return get_dir_file_info($this->path); } /** @@ -251,6 +253,8 @@ protected function getItem(string $filename) /** * Writes a file to disk, or returns false if not successful. * + * @deprecated 4.6.1 Use `write_file()` instead. + * * @param string $path * @param string $data * @param string $mode @@ -283,6 +287,8 @@ protected function writeFile($path, $data, $mode = 'wb') * If the second parameter is set to TRUE, any directories contained * within the supplied base directory will be nuked as well. * + * @deprecated 4.6.1 Use `delete_files()` instead. + * * @param string $path File path * @param bool $delDir Whether to delete any directories found in the path * @param bool $htdocs Whether to skip deleting .htaccess and index page files @@ -318,6 +324,8 @@ protected function deleteFiles(string $path, bool $delDir = false, bool $htdocs * * Any sub-folders contained within the specified path are read as well. * + * @deprecated 4.6.1 Use `get_dir_file_info()` instead. + * * @param string $sourceDir Path to source * @param bool $topLevelOnly Look only at the top level directory specified? * @param bool $_recursion Internal variable to determine recursion status - do not use in calls @@ -360,6 +368,8 @@ protected function getDirFileInfo(string $sourceDir, bool $topLevelOnly = true, * Options are: name, server_path, size, date, readable, writable, executable, fileperms * Returns FALSE if the file cannot be found. * + * @deprecated 4.6.1 Use `get_file_info()` instead. + * * @param string $file Path to file * @param array|string $returnedValues Array or comma separated string of information returned * diff --git a/user_guide_src/source/changelogs/v4.6.1.rst b/user_guide_src/source/changelogs/v4.6.1.rst index 495fcd1b3af5..2eb8db9600f3 100644 --- a/user_guide_src/source/changelogs/v4.6.1.rst +++ b/user_guide_src/source/changelogs/v4.6.1.rst @@ -26,6 +26,11 @@ Changes Deprecations ************ +- **Cache:** The ``FileHandler::writeFile()`` method is deprecated. Use ``write_file()`` instead. +- **Cache:** The ``FileHandler::deleteFiles()`` method is deprecated. Use ``delete_files()`` instead. +- **Cache:** The ``FileHandler::getDirFileInfo()`` method is deprecated. Use ``get_dir_file_info()`` instead. +- **Cache:** The ``FileHandler::getFileInfo()`` method is deprecated. Use ``get_file_info()`` instead. + ********** Bugs Fixed ********** From 7cd4d32af8622a38f1d93810adebca20522a4aa2 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 16:26:02 +0800 Subject: [PATCH 57/83] Fix variable.undefined (and other) errors (#9513) --- phpstan.neon.dist | 89 ++++--- system/Cache/Handlers/FileHandler.php | 4 +- system/Helpers/filesystem_helper.php | 4 +- system/Session/Handlers/FileHandler.php | 4 +- system/Test/FilterTestTrait.php | 4 + utils/phpstan-baseline/argument.type.neon | 7 +- utils/phpstan-baseline/loader.neon | 3 +- .../method.childParameterType.neon | 42 +-- .../method.childReturnType.neon | 12 +- utils/phpstan-baseline/method.notFound.neon | 7 +- .../missingType.iterableValue.neon | 152 +---------- .../missingType.parameter.neon | 87 +----- .../missingType.property.neon | 57 +--- .../phpstan-baseline/missingType.return.neon | 252 +----------------- .../property.defaultValue.neon | 12 +- .../ternary.shortNotAllowed.neon | 7 +- .../phpstan-baseline/variable.undefined.neon | 78 ------ 17 files changed, 70 insertions(+), 751 deletions(-) delete mode 100644 utils/phpstan-baseline/variable.undefined.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 43d658c22c35..bc3a0fc7ef34 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,46 +1,49 @@ includes: - - utils/phpstan-baseline/loader.neon + - utils/phpstan-baseline/loader.neon parameters: - phpVersion: 80100 - tmpDir: build/phpstan - level: 6 - bootstrapFiles: - - phpstan-bootstrap.php - paths: - - admin/starter/tests - - app - - system - - tests - excludePaths: - - app/Views/errors/cli/* - - app/Views/errors/html/* - - system/Commands/Generators/Views/* - - system/Debug/Toolbar/Views/toolbar.tpl.php - - system/Images/Handlers/GDHandler.php - - system/Test/Filters/CITestStreamFilter.php - - system/ThirdParty/* - - system/Validation/Views/single.php - - tests/system/View/Views/* - scanDirectories: - - system/Helpers - ignoreErrors: - - - identifier: missingType.generics - checkMissingCallableSignature: true - treatPhpDocTypesAsCertain: false - strictRules: - allRules: false - disallowedLooseComparison: true - booleansInConditions: true - disallowedBacktick: true - disallowedEmpty: true - disallowedImplicitArrayCreation: true - disallowedShortTernary: true - matchingInheritedMethodNames: true - codeigniter: - additionalServices: - - AfterAutoloadModule\Config\Services - checkArgumentTypeOfModel: false - shipmonkBaselinePerIdentifier: - directory: %currentWorkingDirectory% + phpVersion: 80100 + tmpDir: build/phpstan + level: 6 + bootstrapFiles: + - phpstan-bootstrap.php + paths: + - admin/starter/tests + - app + - system + - tests + excludePaths: + analyseAndScan: + - app/Views/errors/cli/* + - app/Views/errors/html/* + - system/Commands/Generators/Views/* + - system/Debug/Toolbar/Views/toolbar.tpl.php + - system/Images/Handlers/GDHandler.php + - system/Test/Filters/CITestStreamFilter.php + - system/ThirdParty/* + - system/Validation/Views/single.php + - tests/system/View/Views/* + analyse: + - tests/_support/* + scanDirectories: + - system/Helpers + ignoreErrors: + - + identifier: missingType.generics + checkMissingCallableSignature: true + treatPhpDocTypesAsCertain: false + strictRules: + allRules: false + disallowedLooseComparison: true + booleansInConditions: true + disallowedBacktick: true + disallowedEmpty: true + disallowedImplicitArrayCreation: true + disallowedShortTernary: true + matchingInheritedMethodNames: true + codeigniter: + additionalServices: + - AfterAutoloadModule\Config\Services + checkArgumentTypeOfModel: false + shipmonkBaselinePerIdentifier: + directory: %currentWorkingDirectory% diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index 8f63c93acb20..4fd03e7921b0 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -269,7 +269,9 @@ protected function writeFile($path, $data, $mode = 'wb') flock($fp, LOCK_EX); - for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { + $result = 0; + + for ($written = 0, $length = strlen($data); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($data, $written))) === false) { break; } diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index c45bcdae0d64..aa7efbea0468 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -123,7 +123,9 @@ function write_file(string $path, string $data, string $mode = 'wb'): bool flock($fp, LOCK_EX); - for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { + $result = 0; + + for ($written = 0, $length = strlen($data); $written < $length; $written += $result) { if (($result = fwrite($fp, substr($data, $written))) === false) { break; } diff --git a/system/Session/Handlers/FileHandler.php b/system/Session/Handlers/FileHandler.php index 68fcd894c583..dbca9cfa4288 100644 --- a/system/Session/Handlers/FileHandler.php +++ b/system/Session/Handlers/FileHandler.php @@ -201,7 +201,9 @@ public function write($id, $data): bool if (($length = strlen($data)) > 0) { $result = null; - for ($written = 0; $written < $length; $written += $result) { + $written = 0; + + for (; $written < $length; $written += $result) { if (($result = fwrite($this->fileHandle, substr($data, $written))) === false) { break; } diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index d3091b6b4ed7..45411fad0a42 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -163,6 +163,8 @@ protected function getFilterCaller($filter, string $position): Closure if ($position === 'before') { return static function (?array $params = null) use ($filterInstances, $request) { + $result = null; + foreach ($filterInstances as $filter) { $result = $filter->before($request, $params); @@ -188,6 +190,8 @@ protected function getFilterCaller($filter, string $position): Closure $response = clone $this->response; return static function (?array $params = null) use ($filterInstances, $request, $response) { + $result = null; + foreach ($filterInstances as $filter) { $result = $filter->after($request, $response, $params); diff --git a/utils/phpstan-baseline/argument.type.neon b/utils/phpstan-baseline/argument.type.neon index 011377a40084..6e6aa7de51fc 100644 --- a/utils/phpstan-baseline/argument.type.neon +++ b/utils/phpstan-baseline/argument.type.neon @@ -1,4 +1,4 @@ -# total 148 errors +# total 146 errors parameters: ignoreErrors: @@ -32,11 +32,6 @@ parameters: count: 1 path: ../../system/Log/Handlers/ErrorlogHandler.php - - - message: '#^Parameter \#1 \$fields of method CodeIgniter\\Database\\Forge\:\:addField\(\) expects array\\|string, array\\|string\> given\.$#' - count: 2 - path: ../../tests/_support/Database/Migrations/20160428212500_Create_test_tables.php - - message: '#^Parameter \#2 \$to of method CodeIgniter\\Router\\RouteCollection\:\:add\(\) expects array\|\(Closure\(mixed \.\.\.\)\: \(CodeIgniter\\HTTP\\ResponseInterface\|string\|void\)\)\|string, Closure\(mixed\)\: \(CodeIgniter\\HTTP\\DownloadResponse\|null\) given\.$#' count: 1 diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 11c2852f5c57..1372386f4cae 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3760 errors +# total 3615 errors includes: - argument.type.neon - assign.propertyType.neon @@ -39,4 +39,3 @@ includes: - staticMethod.notFound.neon - ternary.shortNotAllowed.neon - varTag.type.neon - - variable.undefined.neon diff --git a/utils/phpstan-baseline/method.childParameterType.neon b/utils/phpstan-baseline/method.childParameterType.neon index 5d9df4b2cdf3..0d10e9cd49d6 100644 --- a/utils/phpstan-baseline/method.childParameterType.neon +++ b/utils/phpstan-baseline/method.childParameterType.neon @@ -1,4 +1,4 @@ -# total 17 errors +# total 9 errors parameters: ignoreErrors: @@ -46,43 +46,3 @@ parameters: message: '#^Parameter \#1 \$level \(string\) of method CodeIgniter\\Log\\Logger\:\:log\(\) should be contravariant with parameter \$level \(mixed\) of method Psr\\Log\\LoggerInterface\:\:log\(\)$#' count: 1 path: ../../system/Log/Logger.php - - - - message: '#^Parameter \#1 \$value \(string\) of method Tests\\Support\\Entity\\Cast\\CastBase64\:\:get\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\BaseCast\:\:get\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Parameter \#1 \$value \(string\) of method Tests\\Support\\Entity\\Cast\\CastBase64\:\:get\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\CastInterface\:\:get\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Parameter \#1 \$value \(string\) of method Tests\\Support\\Entity\\Cast\\CastBase64\:\:set\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\BaseCast\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Parameter \#1 \$value \(string\) of method Tests\\Support\\Entity\\Cast\\CastBase64\:\:set\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\CastInterface\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Parameter \#1 \$binary \(string\) of method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:get\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\BaseCast\:\:get\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php - - - - message: '#^Parameter \#1 \$binary \(string\) of method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:get\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\CastInterface\:\:get\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php - - - - message: '#^Parameter \#1 \$string \(string\) of method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:set\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\BaseCast\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php - - - - message: '#^Parameter \#1 \$string \(string\) of method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:set\(\) should be contravariant with parameter \$value \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\CastInterface\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php diff --git a/utils/phpstan-baseline/method.childReturnType.neon b/utils/phpstan-baseline/method.childReturnType.neon index e2fcf04827da..f443154a490d 100644 --- a/utils/phpstan-baseline/method.childReturnType.neon +++ b/utils/phpstan-baseline/method.childReturnType.neon @@ -1,4 +1,4 @@ -# total 40 errors +# total 38 errors parameters: ignoreErrors: @@ -186,13 +186,3 @@ parameters: message: '#^Return type \(mixed\) of method CodeIgniter\\Test\\Mock\\MockResult\:\:fetchAssoc\(\) should be covariant with return type \(array\|false\|null\) of method CodeIgniter\\Database\\BaseResult\\:\:fetchAssoc\(\)$#' count: 1 path: ../../system/Test/Mock/MockResult.php - - - - message: '#^Return type \(mixed\) of method Tests\\Support\\Entity\\Cast\\CastPassParameters\:\:set\(\) should be covariant with return type \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\BaseCast\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastPassParameters.php - - - - message: '#^Return type \(mixed\) of method Tests\\Support\\Entity\\Cast\\CastPassParameters\:\:set\(\) should be covariant with return type \(array\|bool\|float\|int\|object\|string\|null\) of method CodeIgniter\\Entity\\Cast\\CastInterface\:\:set\(\)$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastPassParameters.php diff --git a/utils/phpstan-baseline/method.notFound.neon b/utils/phpstan-baseline/method.notFound.neon index 71e25c746678..445f071fb3c2 100644 --- a/utils/phpstan-baseline/method.notFound.neon +++ b/utils/phpstan-baseline/method.notFound.neon @@ -1,4 +1,4 @@ -# total 83 errors +# total 82 errors parameters: ignoreErrors: @@ -17,11 +17,6 @@ parameters: count: 2 path: ../../system/Debug/Toolbar/Collectors/Views.php - - - message: '#^Call to an undefined method CodeIgniter\\Database\\ConnectionInterface\:\:tableExists\(\)\.$#' - count: 1 - path: ../../tests/_support/MigrationTestMigrations/Database/Migrations/2018-01-24-102302_Another_migration.php - - message: '#^Call to an undefined method CodeIgniter\\HTTP\\ResponseInterface\:\:pretend\(\)\.$#' count: 1 diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index 9f19deb6ea78..e8c7da4e7a0a 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1659 errors +# total 1629 errors parameters: ignoreErrors: @@ -6242,156 +6242,6 @@ parameters: count: 1 path: ../../system/View/Parser.php - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:fail\(\) has parameter \$messages with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:format\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:respond\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:respondCreated\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:respondDeleted\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:respondUpdated\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Entity\\Cast\\CastBase64\:\:get\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Method Tests\\Support\\Entity\\Cast\\CastBase64\:\:set\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBase64.php - - - - message: '#^Method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:get\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php - - - - message: '#^Method Tests\\Support\\Entity\\Cast\\CastBinaryUUID\:\:set\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastBinaryUUID.php - - - - message: '#^Method Tests\\Support\\Entity\\Cast\\CastPassParameters\:\:set\(\) has parameter \$params with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/Cast/CastPassParameters.php - - - - message: '#^Class Tests\\Support\\Entity\\CustomUser has PHPDoc tag @property for property \$email with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/CustomUser.php - - - - message: '#^Method Tests\\Support\\Entity\\CustomUser\:\:__construct\(\) has parameter \$email with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/CustomUser.php - - - - message: '#^Method Tests\\Support\\Entity\\CustomUser\:\:reconstruct\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Entity/CustomUser.php - - - - message: '#^Method Tests\\Support\\Log\\Handlers\\TestHandler\:\:__construct\(\) has parameter \$config with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Log/Handlers/TestHandler.php - - - - message: '#^Property Tests\\Support\\Log\\Handlers\\TestHandler\:\:\$logs type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Log/Handlers/TestHandler.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterDeleteMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterFindMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterInsertBatchMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterInsertMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterUpdateBatchMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterUpdateMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeDeleteMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeFindMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeInsertBatchMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeInsertMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeUpdateBatchMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeUpdateMethod\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:check_object_rule\(\) has parameter \$data with no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php - - - - message: '#^Property Tests\\Support\\View\\Cells\\ListerCell\:\:\$items type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../tests/_support/View/Cells/ListerCell.php - - message: '#^Method CodeIgniter\\API\\ResponseTraitTest\:\:createRequestAndResponse\(\) has parameter \$userHeaders with no value type specified in iterable type array\.$#' count: 1 diff --git a/utils/phpstan-baseline/missingType.parameter.neon b/utils/phpstan-baseline/missingType.parameter.neon index 7fa258f052cc..687736a425dc 100644 --- a/utils/phpstan-baseline/missingType.parameter.neon +++ b/utils/phpstan-baseline/missingType.parameter.neon @@ -1,4 +1,4 @@ -# total 68 errors +# total 51 errors parameters: ignoreErrors: @@ -27,91 +27,6 @@ parameters: count: 1 path: ../../system/Test/Mock/MockTable.php - - - message: '#^Method Tests\\Support\\Cells\\StarterCell\:\:hello\(\) has parameter \$params with no type specified\.$#' - count: 1 - path: ../../tests/_support/Cells/StarterCell.php - - - - message: '#^Method Tests\\Support\\Controllers\\Newautorouting\:\:postSave\(\) has parameter \$c with no type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Newautorouting.php - - - - message: '#^Method Tests\\Support\\Controllers\\Remap\:\:_remap\(\) has parameter \$method with no type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Remap.php - - - - message: '#^Method Tests\\Support\\Controllers\\Remap\:\:_remap\(\) has parameter \$params with no type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Remap.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateMethod\(\) has parameter \$param1 with no type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateMethod\(\) has parameter \$param2 with no type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateStaticMethod\(\) has parameter \$param1 with no type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateStaticMethod\(\) has parameter \$param2 with no type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:array_count\(\) has parameter \$count with no type specified\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:array_count\(\) has parameter \$value with no type specified\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:echobox\(\) has parameter \$params with no type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:staticEcho\(\) has parameter \$params with no type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:work\(\) has parameter \$p1 with no type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:work\(\) has parameter \$p2 with no type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:work\(\) has parameter \$p4 with no type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method App\\Controllers\\Mycontroller\:\:getSomemethod\(\) has parameter \$first with no type specified\.$#' - count: 1 - path: ../../tests/_support/_controller/Mycontroller.php - - - - message: '#^Method App\\Controllers\\foo\\bar\\baz\\Some_controller\:\:some_method\(\) has parameter \$first with no type specified\.$#' - count: 1 - path: ../../tests/_support/_controller/foo/bar/baz/Some_controller.php - - message: '#^Method class@anonymous/tests/system/API/ResponseTraitTest\.php\:116\:\:__construct\(\) has parameter \$formatter with no type specified\.$#' count: 1 diff --git a/utils/phpstan-baseline/missingType.property.neon b/utils/phpstan-baseline/missingType.property.neon index b4e0a4992eb9..e4842f9f4d25 100644 --- a/utils/phpstan-baseline/missingType.property.neon +++ b/utils/phpstan-baseline/missingType.property.neon @@ -1,4 +1,4 @@ -# total 130 errors +# total 119 errors parameters: ignoreErrors: @@ -87,61 +87,6 @@ parameters: count: 1 path: ../../system/Test/Mock/MockSession.php - - - message: '#^Property Tests\\Support\\Commands\\ParamsReveal\:\:\$args has no type specified\.$#' - count: 1 - path: ../../tests/_support/Commands/ParamsReveal.php - - - - message: '#^Property Tests\\Support\\Config\\Validation\:\:\$signup has no type specified\.$#' - count: 1 - path: ../../tests/_support/Config/Validation.php - - - - message: '#^Property Tests\\Support\\Config\\Validation\:\:\$signup_errors has no type specified\.$#' - count: 1 - path: ../../tests/_support/Config/Validation.php - - - - message: '#^Property Tests\\Support\\Models\\EventModel\:\:\$beforeFindReturnData has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Property Tests\\Support\\Models\\EventModel\:\:\$eventData has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Property Tests\\Support\\Models\\EventModel\:\:\$tokens has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Property Tests\\Support\\Models\\JobModel\:\:\$description has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/JobModel.php - - - - message: '#^Property Tests\\Support\\Models\\JobModel\:\:\$name has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/JobModel.php - - - - message: '#^Property Tests\\Support\\Models\\UserModel\:\:\$country has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/UserModel.php - - - - message: '#^Property Tests\\Support\\Models\\UserModel\:\:\$email has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/UserModel.php - - - - message: '#^Property Tests\\Support\\Models\\UserModel\:\:\$name has no type specified\.$#' - count: 1 - path: ../../tests/_support/Models/UserModel.php - - message: '#^Property class@anonymous/tests/system/API/ResponseTraitTest\.php\:116\:\:\$formatter has no type specified\.$#' count: 2 diff --git a/utils/phpstan-baseline/missingType.return.neon b/utils/phpstan-baseline/missingType.return.neon index 838443fab4f0..693842b12755 100644 --- a/utils/phpstan-baseline/missingType.return.neon +++ b/utils/phpstan-baseline/missingType.return.neon @@ -1,4 +1,4 @@ -# total 200 errors +# total 150 errors parameters: ignoreErrors: @@ -522,256 +522,6 @@ parameters: count: 1 path: ../../system/Test/PhpStreamWrapper.php - - - message: '#^Method Tests\\Support\\Cells\\StarterCell\:\:hello\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Cells/StarterCell.php - - - - message: '#^Method Tests\\Support\\Config\\BadRegistrar\:\:RegistrarConfig\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Config/BadRegistrar.php - - - - message: '#^Method Tests\\Support\\Config\\TestRegistrar\:\:RegistrarConfig\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Config/TestRegistrar.php - - - - message: '#^Method Tests\\Support\\Controllers\\Hello\:\:index\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Hello.php - - - - message: '#^Method Tests\\Support\\Controllers\\Newautorouting\:\:getIndex\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Newautorouting.php - - - - message: '#^Method Tests\\Support\\Controllers\\Newautorouting\:\:postSave\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Newautorouting.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:echoJson\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:goaway\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:index\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:index3\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:json\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:oops\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:pop\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:toindex\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:weasel\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Popcorn\:\:xml\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Popcorn.php - - - - message: '#^Method Tests\\Support\\Controllers\\Remap\:\:_remap\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Remap.php - - - - message: '#^Method Tests\\Support\\Controllers\\Remap\:\:abc\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Remap.php - - - - message: '#^Method Tests\\Support\\Controllers\\Remap\:\:index\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Controllers/Remap.php - - - - message: '#^Method Tests\\Support\\Entity\\CustomUser\:\:__get\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Entity/CustomUser.php - - - - message: '#^Method Tests\\Support\\Language\\SecondMockLanguage\:\:loaded\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Language/SecondMockLanguage.php - - - - message: '#^Method Tests\\Support\\Language\\SecondMockLanguage\:\:loadem\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Language/SecondMockLanguage.php - - - - message: '#^Method Tests\\Support\\Log\\Handlers\\TestHandler\:\:getLogs\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Log/Handlers/TestHandler.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterDeleteMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterFindMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterInsertBatchMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterInsertMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterUpdateBatchMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:afterUpdateMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeDeleteMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeFindMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeInsertBatchMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeInsertMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeUpdateBatchMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:beforeUpdateMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Models\\EventModel\:\:hasToken\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Models/EventModel.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:getPrivate\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:getStaticPrivate\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Test\\TestForReflectionHelper\:\:privateStaticMethod\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Test/TestForReflectionHelper.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:check_object_rule\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php - - - - message: '#^Method Tests\\Support\\Validation\\TestRules\:\:customError\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/Validation/TestRules.php - - - - message: '#^Method Tests\\Support\\View\\Cells\\ListerCell\:\:getItemsProperty\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/Cells/ListerCell.php - - - - message: '#^Method Tests\\Support\\View\\OtherCells\\SampleClass\:\:hello\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/OtherCells/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:echobox\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:hello\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:index\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:staticEcho\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClass\:\:work\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClass.php - - - - message: '#^Method Tests\\Support\\View\\SampleClassWithInitController\:\:index\(\) has no return type specified\.$#' - count: 1 - path: ../../tests/_support/View/SampleClassWithInitController.php - - message: '#^Method CodeIgniter\\API\\ResponseTraitTest\:\:invoke\(\) has no return type specified\.$#' count: 1 diff --git a/utils/phpstan-baseline/property.defaultValue.neon b/utils/phpstan-baseline/property.defaultValue.neon index 8e8914167fe2..21d5acab00f2 100644 --- a/utils/phpstan-baseline/property.defaultValue.neon +++ b/utils/phpstan-baseline/property.defaultValue.neon @@ -1,4 +1,4 @@ -# total 6 errors +# total 4 errors parameters: ignoreErrors: @@ -12,16 +12,6 @@ parameters: count: 1 path: ../../system/Test/CIUnitTestCase.php - - - message: '#^Property Tests\\Support\\Models\\ValidErrorsModel\:\:\$validationRules \(array\\|string\>\|string\>\|string\) does not accept default value of type array\\|string\>\|string\>\.$#' - count: 1 - path: ../../tests/_support/Models/ValidErrorsModel.php - - - - message: '#^Property Tests\\Support\\Models\\ValidModel\:\:\$validationRules \(array\\|string\>\|string\>\|string\) does not accept default value of type array\\|string\>\.$#' - count: 1 - path: ../../tests/_support/Models/ValidModel.php - - message: '#^Property CodeIgniter\\Models\\DataConverterModelTest\:\:\$seed \(class\-string\\|list\\>\) does not accept default value of type ''''\.$#' count: 1 diff --git a/utils/phpstan-baseline/ternary.shortNotAllowed.neon b/utils/phpstan-baseline/ternary.shortNotAllowed.neon index 8fbe74a182db..a04074775f2e 100644 --- a/utils/phpstan-baseline/ternary.shortNotAllowed.neon +++ b/utils/phpstan-baseline/ternary.shortNotAllowed.neon @@ -1,4 +1,4 @@ -# total 37 errors +# total 36 errors parameters: ignoreErrors: @@ -97,11 +97,6 @@ parameters: count: 2 path: ../../system/View/View.php - - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' - count: 1 - path: ../../tests/_support/Commands/LanguageCommand.php - - message: '#^Short ternary operator is not allowed\. Use null coalesce operator if applicable or consider using long ternary\.$#' count: 1 diff --git a/utils/phpstan-baseline/variable.undefined.neon b/utils/phpstan-baseline/variable.undefined.neon deleted file mode 100644 index 00aea3030994..000000000000 --- a/utils/phpstan-baseline/variable.undefined.neon +++ /dev/null @@ -1,78 +0,0 @@ -# total 21 errors - -parameters: - ignoreErrors: - - - message: '#^Variable \$result might not be defined\.$#' - count: 1 - path: ../../system/Cache/Handlers/FileHandler.php - - - - message: '#^Variable \$result might not be defined\.$#' - count: 1 - path: ../../system/Helpers/filesystem_helper.php - - - - message: '#^Variable \$written might not be defined\.$#' - count: 1 - path: ../../system/Session/Handlers/FileHandler.php - - - - message: '#^Variable \$filters might not be defined\.$#' - count: 2 - path: ../../tests/_support/Config/Filters.php - - - - message: '#^Variable \$routes might not be defined\.$#' - count: 5 - path: ../../tests/_support/Config/Routes.php - - - - message: '#^Variable \$value might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/addition.php - - - - message: '#^Variable \$message might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/awesome_cell.php - - - - message: '#^Variable \$this might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/colors.php - - - - message: '#^Variable \$greeting might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/greeting.php - - - - message: '#^Variable \$name might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/greeting.php - - - - message: '#^Variable \$items might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/lister.php - - - - message: '#^Variable \$value might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/multiplier.php - - - - message: '#^Variable \$message might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Cells/notice.php - - - - message: '#^Variable \$testString might not be defined\.$#' - count: 1 - path: ../../tests/_support/View/Views/simple.php - - - - message: '#^Variable \$result might not be defined\.$#' - count: 2 - path: ../../tests/system/Test/FilterTestTraitTest.php From c43119c98d24174e9ee703b1fd838997801bb227 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 19:59:07 +0800 Subject: [PATCH 58/83] refactor: fix `return.unusedType` errors (#9514) --- system/Commands/Utilities/ConfigCheck.php | 2 +- system/Commands/Utilities/Environment.php | 12 ++++--- system/Commands/Utilities/Optimize.php | 6 ++-- system/Commands/Utilities/PhpIniCheck.php | 2 +- system/Test/PhpStreamWrapper.php | 4 +-- utils/phpstan-baseline/loader.neon | 3 +- .../missingType.iterableValue.neon | 7 +--- utils/phpstan-baseline/return.unusedType.neon | 33 ------------------- 8 files changed, 16 insertions(+), 53 deletions(-) delete mode 100644 utils/phpstan-baseline/return.unusedType.neon diff --git a/system/Commands/Utilities/ConfigCheck.php b/system/Commands/Utilities/ConfigCheck.php index fa84cb287caa..4583c67dae87 100644 --- a/system/Commands/Utilities/ConfigCheck.php +++ b/system/Commands/Utilities/ConfigCheck.php @@ -73,7 +73,7 @@ final class ConfigCheck extends BaseCommand protected $options = []; /** - * {@inheritDoc} + * @return int */ public function run(array $params) { diff --git a/system/Commands/Utilities/Environment.php b/system/Commands/Utilities/Environment.php index 103591209d1e..22794fe9d51d 100644 --- a/system/Commands/Utilities/Environment.php +++ b/system/Commands/Utilities/Environment.php @@ -80,7 +80,7 @@ final class Environment extends BaseCommand ]; /** - * {@inheritDoc} + * @return int */ public function run(array $params) { @@ -88,7 +88,7 @@ public function run(array $params) CLI::write(sprintf('Your environment is currently set as %s.', CLI::color($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, 'green'))); CLI::newLine(); - return; + return EXIT_ERROR; } $env = strtolower(array_shift($params)); @@ -98,21 +98,21 @@ public function run(array $params) CLI::error('You will not be able to run spark under a "testing" environment.', 'light_gray', 'red'); CLI::newLine(); - return; + return EXIT_ERROR; } if (! in_array($env, self::$knownTypes, true)) { CLI::error(sprintf('Invalid environment type "%s". Expected one of "%s".', $env, implode('" and "', self::$knownTypes)), 'light_gray', 'red'); CLI::newLine(); - return; + return EXIT_ERROR; } if (! $this->writeNewEnvironmentToEnvFile($env)) { CLI::error('Error in writing new environment to .env file.', 'light_gray', 'red'); CLI::newLine(); - return; + return EXIT_ERROR; } // force DotEnv to reload the new environment @@ -124,6 +124,8 @@ public function run(array $params) CLI::write(sprintf('Environment is successfully changed to "%s".', $env), 'green'); CLI::write('The ENVIRONMENT constant will be changed in the next script execution.'); CLI::newLine(); + + return EXIT_SUCCESS; } /** diff --git a/system/Commands/Utilities/Optimize.php b/system/Commands/Utilities/Optimize.php index 11872bebafa5..1a103a1b9c52 100644 --- a/system/Commands/Utilities/Optimize.php +++ b/system/Commands/Utilities/Optimize.php @@ -55,7 +55,7 @@ final class Optimize extends BaseCommand protected $usage = 'optimize'; /** - * {@inheritDoc} + * @return int */ public function run(array $params) { @@ -63,13 +63,13 @@ public function run(array $params) $this->enableCaching(); $this->clearCache(); $this->removeDevPackages(); + + return EXIT_SUCCESS; } catch (RuntimeException) { CLI::error('The "spark optimize" failed.'); return EXIT_ERROR; } - - return EXIT_SUCCESS; } private function clearCache(): void diff --git a/system/Commands/Utilities/PhpIniCheck.php b/system/Commands/Utilities/PhpIniCheck.php index eb2192434133..f25518fb283d 100644 --- a/system/Commands/Utilities/PhpIniCheck.php +++ b/system/Commands/Utilities/PhpIniCheck.php @@ -68,7 +68,7 @@ final class PhpIniCheck extends BaseCommand protected $options = []; /** - * {@inheritDoc} + * @return int */ public function run(array $params) { diff --git a/system/Test/PhpStreamWrapper.php b/system/Test/PhpStreamWrapper.php index a6be8dd1329c..b49073c1f77b 100644 --- a/system/Test/PhpStreamWrapper.php +++ b/system/Test/PhpStreamWrapper.php @@ -52,7 +52,7 @@ public function stream_open(): bool } /** - * @return false|string + * @return string */ public function stream_read(int $count) { @@ -63,7 +63,7 @@ public function stream_read(int $count) } /** - * @return array|false + * @return array{} */ public function stream_stat() { diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 1372386f4cae..e621c1616cf5 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3615 errors +# total 3608 errors includes: - argument.type.neon - assign.propertyType.neon @@ -35,7 +35,6 @@ includes: - property.readOnlyByPhpDocAssignOutOfClass.neon - property.readOnlyByPhpDocDefaultValue.neon - property.unusedType.neon - - return.unusedType.neon - staticMethod.notFound.neon - ternary.shortNotAllowed.neon - varTag.type.neon diff --git a/utils/phpstan-baseline/missingType.iterableValue.neon b/utils/phpstan-baseline/missingType.iterableValue.neon index e8c7da4e7a0a..773002730217 100644 --- a/utils/phpstan-baseline/missingType.iterableValue.neon +++ b/utils/phpstan-baseline/missingType.iterableValue.neon @@ -1,4 +1,4 @@ -# total 1629 errors +# total 1628 errors parameters: ignoreErrors: @@ -5597,11 +5597,6 @@ parameters: count: 1 path: ../../system/Test/Mock/MockResult.php - - - message: '#^Method CodeIgniter\\Test\\PhpStreamWrapper\:\:stream_stat\(\) return type has no value type specified in iterable type array\.$#' - count: 1 - path: ../../system/Test/PhpStreamWrapper.php - - message: '#^Method CodeIgniter\\Test\\TestResponse\:\:assertJSONExact\(\) has parameter \$test with no value type specified in iterable type array\.$#' count: 1 diff --git a/utils/phpstan-baseline/return.unusedType.neon b/utils/phpstan-baseline/return.unusedType.neon deleted file mode 100644 index fa3d56d30daf..000000000000 --- a/utils/phpstan-baseline/return.unusedType.neon +++ /dev/null @@ -1,33 +0,0 @@ -# total 6 errors - -parameters: - ignoreErrors: - - - message: '#^Method CodeIgniter\\Commands\\Utilities\\ConfigCheck\:\:run\(\) never returns void so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Commands/Utilities/ConfigCheck.php - - - - message: '#^Method CodeIgniter\\Commands\\Utilities\\Environment\:\:run\(\) never returns int so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Commands/Utilities/Environment.php - - - - message: '#^Method CodeIgniter\\Commands\\Utilities\\Optimize\:\:run\(\) never returns void so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Commands/Utilities/Optimize.php - - - - message: '#^Method CodeIgniter\\Commands\\Utilities\\PhpIniCheck\:\:run\(\) never returns void so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Commands/Utilities/PhpIniCheck.php - - - - message: '#^Method CodeIgniter\\Test\\PhpStreamWrapper\:\:stream_read\(\) never returns false so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Test/PhpStreamWrapper.php - - - - message: '#^Method CodeIgniter\\Test\\PhpStreamWrapper\:\:stream_stat\(\) never returns false so it can be removed from the return type\.$#' - count: 1 - path: ../../system/Test/PhpStreamWrapper.php From 578c7c324a8033d9a7f05d007015deeb70e3970d Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 20:09:36 +0800 Subject: [PATCH 59/83] refactor: add `CITestStreamFilter` to phpstan-analysed list and fix errors (#9515) --- phpstan.neon.dist | 1 - system/Test/Filters/CITestStreamFilter.php | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bc3a0fc7ef34..a353de443e81 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -19,7 +19,6 @@ parameters: - system/Commands/Generators/Views/* - system/Debug/Toolbar/Views/toolbar.tpl.php - system/Images/Handlers/GDHandler.php - - system/Test/Filters/CITestStreamFilter.php - system/ThirdParty/* - system/Validation/Views/single.php - tests/system/View/Views/* diff --git a/system/Test/Filters/CITestStreamFilter.php b/system/Test/Filters/CITestStreamFilter.php index 64c3d64d65c5..538c0741ba8d 100644 --- a/system/Test/Filters/CITestStreamFilter.php +++ b/system/Test/Filters/CITestStreamFilter.php @@ -48,13 +48,14 @@ class CITestStreamFilter extends php_user_filter * @param resource $out * @param int $consumed * @param bool $closing + * + * @param-out int $consumed */ public function filter($in, $out, &$consumed, $closing): int { while ($bucket = stream_bucket_make_writeable($in)) { static::$buffer .= $bucket->data; - - $consumed += $bucket->datalen; + $consumed += (int) $bucket->datalen; } return PSFS_PASS_ON; @@ -92,11 +93,13 @@ public static function removeOutputFilter(): void } /** - * @param resource $stream + * @param resource|null $stream + * + * @param-out null $stream */ protected static function removeFilter(&$stream): void { - if (is_resource($stream)) { + if ($stream !== null) { stream_filter_remove($stream); $stream = null; } From ea2ee243c7738d8f6adfd8919ed308103954aab8 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 20:24:17 +0800 Subject: [PATCH 60/83] refactor: fix `property.unusedType` errors (#9516) --- tests/system/HTTP/MessageTest.php | 2 +- tests/system/HTTP/NegotiateTest.php | 4 ++-- utils/phpstan-baseline/loader.neon | 3 +-- .../phpstan-baseline/property.unusedType.neon | 18 ------------------ 4 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 utils/phpstan-baseline/property.unusedType.neon diff --git a/tests/system/HTTP/MessageTest.php b/tests/system/HTTP/MessageTest.php index 3c45471d4b81..5e3343416b12 100644 --- a/tests/system/HTTP/MessageTest.php +++ b/tests/system/HTTP/MessageTest.php @@ -25,7 +25,7 @@ #[Group('Others')] final class MessageTest extends CIUnitTestCase { - private ?Message $message; + private Message $message; protected function setUp(): void { diff --git a/tests/system/HTTP/NegotiateTest.php b/tests/system/HTTP/NegotiateTest.php index a2731ec5ddbf..e52f6f7a3201 100644 --- a/tests/system/HTTP/NegotiateTest.php +++ b/tests/system/HTTP/NegotiateTest.php @@ -25,8 +25,8 @@ #[Group('Others')] final class NegotiateTest extends CIUnitTestCase { - private ?IncomingRequest $request; - private ?Negotiate $negotiate; + private IncomingRequest $request; + private Negotiate $negotiate; protected function setUp(): void { diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index e621c1616cf5..c251023ac4e2 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3608 errors +# total 3605 errors includes: - argument.type.neon - assign.propertyType.neon @@ -34,7 +34,6 @@ includes: - property.protected.neon - property.readOnlyByPhpDocAssignOutOfClass.neon - property.readOnlyByPhpDocDefaultValue.neon - - property.unusedType.neon - staticMethod.notFound.neon - ternary.shortNotAllowed.neon - varTag.type.neon diff --git a/utils/phpstan-baseline/property.unusedType.neon b/utils/phpstan-baseline/property.unusedType.neon deleted file mode 100644 index 184b45953855..000000000000 --- a/utils/phpstan-baseline/property.unusedType.neon +++ /dev/null @@ -1,18 +0,0 @@ -# total 3 errors - -parameters: - ignoreErrors: - - - message: '#^Property CodeIgniter\\HTTP\\MessageTest\:\:\$message \(CodeIgniter\\HTTP\\Message\|null\) is never assigned null so it can be removed from the property type\.$#' - count: 1 - path: ../../tests/system/HTTP/MessageTest.php - - - - message: '#^Property CodeIgniter\\HTTP\\NegotiateTest\:\:\$negotiate \(CodeIgniter\\HTTP\\Negotiate\|null\) is never assigned null so it can be removed from the property type\.$#' - count: 1 - path: ../../tests/system/HTTP/NegotiateTest.php - - - - message: '#^Property CodeIgniter\\HTTP\\NegotiateTest\:\:\$request \(CodeIgniter\\HTTP\\IncomingRequest\|null\) is never assigned null so it can be removed from the property type\.$#' - count: 1 - path: ../../tests/system/HTTP/NegotiateTest.php From 0f7f1a6d4ffc29f9796371bc0c9f2f70e8e3283a Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 20:48:08 +0800 Subject: [PATCH 61/83] refactor: fix `property.protected` errors (#9517) --- system/Encryption/Encryption.php | 5 ++ system/I18n/TimeDifference.php | 8 +++- utils/phpstan-baseline/isset.property.neon | 7 +-- utils/phpstan-baseline/loader.neon | 3 +- .../phpstan-baseline/property.protected.neon | 48 ------------------- 5 files changed, 14 insertions(+), 57 deletions(-) delete mode 100644 utils/phpstan-baseline/property.protected.neon diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index 93236a581f39..c233f1fdfe03 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -23,6 +23,11 @@ * This class determines the driver, cipher, and mode to use, and then * initializes the appropriate encryption handler. * + * @property-read string $digest + * @property-read string $driver + * @property-read list $drivers + * @property-read string $key + * * @see \CodeIgniter\Encryption\EncryptionTest */ class Encryption diff --git a/system/I18n/TimeDifference.php b/system/I18n/TimeDifference.php index 81ca92be6a80..b51baf252472 100644 --- a/system/I18n/TimeDifference.php +++ b/system/I18n/TimeDifference.php @@ -17,7 +17,13 @@ use IntlCalendar; /** - * Class TimeDifference + * @property-read float|int $days + * @property-read float|int $hours + * @property-read float|int $minutes + * @property-read float|int $months + * @property-read int $seconds + * @property-read float|int $weeks + * @property-read float|int $years * * @see \CodeIgniter\I18n\TimeDifferenceTest */ diff --git a/utils/phpstan-baseline/isset.property.neon b/utils/phpstan-baseline/isset.property.neon index e70991bfe0e2..3b82b6f05443 100644 --- a/utils/phpstan-baseline/isset.property.neon +++ b/utils/phpstan-baseline/isset.property.neon @@ -1,4 +1,4 @@ -# total 3 errors +# total 2 errors parameters: ignoreErrors: @@ -11,8 +11,3 @@ parameters: message: '#^Static property CodeIgniter\\Email\\Email\:\:\$func_overload \(bool\) in isset\(\) is not nullable\.$#' count: 1 path: ../../system/Email/Email.php - - - - message: '#^Property CodeIgniter\\I18n\\TimeDifference\:\:\$days \(int\) in isset\(\) is not nullable\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index c251023ac4e2..7cd42b1fec33 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3605 errors +# total 3589 errors includes: - argument.type.neon - assign.propertyType.neon @@ -31,7 +31,6 @@ includes: - property.nonObject.neon - property.notFound.neon - property.phpDocType.neon - - property.protected.neon - property.readOnlyByPhpDocAssignOutOfClass.neon - property.readOnlyByPhpDocDefaultValue.neon - staticMethod.notFound.neon diff --git a/utils/phpstan-baseline/property.protected.neon b/utils/phpstan-baseline/property.protected.neon deleted file mode 100644 index 04b9a637fcbc..000000000000 --- a/utils/phpstan-baseline/property.protected.neon +++ /dev/null @@ -1,48 +0,0 @@ -# total 15 errors - -parameters: - ignoreErrors: - - - message: '#^Access to protected property CodeIgniter\\Encryption\\Encryption\:\:\$digest\.$#' - count: 2 - path: ../../tests/system/Encryption/EncryptionTest.php - - - - message: '#^Access to protected property CodeIgniter\\Encryption\\Encryption\:\:\$key\.$#' - count: 3 - path: ../../tests/system/Encryption/EncryptionTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$days\.$#' - count: 4 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$hours\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$minutes\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$months\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$seconds\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$weeks\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php - - - - message: '#^Access to protected property CodeIgniter\\I18n\\TimeDifference\:\:\$years\.$#' - count: 1 - path: ../../tests/system/I18n/TimeDifferenceTest.php From ce195754317f1d28f497342406e73beeceff04f3 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 21:10:01 +0800 Subject: [PATCH 62/83] refactor: fix `function.alreadyNarrowedType` errors (#9518) --- system/HTTP/Files/FileCollection.php | 2 +- system/Test/DOMParser.php | 6 ++---- .../function.alreadyNarrowedType.neon | 13 ------------- utils/phpstan-baseline/loader.neon | 3 +-- 4 files changed, 4 insertions(+), 20 deletions(-) delete mode 100644 utils/phpstan-baseline/function.alreadyNarrowedType.neon diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 120652e8bd87..484b3ff74872 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -253,7 +253,7 @@ protected function getValueDotNotationSyntax(array $index, array $value) { $currentIndex = array_shift($index); - if (isset($currentIndex) && is_array($index) && $index !== [] && array_key_exists($currentIndex, $value) && is_array($value[$currentIndex])) { + if (isset($currentIndex) && $index !== [] && array_key_exists($currentIndex, $value) && is_array($value[$currentIndex])) { return $this->getValueDotNotationSyntax($index, $value[$currentIndex]); } diff --git a/system/Test/DOMParser.php b/system/Test/DOMParser.php index f46ce1d65206..d8521edfbc86 100644 --- a/system/Test/DOMParser.php +++ b/system/Test/DOMParser.php @@ -233,10 +233,8 @@ protected function doXPath(?string $search, string $element, array $paths = []) // $paths might contain a number of different // ready to go xpath portions to tack on. - if ($paths !== [] && is_array($paths)) { - foreach ($paths as $extra) { - $path .= $extra; - } + foreach ($paths as $extra) { + $path .= $extra; } if ($search !== null) { diff --git a/utils/phpstan-baseline/function.alreadyNarrowedType.neon b/utils/phpstan-baseline/function.alreadyNarrowedType.neon deleted file mode 100644 index 740fa9659412..000000000000 --- a/utils/phpstan-baseline/function.alreadyNarrowedType.neon +++ /dev/null @@ -1,13 +0,0 @@ -# total 2 errors - -parameters: - ignoreErrors: - - - message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#' - count: 1 - path: ../../system/HTTP/Files/FileCollection.php - - - - message: '#^Call to function is_array\(\) with non\-empty\-array will always evaluate to true\.$#' - count: 1 - path: ../../system/Test/DOMParser.php diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 7cd42b1fec33..575c7843ba98 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3589 errors +# total 3587 errors includes: - argument.type.neon - assign.propertyType.neon @@ -11,7 +11,6 @@ includes: - deadCode.unreachable.neon - empty.notAllowed.neon - empty.property.neon - - function.alreadyNarrowedType.neon - generator.valueType.neon - isset.property.neon - method.alreadyNarrowedType.neon From 77ec9e58b0922f81858aeab55a42de62d337a6a9 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 13 Apr 2025 21:30:54 +0800 Subject: [PATCH 63/83] refactor: fix `empty.property` errors (#9519) --- system/Database/BaseBuilder.php | 2 +- system/Images/Handlers/BaseHandler.php | 8 +++-- system/Test/ControllerTestTrait.php | 8 ++--- utils/phpstan-baseline/empty.notAllowed.neon | 11 ++----- utils/phpstan-baseline/empty.property.neon | 33 -------------------- utils/phpstan-baseline/loader.neon | 3 +- 6 files changed, 14 insertions(+), 51 deletions(-) delete mode 100644 utils/phpstan-baseline/empty.property.neon diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index e10dd557fda0..6aee36f14261 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -3407,7 +3407,7 @@ protected function resetSelect() 'QBUnion' => [], ]); - if (! empty($this->db)) { + if ($this->db instanceof BaseConnection) { $this->db->setAliasedTables([]); } diff --git a/system/Images/Handlers/BaseHandler.php b/system/Images/Handlers/BaseHandler.php index 9c263afb89d1..de3e15974a1b 100644 --- a/system/Images/Handlers/BaseHandler.php +++ b/system/Images/Handlers/BaseHandler.php @@ -34,7 +34,7 @@ abstract class BaseHandler implements ImageHandlerInterface /** * The image/file instance * - * @var Image + * @var Image|null */ protected $image; @@ -138,6 +138,8 @@ public function __construct($config = null) * Sets another image for this handler to work on. * Keeps us from needing to continually instantiate the handler. * + * @phpstan-assert Image $this->image + * * @return $this */ public function withFile(string $path) @@ -176,7 +178,7 @@ public function getFile() /** * Verifies that a file has been supplied and it is an image. * - * @return Image The image instance + * @phpstan-assert Image $this->image * * @throws ImageException */ @@ -187,7 +189,7 @@ protected function image(): Image } // Verify withFile has been called - if (empty($this->image)) { + if ($this->image === null) { throw ImageException::forMissingImage(); } diff --git a/system/Test/ControllerTestTrait.php b/system/Test/ControllerTestTrait.php index 2ac68938e251..2a7be526383d 100644 --- a/system/Test/ControllerTestTrait.php +++ b/system/Test/ControllerTestTrait.php @@ -95,7 +95,7 @@ protected function setUpControllerTestTrait(): void // The URL helper is always loaded by the system so ensure it is available. helper('url'); - if (empty($this->appConfig)) { + if (! $this->appConfig instanceof App) { $this->appConfig = config(App::class); } @@ -104,7 +104,7 @@ protected function setUpControllerTestTrait(): void $this->uri = $factory->createFromGlobals(); } - if (empty($this->request)) { + if (! $this->request instanceof IncomingRequest) { // Do some acrobatics, so we can use the Request service with our own URI $tempUri = service('uri'); Services::injectMock('uri', $this->uri); @@ -115,11 +115,11 @@ protected function setUpControllerTestTrait(): void Services::injectMock('uri', $tempUri); } - if (empty($this->response)) { + if (! $this->response instanceof ResponseInterface) { $this->response = service('response', $this->appConfig, false); } - if (empty($this->logger)) { + if (! $this->logger instanceof LoggerInterface) { $this->logger = service('logger'); } } diff --git a/utils/phpstan-baseline/empty.notAllowed.neon b/utils/phpstan-baseline/empty.notAllowed.neon index ad029ff92d04..c0e03d572785 100644 --- a/utils/phpstan-baseline/empty.notAllowed.neon +++ b/utils/phpstan-baseline/empty.notAllowed.neon @@ -1,4 +1,4 @@ -# total 271 errors +# total 265 errors parameters: ignoreErrors: @@ -39,7 +39,7 @@ parameters: - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' - count: 29 + count: 28 path: ../../system/Database/BaseBuilder.php - @@ -289,7 +289,7 @@ parameters: - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' - count: 3 + count: 2 path: ../../system/Images/Handlers/BaseHandler.php - @@ -367,11 +367,6 @@ parameters: count: 1 path: ../../tests/system/Session/SessionTest.php - - - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' - count: 4 - path: ../../tests/system/Test/ControllerTestTraitTest.php - - message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#' count: 1 diff --git a/utils/phpstan-baseline/empty.property.neon b/utils/phpstan-baseline/empty.property.neon deleted file mode 100644 index cbc2397dc84e..000000000000 --- a/utils/phpstan-baseline/empty.property.neon +++ /dev/null @@ -1,33 +0,0 @@ -# total 6 errors - -parameters: - ignoreErrors: - - - message: '#^Property CodeIgniter\\Database\\BaseBuilder\:\:\$db \(CodeIgniter\\Database\\BaseConnection\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../system/Database/BaseBuilder.php - - - - message: '#^Property CodeIgniter\\Images\\Handlers\\BaseHandler\:\:\$image \(CodeIgniter\\Images\\Image\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../system/Images/Handlers/BaseHandler.php - - - - message: '#^Property CodeIgniter\\Test\\ControllerTestTraitTest\:\:\$appConfig \(Config\\App\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../tests/system/Test/ControllerTestTraitTest.php - - - - message: '#^Property CodeIgniter\\Test\\ControllerTestTraitTest\:\:\$logger \(Psr\\Log\\LoggerInterface\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../tests/system/Test/ControllerTestTraitTest.php - - - - message: '#^Property CodeIgniter\\Test\\ControllerTestTraitTest\:\:\$request \(CodeIgniter\\HTTP\\IncomingRequest\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../tests/system/Test/ControllerTestTraitTest.php - - - - message: '#^Property CodeIgniter\\Test\\ControllerTestTraitTest\:\:\$response \(CodeIgniter\\HTTP\\ResponseInterface\) in empty\(\) is not falsy\.$#' - count: 1 - path: ../../tests/system/Test/ControllerTestTraitTest.php diff --git a/utils/phpstan-baseline/loader.neon b/utils/phpstan-baseline/loader.neon index 575c7843ba98..89d0f88ce766 100644 --- a/utils/phpstan-baseline/loader.neon +++ b/utils/phpstan-baseline/loader.neon @@ -1,4 +1,4 @@ -# total 3587 errors +# total 3575 errors includes: - argument.type.neon - assign.propertyType.neon @@ -10,7 +10,6 @@ includes: - codeigniter.unknownServiceMethod.neon - deadCode.unreachable.neon - empty.notAllowed.neon - - empty.property.neon - generator.valueType.neon - isset.property.neon - method.alreadyNarrowedType.neon From 50b3f571d639ac8538c32569342d7ffbe142eb73 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 14 Apr 2025 01:21:16 +0800 Subject: [PATCH 64/83] refactor: import FQCNs (#9520) --- .../tests/_support/Libraries/ConfigReader.php | 4 ++- preload.php | 7 ++-- public/index.php | 7 ++-- spark | 7 ++-- system/Debug/Toolbar/Views/toolbar.tpl.php | 35 ++++++++++--------- .../Config/fixtures/RegistrarConfig.php | 4 ++- tests/system/Config/fixtures/SimpleConfig.php | 4 ++- 7 files changed, 43 insertions(+), 25 deletions(-) diff --git a/admin/starter/tests/_support/Libraries/ConfigReader.php b/admin/starter/tests/_support/Libraries/ConfigReader.php index 40d057acbe22..0bb4a8fcf598 100644 --- a/admin/starter/tests/_support/Libraries/ConfigReader.php +++ b/admin/starter/tests/_support/Libraries/ConfigReader.php @@ -2,6 +2,8 @@ namespace Tests\Support\Libraries; +use Config\App; + /** * Class ConfigReader * @@ -9,7 +11,7 @@ * loading external values. Used to read actual local values from * a config file. */ -class ConfigReader extends \Config\App +class ConfigReader extends App { public function __construct() { diff --git a/preload.php b/preload.php index 0b453122345e..86322d5e7137 100644 --- a/preload.php +++ b/preload.php @@ -9,6 +9,9 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\Boot; +use Config\Paths; + /* *--------------------------------------------------------------- * Sample file for Preloading @@ -69,10 +72,10 @@ public function __construct() private function loadAutoloader(): void { - $paths = new Config\Paths(); + $paths = new Paths(); require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php'; - CodeIgniter\Boot::preload($paths); + Boot::preload($paths); } /** diff --git a/public/index.php b/public/index.php index eb7f5c988838..a0a20db43dbf 100644 --- a/public/index.php +++ b/public/index.php @@ -1,5 +1,8 @@ systemDirectory . '/Boot.php'; -exit(CodeIgniter\Boot::bootWeb($paths)); +exit(Boot::bootWeb($paths)); diff --git a/spark b/spark index 856dc3f8a227..e7871ea8e682 100755 --- a/spark +++ b/spark @@ -10,6 +10,9 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\Boot; +use Config\Paths; + /* * -------------------------------------------------------------------- * CODEIGNITER COMMAND-LINE TOOLS @@ -76,9 +79,9 @@ chdir(FCPATH); require FCPATH . '../app/Config/Paths.php'; // ^^^ Change this line if you move your application folder -$paths = new Config\Paths(); +$paths = new Paths(); // LOAD THE FRAMEWORK BOOTSTRAP FILE require $paths->systemDirectory . '/Boot.php'; -exit(CodeIgniter\Boot::bootSpark($paths)); +exit(Boot::bootSpark($paths)); diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index 8179c1a8e631..0768f62915bb 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -1,21 +1,24 @@