From 67f8876f6ecba3b5daa701b667dbc3be63eb6c83 Mon Sep 17 00:00:00 2001 From: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:34:52 +0300 Subject: [PATCH 001/380] refactor: ViewDecoratorTrait Use `View::$config` instead of `config()` function --- system/View/ViewDecoratorTrait.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/system/View/ViewDecoratorTrait.php b/system/View/ViewDecoratorTrait.php index 97cdbe0a252d..da7a57189981 100644 --- a/system/View/ViewDecoratorTrait.php +++ b/system/View/ViewDecoratorTrait.php @@ -12,7 +12,6 @@ namespace CodeIgniter\View; use CodeIgniter\View\Exceptions\ViewException; -use Config\View as ViewConfig; trait ViewDecoratorTrait { @@ -22,9 +21,7 @@ trait ViewDecoratorTrait */ protected function decorateOutput(string $html): string { - $decorators = \config(ViewConfig::class)->decorators; - - foreach ($decorators as $decorator) { + foreach ($this->config->decorators as $decorator) { if (! is_subclass_of($decorator, ViewDecoratorInterface::class)) { throw ViewException::forInvalidDecorator($decorator); } From b576cd98c8cab80e95bd8fa47f6f07af4fde862f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 09:23:13 +0900 Subject: [PATCH 002/380] chore: update templates for changelog/upgrading --- admin/next-changelog-minor.rst | 8 ++++++++ admin/next-changelog-patch.rst | 6 ++++++ admin/next-upgrading-guide.rst | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/admin/next-changelog-minor.rst b/admin/next-changelog-minor.rst index f5bb20004d77..c22f0be7d9f3 100644 --- a/admin/next-changelog-minor.rst +++ b/admin/next-changelog-minor.rst @@ -1,3 +1,4 @@ +################# Version {version} ################# @@ -9,11 +10,13 @@ Release Date: Unreleased :local: :depth: 3 +********** Highlights ********** - TBD +******** BREAKING ******** @@ -26,6 +29,7 @@ Interface Changes Method Signature Changes ======================== +************ Enhancements ************ @@ -59,15 +63,19 @@ Helpers and Functions Others ====== +*************** Message Changes *************** +******* Changes ******* +************ Deprecations ************ +********** Bugs Fixed ********** diff --git a/admin/next-changelog-patch.rst b/admin/next-changelog-patch.rst index 4c76ca01a112..ed2ba70570b3 100644 --- a/admin/next-changelog-patch.rst +++ b/admin/next-changelog-patch.rst @@ -1,3 +1,4 @@ +################# Version {version} ################# @@ -9,18 +10,23 @@ Release Date: Unreleased :local: :depth: 3 +******** BREAKING ******** +*************** Message Changes *************** +******* Changes ******* +************ Deprecations ************ +********** Bugs Fixed ********** diff --git a/admin/next-upgrading-guide.rst b/admin/next-upgrading-guide.rst index fb97f320e95a..bcffc3fe3de5 100644 --- a/admin/next-upgrading-guide.rst +++ b/admin/next-upgrading-guide.rst @@ -12,15 +12,19 @@ Please refer to the upgrade instructions corresponding to your installation meth :local: :depth: 2 +********************** Mandatory File Changes ********************** +**************** Breaking Changes **************** +********************* Breaking Enhancements ********************* +************* Project Files ************* From 567a4bea3b5da3be4f90aba2a392ab5c8a4451d3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 09:28:17 +0900 Subject: [PATCH 003/380] chore: add scripts for release process --- admin/create-new-changelog.php | 87 ++++++++++++++++++++++++++++++++++ admin/prepare-release.php | 61 ++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 admin/create-new-changelog.php create mode 100644 admin/prepare-release.php diff --git a/admin/create-new-changelog.php b/admin/create-new-changelog.php new file mode 100644 index 000000000000..ff371345d166 --- /dev/null +++ b/admin/create-new-changelog.php @@ -0,0 +1,87 @@ + " . PHP_EOL; + echo "E.g.,: php {$argv[0]} 4.4.3 4.4.4" . PHP_EOL; + + exit(1); +} + +// Gets version number from argument. +$versionCurrent = $argv[1]; // e.g., '4.4.3' +$versionCurrentParts = explode('.', $versionCurrent); +$minorCurrent = $versionCurrentParts[0] . '.' . $versionCurrentParts[1]; +$version = $argv[2]; // e.g., '4.4.4' +$versionParts = explode('.', $version); +$minor = $versionParts[0] . '.' . $versionParts[1]; +$isMinorUpdate = ($minorCurrent !== $minor); + +// Creates a branch for release. +system('git switch develop'); +system('git switch -c docs-changelog-' . $version); +system('git switch docs-changelog-' . $version); + +// Copy changelog +$changelog = "./user_guide_src/source/changelogs/v{$version}.rst"; +$changelogIndex = './user_guide_src/source/changelogs/index.rst'; +if ($isMinorUpdate) { + copy('./admin/next-changelog-minor.rst', $changelog); +} else { + copy('./admin/next-changelog-patch.rst', $changelog); +} +// Add changelog to index.rst. +replace_file_content( + $changelogIndex, + '/\.\. toctree::\n :titlesonly:\n/u', + ".. toctree::\n :titlesonly:\n\n v{$version}" +); +// Replace {version} +$length = mb_strlen("Version {$version}"); +$underline = str_repeat('#', $length); +replace_file_content( + $changelog, + '/#################\nVersion {version}\n#################/u', + "{$underline}\nVersion {$version}\n{$underline}" +); +replace_file_content( + $changelog, + '/{version}/u', + "{$version}" +); + +// Copy upgrading +$versionWithoutDots = str_replace('.', '', $version); +$upgrading = "./user_guide_src/source/installation/upgrade_{$versionWithoutDots}.rst"; +$upgradingIndex = './user_guide_src/source/installation/upgrading.rst'; +copy('./admin/next-upgrading-guide.rst', $upgrading); +// Add upgrading to upgrading.rst. +replace_file_content( + $upgradingIndex, + '/ backward_compatibility_notes\n/u', + " backward_compatibility_notes\n\n upgrade_{$versionWithoutDots}" +); +// Replace {version} +$length = mb_strlen("Upgrading from {$versionCurrent} to {$version}"); +$underline = str_repeat('#', $length); +replace_file_content( + $upgrading, + '/##############################\nUpgrading from {version} to {version}\n##############################/u', + "{$underline}\nUpgrading from {$versionCurrent} to {$version}\n{$underline}" +); + +// Commits +system("git add {$changelog} {$changelogIndex}"); +system("git add {$upgrading} {$upgradingIndex}"); +system('git commit -m "docs: add changelog and upgrade for v' . $version . '"'); diff --git a/admin/prepare-release.php b/admin/prepare-release.php new file mode 100644 index 000000000000..1b173a0f75d6 --- /dev/null +++ b/admin/prepare-release.php @@ -0,0 +1,61 @@ +" . PHP_EOL; + echo "E.g.,: php {$argv[0]} 4.4.3" . PHP_EOL; + + exit(1); +} + +// Gets version number from argument. +$version = $argv[1]; // e.g., '4.4.3' +$versionParts = explode('.', $version); +$minor = $versionParts[0] . '.' . $versionParts[1]; + +// Creates a branch for release. +system('git switch develop'); +system('git switch -c release-' . $version); +system('git switch docs-changelog-' . $version); + +// Updates version number in "CodeIgniter.php". +replace_file_content( + './system/CodeIgniter.php', + '/public const CI_VERSION = \'.*?\';/u', + "public const CI_VERSION = '{$version}';" +); + +// Updates version number in "conf.py". +replace_file_content( + './user_guide_src/source/conf.py', + '/^version = \'.*?\'/mu', + "version = '{$minor}'" +); +replace_file_content( + './user_guide_src/source/conf.py', + '/^release = \'.*?\'/mu', + "release = '{$version}'" +); + +// Updates release date in changelogs. +$date = date('F j, Y'); +replace_file_content( + "./user_guide_src/source/changelogs/v{$version}.rst", + '/^Release Date: .*/mu', + "Release Date: {$date}" +); + +// Commits +system('git add -u'); +system('git commit -m "Prep for ' . $version . ' release"'); From ea2b26b9c41e17436ab5bca696562b56f9f63b1e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 09:28:48 +0900 Subject: [PATCH 004/380] docs: update RELEASE.md --- admin/RELEASE.md | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/admin/RELEASE.md b/admin/RELEASE.md index 98089ae8181f..731527de0ed7 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -2,7 +2,7 @@ > Documentation guide based on the releases of `4.0.5` and `4.1.0` on January 31, 2021. > -> Updated for `4.3.0` on January 10, 2023. +> Updated for `4.4.3` on October 27, 2023. > > -MGatner, kenjis @@ -53,12 +53,18 @@ Work off direct clones of the repos so the release branches persist for a time. * [ ] Clone both **codeigniter4/CodeIgniter4** and **codeigniter4/userguide** and resolve any necessary PRs ```console + rm -rf CodeIgniter4.bk userguide.bk + mv CodeIgniter4 CodeIgniter4.bk + mv userguide userguide.bk git clone git@github.com:codeigniter4/CodeIgniter4.git git clone git@github.com:codeigniter4/userguide.git ``` * [ ] Vet the **admin/** folders for any removed hidden files (Action deploy scripts *do not remove these*) - * git diff --name-status origin/master admin/ + ```console + cd CodeIgniter4 + git diff --name-status origin/master admin/ + ``` * [ ] Merge any Security Advisory PRs in private forks ## Process @@ -67,21 +73,24 @@ Work off direct clones of the repos so the release branches persist for a time. > been included with their PR, so this process assumes you will not be > generating much new content. -* [ ] 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'` * [ ] Replace **CHANGELOG.md** with the new version generated above * [ ] Update **user_guide_src/source/changelogs/{version}.rst** - * Set the date to format `Release Date: January 31, 2021` * Remove the section titles that have no items * [ ] Update **user_guide_src/source/installation/upgrade_{ver}.rst** * fill in the "All Changes" section, and add it to **upgrading.rst** * git diff --name-status origin/master -- . ':!system' * 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` -* [ ] Commit the changes with `Prep for 4.x.x release` and push to origin +* [ ] 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/changelogs/{version}.rst** + * Set the date to format `Release Date: January 31, 2021` + * Commit the changes with `Prep for 4.x.x release` * [ ] Create a new PR from `release-4.x.x` to `develop`: * Title: `Prep for 4.x.x release` * Description: @@ -119,6 +128,7 @@ Work off direct clones of the repos so the release branches persist for a time. * [ ] Run the following commands to install and test `appstarter` and verify the new version: ```console + rm -rf release-test composer create-project codeigniter4/appstarter release-test cd release-test composer test && composer info codeigniter4/framework @@ -152,7 +162,7 @@ Work off direct clones of the repos so the release branches persist for a time. git switch -c 4.x git push origin HEAD ``` -* [ ] Publish any Security Advisories that were resolved from private forks +* [ ] 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): @@ -160,11 +170,13 @@ Work off direct clones of the repos so the release branches persist for a time. https://forum.codeigniter.com/forum-2.html * The content is somewhat organic, but should include any major features and changes as well as a link to the User Guide's changelog +* [ ] Run `php admin/create-new-changelog.php ` + * The above command does the following: + * Create **user_guide_src/source/changelogs/{next_version}.rst** and add it to + **index.rst** (See **next-changelog-*.rst**) + * Create **user_guide_src/source/installation/upgrade_{next_version}.rst** and add it to + **upgrading.rst** (See **next-upgrading-guide.rst**) * [ ] Create a PR for new changelog and upgrade for the next version - * Create **user_guide_src/source/changelogs/{next_version}.rst** and add it to - **index.rst** (See **next-changelog-*.rst**) - * Create **user_guide_src/source/installation/upgrade_{next_version}.rst** and add it to - **upgrading.rst** (See **next-upgrading-guide.rst**) ## Appendix From ac49623389927b5ed9be20217ed61d7f7761cd1b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 09:22:07 +0900 Subject: [PATCH 005/380] docs: add changelog and upgrade for v4.4.4 --- user_guide_src/source/changelogs/index.rst | 1 + user_guide_src/source/changelogs/v4.4.4.rst | 35 ++++++++++++ .../source/installation/upgrade_444.rst | 54 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 4 files changed, 91 insertions(+) create mode 100644 user_guide_src/source/changelogs/v4.4.4.rst create mode 100644 user_guide_src/source/installation/upgrade_444.rst diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index 5863f9c4fd8f..eb9f7f1f5edb 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.4.4 v4.4.3 v4.4.2 v4.4.1 diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst new file mode 100644 index 000000000000..218c56e738d7 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -0,0 +1,35 @@ +############# +Version 4.4.4 +############# + +Release Date: Unreleased + +**4.4.4 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_444.rst b/user_guide_src/source/installation/upgrade_444.rst new file mode 100644 index 000000000000..6dbfa8e7baac --- /dev/null +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -0,0 +1,54 @@ +############################# +Upgrading from 4.4.3 to 4.4.4 +############################# + +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. + +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 b768959eb6c4..2c0731f3a437 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_444 upgrade_443 upgrade_442 upgrade_441 From 94e082f252d36ee685295966d4414ed898247f20 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 09:18:18 +0900 Subject: [PATCH 006/380] chore: add names to github workflows To change the GitHub PR page display. --- .github/workflows/test-autoreview.yml | 1 + .github/workflows/test-phpunit.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml index 44feb4e33139..1f2f785fb77c 100644 --- a/.github/workflows/test-autoreview.yml +++ b/.github/workflows/test-autoreview.yml @@ -23,6 +23,7 @@ permissions: jobs: auto-review-tests: + name: AutoReview uses: ./.github/workflows/reusable-serviceless-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: job-name: Automatic Code Review [PHP 8.1] diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 9ca4ed8e15e4..856d11b17249 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -50,6 +50,7 @@ jobs: echo "version=8.1" >> $GITHUB_OUTPUT sanity-tests: + name: Others needs: coverage-php-version strategy: @@ -77,6 +78,7 @@ jobs: extra-composer-options: ${{ matrix.composer-option }} database-live-tests: + name: DatabaseLive needs: - coverage-php-version - sanity-tests @@ -120,6 +122,7 @@ jobs: extra-composer-options: ${{ matrix.composer-option }} separate-process-tests: + name: SeparateProcess needs: - coverage-php-version - sanity-tests @@ -149,6 +152,7 @@ jobs: extra-composer-options: ${{ matrix.composer-option }} cache-live-tests: + name: CacheLive needs: - coverage-php-version - sanity-tests From f22efe17e07dbb775601595a44d5d76fad49ea05 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 10:11:11 +0900 Subject: [PATCH 007/380] chore: change names for shorter name display --- .github/workflows/test-autoreview.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml index 1f2f785fb77c..69545ca6af01 100644 --- a/.github/workflows/test-autoreview.yml +++ b/.github/workflows/test-autoreview.yml @@ -1,4 +1,4 @@ -name: Automatic Code Review +name: AutoReview on: pull_request: @@ -23,10 +23,10 @@ permissions: jobs: auto-review-tests: - name: AutoReview + name: Automatic Code Review uses: ./.github/workflows/reusable-serviceless-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: - job-name: Automatic Code Review [PHP 8.1] + job-name: PHP 8.1 php-version: '8.1' job-id: auto-review-tests group-name: AutoReview From 1bae325c9f0132bfc8b2edb0196f516c36ccbd4a Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 10:54:09 +0900 Subject: [PATCH 008/380] chore: make long job-names empty --- .github/workflows/test-phpunit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 856d11b17249..c6deb546bb7d 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -109,7 +109,7 @@ jobs: uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: - job-name: Database Live Tests + job-name: php-version: ${{ matrix.php-version }} job-id: database-live-tests db-platform: ${{ matrix.db-platform }} @@ -141,7 +141,7 @@ jobs: uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: - job-name: Separate Process Tests + job-name: php-version: ${{ matrix.php-version }} job-id: separate-process-tests group-name: SeparateProcess From 1de08fa47e0cc465330aa1b13659088b830d5e38 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 27 Oct 2023 13:22:26 +0700 Subject: [PATCH 009/380] [Rector] Apply SingleInArrayToCompareRector --- rector.php | 2 ++ system/Config/BaseService.php | 2 +- tests/system/Database/Live/GroupTest.php | 16 ++++++++-------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/rector.php b/rector.php index 89b92f15e58d..747cd4ce8bbd 100644 --- a/rector.php +++ b/rector.php @@ -16,6 +16,7 @@ use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector; use Rector\CodeQuality\Rector\FuncCall\SimplifyRegexPatternRector; use Rector\CodeQuality\Rector\FuncCall\SimplifyStrposLowerRector; +use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector; use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\If_\CombineIfRector; use Rector\CodeQuality\Rector\If_\ShortenElseIfRector; @@ -142,4 +143,5 @@ $rectorConfig->rule(PrivatizeFinalClassPropertyRector::class); $rectorConfig->rule(CompleteDynamicPropertiesRector::class); $rectorConfig->rule(BooleanInIfConditionRuleFixerRector::class); + $rectorConfig->rule(SingleInArrayToCompareRector::class); }; diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 22daf7b69e4b..1c80c80d77c6 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -343,7 +343,7 @@ protected static function discoverServices(string $name, array $arguments) foreach ($files as $file) { $classname = $locator->getClassname($file); - if (! in_array($classname, [Services::class], true)) { + if ($classname !== Services::class) { static::$services[] = new $classname(); } } diff --git a/tests/system/Database/Live/GroupTest.php b/tests/system/Database/Live/GroupTest.php index c953645dcab4..b509229ece08 100644 --- a/tests/system/Database/Live/GroupTest.php +++ b/tests/system/Database/Live/GroupTest.php @@ -40,7 +40,7 @@ public function testGroupBy(): void public function testHavingBy(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -63,7 +63,7 @@ public function testHavingBy(): void public function testOrHavingBy(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('user') @@ -134,7 +134,7 @@ public function testHavingNotIn(): void public function testOrHavingNotIn(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -207,7 +207,7 @@ public function testOrHavingLike(): void public function testOrNotHavingLike(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -237,7 +237,7 @@ public function testOrNotHavingLike(): void public function testAndHavingGroupStart(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -271,7 +271,7 @@ public function testAndHavingGroupStart(): void public function testOrHavingGroupStart(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -306,7 +306,7 @@ public function testOrHavingGroupStart(): void public function testNotHavingGroupStart(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') @@ -340,7 +340,7 @@ public function testNotHavingGroupStart(): void public function testOrNotHavingGroupStart(): void { - $isANSISQL = in_array($this->db->DBDriver, ['OCI8'], true); + $isANSISQL = $this->db->DBDriver === 'OCI8'; if ($isANSISQL) { $result = $this->db->table('job') From 246ed66f7c6e3bf32f476182c2927f1688704e6e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 27 Oct 2023 19:17:02 +0900 Subject: [PATCH 010/380] config: update curlrequest.shareOptions The default value is false now. --- env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env b/env index cb99e19c3a80..e60354b3c4f8 100644 --- a/env +++ b/env @@ -140,4 +140,4 @@ # CURLRequest #-------------------------------------------------------------------- -# curlrequest.shareOptions = true +# curlrequest.shareOptions = false From 2b5b0814dc8e57f5fe205f166314aae267b73b27 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 27 Oct 2023 23:20:40 +0800 Subject: [PATCH 011/380] style: run cs-fix --- system/Exceptions/FrameworkException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Exceptions/FrameworkException.php b/system/Exceptions/FrameworkException.php index 4cafd71177e2..faf3f1480126 100644 --- a/system/Exceptions/FrameworkException.php +++ b/system/Exceptions/FrameworkException.php @@ -66,7 +66,7 @@ public static function forMissingExtension(string $extension) 'The framework needs the following extension(s) installed and loaded: %s.', $extension ); - // @codeCoverageIgnoreEnd + // @codeCoverageIgnoreEnd } else { $message = lang('Core.missingExtension', [$extension]); } From b421974ad3fbda6d089c1d523f9827c4784d6d30 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 27 Oct 2023 23:40:29 +0800 Subject: [PATCH 012/380] fix: add Closure signature for CodeIgniter::$controller --- phpstan-baseline.php | 5 ----- system/CodeIgniter.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 0d372afdb97c..c56d1becdfee 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -186,11 +186,6 @@ 'count' => 6, 'path' => __DIR__ . '/system/CodeIgniter.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\CodeIgniter\\:\\:\\$controller type has no signature specified for Closure\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/CodeIgniter.php', -]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 1, diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 9f9f6e174ca7..8299bfafa992 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -108,7 +108,7 @@ class CodeIgniter /** * Controller to use. * - * @var Closure|string + * @var (Closure(mixed...): ResponseInterface|string)|string */ protected $controller; From 42d77d6f9b1987449040b6c0530242bd6e9629b1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 28 Oct 2023 09:00:24 +0900 Subject: [PATCH 013/380] fix: change make:command default $group to `App` `CodeIgniter` is already used for the framework commands. CodeIgniter env Retrieves the current environment, or set a new one. filter:check Check filters for a route. help Displays basic usage information. list Lists the available commands. namespaces Verifies your namespaces are setup correctly. publish Discovers and executes all predefined Publisher classes. routes Displays all routes. serve Launches the CodeIgniter PHP-Development Server. --- system/Commands/Generators/CommandGenerator.php | 4 ++-- tests/system/Commands/CommandGeneratorTest.php | 4 ++-- user_guide_src/source/cli/cli_generators.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/system/Commands/Generators/CommandGenerator.php b/system/Commands/Generators/CommandGenerator.php index 7ccae13f7163..55755643e949 100644 --- a/system/Commands/Generators/CommandGenerator.php +++ b/system/Commands/Generators/CommandGenerator.php @@ -67,7 +67,7 @@ class CommandGenerator extends BaseCommand protected $options = [ '--command' => 'The command name. Default: "command:name"', '--type' => 'The command type. Options [basic, generator]. Default: "basic".', - '--group' => 'The command group. Default: [basic -> "CodeIgniter", generator -> "Generators"].', + '--group' => 'The command group. Default: [basic -> "App", generator -> "Generators"].', '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', '--suffix' => 'Append the component title to the class name (e.g. User => UserCommand).', '--force' => 'Force overwrite existing file.', @@ -106,7 +106,7 @@ protected function prepare(string $class): string } if (! is_string($group)) { - $group = $type === 'generator' ? 'Generators' : 'CodeIgniter'; + $group = $type === 'generator' ? 'Generators' : 'App'; } return $this->parseTemplate( diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index 64ab5a21d2d9..aabb86f9a843 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -52,7 +52,7 @@ public function testGenerateCommand(): void $file = APPPATH . 'Commands/Deliver.php'; $this->assertFileExists($file); $contents = $this->getFileContents($file); - $this->assertStringContainsString('protected $group = \'CodeIgniter\';', $contents); + $this->assertStringContainsString('protected $group = \'App\';', $contents); $this->assertStringContainsString('protected $name = \'command:name\';', $contents); } @@ -72,7 +72,7 @@ public function testGenerateCommandWithOptionTypeBasic(): void $file = APPPATH . 'Commands/Deliver.php'; $this->assertFileExists($file); $contents = $this->getFileContents($file); - $this->assertStringContainsString('protected $group = \'CodeIgniter\';', $contents); + $this->assertStringContainsString('protected $group = \'App\';', $contents); $this->assertStringContainsString('protected $name = \'command:name\';', $contents); } diff --git a/user_guide_src/source/cli/cli_generators.rst b/user_guide_src/source/cli/cli_generators.rst index 8636901644f2..e04772f6ab00 100644 --- a/user_guide_src/source/cli/cli_generators.rst +++ b/user_guide_src/source/cli/cli_generators.rst @@ -86,7 +86,7 @@ Argument: Options: ======== * ``--command``: The command name to run in spark. Defaults to ``command:name``. -* ``--group``: The group/namespace of the command. Defaults to ``CodeIgniter`` for basic commands, and ``Generators`` for generator commands. +* ``--group``: The group/namespace of the command. Defaults to ``App`` for basic commands, and ``Generators`` for generator commands. * ``--type``: The type of command, whether a ``basic`` command or a ``generator`` command. Defaults to ``basic``. * ``--namespace``: Set the root namespace. Defaults to value of ``APP_NAMESPACE``. * ``--suffix``: Append the component suffix to the generated class name. From 543c2a844c94ea0ec445141bdb4ae819de7cc31f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 28 Oct 2023 11:48:52 +0900 Subject: [PATCH 014/380] docs: fix @param array type for Commands --- phpstan-baseline.php | 50 ------------------- system/CLI/BaseCommand.php | 20 ++++---- system/Commands/Cache/ClearCache.php | 2 +- system/Commands/Database/Migrate.php | 2 +- system/Commands/Database/MigrateRefresh.php | 2 +- system/Commands/Database/MigrateRollback.php | 2 +- system/Commands/Encryption/GenerateKey.php | 2 +- system/Commands/Generators/CellGenerator.php | 4 +- .../Commands/Generators/CommandGenerator.php | 4 +- .../Commands/Generators/ConfigGenerator.php | 4 +- .../Generators/ControllerGenerator.php | 4 +- .../Commands/Generators/EntityGenerator.php | 4 +- .../Commands/Generators/FilterGenerator.php | 4 +- system/Commands/Generators/MigrateCreate.php | 4 +- .../Generators/MigrationGenerator.php | 4 +- system/Commands/Generators/ModelGenerator.php | 4 +- .../Commands/Generators/ScaffoldGenerator.php | 4 +- .../Commands/Generators/SeederGenerator.php | 4 +- .../Generators/SessionMigrationGenerator.php | 2 +- .../Generators/ValidationGenerator.php | 4 +- system/Commands/Help.php | 4 +- system/Commands/Housekeeping/ClearLogs.php | 2 +- system/Commands/ListCommands.php | 4 +- system/Commands/Server/Serve.php | 4 +- system/Commands/Utilities/Environment.php | 2 +- system/Commands/Utilities/FilterCheck.php | 2 +- system/Commands/Utilities/Namespaces.php | 4 +- system/Commands/Utilities/Publish.php | 2 +- system/Commands/Utilities/Routes.php | 2 +- tests/_support/Commands/Unsuffixable.php | 4 +- 30 files changed, 55 insertions(+), 105 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 0d372afdb97c..c32d18872464 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -196,16 +196,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Database/CreateDatabase.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\CreateDatabase\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/CreateDatabase.php', -]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\CreateDatabase\\:\\:\\$options is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$options\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/CreateDatabase.php', -]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 1, @@ -216,11 +206,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Database/MigrateStatus.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\MigrateStatus\\:\\:\\$options is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$options\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/MigrateStatus.php', -]; $ignoreErrors[] = [ 'message' => '#^Parameter \\#1 \\$params \\(array\\\\) of method CodeIgniter\\\\Commands\\\\Database\\\\MigrateStatus\\:\\:run\\(\\) should be contravariant with parameter \\$params \\(array\\\\) of method CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:run\\(\\)$#', 'count' => 1, @@ -231,11 +216,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Database/Seed.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\Seed\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/Seed.php', -]; $ignoreErrors[] = [ 'message' => '#^Method CodeIgniter\\\\Commands\\\\Database\\\\ShowTableInfo\\:\\:showAllTables\\(\\) has no return type specified\\.$#', 'count' => 1, @@ -246,16 +226,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Database/ShowTableInfo.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\ShowTableInfo\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/ShowTableInfo.php', -]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Database\\\\ShowTableInfo\\:\\:\\$options is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$options\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Database/ShowTableInfo.php', -]; $ignoreErrors[] = [ 'message' => '#^Accessing offset \'encryption\\.key\' directly on \\$_SERVER is discouraged\\.$#', 'count' => 1, @@ -756,26 +726,11 @@ 'count' => 3, 'path' => __DIR__ . '/system/Commands/Utilities/Environment.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Utilities\\\\Environment\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Utilities/Environment.php', -]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Utilities\\\\FilterCheck\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Utilities/FilterCheck.php', -]; $ignoreErrors[] = [ 'message' => '#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#', 'count' => 1, 'path' => __DIR__ . '/system/Commands/Utilities/Namespaces.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Utilities\\\\Publish\\:\\:\\$arguments is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$arguments\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Utilities/Publish.php', -]; $ignoreErrors[] = [ 'message' => '#^Accessing offset \'HTTP_HOST\' directly on \\$_SERVER is discouraged\\.$#', 'count' => 1, @@ -796,11 +751,6 @@ 'count' => 3, 'path' => __DIR__ . '/system/Commands/Utilities/Routes.php', ]; -$ignoreErrors[] = [ - 'message' => '#^PHPDoc type array\\ of property CodeIgniter\\\\Commands\\\\Utilities\\\\Routes\\:\\:\\$options is not the same as PHPDoc type array of overridden property CodeIgniter\\\\CLI\\\\BaseCommand\\:\\:\\$options\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Utilities/Routes.php', -]; $ignoreErrors[] = [ 'message' => '#^Implicit array creation is not allowed \\- variable \\$filters might not exist\\.$#', 'count' => 1, diff --git a/system/CLI/BaseCommand.php b/system/CLI/BaseCommand.php index c4448d56b01a..d837f50dbeef 100644 --- a/system/CLI/BaseCommand.php +++ b/system/CLI/BaseCommand.php @@ -19,14 +19,14 @@ /** * BaseCommand is the base class used in creating CLI commands. * - * @property array $arguments - * @property Commands $commands - * @property string $description - * @property string $group - * @property LoggerInterface $logger - * @property string $name - * @property array $options - * @property string $usage + * @property array $arguments + * @property Commands $commands + * @property string $description + * @property string $group + * @property LoggerInterface $logger + * @property string $name + * @property array $options + * @property string $usage */ abstract class BaseCommand { @@ -62,14 +62,14 @@ abstract class BaseCommand /** * the Command's options description * - * @var array + * @var array */ protected $options = []; /** * the Command's Arguments description * - * @var array + * @var array */ protected $arguments = []; diff --git a/system/Commands/Cache/ClearCache.php b/system/Commands/Cache/ClearCache.php index b903425ba795..79fab9dfae3c 100644 --- a/system/Commands/Cache/ClearCache.php +++ b/system/Commands/Cache/ClearCache.php @@ -52,7 +52,7 @@ class ClearCache extends BaseCommand /** * the Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'driver' => 'The cache driver to use', diff --git a/system/Commands/Database/Migrate.php b/system/Commands/Database/Migrate.php index bcf71cade337..119335170d5e 100644 --- a/system/Commands/Database/Migrate.php +++ b/system/Commands/Database/Migrate.php @@ -53,7 +53,7 @@ class Migrate extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = [ '-n' => 'Set migration namespace', diff --git a/system/Commands/Database/MigrateRefresh.php b/system/Commands/Database/MigrateRefresh.php index 689c75424f80..f683219e9d2c 100644 --- a/system/Commands/Database/MigrateRefresh.php +++ b/system/Commands/Database/MigrateRefresh.php @@ -52,7 +52,7 @@ class MigrateRefresh extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = [ '-n' => 'Set migration namespace', diff --git a/system/Commands/Database/MigrateRollback.php b/system/Commands/Database/MigrateRollback.php index c104a81fd9fa..2df223c0f8ad 100644 --- a/system/Commands/Database/MigrateRollback.php +++ b/system/Commands/Database/MigrateRollback.php @@ -54,7 +54,7 @@ class MigrateRollback extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = [ '-b' => 'Specify a batch to roll back to; e.g. "3" to return to batch #3', diff --git a/system/Commands/Encryption/GenerateKey.php b/system/Commands/Encryption/GenerateKey.php index 5837bfb02636..419ae6ef3e34 100644 --- a/system/Commands/Encryption/GenerateKey.php +++ b/system/Commands/Encryption/GenerateKey.php @@ -52,7 +52,7 @@ class GenerateKey extends BaseCommand /** * The command's options * - * @var array + * @var array */ protected $options = [ '--force' => 'Force overwrite existing key in `.env` file.', diff --git a/system/Commands/Generators/CellGenerator.php b/system/Commands/Generators/CellGenerator.php index cdb819d869f9..cf4757d10eeb 100644 --- a/system/Commands/Generators/CellGenerator.php +++ b/system/Commands/Generators/CellGenerator.php @@ -52,7 +52,7 @@ class CellGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The cell class name.', @@ -61,7 +61,7 @@ class CellGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Generators/CommandGenerator.php b/system/Commands/Generators/CommandGenerator.php index 7ccae13f7163..4b2ec360ad38 100644 --- a/system/Commands/Generators/CommandGenerator.php +++ b/system/Commands/Generators/CommandGenerator.php @@ -53,7 +53,7 @@ class CommandGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The command class name.', @@ -62,7 +62,7 @@ class CommandGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--command' => 'The command name. Default: "command:name"', diff --git a/system/Commands/Generators/ConfigGenerator.php b/system/Commands/Generators/ConfigGenerator.php index 606af47b33f0..a83a9671201d 100644 --- a/system/Commands/Generators/ConfigGenerator.php +++ b/system/Commands/Generators/ConfigGenerator.php @@ -52,7 +52,7 @@ class ConfigGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The config class name.', @@ -61,7 +61,7 @@ class ConfigGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Generators/ControllerGenerator.php b/system/Commands/Generators/ControllerGenerator.php index f27c77ee0fe5..2cf912b1c7ff 100644 --- a/system/Commands/Generators/ControllerGenerator.php +++ b/system/Commands/Generators/ControllerGenerator.php @@ -56,7 +56,7 @@ class ControllerGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The controller class name.', @@ -65,7 +65,7 @@ class ControllerGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--bare' => 'Extends from CodeIgniter\Controller instead of BaseController.', diff --git a/system/Commands/Generators/EntityGenerator.php b/system/Commands/Generators/EntityGenerator.php index 8cd84785c311..bd20daf59662 100644 --- a/system/Commands/Generators/EntityGenerator.php +++ b/system/Commands/Generators/EntityGenerator.php @@ -52,7 +52,7 @@ class EntityGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The entity class name.', @@ -61,7 +61,7 @@ class EntityGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Generators/FilterGenerator.php b/system/Commands/Generators/FilterGenerator.php index 02060b020291..620bee5a9ad4 100644 --- a/system/Commands/Generators/FilterGenerator.php +++ b/system/Commands/Generators/FilterGenerator.php @@ -52,7 +52,7 @@ class FilterGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The filter class name.', @@ -61,7 +61,7 @@ class FilterGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Generators/MigrateCreate.php b/system/Commands/Generators/MigrateCreate.php index 0b4935342831..a2fa6bf76667 100644 --- a/system/Commands/Generators/MigrateCreate.php +++ b/system/Commands/Generators/MigrateCreate.php @@ -55,7 +55,7 @@ class MigrateCreate extends BaseCommand /** * The Command's arguments. * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The migration file name.', @@ -64,7 +64,7 @@ class MigrateCreate extends BaseCommand /** * The Command's options. * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Defaults to APP_NAMESPACE', diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php index 82428a6948b3..52f9e6e53535 100644 --- a/system/Commands/Generators/MigrationGenerator.php +++ b/system/Commands/Generators/MigrationGenerator.php @@ -56,7 +56,7 @@ class MigrationGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The migration class name.', @@ -65,7 +65,7 @@ class MigrationGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--session' => 'Generates the migration file for database sessions.', diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php index eb0a1aa9802f..f4946a9441c9 100644 --- a/system/Commands/Generators/ModelGenerator.php +++ b/system/Commands/Generators/ModelGenerator.php @@ -53,7 +53,7 @@ class ModelGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The model class name.', @@ -62,7 +62,7 @@ class ModelGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--table' => 'Supply a table name. Default: "the lowercased plural of the class name".', diff --git a/system/Commands/Generators/ScaffoldGenerator.php b/system/Commands/Generators/ScaffoldGenerator.php index 351ee009459e..ef34b92ed572 100644 --- a/system/Commands/Generators/ScaffoldGenerator.php +++ b/system/Commands/Generators/ScaffoldGenerator.php @@ -53,7 +53,7 @@ class ScaffoldGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The class name', @@ -62,7 +62,7 @@ class ScaffoldGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--bare' => 'Add the "--bare" option to controller component.', diff --git a/system/Commands/Generators/SeederGenerator.php b/system/Commands/Generators/SeederGenerator.php index 09a1037f0bdc..e60525ae0d57 100644 --- a/system/Commands/Generators/SeederGenerator.php +++ b/system/Commands/Generators/SeederGenerator.php @@ -52,7 +52,7 @@ class SeederGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The seeder class name.', @@ -61,7 +61,7 @@ class SeederGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Generators/SessionMigrationGenerator.php b/system/Commands/Generators/SessionMigrationGenerator.php index a04527e866d1..cb7da5892780 100644 --- a/system/Commands/Generators/SessionMigrationGenerator.php +++ b/system/Commands/Generators/SessionMigrationGenerator.php @@ -59,7 +59,7 @@ class SessionMigrationGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '-t' => 'Supply a table name.', diff --git a/system/Commands/Generators/ValidationGenerator.php b/system/Commands/Generators/ValidationGenerator.php index 0c58ca5b0866..1b2efb8db18a 100644 --- a/system/Commands/Generators/ValidationGenerator.php +++ b/system/Commands/Generators/ValidationGenerator.php @@ -52,7 +52,7 @@ class ValidationGenerator extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'The validation class name.', @@ -61,7 +61,7 @@ class ValidationGenerator extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = [ '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', diff --git a/system/Commands/Help.php b/system/Commands/Help.php index 74dcbeab855a..338a5c868c72 100644 --- a/system/Commands/Help.php +++ b/system/Commands/Help.php @@ -53,7 +53,7 @@ class Help extends BaseCommand /** * the Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'command_name' => 'The command name [default: "help"]', @@ -62,7 +62,7 @@ class Help extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = []; diff --git a/system/Commands/Housekeeping/ClearLogs.php b/system/Commands/Housekeeping/ClearLogs.php index eb2489c5ea72..56cfeab36ae7 100644 --- a/system/Commands/Housekeeping/ClearLogs.php +++ b/system/Commands/Housekeeping/ClearLogs.php @@ -51,7 +51,7 @@ class ClearLogs extends BaseCommand /** * The Command's options * - * @var array + * @var array */ protected $options = [ '--force' => 'Force delete of all logs files without prompting.', diff --git a/system/Commands/ListCommands.php b/system/Commands/ListCommands.php index 0c808322af6a..9accecf0ad79 100644 --- a/system/Commands/ListCommands.php +++ b/system/Commands/ListCommands.php @@ -54,14 +54,14 @@ class ListCommands extends BaseCommand /** * the Command's Arguments * - * @var array + * @var array */ protected $arguments = []; /** * the Command's Options * - * @var array + * @var array */ protected $options = [ '--simple' => 'Prints a list of the commands with no other info', diff --git a/system/Commands/Server/Serve.php b/system/Commands/Server/Serve.php index 2dc9e5ddc8d8..b53820205fba 100644 --- a/system/Commands/Server/Serve.php +++ b/system/Commands/Server/Serve.php @@ -54,7 +54,7 @@ class Serve extends BaseCommand /** * Arguments * - * @var array + * @var array */ protected $arguments = []; @@ -75,7 +75,7 @@ class Serve extends BaseCommand /** * Options * - * @var array + * @var array */ protected $options = [ '--php' => 'The PHP Binary [default: "PHP_BINARY"]', diff --git a/system/Commands/Utilities/Environment.php b/system/Commands/Utilities/Environment.php index b844e7a260f2..fd8f68fabdbd 100644 --- a/system/Commands/Utilities/Environment.php +++ b/system/Commands/Utilities/Environment.php @@ -62,7 +62,7 @@ final class Environment extends BaseCommand /** * The Command's options * - * @var array + * @var array */ protected $options = []; diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index d2eb2fb728a4..38dbe8b4bc8d 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -63,7 +63,7 @@ class FilterCheck extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = []; diff --git a/system/Commands/Utilities/Namespaces.php b/system/Commands/Utilities/Namespaces.php index ef37736c56b8..71461933c5a0 100644 --- a/system/Commands/Utilities/Namespaces.php +++ b/system/Commands/Utilities/Namespaces.php @@ -57,14 +57,14 @@ class Namespaces extends BaseCommand /** * the Command's Arguments * - * @var array + * @var array */ protected $arguments = []; /** * the Command's Options * - * @var array + * @var array */ protected $options = [ '-c' => 'Show only CodeIgniter config namespaces.', diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php index cfed0472c439..1e4103c114d8 100644 --- a/system/Commands/Utilities/Publish.php +++ b/system/Commands/Utilities/Publish.php @@ -63,7 +63,7 @@ class Publish extends BaseCommand /** * the Command's Options * - * @var array + * @var array */ protected $options = []; diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index b3693ec6860e..5d20da07d514 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -61,7 +61,7 @@ class Routes extends BaseCommand /** * the Command's Arguments * - * @var array + * @var array */ protected $arguments = []; diff --git a/tests/_support/Commands/Unsuffixable.php b/tests/_support/Commands/Unsuffixable.php index cf906071d7ef..087dc558fdc0 100644 --- a/tests/_support/Commands/Unsuffixable.php +++ b/tests/_support/Commands/Unsuffixable.php @@ -49,7 +49,7 @@ class Unsuffixable extends BaseCommand /** * The Command's Arguments * - * @var array + * @var array */ protected $arguments = [ 'name' => 'Class name', @@ -58,7 +58,7 @@ class Unsuffixable extends BaseCommand /** * The Command's Options * - * @var array + * @var array */ protected $options = []; From 7c63e51aebe76034f42cf1bb1f5d10e09d299845 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 28 Oct 2023 12:59:11 +0200 Subject: [PATCH 015/380] remove the double slash from the URL --- system/Debug/Toolbar/Views/toolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 073a76ab4312..cd0b05581e2a 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -650,7 +650,7 @@ var ciDebugBar = { }, hotReloadConnect: function () { - const eventSource = new EventSource(ciSiteURL + "/__hot-reload"); + const eventSource = new EventSource(ciSiteURL + "__hot-reload"); eventSource.addEventListener("reload", function (e) { console.log("reload", e); From cdda18dd8090a03d9c5b166b46c7d4e10da8e96b Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 28 Oct 2023 12:59:28 +0200 Subject: [PATCH 016/380] close session ASAP if active --- system/HotReloader/HotReloader.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/HotReloader/HotReloader.php b/system/HotReloader/HotReloader.php index 564ba544283a..579bcd4ac598 100644 --- a/system/HotReloader/HotReloader.php +++ b/system/HotReloader/HotReloader.php @@ -18,6 +18,10 @@ final class HotReloader { public function run(): void { + if (session_status() === PHP_SESSION_ACTIVE) { + session_write_close(); + } + ini_set('zlib.output_compression', 'Off'); header('Cache-Control: no-store'); From ca13b97df73c69d95e814eabcb1235e9a1d362bb Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 27 Oct 2023 23:29:18 +0800 Subject: [PATCH 017/380] fix: add correct array signatures for Modules --- app/Config/Modules.php | 4 ++-- phpstan-baseline.php | 5 ----- system/Modules/Modules.php | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/Config/Modules.php b/app/Config/Modules.php index f84580c856d3..8d4bf56544b0 100644 --- a/app/Config/Modules.php +++ b/app/Config/Modules.php @@ -58,7 +58,7 @@ class Modules extends BaseModules * ], * ] * - * @var array + * @var array{only?: list, exclude?: list} */ public $composerPackages = []; @@ -72,7 +72,7 @@ class Modules extends BaseModules * * If it is not listed, only the base application elements will be used. * - * @var string[] + * @var list */ public $aliases = [ 'events', diff --git a/phpstan-baseline.php b/phpstan-baseline.php index cfde40738834..34add57538ac 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -1,11 +1,6 @@ '#^PHPDoc type array\\ of property Config\\\\Modules\\:\\:\\$aliases is not the same as PHPDoc type array of overridden property CodeIgniter\\\\Modules\\\\Modules\\:\\:\\$aliases\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/app/Config/Modules.php', -]; $ignoreErrors[] = [ 'message' => '#^PHPDoc type CodeIgniter\\\\HTTP\\\\CLIRequest\\|CodeIgniter\\\\HTTP\\\\IncomingRequest of property App\\\\Controllers\\\\BaseController\\:\\:\\$request is not the same as PHPDoc type CodeIgniter\\\\HTTP\\\\RequestInterface of overridden property CodeIgniter\\\\Controller\\:\\:\\$request\\.$#', 'count' => 1, diff --git a/system/Modules/Modules.php b/system/Modules/Modules.php index f99e7215e733..e17b9f3c2415 100644 --- a/system/Modules/Modules.php +++ b/system/Modules/Modules.php @@ -37,7 +37,7 @@ class Modules /** * Auto-Discover Rules Handler * - * @var array + * @var list */ public $aliases = []; From e2ed766d4c8592b997c02adef1a0e348288933f2 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 28 Oct 2023 15:42:22 +0200 Subject: [PATCH 018/380] update ciSiteURL --- system/Debug/Toolbar/Views/toolbar.js | 2 +- system/Debug/Toolbar/Views/toolbar.tpl.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index cd0b05581e2a..073a76ab4312 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -650,7 +650,7 @@ var ciDebugBar = { }, hotReloadConnect: function () { - const eventSource = new EventSource(ciSiteURL + "__hot-reload"); + const eventSource = new EventSource(ciSiteURL + "/__hot-reload"); eventSource.addEventListener("reload", function (e) { console.log("reload", e); diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index 6e62340c6ded..aadf72ee19ad 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -23,7 +23,7 @@
From f701ccebb4a7d0a5b232f498f984c0dc7b88fa98 Mon Sep 17 00:00:00 2001 From: Pieter Gerets <123326988+pieter-gerets@users.noreply.github.com> Date: Sat, 28 Oct 2023 19:42:11 +0200 Subject: [PATCH 019/380] Fix typo --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 36a7e4912283..0288090b6f6f 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -565,7 +565,7 @@ or the value that was validated you can add the ``{field}``, ``{param}`` and ``{ On a field with the human name Username and a rule of ``min_length[6]`` with a value of "Pizza", an error would display: "Supplied value (Pizza) for Username must have at least 6 characters." -.. warning:: If you get the error messages with ``getErrors()`` or ``getError()``, the messages are not HTML escaped. If you use user input data like ``({value})`` to make the error message, it might contain HTML tags. If you don't escape the messages before displying them, XSS attacks are possible. +.. warning:: If you get the error messages with ``getErrors()`` or ``getError()``, the messages are not HTML escaped. If you use user input data like ``({value})`` to make the error message, it might contain HTML tags. If you don't escape the messages before displaying them, XSS attacks are possible. .. note:: When using label-style error messages, if you pass the second parameter to ``setRules()``, it will be overwritten with the value of the first parameter. From df30b5bf2d137a286151f40f5aa261958ac73527 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 10:10:34 +0900 Subject: [PATCH 020/380] docs: change filter alias We use `auth-rates` or `force-reset` in Shield. --- user_guide_src/source/incoming/filters/004.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php index 304bd21b53eb..fbaa8358ad60 100644 --- a/user_guide_src/source/incoming/filters/004.php +++ b/user_guide_src/source/incoming/filters/004.php @@ -7,7 +7,7 @@ class Filters extends BaseConfig { public array $aliases = [ - 'apiPrep' => [ + 'api-prep' => [ \App\Filters\Negotiate::class, \App\Filters\ApiAuth::class, ], From 2b9ffe28fbbcbe894d0cfd3d3dfb89cbe2c0f8fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 10:11:25 +0900 Subject: [PATCH 021/380] docs: fix incorrect filter alias --- user_guide_src/source/incoming/filters/008.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php index 945e9498b4f9..8d417fd436aa 100644 --- a/user_guide_src/source/incoming/filters/008.php +++ b/user_guide_src/source/incoming/filters/008.php @@ -9,7 +9,7 @@ class Filters extends BaseConfig // ... public array $methods = [ - 'post' => ['InvalidChars', 'csrf'], + 'post' => ['invalidchars', 'csrf'], 'get' => ['csrf'], ]; From 6e85e2c80cd7c72854c57352367c3887944a95f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 10:11:49 +0900 Subject: [PATCH 022/380] docs: add empty lines --- user_guide_src/source/incoming/filters.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 3965dce51b0e..f6fea6551c37 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -121,7 +121,9 @@ $globals The second section allows you to define any filters that should be applied to every request made by the framework. You should take care with how many you use here, since it could have performance implications to have too many -run on every request. Filters can be specified by adding their alias to either the before or after array: +run on every request. + +Filters can be specified by adding their alias to either the ``before`` or ``after`` array: .. literalinclude:: filters/005.php @@ -130,14 +132,18 @@ Except for a Few URIs There are times where you want to apply a filter to almost every request, but have a few that should be left alone. One common example is if you need to exclude a few URI's from the CSRF protection filter to allow requests from -third-party websites to hit one or two specific URI's, while keeping the rest of them protected. To do this, add +third-party websites to hit one or two specific URI's, while keeping the rest of them protected. + +To do this, add an array with the ``except`` key and a URI path (relative to BaseURL) to match as the value alongside the alias: .. literalinclude:: filters/006.php Any place you can use a URI path (relative to BaseURL) in the filter settings, you can use a regular expression or, like in this example, use an asterisk (``*``) for a wildcard that will match all characters after that. In this example, any URI path starting with ``api/`` -would be exempted from CSRF protection, but the site's forms would all be protected. If you need to specify multiple +would be exempted from CSRF protection, but the site's forms would all be protected. + +If you need to specify multiple URI paths, you can use an array of URI path patterns: .. literalinclude:: filters/007.php From 97c3f7704cde3d9cc1fa66283683c31017f7d54e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 10:17:42 +0900 Subject: [PATCH 023/380] docs: add "valid" Because controller filters are applied before controller execution. If there is no controller found, the filters are not applied. --- user_guide_src/source/incoming/filters.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index f6fea6551c37..29462ccc6538 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -119,7 +119,8 @@ You should define as many aliases as you need. $globals ======== -The second section allows you to define any filters that should be applied to every request made by the framework. +The second section allows you to define any filters that should be applied to every valid request made by the framework. + You should take care with how many you use here, since it could have performance implications to have too many run on every request. From 1a921c9c24673caab7d100e7aa3d991f4187e0c9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 10:22:07 +0900 Subject: [PATCH 024/380] fix: typo in help message --- system/Commands/Utilities/FilterCheck.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index 38dbe8b4bc8d..1b9937d22a89 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -57,7 +57,7 @@ class FilterCheck extends BaseCommand */ protected $arguments = [ 'method' => 'The HTTP method. get, post, put, etc.', - 'route' => 'The route (URI path) to check filtes.', + 'route' => 'The route (URI path) to check filters.', ]; /** From 339d5276ab1212e85ab252276e5bcf2d22356d17 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 28 Oct 2023 21:52:04 +0800 Subject: [PATCH 025/380] Use native PHPDocs instead of `@phpstan-` --- app/Config/App.php | 3 +- app/Config/Autoload.php | 9 ++-- app/Config/Cache.php | 3 +- app/Config/Filters.php | 8 ++-- app/Config/Kint.php | 9 ++-- app/Config/Session.php | 2 +- phpstan-baseline.php | 5 +++ system/Autoloader/Autoloader.php | 11 ++--- system/BaseModel.php | 3 +- system/Cache/Handlers/BaseHandler.php | 7 ++- system/Cache/Handlers/FileHandler.php | 3 +- system/Commands/Database/ShowTableInfo.php | 2 +- .../Utilities/Routes/AutoRouteCollector.php | 3 +- .../AutoRouterImproved/AutoRouteCollector.php | 3 +- .../ControllerMethodReader.php | 12 +++-- .../Utilities/Routes/ControllerFinder.php | 5 +-- .../Routes/ControllerMethodReader.php | 7 ++- system/Common.php | 2 +- system/Config/AutoloadConfig.php | 6 +-- system/Config/Factories.php | 13 +++--- system/Database/BaseBuilder.php | 44 +++++++------------ system/Database/Config.php | 9 ++-- system/Database/Forge.php | 4 +- system/Database/SQLite3/Table.php | 3 +- system/Database/Seeder.php | 3 +- system/Debug/Exceptions.php | 3 -- system/Debug/Iterator.php | 2 +- system/Debug/Timer.php | 4 +- system/Debug/Toolbar.php | 1 - system/Debug/Toolbar/Collectors/Database.php | 1 - system/Email/Email.php | 3 +- system/Entity/Entity.php | 3 +- system/Filters/Filters.php | 9 ++-- system/Helpers/kint_helper.php | 2 +- system/Log/Logger.php | 3 +- system/Router/AutoRouterImproved.php | 6 +-- system/Router/DefinedRouteCollector.php | 2 +- system/Router/RouteCollection.php | 15 +++---- system/Test/CIUnitTestCase.php | 3 +- tests/system/AutoReview/FrameworkCodeTest.php | 2 +- tests/system/Autoloader/AutoloaderTest.php | 2 +- tests/system/Cache/ResponseCacheTest.php | 2 +- 42 files changed, 94 insertions(+), 148 deletions(-) diff --git a/app/Config/App.php b/app/Config/App.php index 186bfa86bb02..6ae678625e7b 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -27,8 +27,7 @@ class App extends BaseConfig * 'http://accounts.example.com/': * ['media.example.com', 'accounts.example.com'] * - * @var string[] - * @phpstan-var list + * @var list */ public array $allowedHostnames = []; diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php index 22f05ecdab26..7a4602d72920 100644 --- a/app/Config/Autoload.php +++ b/app/Config/Autoload.php @@ -41,8 +41,7 @@ class Autoload extends AutoloadConfig * 'App' => APPPATH * ]; * - * @var array|string> - * @phpstan-var array> + * @var array|string> */ public $psr4 = [ APP_NAMESPACE => APPPATH, // For custom app namespace @@ -81,8 +80,7 @@ class Autoload extends AutoloadConfig * '/path/to/my/file.php', * ]; * - * @var string[] - * @phpstan-var list + * @var list */ public $files = []; @@ -95,8 +93,7 @@ class Autoload extends AutoloadConfig * 'form', * ]; * - * @var string[] - * @phpstan-var list + * @var list */ public $helpers = []; } diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 61cdd50de890..b5b2cdc1738f 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -158,8 +158,7 @@ class Cache extends BaseConfig * This is an array of cache engine alias' and class names. Only engines * that are listed here are allowed to be used. * - * @var array - * @phpstan-var array> + * @var array> */ public array $validHandlers = [ 'dummy' => DummyHandler::class, diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 41e76267a448..ac37b414c45c 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -15,9 +15,8 @@ class Filters extends BaseConfig * Configures aliases for Filter classes to * make reading things nicer and simpler. * - * @var array|string> [filter_name => classname] - * or [filter_name => [classname1, classname2, ...]] - * @phpstan-var array> + * @var array> [filter_name => classname] + * or [filter_name => [classname1, classname2, ...]] */ public array $aliases = [ 'csrf' => CSRF::class, @@ -31,8 +30,7 @@ class Filters extends BaseConfig * List of filter aliases that are always * applied before and after every request. * - * @var array>>|array> - * @phpstan-var array>|array>> + * @var array>>|array> */ public array $globals = [ 'before' => [ diff --git a/app/Config/Kint.php b/app/Config/Kint.php index cc8b54592b6b..77aeb08f1432 100644 --- a/app/Config/Kint.php +++ b/app/Config/Kint.php @@ -27,8 +27,7 @@ class Kint extends BaseConfig */ /** - * @var array - * @phpstan-var list|ConstructablePluginInterface> + * @var list|ConstructablePluginInterface> */ public $plugins; @@ -46,14 +45,12 @@ class Kint extends BaseConfig public int $richSort = AbstractRenderer::SORT_FULL; /** - * @var array - * @phpstan-var array> + * @var array> */ public $richObjectPlugins; /** - * @var array - * @phpstan-var array> + * @var array> */ public $richTabPlugins; diff --git a/app/Config/Session.php b/app/Config/Session.php index ea834805e5a6..e077df64bd46 100644 --- a/app/Config/Session.php +++ b/app/Config/Session.php @@ -19,7 +19,7 @@ class Session extends BaseConfig * - `CodeIgniter\Session\Handlers\MemcachedHandler` * - `CodeIgniter\Session\Handlers\RedisHandler` * - * @phpstan-var class-string + * @var class-string */ public string $driver = FileHandler::class; diff --git a/phpstan-baseline.php b/phpstan-baseline.php index cfde40738834..6071e62e3785 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -16,6 +16,11 @@ 'count' => 1, 'path' => __DIR__ . '/system/Autoloader/Autoloader.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Property Config\\\\Autoload\\:\\:\\$helpers \\(array\\\\) in isset\\(\\) is not nullable\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/system/Autoloader/Autoloader.php', +]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 13, diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index ecfd92b5ef8b..ca886fb535bf 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -75,8 +75,7 @@ class Autoloader /** * Stores files as a list. * - * @var string[] - * @phpstan-var list + * @var list */ protected $files = []; @@ -84,8 +83,7 @@ class Autoloader * Stores helper list. * Always load the URL helper, it should be used in most apps. * - * @var string[] - * @phpstan-var list + * @var list */ protected $helpers = ['url']; @@ -119,7 +117,7 @@ public function initialize(Autoload $config, Modules $modules) $this->files = $config->files; } - if (isset($config->helpers)) { // @phpstan-ignore-line + if (isset($config->helpers)) { $this->helpers = [...$this->helpers, ...$config->helpers]; } @@ -185,8 +183,7 @@ public function unregister(): void /** * Registers namespaces with the autoloader. * - * @param array|string>|string $namespace - * @phpstan-param array|string>|string $namespace + * @param array|string>|string $namespace * * @return $this */ diff --git a/system/BaseModel.php b/system/BaseModel.php index c27afd027423..80baaf3fb024 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -63,8 +63,7 @@ abstract class BaseModel * The Database connection group that * should be instantiated. * - * @var string|null - * @phpstan-var non-empty-string|null + * @var non-empty-string|null */ protected $DBGroup; diff --git a/system/Cache/Handlers/BaseHandler.php b/system/Cache/Handlers/BaseHandler.php index c12b330bc469..061a4a661b8a 100644 --- a/system/Cache/Handlers/BaseHandler.php +++ b/system/Cache/Handlers/BaseHandler.php @@ -76,10 +76,9 @@ public static function validateKey($key, $prefix = ''): string /** * Get an item from the cache, or execute the given Closure and store the result. * - * @param string $key Cache item name - * @param int $ttl Time to live - * @param Closure $callback Callback return value - * @phpstan-param Closure(): mixed $callback + * @param string $key Cache item name + * @param int $ttl Time to live + * @param Closure(): mixed $callback Callback return value * * @return array|bool|float|int|object|string|null */ diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index e22543d27891..54cafdc5f35b 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -222,8 +222,7 @@ public function isSupported(): bool * Does the heavy lifting of actually retrieving the file and * verifying it's age. * - * @return array|false - * @phpstan-return array{data: mixed, ttl: int, time: int}|false + * @return array{data: mixed, ttl: int, time: int}|false */ protected function getItem(string $filename) { diff --git a/system/Commands/Database/ShowTableInfo.php b/system/Commands/Database/ShowTableInfo.php index 07aa60c961ca..f955c6b27011 100644 --- a/system/Commands/Database/ShowTableInfo.php +++ b/system/Commands/Database/ShowTableInfo.php @@ -84,7 +84,7 @@ class ShowTableInfo extends BaseCommand ]; /** - * @phpstan-var list> Table Data. + * @var list> Table Data. */ private array $tbody; diff --git a/system/Commands/Utilities/Routes/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouteCollector.php index ee331332291b..cc45608f21e8 100644 --- a/system/Commands/Utilities/Routes/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouteCollector.php @@ -37,8 +37,7 @@ public function __construct(string $namespace, string $defaultController, string } /** - * @return array> - * @phpstan-return list> + * @return list> */ public function get(): array { diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index 0b9089ce2ade..18a158cffa4f 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -62,8 +62,7 @@ public function __construct( } /** - * @return array> - * @phpstan-return list> + * @return list> */ public function get(): array { diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php index a8b6912d4bf7..6b865226d626 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/ControllerMethodReader.php @@ -27,8 +27,7 @@ final class ControllerMethodReader private string $namespace; /** - * @var array - * @phpstan-var list + * @var list */ private array $httpMethods; @@ -44,10 +43,9 @@ public function __construct(string $namespace, array $httpMethods) /** * Returns found route info in the controller. * - * @phpstan-param class-string $class + * @param class-string $class * - * @return array> - * @phpstan-return list> + * @return list> */ public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array { @@ -154,7 +152,7 @@ private function getParameters(ReflectionMethod $method): array } /** - * @phpstan-param class-string $classname + * @param class-string $classname * * @return string URI path part from the folder(s) and controller */ @@ -179,7 +177,7 @@ private function getUriByClass(string $classname): string /** * Gets a route for the default controller. * - * @phpstan-return list + * @return list */ private function getRouteForDefaultController( string $classShortname, diff --git a/system/Commands/Utilities/Routes/ControllerFinder.php b/system/Commands/Utilities/Routes/ControllerFinder.php index f801d531fa92..3982c454a78e 100644 --- a/system/Commands/Utilities/Routes/ControllerFinder.php +++ b/system/Commands/Utilities/Routes/ControllerFinder.php @@ -38,8 +38,7 @@ public function __construct(string $namespace) } /** - * @return string[] - * @phpstan-return class-string[] + * @return class-string[] */ public function find(): array { @@ -66,7 +65,7 @@ public function find(): array $classnameOrEmpty = $this->locator->getClassname($file); if ($classnameOrEmpty !== '') { - /** @phpstan-var class-string $classname */ + /** @var class-string $classname */ $classname = $classnameOrEmpty; $classes[] = $classname; diff --git a/system/Commands/Utilities/Routes/ControllerMethodReader.php b/system/Commands/Utilities/Routes/ControllerMethodReader.php index eb0152dec623..31bcde12dfb8 100644 --- a/system/Commands/Utilities/Routes/ControllerMethodReader.php +++ b/system/Commands/Utilities/Routes/ControllerMethodReader.php @@ -35,10 +35,9 @@ public function __construct(string $namespace) } /** - * @phpstan-param class-string $class + * @param class-string $class * - * @return array - * @phpstan-return list + * @return list */ public function read(string $class, string $defaultController = 'Home', string $defaultMethod = 'index'): array { @@ -128,7 +127,7 @@ private function hasRemap(ReflectionClass $class): bool } /** - * @phpstan-param class-string $classname + * @param class-string $classname * * @return string URI path part from the folder(s) and controller */ diff --git a/system/Common.php b/system/Common.php index 80dca72c74e3..9ad7fe5b842b 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1139,7 +1139,7 @@ function stringify_attributes($attributes, bool $js = false): string * returns its return value if any. * Otherwise will start or stop the timer intelligently. * - * @phpstan-param (callable(): mixed)|null $callable + * @param (callable(): mixed)|null $callable * * @return Timer */ diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index da08dd6f6640..33c977cc0bb6 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -45,8 +45,7 @@ class AutoloadConfig * but this should be done prior to creating any namespaced classes, * else you will need to modify all of those classes for this to work. * - * @var array|string> - * @phpstan-var array> + * @var array|string> */ public $psr4 = []; @@ -72,8 +71,7 @@ class AutoloadConfig * that will be autoloaded. This can be useful for bootstrap operations * or for loading functions. * - * @var array - * @phpstan-var list + * @var list */ public $files = []; diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 8eb68b0d3643..c86bfd95cc5d 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -62,8 +62,7 @@ class Factories * * [component => [alias => FQCN]] * - * @var array> - * @phpstan-var array> + * @var array> */ protected static $aliases = []; @@ -76,8 +75,7 @@ class Factories * * [component => [FQCN => instance]] * - * @var array> - * @phpstan-var array> + * @var array> */ protected static $instances = []; @@ -93,10 +91,9 @@ class Factories /** * Define the class to load. You can *override* the concrete class. * - * @param string $component Lowercase, plural component name - * @param string $alias Class alias. See the $aliases property. - * @param string $classname FQCN to be loaded - * @phpstan-param class-string $classname FQCN to be loaded + * @param string $component Lowercase, plural component name + * @param string $alias Class alias. See the $aliases property. + * @param class-string $classname FQCN to be loaded */ public static function define(string $component, string $alias, string $classname): void { diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 302020323577..12bd14f73ab1 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -88,8 +88,7 @@ class BaseBuilder * QB keys * list of column names. * - * @var string[] - * @phpstan-var list + * @var list */ protected $QBKeys = []; @@ -131,8 +130,7 @@ class BaseBuilder /** * QB data sets * - * @var array[]|string[] - * @phpstan-var array|list> + * @var array|list> */ protected $QBSet = []; @@ -164,7 +162,7 @@ class BaseBuilder * Holds additional options and data used to render SQL * and is reset by resetWrite() * - * @phpstan-var array{ + * @var array{ * updateFieldsAdditional?: array, * tableIdentity?: string, * updateFields?: array, @@ -173,7 +171,6 @@ class BaseBuilder * sql?: string, * alias?: string * } - * @var array */ protected $QBOptions; @@ -1967,11 +1964,9 @@ public function upsertBatch($set = null, ?bool $escape = null, int $batchSize = * * @used-by batchExecute * - * @param string $table Protected table name - * @param string[] $keys QBKeys - * @phpstan-param list $keys QBKeys - * @param array> $values QBSet - * @phpstan-param list> $values QBSet + * @param string $table Protected table name + * @param list $keys QBKeys + * @param list> $values QBSet */ protected function _upsertBatch(string $table, array $keys, array $values): string { @@ -2196,11 +2191,9 @@ public function insertBatch($set = null, ?bool $escape = null, int $batchSize = * * @used-by batchExecute * - * @param string $table Protected table name - * @param string[] $keys QBKeys - * @phpstan-param list $keys QBKeys - * @param array> $values QBSet - * @phpstan-param list> $values QBSet + * @param string $table Protected table name + * @param list $keys QBKeys + * @param list> $values QBSet */ protected function _insertBatch(string $table, array $keys, array $values): string { @@ -2566,11 +2559,9 @@ public function updateBatch($set = null, $constraints = null, int $batchSize = 1 * * @used-by batchExecute * - * @param string $table Protected table name - * @param string[] $keys QBKeys - * @phpstan-param list $keys QBKeys - * @param array[] $values QBSet - * @phpstan-param list> $values QBSet + * @param string $table Protected table name + * @param list $keys QBKeys + * @param list> $values QBSet */ protected function _updateBatch(string $table, array $keys, array $values): string { @@ -2830,11 +2821,9 @@ public function deleteBatch($set = null, $constraints = null, int $batchSize = 1 * * @used-by batchExecute * - * @param string $table Protected table name - * @param string[] $keys QBKeys - * @phpstan-param list $keys QBKeys - * @param array> $values QBSet - * @phpstan-param list> $values QBSet + * @param string $table Protected table name + * @param list $keys QBKeys + * @paramst> $values QBSet */ protected function _deleteBatch(string $table, array $keys, array $values): string { @@ -3412,8 +3401,7 @@ protected function getOperator(string $str, bool $list = false) /** * Returns the SQL string operator from where key * - * @return array|false - * @phpstan-return list|false + * @return false|list */ private function getOperatorFromWhereKey(string $whereKey) { diff --git a/system/Database/Config.php b/system/Database/Config.php index 62fa79202d26..92556c6d8fef 100644 --- a/system/Database/Config.php +++ b/system/Database/Config.php @@ -41,10 +41,9 @@ class Config extends BaseConfig /** * Returns the database connection * - * @param array|BaseConnection|string|null $group The name of the connection group to use, - * or an array of configuration settings. - * @phpstan-param array|BaseConnection|non-empty-string|null $group - * @param bool $getShared Whether to return a shared instance of the connection. + * @param array|BaseConnection|non-empty-string|null $group The name of the connection group to use, + * or an array of configuration settings. + * @param bool $getShared Whether to return a shared instance of the connection. * * @return BaseConnection */ @@ -127,7 +126,7 @@ public static function utils($group = null) /** * Returns a new instance of the Database Seeder. * - * @phpstan-param null|non-empty-string $group + * @param non-empty-string|null $group * * @return Seeder */ diff --git a/system/Database/Forge.php b/system/Database/Forge.php index ae26f6e7457d..57e43bf199fe 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -39,7 +39,7 @@ class Forge /** * List of keys. * - * @phpstan-var array{}|list + * @var list */ protected $keys = []; @@ -53,7 +53,7 @@ class Forge /** * Primary keys. * - * @phpstan-var array{}|array{fields: string[], keyName: string} + * @var array{fields?: string[], keyName?: string} */ protected $primaryKeys = []; diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 4ed9b5152eea..879437da6f6a 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -28,8 +28,7 @@ class Table /** * All of the fields this table represents. * - * @var array - * @phpstan-var array> + * @var array> */ protected $fields = []; diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index f51fa417b4ed..749f6f34d5c7 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -25,8 +25,7 @@ class Seeder /** * The name of the database group to use. * - * @var string - * @phpstan-var non-empty-string + * @var non-empty-string */ protected $DBGroup; diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index bbcfcc8e8889..a9887fba15ce 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -117,7 +117,6 @@ public function initialize() * and fire an event that allows custom actions to be taken at this point. * * @return void - * @phpstan-return never|void */ public function exceptionHandler(Throwable $exception) { @@ -215,7 +214,6 @@ public function errorHandler(int $severity, string $message, ?string $file = nul * @codeCoverageIgnore * * @return void - * @phpstan-return never|void */ public function shutdownHandler() { @@ -280,7 +278,6 @@ protected function determineView(Throwable $exception, string $templatePath): st * Given an exception and status code will display the error to the client. * * @return void - * @phpstan-return never|void * * @deprecated 4.4.0 No longer used. Moved to BaseExceptionHandler. */ diff --git a/system/Debug/Iterator.php b/system/Debug/Iterator.php index f54335b6dd70..2163bb0b2587 100644 --- a/system/Debug/Iterator.php +++ b/system/Debug/Iterator.php @@ -38,7 +38,7 @@ class Iterator * Tests are simply closures that the user can define any sequence of * things to happen during the test. * - * @phpstan-param Closure(): mixed $closure + * @param Closure(): mixed $closure * * @return $this */ diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index d43bf1c5a32a..103094b0a641 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -133,8 +133,8 @@ public function has(string $name): bool * Executes callable and measures its time. * Returns its return value if any. * - * @param string $name The name of the timer - * @phpstan-param callable(): mixed $callable callable to be executed + * @param string $name The name of the timer + * @param callable(): mixed $callable callable to be executed * * @return array|bool|float|int|object|resource|string|null */ diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 73c777ba7289..4a7a20632fd7 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -435,7 +435,6 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r * @codeCoverageIgnore * * @return void - * @phpstan-return never|void */ public function respond() { diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index 4b2ff96fe8b5..b527f2ed3c95 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -80,7 +80,6 @@ public function __construct() * @internal * * @return void - * @phpstan-return never|void */ public static function collect(Query $query) { diff --git a/system/Email/Email.php b/system/Email/Email.php index a6ad2d993204..0adb3e6eb5e6 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -352,8 +352,7 @@ class Email * Character sets valid for 7-bit encoding, * excluding language suffix. * - * @var array - * @phpstan-var list + * @var list */ protected $baseCharsets = [ 'us-ascii', diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 65898c012dc9..90d3ab46a297 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -55,8 +55,7 @@ class Entity implements JsonSerializable /** * The date fields. * - * @var array - * @phpstan-var list + * @var list */ protected $dates = [ 'created_at', diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index df27e3f6cee3..18001b103844 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -87,16 +87,14 @@ class Filters /** * Any arguments to be passed to filters. * - * @var array|null> [name => params] - * @phpstan-var array|null> + * @var array|null> [name => params] */ protected $arguments = []; /** * Any arguments to be passed to filtersClass. * - * @var array [classname => arguments] - * @phpstan-var array>|null> + * @var array>|null> [classname => arguments] */ protected $argumentsClass = []; @@ -373,8 +371,7 @@ public function enableFilter(string $name, string $when = 'before') * * @param string $name filter_name or filter_name:arguments like 'role:admin,manager' * - * @return array [name, arguments] - * @phpstan-return array{0: string, 1: list} + * @return array{0: string, 1: list} [name, arguments] */ private function getCleanName(string $name): array { diff --git a/system/Helpers/kint_helper.php b/system/Helpers/kint_helper.php index eaa2e947bc96..4221573a2ce6 100644 --- a/system/Helpers/kint_helper.php +++ b/system/Helpers/kint_helper.php @@ -18,7 +18,7 @@ * * @param array $vars * - * @phpstan-return never + * @return never * * @codeCoverageIgnore Can't be tested ... exits */ diff --git a/system/Log/Logger.php b/system/Log/Logger.php index afd703147870..0964edc4f3bf 100644 --- a/system/Log/Logger.php +++ b/system/Log/Logger.php @@ -93,8 +93,7 @@ class Logger implements LoggerInterface * value is an associative array of configuration * items. * - * @var array - * @phpstan-var array|string|int>> + * @var array|string>> */ protected $handlerConfig = []; diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 0a26fc12f865..a86e92f0161a 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -49,7 +49,7 @@ final class AutoRouterImproved implements AutoRouterInterface /** * An array of params to the controller method. * - * @phpstan-var list + * @var list */ private array $params = []; @@ -77,7 +77,7 @@ final class AutoRouterImproved implements AutoRouterInterface /** * The URI segments. * - * @phpstan-var list + * @var list */ private array $segments = []; @@ -286,7 +286,7 @@ public function getRoute(string $uri, string $httpVerb): array } // The first item may be a method name. - /** @phpstan-var list $params */ + /** @var list $params */ $params = $this->params; $methodParam = array_shift($params); diff --git a/system/Router/DefinedRouteCollector.php b/system/Router/DefinedRouteCollector.php index f8e245d19723..4fdbbb02597b 100644 --- a/system/Router/DefinedRouteCollector.php +++ b/system/Router/DefinedRouteCollector.php @@ -29,7 +29,7 @@ public function __construct(RouteCollection $routes) } /** - * @phpstan-return Generator + * @return Generator */ public function collect(): Generator { diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index b3bb96e9fa2b..9a51e6f89a98 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1267,8 +1267,7 @@ public function getFilterForRoute(string $search, ?string $verb = null): string * * @param string $search routeKey * - * @return array filter_name or filter_name:arguments like 'role:admin,manager' - * @phpstan-return list + * @return list filter_name or filter_name:arguments like 'role:admin,manager' */ public function getFiltersForRoute(string $search, ?string $verb = null): array { @@ -1305,8 +1304,7 @@ protected function fillRouteParams(string $from, ?array $params = null): string * Build our resulting string, inserting the $params in * the appropriate places. * - * @var array $patterns - * @phpstan-var list $patterns + * @var list $patterns */ $patterns = $matches[0]; @@ -1357,8 +1355,7 @@ protected function buildReverseRoute(string $from, array $params): string * Build our resulting string, inserting the $params in * the appropriate places. * - * @var array $placeholders - * @phpstan-var list $placeholders + * @var list $placeholders */ $placeholders = $matches[0]; @@ -1691,8 +1688,7 @@ public function resetRoutes() /** * Load routes options based on verb * - * @return array> [routeKey(or from) => [key => value]] - * @phpstan-return array< + * @return array< * string, * array{ * filter?: string|list, namespace?: string, hostname?: string, @@ -1740,8 +1736,7 @@ public function setPrioritize(bool $enabled = true) * * @param string|null $verb HTTP verb. `'*'` returns all controllers in any verb. * - * @return array controller name list - * @phpstan-return list + * @return list controller name list */ public function getRegisteredControllers(?string $verb = '*'): array { diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index a0c84c48f2b7..4e889b5ea1d0 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -135,8 +135,7 @@ abstract class CIUnitTestCase extends TestCase * The name of the database group to connect to. * If not present, will use the defaultGroup. * - * @var string - * @phpstan-var non-empty-string + * @var non-empty-string */ protected $DBGroup = 'tests'; diff --git a/tests/system/AutoReview/FrameworkCodeTest.php b/tests/system/AutoReview/FrameworkCodeTest.php index e61e0663836b..6583c9f2839e 100644 --- a/tests/system/AutoReview/FrameworkCodeTest.php +++ b/tests/system/AutoReview/FrameworkCodeTest.php @@ -41,7 +41,7 @@ final class FrameworkCodeTest extends TestCase /** * @dataProvider provideEachTestClassHasCorrectGroupAnnotation * - * @phpstan-param class-string $class + * @param class-string $class */ public function testEachTestClassHasCorrectGroupAnnotation(string $class): void { diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 4c81537dbf09..6624c6f3cf1b 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -35,7 +35,7 @@ final class AutoloaderTest extends CIUnitTestCase private Autoloader $loader; /** - * @phpstan-var Closure(string): (false|string) + * @var Closure(string): (false|string) */ private Closure $classLoader; diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index a1079e63a463..12eaeb1a2d23 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -68,7 +68,7 @@ private function createIncomingRequest( } /** - * @phpstan-param list $params + * @param list $params */ private function createCLIRequest(array $params = [], ?AppConfig $appConfig = null): CLIRequest { From 51391df5933d474595e12a9b96685d66aa19a039 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 30 Oct 2023 16:28:25 +0900 Subject: [PATCH 026/380] fix: cannot see "Controller" row in dark mode --- admin/css/debug-toolbar/_theme-dark.scss | 4 ---- system/Debug/Toolbar/Views/toolbar.css | 6 ------ 2 files changed, 10 deletions(-) diff --git a/admin/css/debug-toolbar/_theme-dark.scss b/admin/css/debug-toolbar/_theme-dark.scss index 5f68f8c20b5f..ead7d02a58e3 100644 --- a/admin/css/debug-toolbar/_theme-dark.scss +++ b/admin/css/debug-toolbar/_theme-dark.scss @@ -150,10 +150,6 @@ .timer { background-color: $g-orange; } - - .timeline-parent-open td { - color: $t-dark; - } } } diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 89555b4f7d40..8a302b4019e9 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -532,9 +532,6 @@ #debug-bar .timeline .timer { background-color: #DD8615; } - #debug-bar .timeline .timeline-parent-open td { - color: #252525; - } .debug-view.show-view { border-color: #DD8615; } @@ -647,9 +644,6 @@ #toolbarContainer.dark #debug-bar .timeline .timer { background-color: #DD8615; } -#toolbarContainer.dark #debug-bar .timeline .timeline-parent-open td { - color: #252525; -} #toolbarContainer.dark .debug-view.show-view { border-color: #DD8615; } From e3440d756071373cc3f20c90677e7c727fad0745 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 30 Oct 2023 16:29:56 +0900 Subject: [PATCH 027/380] docs: update css.md --- contributing/css.md | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/contributing/css.md b/contributing/css.md index 7accf5e83801..267d4f7a5609 100644 --- a/contributing/css.md +++ b/contributing/css.md @@ -9,7 +9,9 @@ the official website: Open your terminal, and navigate to CodeIgniter's root folder. To generate the CSS file, use the following command: -`sass --no-source-map admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css` +```console +sass --no-source-map admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css` +``` Details: - `--no-source-map` is an option which prevents sourcemap files from being generated @@ -18,23 +20,4 @@ Details: ## Color scheme -**Themes** - -Dark: `#252525` / `rgb(37, 37, 37)` -Light: `#FFFFFF` / `rgb(255, 255, 255)` - -**Glossy colors** - -Blue: `#5BC0DE` / `rgb(91, 192, 222)` -Gray: `#434343` / `rgb(67, 67, 67)` -Green: `#9ACE25` / `rgb(154, 206, 37)` -Orange: `#DD8615` / `rgb(221, 134, 21)` -Red: `#DD4814` / `rgb(221, 72, 20)` - -**Matt colors** - -Blue: `#D8EAF0` / `rgb(216, 234, 240)` -Gray: `#DFDFDF` / `rgb(223, 223, 223)` -Green: `#DFF0D8` / `rgb(223, 240, 216)` -Orange: `#FDC894` / `rgb(253, 200, 148)` -Red: `#EF9090` / `rgb(239, 144, 144)` +See [_graphic-charter.scss](../admin/css/debug-toolbar/_graphic-charter.scss). From 50da2138d553bf01d7cad8e1ea9fcc6f31cf34b0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 09:03:40 +0900 Subject: [PATCH 028/380] fix!: Validation rule with * gets incorrect values as dot array syntax --- system/Validation/Validation.php | 45 ++++++++++++++++------ tests/system/Validation/ValidationTest.php | 12 +++--- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index ad95cde7bc6b..f8c64e63ab3c 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -168,12 +168,21 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup } if (strpos($field, '*') !== false) { - $values = array_filter(array_flatten_with_dots($data), static fn ($key) => preg_match( - '/^' - . str_replace(['\.\*', '\*\.'], ['\..+', '.+\.'], preg_quote($field, '/')) - . '$/', - $key - ), ARRAY_FILTER_USE_KEY); + $flattenedArray = array_flatten_with_dots($data); + + $pattern = '/\A' + . str_replace( + ['\.\*', '\*\.'], + ['\.[^.]+', '[^.]+\.'], + preg_quote($field, '/') + ) + . '\z/'; + $values = array_filter( + $flattenedArray, + static fn ($key) => preg_match($pattern, $key), + ARRAY_FILTER_USE_KEY + ); + // if keys not found $values = $values ?: [$field => null]; } else { @@ -814,7 +823,13 @@ private function retrievePlaceholders(string $rule, array $data): array */ public function hasError(string $field): bool { - $pattern = '/^' . str_replace('\.\*', '\..+', preg_quote($field, '/')) . '$/'; + $pattern = '/\A' + . str_replace( + ['\.\*', '\*\.'], + ['\.[^.]+', '[^.]+\.'], + preg_quote($field, '/') + ) + . '\z/'; return (bool) preg_grep($pattern, array_keys($this->getErrors())); } @@ -829,10 +844,18 @@ public function getError(?string $field = null): string $field = array_key_first($this->rules); } - $errors = array_filter($this->getErrors(), static fn ($key) => preg_match( - '/^' . str_replace(['\.\*', '\*\.'], ['\..+', '.+\.'], preg_quote($field, '/')) . '$/', - $key - ), ARRAY_FILTER_USE_KEY); + $pattern = '/\A' + . str_replace( + ['\.\*', '\*\.'], + ['\.[^.]+', '[^.]+\.'], + preg_quote($field, '/') + ) + . '\z/'; + $errors = array_filter( + $this->getErrors(), + static fn ($key) => preg_match($pattern, $key), + ARRAY_FILTER_USE_KEY + ); return $errors === [] ? '' : implode("\n", $errors); } diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index e015c8b21de9..1c42b263b499 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -1111,9 +1111,9 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); $this->validation->setRules([ - 'id_user.*' => 'numeric', - 'name_user.*' => 'alpha', - 'contacts.*.name' => 'required', + 'id_user.*' => 'numeric', + 'name_user.*' => 'alpha', + 'contacts.friends.*.name' => 'required', ]); $this->validation->withRequest($request->withMethod('post'))->run(); @@ -1121,7 +1121,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void 'id_user.0' => 'The id_user.* field must contain only numbers.', 'name_user.0' => 'The name_user.* field may only contain alphabetical characters.', 'name_user.2' => 'The name_user.* field may only contain alphabetical characters.', - 'contacts.friends.0.name' => 'The contacts.*.name field is required.', + 'contacts.friends.0.name' => 'The contacts.friends.*.name field is required.', ], $this->validation->getErrors()); $this->assertSame( @@ -1130,8 +1130,8 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void $this->validation->getError('name_user.*') ); $this->assertSame( - 'The contacts.*.name field is required.', - $this->validation->getError('contacts.*.name') + 'The contacts.friends.*.name field is required.', + $this->validation->getError('contacts.friends.*.name') ); } From 340e28efb49f4a2e053e4dfe9a076be57a4d24c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 09:12:27 +0900 Subject: [PATCH 029/380] docs: fix incorrect dot array syntax keys --- user_guide_src/source/libraries/validation.rst | 6 +++--- user_guide_src/source/libraries/validation/009.php | 7 +------ user_guide_src/source/libraries/validation/010.php | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 0288090b6f6f..7300fa88ff56 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -591,7 +591,7 @@ If you need to retrieve all error messages for failed fields, you can use the `` If no errors exist, an empty array will be returned. -When using a wildcard, the error will point to a specific field, replacing the asterisk with the appropriate key/keys:: +When using a wildcard (``*``), the error will point to a specific field, replacing the asterisk with the appropriate key/keys:: // for data 'contacts' => [ @@ -606,10 +606,10 @@ When using a wildcard, the error will point to a specific field, replacing the a ] // rule - 'contacts.*.name' => 'required' + 'contacts.friends.*.name' => 'required' // error will be - 'contacts.friends.1.name' => 'The contacts.*.name field is required.' + 'contacts.friends.1.name' => 'The contacts.friends.*.name field is required.' Getting a Single Error ====================== diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php index 7e321e9664ff..85be52b7abb2 100644 --- a/user_guide_src/source/libraries/validation/009.php +++ b/user_guide_src/source/libraries/validation/009.php @@ -4,7 +4,7 @@ * The data to test: * [ * 'contacts' => [ - * 'name' => 'Joe Smith', + * 'name' => 'Joe Smith', * 'friends' => [ * [ * 'name' => 'Fred Flinstone', @@ -21,8 +21,3 @@ $validation->setRules([ 'contacts.name' => 'required|max_length[60]', ]); - -// Fred Flintsone & Wilma -$validation->setRules([ - 'contacts.friends.name' => 'required|max_length[60]', -]); diff --git a/user_guide_src/source/libraries/validation/010.php b/user_guide_src/source/libraries/validation/010.php index 0951f582c882..2646fcc32b99 100644 --- a/user_guide_src/source/libraries/validation/010.php +++ b/user_guide_src/source/libraries/validation/010.php @@ -2,5 +2,5 @@ // Fred Flintsone & Wilma $validation->setRules([ - 'contacts.*.name' => 'required|max_length[60]', + 'contacts.friends.*.name' => 'required|max_length[60]', ]); From 1b48e13064f95b817aac9e6088227797fdb774e0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 09:12:55 +0900 Subject: [PATCH 030/380] docs: fix text decoration --- user_guide_src/source/libraries/validation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 7300fa88ff56..e1b0161ff714 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -830,7 +830,8 @@ alpha_numeric_punct No Fails if field contains anything other than alphanumeric, space, or this limited set of punctuation characters: ``~`` (tilde), ``!`` (exclamation), ``#`` (number), - ``$`` (dollar), ``% (percent), & (ampersand), + ``$`` (dollar), ``%`` (percent), + ``&`` (ampersand), ``*`` (asterisk), ``-`` (dash), ``_`` (underscore), ``+`` (plus), ``=`` (equals), ``|`` (vertical bar), From 77a17aac29c76c66019b61e31a5906072909d089 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 09:27:04 +0900 Subject: [PATCH 031/380] test: rename test method We use the word asterisk here. --- tests/system/Validation/ValidationTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 1c42b263b499..7f11b86d916a 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -1228,17 +1228,17 @@ public function testTranslatedLabelTagReplacement(): void } /** - * @dataProvider provideDotNotationOnIfExistRule + * @dataProvider provideIfExistRuleWithAsterisk * * @see https://github.com/codeigniter4/CodeIgniter4/issues/4521 */ - public function testDotNotationOnIfExistRule(bool $expected, array $rules, array $data): void + public function testIfExistRuleWithAsterisk(bool $expected, array $rules, array $data): void { $actual = $this->validation->setRules($rules)->run($data); $this->assertSame($expected, $actual); } - public static function provideDotNotationOnIfExistRule(): iterable + public static function provideIfExistRuleWithAsterisk(): iterable { yield 'dot-on-end-fail' => [ false, @@ -1613,7 +1613,7 @@ public function testRuleWithLeadingAsterisk(): void /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/5942 */ - public function testRequireWithoutWithWildCard(): void + public function testRequireWithoutWithAsterisk(): void { $data = [ 'a' => [ From 09e194dc591633dbac0aad96a3987ff671e4c3f4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 09:43:51 +0900 Subject: [PATCH 032/380] test: add test for multidimensinal array and `*` --- tests/system/Validation/ValidationTest.php | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 7f11b86d916a..7cc6f99c40d5 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -1631,4 +1631,50 @@ public function testRequireWithoutWithAsterisk(): void $this->validation->getError('a.1.c') ); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/8128 + */ + public function testRuleWithAsteriskToMultiDimensionalArray(): void + { + $data = [ + 'contacts' => [ + 'name' => 'Joe Smith', + 'just' => [ + 'friends' => [ + [ + 'name' => 'Fred Flinstone', + ], + [ + 'name' => 'Wilma', + ], + ], + ], + ], + ]; + + $this->validation->setRules( + ['contacts.just.friends.*.name' => 'required|max_length[1]'] + ); + $this->assertFalse($this->validation->run($data)); + $this->assertSame( + [ + 'contacts.just.friends.0.name' => 'The contacts.just.friends.*.name field cannot exceed 1 characters in length.', + 'contacts.just.friends.1.name' => 'The contacts.just.friends.*.name field cannot exceed 1 characters in length.', + ], + $this->validation->getErrors() + ); + + $this->validation->reset(); + $this->validation->setRules( + ['contacts.*.name' => 'required|max_length[1]'] + ); + $this->assertFalse($this->validation->run($data)); + $this->assertSame( + // The data for `contacts.*.name` does not exist. So it is interpreted + // as `null`, and this error message returns. + ['contacts.*.name' => 'The contacts.*.name field is required.'], + $this->validation->getErrors() + ); + } } From 410b7a9041bd33001122079f312e592a6b74683f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 10:54:51 +0900 Subject: [PATCH 033/380] docs: add changelog and upgrade --- user_guide_src/source/changelogs/v4.4.4.rst | 7 ++++ .../source/installation/upgrade_444.rst | 19 ++++++++++ .../source/installation/upgrade_444/001.php | 38 +++++++++++++++++++ .../source/libraries/validation.rst | 6 +++ 4 files changed, 70 insertions(+) create mode 100644 user_guide_src/source/installation/upgrade_444/001.php diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index 218c56e738d7..cfb0aeb4f121 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -14,6 +14,13 @@ Release Date: Unreleased BREAKING ******** +Validation with Dot Array Syntax +================================ + +A validation rule with the wildcard ``*`` now validates only data in correct +dimensions as "dot array syntax". +See :ref:`Upgrading ` for details. + *************** Message Changes *************** diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst index 6dbfa8e7baac..c0b4def6e34d 100644 --- a/user_guide_src/source/installation/upgrade_444.rst +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -20,6 +20,25 @@ Mandatory File Changes Breaking Changes **************** +.. _upgrade-444-validation-with-dot-array-syntax: + +Validation with Dot Array Syntax +================================ + +If you are using :ref:`dot array syntax ` in validation +rules, a bug where ``*`` would validate data in incorrect dimensions has been fixed. + +In previous versions, the rule key ``contacts.*.name`` captured data with any +level like ``contacts.*.name``, ``contacts.*.*.name``, ``contacts.*.*.*.name``, +etc., incorrectly. + +The following code explains details: + +.. literalinclude:: upgrade_444/001.php + :lines: 2- + +If you have code that depends on the bug, fix the the rule key. + ********************* Breaking Enhancements ********************* diff --git a/user_guide_src/source/installation/upgrade_444/001.php b/user_guide_src/source/installation/upgrade_444/001.php new file mode 100644 index 000000000000..9bcc6412141f --- /dev/null +++ b/user_guide_src/source/installation/upgrade_444/001.php @@ -0,0 +1,38 @@ + [ + 'name' => 'Joe Smith', + 'just' => [ + 'friends' => [ + ['name' => 'SATO Taro'], + ['name' => 'Li Ming'], + ['name' => 'Heinz Müller'], + ], + ], + ], +]; + +$validation->setRules( + ['contacts.*.name' => 'required|max_length[8]'] +); + +$validation->run($data); // false + +d($validation->getErrors()); +/* + Before: Captured `contacts.*.*.*.name` incorrectly. + [ + contacts.just.friends.0.name => "The contacts.*.name field cannot exceed 8 characters in length.", + contacts.just.friends.2.name => "The contacts.*.name field cannot exceed 8 characters in length.", + ] + + After: Captures no data for `contacts.*.name`. + [ + contacts.*.name => string (38) "The contacts.*.name field is required.", + ] +*/ diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index e1b0161ff714..8ebec266c0bf 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -314,6 +314,8 @@ To give a labeled error message you can set up as: .. note:: ``setRules()`` will overwrite any rules that were set previously. To add more than one rule to an existing set of rules, use ``setRule()`` multiple times. +.. _validation-dot-array-syntax: + Setting Rules for Array Data ============================ @@ -328,6 +330,10 @@ You can use the ``*`` wildcard symbol to match any one level of the array: .. literalinclude:: validation/010.php :lines: 2- +.. note:: Prior to v4.4.4, due to a bug, the wildcard ``*`` validated data in incorrect + dimensions. See :ref:`Upgrading ` + for details. + "dot array syntax" can also be useful when you have single dimension array data. For example, data returned by multi select dropdown: From 4913acc1d6bab342e45a95fe14afd1866e3b23c9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 31 Oct 2023 11:22:33 +0900 Subject: [PATCH 034/380] refactor: extract getRegex() --- system/Validation/Validation.php | 42 +++++++++++++------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index f8c64e63ab3c..b1612481b97b 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -170,16 +170,9 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup if (strpos($field, '*') !== false) { $flattenedArray = array_flatten_with_dots($data); - $pattern = '/\A' - . str_replace( - ['\.\*', '\*\.'], - ['\.[^.]+', '[^.]+\.'], - preg_quote($field, '/') - ) - . '\z/'; $values = array_filter( $flattenedArray, - static fn ($key) => preg_match($pattern, $key), + static fn ($key) => preg_match(self::getRegex($field), $key), ARRAY_FILTER_USE_KEY ); @@ -220,6 +213,20 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup return false; } + /** + * Returns regex pattern for key with dot array syntax. + */ + private static function getRegex(string $field): string + { + return '/\A' + . str_replace( + ['\.\*', '\*\.'], + ['\.[^.]+', '[^.]+\.'], + preg_quote($field, '/') + ) + . '\z/'; + } + /** * Runs the validation process, returning true or false determining whether * validation was successful or not. @@ -823,15 +830,7 @@ private function retrievePlaceholders(string $rule, array $data): array */ public function hasError(string $field): bool { - $pattern = '/\A' - . str_replace( - ['\.\*', '\*\.'], - ['\.[^.]+', '[^.]+\.'], - preg_quote($field, '/') - ) - . '\z/'; - - return (bool) preg_grep($pattern, array_keys($this->getErrors())); + return (bool) preg_grep(self::getRegex($field), array_keys($this->getErrors())); } /** @@ -844,16 +843,9 @@ public function getError(?string $field = null): string $field = array_key_first($this->rules); } - $pattern = '/\A' - . str_replace( - ['\.\*', '\*\.'], - ['\.[^.]+', '[^.]+\.'], - preg_quote($field, '/') - ) - . '\z/'; $errors = array_filter( $this->getErrors(), - static fn ($key) => preg_match($pattern, $key), + static fn ($key) => preg_match(self::getRegex($field), $key), ARRAY_FILTER_USE_KEY ); From f057c17aa2e6c220b944b2770e35b068ef75374c Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 09:00:07 +0900 Subject: [PATCH 035/380] docs: add section "Simple and Controlled Cells" --- user_guide_src/source/outgoing/view_cells.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst index 09b62bcad16a..ffca2d4bab69 100644 --- a/user_guide_src/source/outgoing/view_cells.rst +++ b/user_guide_src/source/outgoing/view_cells.rst @@ -4,12 +4,20 @@ View Cells Many applications have small view fragments that can be repeated from page to page, or in different places on the pages. These are often help boxes, navigation controls, ads, login forms, etc. CodeIgniter lets you encapsulate the logic for these presentation blocks within View Cells. They are basically mini-views that can be included in other views. They can have logic built in to handle any cell-specific display logic. They can be used to make your views more readable and maintainable by separating the logic for each cell into its own class. -CodeIgniter supports two types of View Cells: simple and controlled. Simple View Cells can be generated from any class and method of your choice and does not have to follow any rules, except that it must return a string. Controlled View Cells must be generated from a class that extends ``Codeigniter\View\Cells\Cell`` class which provides additional capability making your View Cells more flexible and faster to use. - .. contents:: :local: :depth: 2 +*************************** +Simple and Controlled Cells +*************************** + +CodeIgniter supports two types of View Cells: simple and controlled. + +**Simple View Cells** can be generated from any class and method of your choice and does not have to follow any rules, except that it must return a string. + +**Controlled View Cells** must be generated from a class that extends ``Codeigniter\View\Cells\Cell`` class which provides additional capability making your View Cells more flexible and faster to use. + .. _app-cells: ******************* From 44806d844c1ddddb9cdd44921db0fe3a94f99465 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 09:01:25 +0900 Subject: [PATCH 036/380] docs: improve explanation for "Calling a View Cell" --- user_guide_src/source/outgoing/view_cells.rst | 6 ++++-- user_guide_src/source/outgoing/view_cells/001.php | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst index ffca2d4bab69..acd2d3b0f86c 100644 --- a/user_guide_src/source/outgoing/view_cells.rst +++ b/user_guide_src/source/outgoing/view_cells.rst @@ -26,11 +26,13 @@ Calling a View Cell No matter which type of View Cell you are using, you can call it from any view by using the ``view_cell()`` helper function. -The first parameter is the name of the class and method to call, and the second parameter is an array of parameters to pass to the method: +The first parameter is (1) *the name of the class and method* (Simple Cell) or (2) *the name of the class* (Controlled Cell) to call, +and the second parameter is an array of parameters to pass to the method: .. literalinclude:: view_cells/001.php -The Cell method must return a string, which will be inserted into the view where the ``view_cell()`` function was called. +The string that the Cell returns will be inserted into the view where the +``view_cell()`` function was called. Namespace Omission ================== diff --git a/user_guide_src/source/outgoing/view_cells/001.php b/user_guide_src/source/outgoing/view_cells/001.php index 2a9e4361796e..57a4fdc425dc 100644 --- a/user_guide_src/source/outgoing/view_cells/001.php +++ b/user_guide_src/source/outgoing/view_cells/001.php @@ -1,2 +1,7 @@ // In a View. + +// Simple Cell 'value1', 'param2' => 'value2']) ?> + +// Controlled Cell + 'value1', 'param2' => 'value2']) ?> From c99c118cfe666e9b1e3a9ab7942d9a0501d8319c Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 09:02:40 +0900 Subject: [PATCH 037/380] docs: add empty lines for readability --- user_guide_src/source/outgoing/view_cells.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst index acd2d3b0f86c..da60d6644d8a 100644 --- a/user_guide_src/source/outgoing/view_cells.rst +++ b/user_guide_src/source/outgoing/view_cells.rst @@ -77,8 +77,10 @@ Controlled Cells .. versionadded:: 4.3.0 -Controlled cells have two primary goals: to make it as fast as possible to build the cell, and provide additional logic and -flexibility to your views, if they need it. The class must extend ``CodeIgniter\View\Cells\Cell``. They should have a view file +Controlled cells have two primary goals: (1) to make it as fast as possible to build the cell, and (2) provide additional logic and +flexibility to your views, if they need it. + +The class must extend ``CodeIgniter\View\Cells\Cell``. They should have a view file in the same folder. By convention, the class name should be in PascalCase suffixed with ``Cell`` and the view should be the snake_cased version of the class name, without the suffix. For example, if you have a ``MyCell`` class, the view file should be ``my.php``. @@ -89,7 +91,9 @@ should be ``my.php``. Creating a Controlled Cell ========================== -At the most basic level, all you need to implement within the class are public properties. These properties will be made available to the view file automatically. Implementing the AlertMessage from above as a Controlled Cell would look like this: +At the most basic level, all you need to implement within the class are public properties. These properties will be made available to the view file automatically. + +Implementing the AlertMessage from above as a Controlled Cell would look like this: .. literalinclude:: view_cells/008.php @@ -118,7 +122,9 @@ You can specify a custom view name by setting the ``view`` property in the class Customize the Rendering ======================= -If you need more control over the rendering of the HTML, you can implement a ``render()`` method. This method allows you to perform additional logic and pass extra data the view, if needed. The ``render()`` method must return a string. To take advantage of the full features of controlled Cells, you should use ``$this->view()`` instead of the normal ``view()`` helper function: +If you need more control over the rendering of the HTML, you can implement a ``render()`` method. This method allows you to perform additional logic and pass extra data the view, if needed. The ``render()`` method must return a string. + +To take advantage of the full features of controlled Cells, you should use ``$this->view()`` instead of the normal ``view()`` helper function: .. literalinclude:: view_cells/012.php From 7a04c51aa25f492369880ab5adca7147cf09a48b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 09:03:08 +0900 Subject: [PATCH 038/380] docs: add return types in sample code --- user_guide_src/source/outgoing/view_cells/014.php | 2 +- user_guide_src/source/outgoing/view_cells/016.php | 2 +- user_guide_src/source/outgoing/view_cells/018.php | 2 +- user_guide_src/source/outgoing/view_cells/019.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/outgoing/view_cells/014.php b/user_guide_src/source/outgoing/view_cells/014.php index 29378e1199ab..7aa1ad4c9d8c 100644 --- a/user_guide_src/source/outgoing/view_cells/014.php +++ b/user_guide_src/source/outgoing/view_cells/014.php @@ -12,7 +12,7 @@ class AlertMessageCell extends Cell protected $message; private $computed; - public function mount() + public function mount(): void { $this->computed = sprintf('%s - %s', $this->type, $this->message); } diff --git a/user_guide_src/source/outgoing/view_cells/016.php b/user_guide_src/source/outgoing/view_cells/016.php index 4b2c10ef0cc6..54d9d7d994a4 100644 --- a/user_guide_src/source/outgoing/view_cells/016.php +++ b/user_guide_src/source/outgoing/view_cells/016.php @@ -10,7 +10,7 @@ class RecentPostsCell extends Cell { protected $posts; - public function linkPost($post) + public function linkPost($post): string { return anchor('posts/' . $post->id, $post->title); } diff --git a/user_guide_src/source/outgoing/view_cells/018.php b/user_guide_src/source/outgoing/view_cells/018.php index 3f64e68464e9..8767af1b40a2 100644 --- a/user_guide_src/source/outgoing/view_cells/018.php +++ b/user_guide_src/source/outgoing/view_cells/018.php @@ -8,7 +8,7 @@ class RecentPostsCell extends Cell { protected $posts; - public function mount() + public function mount(): void { $this->posts = model('PostModel')->orderBy('created_at', 'DESC')->findAll(10); } diff --git a/user_guide_src/source/outgoing/view_cells/019.php b/user_guide_src/source/outgoing/view_cells/019.php index df78ab0acec5..db1b12b56b54 100644 --- a/user_guide_src/source/outgoing/view_cells/019.php +++ b/user_guide_src/source/outgoing/view_cells/019.php @@ -10,7 +10,7 @@ class RecentPostsCell extends Cell { protected $posts; - public function mount(?int $categoryId) + public function mount(?int $categoryId): void { $this->posts = model('PostModel') ->when( From 7de126005ec4e678764ea4f368605fdae9bd7617 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 09:18:48 +0900 Subject: [PATCH 039/380] fix: make:cell help message --- system/Commands/Generators/CellGenerator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Commands/Generators/CellGenerator.php b/system/Commands/Generators/CellGenerator.php index cf4757d10eeb..358bacc0c434 100644 --- a/system/Commands/Generators/CellGenerator.php +++ b/system/Commands/Generators/CellGenerator.php @@ -40,7 +40,7 @@ class CellGenerator extends BaseCommand * * @var string */ - protected $description = 'Generates a new Cell file and its view.'; + protected $description = 'Generates a new Controlled Cell file and its view.'; /** * The Command's Usage @@ -55,7 +55,7 @@ class CellGenerator extends BaseCommand * @var array */ protected $arguments = [ - 'name' => 'The cell class name.', + 'name' => 'The Controlled Cell class name.', ]; /** From b0534cc2e587c5fefae57dd19a4a31e190fdccf0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Nov 2023 17:25:59 +0900 Subject: [PATCH 040/380] docs: fix incorrect description Co-authored-by: Michal Sniatala --- user_guide_src/source/outgoing/view_cells.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst index da60d6644d8a..f940bc99ea17 100644 --- a/user_guide_src/source/outgoing/view_cells.rst +++ b/user_guide_src/source/outgoing/view_cells.rst @@ -26,8 +26,8 @@ Calling a View Cell No matter which type of View Cell you are using, you can call it from any view by using the ``view_cell()`` helper function. -The first parameter is (1) *the name of the class and method* (Simple Cell) or (2) *the name of the class* (Controlled Cell) to call, -and the second parameter is an array of parameters to pass to the method: +The first parameter is (1) *the name of the class and method* (Simple Cell) or (2) *the name of the class and optional method* (Controlled Cell) to call, +and the second parameter is an array or string of parameters to pass to the method: .. literalinclude:: view_cells/001.php From 66dbcf1f861b6a793fcf0c15a0457631daac8be4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Nov 2023 10:10:52 +0900 Subject: [PATCH 041/380] docs: fix incorrect sample code It is not valid that "application/json" and "GET". --- user_guide_src/source/general/ajax.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/ajax.rst b/user_guide_src/source/general/ajax.rst index ac113456053b..967e2c280c59 100644 --- a/user_guide_src/source/general/ajax.rst +++ b/user_guide_src/source/general/ajax.rst @@ -18,7 +18,7 @@ Fetch API .. code-block:: javascript fetch(url, { - method: "get", + method: "POST", headers: { "Content-Type": "application/json", "X-Requested-With": "XMLHttpRequest" From 45e202701223306c4dc967b0f4b261afab281cec Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 16:57:55 +0900 Subject: [PATCH 042/380] test: add tests for current behavior to matches and differs --- tests/system/Validation/RulesTest.php | 35 ++++++++++--- .../Validation/StrictRules/RulesTest.php | 51 +++++++++++++++++++ 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 23358d08904b..346b323563e5 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -290,7 +290,7 @@ public static function providePermitEmpty(): iterable } /** - * @dataProvider provideMatchesCases + * @dataProvider provideMatches */ public function testMatches(array $data, bool $expected): void { @@ -298,12 +298,18 @@ public function testMatches(array $data, bool $expected): void $this->assertSame($expected, $this->validation->run($data)); } - public static function provideMatchesCases(): iterable + public static function provideMatches(): iterable { yield from [ - [['foo' => null, 'bar' => null], true], - [['foo' => 'match', 'bar' => 'match'], true], - [['foo' => 'match', 'bar' => 'nope'], false], + 'foo bar not exist' => [[], false], + 'bar not exist' => [['foo' => null], false], + 'foo not exist' => [['bar' => null], true], // should be false? + 'foo bar null' => [['foo' => null, 'bar' => null], true], + 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true], + 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false], + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], // should be true + 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], + 'foo bar bool match' => [['foo' => true, 'bar' => true], false], // should be true ]; } @@ -325,12 +331,27 @@ public static function provideMatchesNestedCases(): iterable } /** - * @dataProvider provideMatchesCases + * @dataProvider provideDiffers */ public function testDiffers(array $data, bool $expected): void { $this->validation->setRules(['foo' => 'differs[bar]']); - $this->assertSame(! $expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); + } + + public static function provideDiffers(): iterable + { + yield from [ + 'foo bar not exist' => [[], false], + 'bar not exist' => [['foo' => null], false], + 'foo not exist' => [['bar' => null], false], + 'foo bar null' => [['foo' => null, 'bar' => null], false], + 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false], + 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true], + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], // should be false + 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true], + 'foo bar bool match' => [['foo' => true, 'bar' => true], true], // should be false + ]; } /** diff --git a/tests/system/Validation/StrictRules/RulesTest.php b/tests/system/Validation/StrictRules/RulesTest.php index 495fa02e20e9..62b7241331a4 100644 --- a/tests/system/Validation/StrictRules/RulesTest.php +++ b/tests/system/Validation/StrictRules/RulesTest.php @@ -198,4 +198,55 @@ public static function provideLessEqualThanStrict(): iterable [true, '0', false], ]; } + + /** + * @dataProvider provideMatches + */ + public function testMatches(array $data, bool $expected): void + { + $this->validation->setRules(['foo' => 'matches[bar]']); + $this->assertSame($expected, $this->validation->run($data)); + } + + public static function provideMatches(): iterable + { + yield from [ + 'foo bar not exist' => [[], false], + 'bar not exist' => [['foo' => null], false], + 'foo not exist' => [['bar' => null], true], + 'foo bar null' => [['foo' => null, 'bar' => null], true], + 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true], + 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false], + // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given + // 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], + // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given + // 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], + // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given + // 'foo bar bool match' => [['foo' => true, 'bar' => true], true], + ]; + } + + /** + * @dataProvider provideDiffers + */ + public function testDiffers(array $data, bool $expected): void + { + $this->validation->setRules(['foo' => 'differs[bar]']); + $this->assertSame($expected, $this->validation->run($data)); + } + + public static function provideDiffers(): iterable + { + yield from [ + 'foo bar not exist' => [[], false], + 'bar not exist' => [['foo' => null], false], + 'foo not exist' => [['bar' => null], false], + 'foo bar null' => [['foo' => null, 'bar' => null], false], + 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false], + 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true], + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], + 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], + 'foo bar bool match' => [['foo' => true, 'bar' => true], false], + ]; + } } From c06e0b3a3c7889374120ab80f698243f853c8424 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 29 Oct 2023 21:00:36 +0900 Subject: [PATCH 043/380] fix: strict validation rule matches and differs --- system/Validation/StrictRules/Rules.php | 44 ++++++++++++++++--- tests/system/Validation/RulesTest.php | 10 ++--- .../Validation/StrictRules/RulesTest.php | 13 +++--- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/system/Validation/StrictRules/Rules.php b/system/Validation/StrictRules/Rules.php index 0887eff28ada..70d081975a62 100644 --- a/system/Validation/StrictRules/Rules.php +++ b/system/Validation/StrictRules/Rules.php @@ -36,13 +36,26 @@ public function __construct() * @param array|bool|float|int|object|string|null $str * @param array $data Other field/value pairs */ - public function differs($str, string $field, array $data): bool - { - if (! is_string($str)) { + public function differs( + $str, + string $otherField, + array $data, + ?string $error = null, + ?string $field = null + ): bool { + if (strpos($otherField, '.') !== false) { + return $str !== dot_array_search($otherField, $data); + } + + if (! array_key_exists($field, $data)) { return false; } - return $this->nonStrictRules->differs($str, $field, $data); + if (! array_key_exists($otherField, $data)) { + return false; + } + + return $str !== ($data[$otherField] ?? null); } /** @@ -254,9 +267,26 @@ public function less_than_equal_to($str, string $max): bool * @param array|bool|float|int|object|string|null $str * @param array $data Other field/value pairs */ - public function matches($str, string $field, array $data): bool - { - return $this->nonStrictRules->matches($str, $field, $data); + public function matches( + $str, + string $otherField, + array $data, + ?string $error = null, + ?string $field = null + ): bool { + if (strpos($otherField, '.') !== false) { + return $str === dot_array_search($otherField, $data); + } + + if (! array_key_exists($field, $data)) { + return false; + } + + if (! array_key_exists($otherField, $data)) { + return false; + } + + return $str === ($data[$otherField] ?? null); } /** diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 346b323563e5..601be2d0e7ca 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -303,13 +303,13 @@ public static function provideMatches(): iterable yield from [ 'foo bar not exist' => [[], false], 'bar not exist' => [['foo' => null], false], - 'foo not exist' => [['bar' => null], true], // should be false? + 'foo not exist' => [['bar' => null], true], // Strict Rule: false 'foo bar null' => [['foo' => null, 'bar' => null], true], 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false], - 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], // should be true + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], // Strict Rule: true 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], - 'foo bar bool match' => [['foo' => true, 'bar' => true], false], // should be true + 'foo bar bool match' => [['foo' => true, 'bar' => true], false], // Strict Rule: true ]; } @@ -348,9 +348,9 @@ public static function provideDiffers(): iterable 'foo bar null' => [['foo' => null, 'bar' => null], false], 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true], - 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], // should be false + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], // Strict Rule: false 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true], - 'foo bar bool match' => [['foo' => true, 'bar' => true], true], // should be false + 'foo bar bool match' => [['foo' => true, 'bar' => true], true], // Strict Rule: false ]; } diff --git a/tests/system/Validation/StrictRules/RulesTest.php b/tests/system/Validation/StrictRules/RulesTest.php index 62b7241331a4..74ed4d6cecd6 100644 --- a/tests/system/Validation/StrictRules/RulesTest.php +++ b/tests/system/Validation/StrictRules/RulesTest.php @@ -213,16 +213,13 @@ public static function provideMatches(): iterable yield from [ 'foo bar not exist' => [[], false], 'bar not exist' => [['foo' => null], false], - 'foo not exist' => [['bar' => null], true], + 'foo not exist' => [['bar' => null], false], 'foo bar null' => [['foo' => null, 'bar' => null], true], 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false], - // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given - // 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], - // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given - // 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], - // TypeError: CodeIgniter\Validation\Rules::matches(): Argument #1 ($str) must be of type ?string, float given - // 'foo bar bool match' => [['foo' => true, 'bar' => true], true], + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], + 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], + 'foo bar bool match' => [['foo' => true, 'bar' => true], true], ]; } @@ -245,7 +242,7 @@ public static function provideDiffers(): iterable 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true], 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], - 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], + 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true], 'foo bar bool match' => [['foo' => true, 'bar' => true], false], ]; } From c83e2ea981d5a8814749e64f7c2ebe03894c565c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 30 Oct 2023 06:39:42 +0900 Subject: [PATCH 044/380] fix: traditional validation rule matches and differs Match CI3 behaviros. --- system/Validation/Rules.php | 12 +++++++----- tests/system/Validation/RulesTest.php | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index b7c585f56c30..6a809dc534cc 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -24,9 +24,10 @@ class Rules /** * The value does not match another field in $data. * - * @param array $data Other field/value pairs + * @param string|null $str + * @param array $data Other field/value pairs */ - public function differs(?string $str, string $field, array $data): bool + public function differs($str, string $field, array $data): bool { if (strpos($field, '.') !== false) { return $str !== dot_array_search($field, $data); @@ -177,15 +178,16 @@ public function less_than_equal_to(?string $str, string $max): bool /** * Matches the value of another field in $data. * - * @param array $data Other field/value pairs + * @param string|null $str + * @param array $data Other field/value pairs */ - public function matches(?string $str, string $field, array $data): bool + public function matches($str, string $field, array $data): bool { if (strpos($field, '.') !== false) { return $str === dot_array_search($field, $data); } - return array_key_exists($field, $data) && $str === $data[$field]; + return isset($data[$field]) ? ($str === $data[$field]) : false; } /** diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 601be2d0e7ca..ac2f34bf825a 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -303,13 +303,13 @@ public static function provideMatches(): iterable yield from [ 'foo bar not exist' => [[], false], 'bar not exist' => [['foo' => null], false], - 'foo not exist' => [['bar' => null], true], // Strict Rule: false - 'foo bar null' => [['foo' => null, 'bar' => null], true], + 'foo not exist' => [['bar' => null], false], + 'foo bar null' => [['foo' => null, 'bar' => null], false], // Strict Rule: true 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], true], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], false], - 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], // Strict Rule: true + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], false], - 'foo bar bool match' => [['foo' => true, 'bar' => true], false], // Strict Rule: true + 'foo bar bool match' => [['foo' => true, 'bar' => true], true], ]; } @@ -348,9 +348,9 @@ public static function provideDiffers(): iterable 'foo bar null' => [['foo' => null, 'bar' => null], false], 'foo bar string match' => [['foo' => 'match', 'bar' => 'match'], false], 'foo bar string not match' => [['foo' => 'match', 'bar' => 'nope'], true], - 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], true], // Strict Rule: false + 'foo bar float match' => [['foo' => 1.2, 'bar' => 1.2], false], 'foo bar float not match' => [['foo' => 1.2, 'bar' => 2.3], true], - 'foo bar bool match' => [['foo' => true, 'bar' => true], true], // Strict Rule: false + 'foo bar bool match' => [['foo' => true, 'bar' => true], false], ]; } From fdd9ec88d8e267db6d3245e3c5255642268b0252 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 30 Oct 2023 06:53:20 +0900 Subject: [PATCH 045/380] refactor: by rector --- system/Validation/Rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 6a809dc534cc..eae6d961ce7d 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -187,7 +187,7 @@ public function matches($str, string $field, array $data): bool return $str === dot_array_search($field, $data); } - return isset($data[$field]) ? ($str === $data[$field]) : false; + return isset($data[$field]) && $str === $data[$field]; } /** From db0ad7e22f28587f9ec062a4859bb4af42e26bd4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Nov 2023 16:57:20 +0900 Subject: [PATCH 046/380] docs: add changelog and upgrade --- user_guide_src/source/changelogs/v4.4.4.rst | 6 ++++++ user_guide_src/source/installation/upgrade_444.rst | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index cfb0aeb4f121..bb4250f1e63f 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -21,6 +21,12 @@ A validation rule with the wildcard ``*`` now validates only data in correct dimensions as "dot array syntax". See :ref:`Upgrading ` for details. +Validation rules matches and differs +==================================== + +Bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict +and Traditional rules validate data of non-string types. + *************** Message Changes *************** diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst index c0b4def6e34d..b3773947efd9 100644 --- a/user_guide_src/source/installation/upgrade_444.rst +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -39,6 +39,17 @@ The following code explains details: If you have code that depends on the bug, fix the the rule key. +Validation rules matches and differs +==================================== + +Because bugs have been fixed in the case where ``matches`` and ``differs`` in +the Strict and Traditional rules validate data of non-string types, if you are +using these rules and validate non-string data, the validation results might be +changed (fixed). + +Note that Traditional Rules should not be used to validate data that is not a +string. + ********************* Breaking Enhancements ********************* From 552ea6885ecff386e7b3f7bdb1419018442e20f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Nov 2023 16:29:02 +0900 Subject: [PATCH 047/380] docs: remove unneeded @depreacted in ResponseInterface::getStatusCode() See https://github.com/php-fig/http-message/blob/master/src/ResponseInterface.php#L30 --- system/HTTP/ResponseInterface.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index 878d1488c25d..a6d41c77be3c 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -110,8 +110,6 @@ interface ResponseInterface extends MessageInterface * to understand and satisfy the request. * * @return int Status code. - * - * @deprecated To be replaced by the PSR-7 version (compatible) */ public function getStatusCode(): int; From f9663572471b2c73414bbe92ac919ac0d624b098 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 13:32:21 +0900 Subject: [PATCH 048/380] fix: improve error message --- system/HTTP/SiteURI.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/SiteURI.php b/system/HTTP/SiteURI.php index d01f614a1c85..6d56507314e7 100644 --- a/system/HTTP/SiteURI.php +++ b/system/HTTP/SiteURI.php @@ -197,7 +197,7 @@ private function normalizeBaseURL(App $configApp): string // Validate baseURL if (filter_var($baseURL, FILTER_VALIDATE_URL) === false) { throw new ConfigException( - 'Config\App::$baseURL is invalid.' + 'Config\App::$baseURL "' . $baseURL . '" is not a valid URL.' ); } From bb68857fdbf46e4b2cf1e977a93468fc803b12c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 14:02:32 +0900 Subject: [PATCH 049/380] fix: PHPDoc types in controller.tpl.php --- .../Generators/Views/controller.tpl.php | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/system/Commands/Generators/Views/controller.tpl.php b/system/Commands/Generators/Views/controller.tpl.php index de4447c56268..2fe99e1b296b 100644 --- a/system/Commands/Generators/Views/controller.tpl.php +++ b/system/Commands/Generators/Views/controller.tpl.php @@ -3,6 +3,7 @@ namespace {namespace}; use {useStatement}; +use CodeIgniter\HTTP\ResponseInterface; class {class} extends {extends} { @@ -10,7 +11,7 @@ class {class} extends {extends} /** * Return an array of resource objects, themselves in array format * - * @return mixed + * @return ResponseInterface */ public function index() { @@ -20,7 +21,7 @@ public function index() /** * Return the properties of a resource object * - * @return mixed + * @return ResponseInterface */ public function show($id = null) { @@ -30,7 +31,7 @@ public function show($id = null) /** * Return a new resource object, with default properties * - * @return mixed + * @return ResponseInterface */ public function new() { @@ -40,7 +41,7 @@ public function new() /** * Create a new resource object, from "posted" parameters * - * @return mixed + * @return ResponseInterface */ public function create() { @@ -50,7 +51,7 @@ public function create() /** * Return the editable properties of a resource object * - * @return mixed + * @return ResponseInterface */ public function edit($id = null) { @@ -60,7 +61,7 @@ public function edit($id = null) /** * Add or update a model resource, from "posted" properties * - * @return mixed + * @return ResponseInterface */ public function update($id = null) { @@ -70,7 +71,7 @@ public function update($id = null) /** * Delete the designated resource object from the model * - * @return mixed + * @return ResponseInterface */ public function delete($id = null) { @@ -80,7 +81,7 @@ public function delete($id = null) /** * Present a view of resource objects * - * @return mixed + * @return ResponseInterface */ public function index() { @@ -90,9 +91,9 @@ public function index() /** * Present a view to present a specific resource object * - * @param mixed $id + * @param string $id * - * @return mixed + * @return ResponseInterface */ public function show($id = null) { From a884251c42bc72c02bb211547f641160f2283445 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 14:20:11 +0900 Subject: [PATCH 050/380] fix: @return in filter.tpl.php --- system/Commands/Generators/Views/filter.tpl.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Commands/Generators/Views/filter.tpl.php b/system/Commands/Generators/Views/filter.tpl.php index c080e920a021..767ac0bd9208 100644 --- a/system/Commands/Generators/Views/filter.tpl.php +++ b/system/Commands/Generators/Views/filter.tpl.php @@ -21,7 +21,7 @@ class {class} implements FilterInterface * @param RequestInterface $request * @param array|null $arguments * - * @return mixed + * @return RequestInterface|ResponseInterface|string|void */ public function before(RequestInterface $request, $arguments = null) { @@ -38,7 +38,7 @@ public function before(RequestInterface $request, $arguments = null) * @param ResponseInterface $response * @param array|null $arguments * - * @return mixed + * @return ResponseInterface|void */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { From 9d2b0713894822803693f30f54cdc6fb589ee5ff Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 14:23:53 +0900 Subject: [PATCH 051/380] docs: fix @param in ControllerTestTrait --- system/Test/ControllerTestTrait.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Test/ControllerTestTrait.php b/system/Test/ControllerTestTrait.php index 2da65d1aa2f7..a99b899eaf63 100644 --- a/system/Test/ControllerTestTrait.php +++ b/system/Test/ControllerTestTrait.php @@ -215,7 +215,7 @@ public function execute(string $method, ...$params) /** * Set controller's config, with method chaining. * - * @param mixed $appConfig + * @param App $appConfig * * @return $this */ @@ -229,7 +229,7 @@ public function withConfig($appConfig) /** * Set controller's request, with method chaining. * - * @param mixed $request + * @param IncomingRequest $request * * @return $this */ @@ -260,7 +260,7 @@ public function withResponse($response) /** * Set controller's logger, with method chaining. * - * @param mixed $logger + * @param LoggerInterface $logger * * @return $this */ From a851a0b66b1133cb8fa8fbe813ac41d797438b2a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 14:26:52 +0900 Subject: [PATCH 052/380] docs: fix @return in View/Plugins.php --- system/View/Plugins.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/View/Plugins.php b/system/View/Plugins.php index b74ad96bd385..4b20caef8d3f 100644 --- a/system/View/Plugins.php +++ b/system/View/Plugins.php @@ -32,7 +32,7 @@ public static function currentURL() /** * Wrap helper function to use as view plugin. * - * @return mixed|string|URI + * @return string|URI */ public static function previousURL() { From d58ce836695e122c418171efcaf5a7a7a6e3fad3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 15:45:13 +0900 Subject: [PATCH 053/380] docs: add csp.rst and move existing contents --- user_guide_src/source/outgoing/csp.rst | 127 ++++++++++++++++++ .../source/outgoing/{response => csp}/011.php | 0 .../source/outgoing/{response => csp}/012.php | 0 .../source/outgoing/{response => csp}/013.php | 0 user_guide_src/source/outgoing/index.rst | 1 + user_guide_src/source/outgoing/response.rst | 116 ---------------- 6 files changed, 128 insertions(+), 116 deletions(-) create mode 100644 user_guide_src/source/outgoing/csp.rst rename user_guide_src/source/outgoing/{response => csp}/011.php (100%) rename user_guide_src/source/outgoing/{response => csp}/012.php (100%) rename user_guide_src/source/outgoing/{response => csp}/013.php (100%) diff --git a/user_guide_src/source/outgoing/csp.rst b/user_guide_src/source/outgoing/csp.rst new file mode 100644 index 000000000000..b0ca5263c1ef --- /dev/null +++ b/user_guide_src/source/outgoing/csp.rst @@ -0,0 +1,127 @@ +.. _content-security-policy: + +####################### +Content Security Policy +####################### + +.. contents:: + :local: + :depth: 2 + +******************************** +What is Content Security Policy? +******************************** + +One of the best protections you have against XSS attacks is to implement a Content Security Policy on the site. +This forces you to whitelist every single source of content that is pulled in from your site's HTML, +including images, stylesheets, javascript files, etc. The browser will refuse content from sources that don't meet +the whitelist. This whitelist is created within the response's ``Content-Security-Policy`` header and has many +different ways it can be configured. + +This sounds complex, and on some sites, can definitely be challenging. For many simple sites, though, where all content +is served by the same domain (http://example.com), it is very simple to integrate. + +As this is a complex subject, this user guide will not go over all of the details. For more information, you should +visit the following sites: + +* `Content Security Policy main site `_ +* `W3C Specification `_ +* `Introduction at HTML5Rocks `_ +* `Article at SitePoint `_ + +************** +Turning CSP On +************** + +.. important:: The :ref:`Debug Toolbar ` may use Kint, which + outputs inline scripts. Therefore, when CSP is turned on, CSP nonce is + automatically output for the Debug Toolbar. However, if you are not using + CSP nonce, this will change the CSP header to something you do not intend, + and it will behave differently than in production; if you want to verify CSP + behavior, turn off the Debug Toolbar. + +By default, support for this is off. To enable support in your application, edit the ``CSPEnabled`` value in +**app/Config/App.php**: + +.. literalinclude:: csp/011.php + +When enabled, the response object will contain an instance of ``CodeIgniter\HTTP\ContentSecurityPolicy``. The +values set in **app/Config/ContentSecurityPolicy.php** are applied to that instance, and if no changes are +needed during runtime, then the correctly formatted header is sent and you're all done. + +With CSP enabled, two header lines are added to the HTTP response: a **Content-Security-Policy** header, with +policies identifying content types or origins that are explicitly allowed for different +contexts, and a **Content-Security-Policy-Report-Only** header, which identifies content types +or origins that will be allowed but which will also be reported to the destination +of your choice. + +Our implementation provides for a default treatment, changeable through the ``reportOnly()`` method. +When an additional entry is added to a CSP directive, as shown below, it will be added +to the CSP header appropriate for blocking or preventing. That can be overridden on a per +call basis, by providing an optional second parameter to the adding method call. + +********************* +Runtime Configuration +********************* + +If your application needs to make changes at run-time, you can access the instance at ``$this->response->getCSP()`` in your controllers. The +class holds a number of methods that map pretty clearly to the appropriate header value that you need to set. +Examples are shown below, with different combinations of parameters, though all accept either a directive +name or an array of them: + +.. literalinclude:: csp/012.php + +The first parameter to each of the "add" methods is an appropriate string value, +or an array of them. + +The ``reportOnly()`` method allows you to specify the default reporting treatment +for subsequent sources, unless over-ridden. For instance, you could specify +that youtube.com was allowed, and then provide several allowed but reported sources: + +.. literalinclude:: csp/013.php + +************** +Inline Content +************** + +It is possible to set a website to not protect even inline scripts and styles on its own pages, since this might have +been the result of user-generated content. To protect against this, CSP allows you to specify a nonce within the +`` + +.. warning:: If an attacker injects a string like `` + + // Becomes + + + // OR + diff --git a/user_guide_src/source/outgoing/response/011.php b/user_guide_src/source/outgoing/csp/011.php similarity index 100% rename from user_guide_src/source/outgoing/response/011.php rename to user_guide_src/source/outgoing/csp/011.php diff --git a/user_guide_src/source/outgoing/response/012.php b/user_guide_src/source/outgoing/csp/012.php similarity index 100% rename from user_guide_src/source/outgoing/response/012.php rename to user_guide_src/source/outgoing/csp/012.php diff --git a/user_guide_src/source/outgoing/response/013.php b/user_guide_src/source/outgoing/csp/013.php similarity index 100% rename from user_guide_src/source/outgoing/response/013.php rename to user_guide_src/source/outgoing/csp/013.php diff --git a/user_guide_src/source/outgoing/index.rst b/user_guide_src/source/outgoing/index.rst index 2b95096511c3..a08a2e52a125 100644 --- a/user_guide_src/source/outgoing/index.rst +++ b/user_guide_src/source/outgoing/index.rst @@ -16,5 +16,6 @@ View components are used to build what is returned to the user. table response api_responses + csp localization alternative_php diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 078d9d11042a..d5785756d461 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -199,122 +199,6 @@ to the ``Cache-Control`` header. You are free to set all of the options exactly situation. While most of the options are applied to the ``Cache-Control`` header, it intelligently handles the ``etag`` and ``last-modified`` options to their appropriate header. -.. _content-security-policy: - -Content Security Policy -======================= - -One of the best protections you have against XSS attacks is to implement a Content Security Policy on the site. -This forces you to whitelist every single source of content that is pulled in from your site's HTML, -including images, stylesheets, javascript files, etc. The browser will refuse content from sources that don't meet -the whitelist. This whitelist is created within the response's ``Content-Security-Policy`` header and has many -different ways it can be configured. - -This sounds complex, and on some sites, can definitely be challenging. For many simple sites, though, where all content -is served by the same domain (http://example.com), it is very simple to integrate. - -As this is a complex subject, this user guide will not go over all of the details. For more information, you should -visit the following sites: - -* `Content Security Policy main site `_ -* `W3C Specification `_ -* `Introduction at HTML5Rocks `_ -* `Article at SitePoint `_ - -Turning CSP On --------------- - -.. important:: The :ref:`Debug Toolbar ` may use Kint, which - outputs inline scripts. Therefore, when CSP is turned on, CSP nonce is - automatically output for the Debug Toolbar. However, if you are not using - CSP nonce, this will change the CSP header to something you do not intend, - and it will behave differently than in production; if you want to verify CSP - behavior, turn off the Debug Toolbar. - -By default, support for this is off. To enable support in your application, edit the ``CSPEnabled`` value in -**app/Config/App.php**: - -.. literalinclude:: response/011.php - -When enabled, the response object will contain an instance of ``CodeIgniter\HTTP\ContentSecurityPolicy``. The -values set in **app/Config/ContentSecurityPolicy.php** are applied to that instance, and if no changes are -needed during runtime, then the correctly formatted header is sent and you're all done. - -With CSP enabled, two header lines are added to the HTTP response: a **Content-Security-Policy** header, with -policies identifying content types or origins that are explicitly allowed for different -contexts, and a **Content-Security-Policy-Report-Only** header, which identifies content types -or origins that will be allowed but which will also be reported to the destination -of your choice. - -Our implementation provides for a default treatment, changeable through the ``reportOnly()`` method. -When an additional entry is added to a CSP directive, as shown below, it will be added -to the CSP header appropriate for blocking or preventing. That can be overridden on a per -call basis, by providing an optional second parameter to the adding method call. - -Runtime Configuration ---------------------- - -If your application needs to make changes at run-time, you can access the instance at ``$this->response->getCSP()`` in your controllers. The -class holds a number of methods that map pretty clearly to the appropriate header value that you need to set. -Examples are shown below, with different combinations of parameters, though all accept either a directive -name or an array of them: - -.. literalinclude:: response/012.php - -The first parameter to each of the "add" methods is an appropriate string value, -or an array of them. - -The ``reportOnly()`` method allows you to specify the default reporting treatment -for subsequent sources, unless over-ridden. For instance, you could specify -that youtube.com was allowed, and then provide several allowed but reported sources: - -.. literalinclude:: response/013.php - -Inline Content --------------- - -It is possible to set a website to not protect even inline scripts and styles on its own pages, since this might have -been the result of user-generated content. To protect against this, CSP allows you to specify a nonce within the -`` - -.. warning:: If an attacker injects a string like `` - - // Becomes - - - // OR - - Class Reference =============== From 202a8751419a3e5024b748a70619d9696be83ad3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 15:47:14 +0900 Subject: [PATCH 054/380] docs: trivail fix in sample code --- user_guide_src/source/outgoing/csp/011.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/csp/011.php b/user_guide_src/source/outgoing/csp/011.php index bfac115c6bd3..193105592586 100644 --- a/user_guide_src/source/outgoing/csp/011.php +++ b/user_guide_src/source/outgoing/csp/011.php @@ -6,7 +6,7 @@ class App extends BaseConfig { - public bool $CSPEnabled = true; - // ... + + public bool $CSPEnabled = true; } From fd2fd4d633a2b03ff4c265b868b7fcd8d0537c70 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 15:52:10 +0900 Subject: [PATCH 055/380] docs: add (CSP) --- user_guide_src/source/outgoing/csp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/csp.rst b/user_guide_src/source/outgoing/csp.rst index b0ca5263c1ef..44eb585256db 100644 --- a/user_guide_src/source/outgoing/csp.rst +++ b/user_guide_src/source/outgoing/csp.rst @@ -12,7 +12,7 @@ Content Security Policy What is Content Security Policy? ******************************** -One of the best protections you have against XSS attacks is to implement a Content Security Policy on the site. +One of the best protections you have against XSS attacks is to implement a Content Security Policy (CSP) on the site. This forces you to whitelist every single source of content that is pulled in from your site's HTML, including images, stylesheets, javascript files, etc. The browser will refuse content from sources that don't meet the whitelist. This whitelist is created within the response's ``Content-Security-Policy`` header and has many From 178c4c07d3c181aaf74caa60b6c51bbc35c5210f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Nov 2023 15:57:29 +0900 Subject: [PATCH 056/380] docs: remove `whitelist` --- user_guide_src/source/outgoing/csp.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/outgoing/csp.rst b/user_guide_src/source/outgoing/csp.rst index 44eb585256db..0761f289a611 100644 --- a/user_guide_src/source/outgoing/csp.rst +++ b/user_guide_src/source/outgoing/csp.rst @@ -12,11 +12,13 @@ Content Security Policy What is Content Security Policy? ******************************** -One of the best protections you have against XSS attacks is to implement a Content Security Policy (CSP) on the site. -This forces you to whitelist every single source of content that is pulled in from your site's HTML, -including images, stylesheets, javascript files, etc. The browser will refuse content from sources that don't meet -the whitelist. This whitelist is created within the response's ``Content-Security-Policy`` header and has many -different ways it can be configured. +One of the best protections you have against XSS attacks is to implement a Content +Security Policy (CSP) on the site. This requires you to specify and authorize each +source of content that is included in your site's HTML, including images, +stylesheets, JavaScript files, and so on. The browser will reject content from +sources that are not explicitly approved. This authorization is defined within +the response's ``Content-Security-Policy`` header and offers various configuration +options. This sounds complex, and on some sites, can definitely be challenging. For many simple sites, though, where all content is served by the same domain (http://example.com), it is very simple to integrate. From 6e15dad0e446a3aa4579f6ed5cb07575bbe1ecea Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 5 Nov 2023 18:46:13 +0800 Subject: [PATCH 057/380] Update to phpstan-codeigniter v1.4.2 --- phpstan-baseline.php | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index ce98e8633277..ba2ed9354d05 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -701,21 +701,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Commands/Server/Serve.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Accessing offset \'DOCUMENT_ROOT\' directly on \\$_SERVER is discouraged\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/system/Commands/Server/rewrite.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Accessing offset \'REQUEST_URI\' directly on \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Server/rewrite.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'/index\\.php\' directly on offset \'SCRIPT_NAME\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Commands/Server/rewrite.php', -]; $ignoreErrors[] = [ 'message' => '#^Accessing offset \'CI_ENVIRONMENT\' directly on \\$_SERVER is discouraged\\.$#', 'count' => 3, @@ -3916,21 +3901,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Test/TestResponse.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Accessing offset \'app\\.baseURL\' directly on \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Test/bootstrap.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'http\\://example\\.com/\' directly on offset \'app\\.baseURL\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Test/bootstrap.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Assigning \'testing\' directly on offset \'CI_ENVIRONMENT\' of \\$_SERVER is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Test/bootstrap.php', -]; $ignoreErrors[] = [ 'message' => '#^Property CodeIgniter\\\\Throttle\\\\Throttler\\:\\:\\$testTime \\(int\\) on left side of \\?\\? is not nullable\\.$#', 'count' => 1, From 626a7747b361f1d09e2135bda797c3a545004b6f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Nov 2023 08:03:48 +0900 Subject: [PATCH 058/380] docs: fix incorrect label position --- user_guide_src/source/libraries/validation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 8ebec266c0bf..eb2c497426b2 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -309,8 +309,6 @@ To give a labeled error message you can set up as: .. literalinclude:: validation/007.php :lines: 2- -.. _validation-withrequest: - .. note:: ``setRules()`` will overwrite any rules that were set previously. To add more than one rule to an existing set of rules, use ``setRule()`` multiple times. @@ -340,6 +338,8 @@ For example, data returned by multi select dropdown: .. literalinclude:: validation/011.php :lines: 2- +.. _validation-withrequest: + withRequest() ============= From 75907cff0152c47201f4cdd16d8f0a0f9732b7e0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Nov 2023 08:04:05 +0900 Subject: [PATCH 059/380] docs: fix comment in sample code --- user_guide_src/source/libraries/validation/008.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation/008.php b/user_guide_src/source/libraries/validation/008.php index 38656dda37cb..41e37f0652ef 100644 --- a/user_guide_src/source/libraries/validation/008.php +++ b/user_guide_src/source/libraries/validation/008.php @@ -4,7 +4,8 @@ $request = \Config\Services::request(); if ($validation->withRequest($request)->run()) { - // If you want to get the validated data. + // If you use the input data, you should get it from the getValidated() method. + // Otherwise you may create a vulnerability. $validData = $validation->getValidated(); // ... From 3a2cc73f05db563ecc01d7ae0e90b6117ea3d45e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Nov 2023 09:22:38 +0900 Subject: [PATCH 060/380] refactor: fix PHPStan errors --- phpstan-baseline.php | 5 ----- system/Cache/Handlers/RedisHandler.php | 1 + system/Session/Handlers/RedisHandler.php | 5 ++++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index ba2ed9354d05..451c925f373a 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -3036,11 +3036,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Session/Handlers/RedisHandler.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a negated boolean, int given\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Session/Handlers/RedisHandler.php', -]; $ignoreErrors[] = [ 'message' => '#^Accessing offset \'HTTP_X_REQUESTED_WITH\' directly on \\$_SERVER is discouraged\\.$#', 'count' => 2, diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index 42b44cd98a96..953de2dc20be 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -245,6 +245,7 @@ public function getMetaData(string $key) if ($value !== null) { $time = Time::now()->getTimestamp(); $ttl = $this->redis->ttl(static::validateKey($key, $this->prefix)); + assert(is_int($ttl)); return [ 'expire' => $ttl > 0 ? $time + $ttl : null, diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index 815e3644984b..1fb87597ab8a 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -293,7 +293,10 @@ protected function lockSession(string $sessionID): bool $attempt = 0; do { - if (($ttl = $this->redis->ttl($lockKey)) > 0) { + $ttl = $this->redis->ttl($lockKey); + assert(is_int($ttl)); + + if ($ttl > 0) { sleep(1); continue; From bc919912f29c168bc21a988e3b86ff3fef24ad37 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Nov 2023 21:00:47 +0700 Subject: [PATCH 061/380] [Testing] Use assertEqualsWithDelta() when possible --- tests/system/Config/BaseConfigTest.php | 2 +- tests/system/Database/Live/SelectTest.php | 4 ++-- tests/system/Entity/EntityTest.php | 8 ++++---- tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php | 10 +++++----- tests/system/HTTP/CURLRequestTest.php | 10 +++++----- tests/system/HTTP/IncomingRequestTest.php | 4 ++-- .../Session/Handlers/Database/RedisHandlerTest.php | 4 ++-- tests/system/Throttle/ThrottleTest.php | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/system/Config/BaseConfigTest.php b/tests/system/Config/BaseConfigTest.php index 7c05af3a390e..6b53689d04e2 100644 --- a/tests/system/Config/BaseConfigTest.php +++ b/tests/system/Config/BaseConfigTest.php @@ -80,7 +80,7 @@ public function testUseDefaultValueTypeIntAndFloatValues(): void $dotenv->load(); $config = new SimpleConfig(); - $this->assertSame(0.0, $config->float); + $this->assertEqualsWithDelta(0.0, $config->float, PHP_FLOAT_EPSILON); $this->assertSame(999, $config->int); } diff --git a/tests/system/Database/Live/SelectTest.php b/tests/system/Database/Live/SelectTest.php index c32f5e116828..cd4b1a5f93d1 100644 --- a/tests/system/Database/Live/SelectTest.php +++ b/tests/system/Database/Live/SelectTest.php @@ -86,14 +86,14 @@ public function testSelectAvg(): void { $result = $this->db->table('job')->selectAvg('id')->get()->getRow(); - $this->assertSame(2.5, (float) $result->id); + $this->assertEqualsWithDelta(2.5, (float) $result->id, PHP_FLOAT_EPSILON); } public function testSelectAvgWithAlias(): void { $result = $this->db->table('job')->selectAvg('id', 'xam')->get()->getRow(); - $this->assertSame(2.5, (float) $result->xam); + $this->assertEqualsWithDelta(2.5, (float) $result->xam, PHP_FLOAT_EPSILON); } public function testSelectSum(): void diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index dadea32b5680..b02756c22406 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -373,12 +373,12 @@ public function testCastFloat(): void $entity->second = 3; $this->assertIsFloat($entity->second); - $this->assertSame(3.0, $entity->second); + $this->assertEqualsWithDelta(3.0, $entity->second, PHP_FLOAT_EPSILON); $entity->second = '3.6'; $this->assertIsFloat($entity->second); - $this->assertSame(3.6, $entity->second); + $this->assertEqualsWithDelta(3.6, $entity->second, PHP_FLOAT_EPSILON); } public function testCastDouble(): void @@ -388,12 +388,12 @@ public function testCastDouble(): void $entity->third = 3; $this->assertIsFloat($entity->third); - $this->assertSame(3.0, $entity->third); + $this->assertEqualsWithDelta(3.0, $entity->third, PHP_FLOAT_EPSILON); $entity->third = '3.6'; $this->assertIsFloat($entity->third); - $this->assertSame(3.6, $entity->third); + $this->assertEqualsWithDelta(3.6, $entity->third, PHP_FLOAT_EPSILON); } public function testCastString(): void diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index a0a9ffcda4c6..d8e96424dae5 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -267,14 +267,14 @@ public function testHeaderContentLengthNotSharedBetweenClients(): void public function testOptionsDelay(): void { $request = $this->getRequest(); - $this->assertSame(0.0, $request->getDelay()); + $this->assertEqualsWithDelta(0.0, $request->getDelay(), PHP_FLOAT_EPSILON); $options = [ 'delay' => 2000, 'headers' => ['fruit' => 'apple'], ]; $request = $this->getRequest($options); - $this->assertSame(2.0, $request->getDelay()); + $this->assertEqualsWithDelta(2.0, $request->getDelay(), PHP_FLOAT_EPSILON); } public function testPatchSetsCorrectMethod(): void @@ -356,10 +356,10 @@ public function testRequestSetsBasicCurlOptions(): void $this->assertTrue($options[CURLOPT_FRESH_CONNECT]); $this->assertArrayHasKey(CURLOPT_TIMEOUT_MS, $options); - $this->assertSame(0.0, $options[CURLOPT_TIMEOUT_MS]); + $this->assertEqualsWithDelta(0.0, $options[CURLOPT_TIMEOUT_MS], PHP_FLOAT_EPSILON); $this->assertArrayHasKey(CURLOPT_CONNECTTIMEOUT_MS, $options); - $this->assertSame(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS]); + $this->assertEqualsWithDelta(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS], PHP_FLOAT_EPSILON); } public function testAuthBasicOption(): void @@ -734,7 +734,7 @@ public function testSendWithDelay(): void $request->get('products'); // we still need to check the code coverage to make sure this was done - $this->assertSame(0.1, $request->getDelay()); + $this->assertEqualsWithDelta(0.1, $request->getDelay(), PHP_FLOAT_EPSILON); } public function testSendContinued(): void diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index f7a1ce6fe9e7..186284da6ba6 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -250,14 +250,14 @@ public function testHeaderContentLengthNotSharedBetweenClients(): void public function testOptionsDelay(): void { $request = $this->getRequest(); - $this->assertSame(0.0, $request->getDelay()); + $this->assertEqualsWithDelta(0.0, $request->getDelay(), PHP_FLOAT_EPSILON); $options = [ 'delay' => 2000, 'headers' => ['fruit' => 'apple'], ]; $request = $this->getRequest($options); - $this->assertSame(2.0, $request->getDelay()); + $this->assertEqualsWithDelta(2.0, $request->getDelay(), PHP_FLOAT_EPSILON); } public function testPatchSetsCorrectMethod(): void @@ -339,10 +339,10 @@ public function testRequestSetsBasicCurlOptions(): void $this->assertTrue($options[CURLOPT_FRESH_CONNECT]); $this->assertArrayHasKey(CURLOPT_TIMEOUT_MS, $options); - $this->assertSame(0.0, $options[CURLOPT_TIMEOUT_MS]); + $this->assertEqualsWithDelta(0.0, $options[CURLOPT_TIMEOUT_MS], PHP_FLOAT_EPSILON); $this->assertArrayHasKey(CURLOPT_CONNECTTIMEOUT_MS, $options); - $this->assertSame(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS]); + $this->assertEqualsWithDelta(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS], PHP_FLOAT_EPSILON); } public function testAuthBasicOption(): void @@ -717,7 +717,7 @@ public function testSendWithDelay(): void $request->get('products'); // we still need to check the code coverage to make sure this was done - $this->assertSame(0.1, $request->getDelay()); + $this->assertEqualsWithDelta(0.1, $request->getDelay(), PHP_FLOAT_EPSILON); } public function testSendContinued(): void diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 3855a4b85c94..98fef5322df2 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -348,7 +348,7 @@ public function testCanGetAVariableFromJson(): void $this->assertSame('buzz', $jsonVar->fizz); $this->assertSame('buzz', $request->getJsonVar('baz.fizz')); $this->assertSame(123, $request->getJsonVar('int')); - $this->assertSame(3.14, $request->getJsonVar('float')); + $this->assertEqualsWithDelta(3.14, $request->getJsonVar('float'), PHP_FLOAT_EPSILON); $this->assertTrue($request->getJsonVar('true')); $this->assertFalse($request->getJsonVar('false')); $this->assertNull($request->getJsonVar('null')); @@ -379,7 +379,7 @@ public function testGetJsonVarAsArray(): void $this->assertSame('buzz', $jsonVar['fizz']); $this->assertSame('bar', $jsonVar['foo']); $this->assertSame(123, $jsonVar['int']); - $this->assertSame(3.14, $jsonVar['float']); + $this->assertEqualsWithDelta(3.14, $jsonVar['float'], PHP_FLOAT_EPSILON); $this->assertTrue($jsonVar['true']); $this->assertFalse($jsonVar['false']); $this->assertNull($jsonVar['null']); diff --git a/tests/system/Session/Handlers/Database/RedisHandlerTest.php b/tests/system/Session/Handlers/Database/RedisHandlerTest.php index 94d17461d243..d5e8b61e7700 100644 --- a/tests/system/Session/Handlers/Database/RedisHandlerTest.php +++ b/tests/system/Session/Handlers/Database/RedisHandlerTest.php @@ -93,7 +93,7 @@ public function testSavePathTimeoutFloat(): void $savePath = $this->getPrivateProperty($handler, 'savePath'); - $this->assertSame(2.5, $savePath['timeout']); + $this->assertEqualsWithDelta(2.5, $savePath['timeout'], PHP_FLOAT_EPSILON); } public function testSavePathTimeoutInt(): void @@ -104,7 +104,7 @@ public function testSavePathTimeoutInt(): void $savePath = $this->getPrivateProperty($handler, 'savePath'); - $this->assertSame(10.0, $savePath['timeout']); + $this->assertEqualsWithDelta(10.0, $savePath['timeout'], PHP_FLOAT_EPSILON); } public function testOpen(): void diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 16d58ac506d4..1cd0abf99407 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -185,7 +185,7 @@ public function testFlooding(): void $throttler = $throttler->setTestTime($time + 10); $this->assertTrue($throttler->check('127.0.0.1', $rate, MINUTE, 0)); - $this->assertSame(10.0, round($this->cache->get('throttler_127.0.0.1'))); + $this->assertEqualsWithDelta(10.0, round($this->cache->get('throttler_127.0.0.1')), PHP_FLOAT_EPSILON); } /** From 6293b6b5e582a88a8e2f6c7e442bb9c2028a683b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 07:11:50 +0900 Subject: [PATCH 062/380] docs: add warning to getVar() in validation.rst --- user_guide_src/source/libraries/validation.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index eb2c497426b2..6fc55822b71a 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -343,6 +343,13 @@ For example, data returned by multi select dropdown: withRequest() ============= +.. warning:: If you want to validate POST data only, don't use ``withRequest()``. + This method uses :ref:`$request->getVar() ` + which returns ``$_GET``, ``$_POST`` or ``$_COOKIE`` data in that order + (depending on php.ini `request-order `_). + Newer values override older values. POST values may be overridden by the + cookies if they have the same name. + One of the most common times you will use the validation library is when validating data that was input from an HTTP Request. If desired, you can pass an instance of the current Request object and it will take all of the input data and set it as the From 1149f271913f32ce57ff9adceca721bd1b952067 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 07:12:15 +0900 Subject: [PATCH 063/380] docs: add warning to getVar() in incomingrequest.rst --- user_guide_src/source/incoming/incomingrequest.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 5a58ea1c1608..d3b04bd0c698 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -101,6 +101,11 @@ Getting Data The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data from ``$_GET``, ``$POST``, or ``$_COOKIE`` (depending on php.ini `request-order `_). +.. warning:: If you want to validate POST data only, don't use ``getVar()``. + Newer values override older values. POST values may be overridden by the + cookies if they have the same name, and you set "C" after "P" in + `request-order `_. + .. note:: If the incoming request has a ``Content-Type`` header set to ``application/json``, the ``getVar()`` method returns the JSON data instead of ``$_REQUEST`` data. From 82c2977813c0a28201379c141e0de7d092b1adf1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 09:35:02 +0900 Subject: [PATCH 064/380] test: fix typo in method name --- tests/system/HTTP/IncomingRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 3855a4b85c94..0211dccacef6 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -518,7 +518,7 @@ public function testGetJsonVarReturnsNullFromNullBody(): void $this->assertNull($request->getJsonVar('myKey')); } - public function testgetJSONReturnsNullFromNullBody(): void + public function testGetJSONReturnsNullFromNullBody(): void { $config = new App(); $config->baseURL = 'http://example.com/'; From ee34dcaedb1af465124a8fb72135ee5dd0e32b7f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 09:36:46 +0900 Subject: [PATCH 065/380] test: rename test method --- tests/system/HTTP/IncomingRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 0211dccacef6..4830837c1fb6 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -847,7 +847,7 @@ public function testGetPostSecondStreams(): void $this->assertSame(array_merge($_POST, $_GET), $this->request->getGetPost()); } - public function testWithFalseBody(): void + public function testGetBodyWithFalseBody(): void { // Use `false` here to simulate file_get_contents returning a false value $request = $this->createRequest(null, false); From 5e4e13bb59b578267d349ecd46f1a8d3a28a024f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 09:46:48 +0900 Subject: [PATCH 066/380] test: add test when body is '0' --- tests/system/HTTP/IncomingRequestTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 4830837c1fb6..cfc26a988857 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -856,6 +856,13 @@ public function testGetBodyWithFalseBody(): void $this->assertNull($request->getBody()); } + public function testGetBodyWithZero(): void + { + $request = $this->createRequest(null, '0'); + + $this->assertSame('0', $request->getBody()); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/3020 */ From 05966db888ddd749d1f69e60c11bdf12f2444b8b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 09:47:42 +0900 Subject: [PATCH 067/380] fix: bug that if body is '0', $this->body will be null --- system/HTTP/IncomingRequest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 079a3b69d02f..307a78d38b4a 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -169,9 +169,14 @@ public function __construct($config, ?URI $uri = null, $body = 'php://input', ?U $body = file_get_contents('php://input'); } + // If file_get_contents() returns false or empty string, set null. + if ($body === false || $body === '') { + $body = null; + } + $this->config = $config; $this->uri = $uri; - $this->body = ! empty($body) ? $body : null; + $this->body = $body; $this->userAgent = $userAgent; $this->validLocales = $config->supportedLocales; From 42be01d92566eb2b946435be40b4f26cd84131b9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 09:51:36 +0900 Subject: [PATCH 068/380] chore: update phpstan-baseline.php --- phpstan-baseline.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 451c925f373a..3cbe5a4732fc 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2148,7 +2148,7 @@ ]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 6, + 'count' => 5, 'path' => __DIR__ . '/system/HTTP/IncomingRequest.php', ]; $ignoreErrors[] = [ From 5c55c435e4db9e38afe6a5292e3366e9cf5d5f3b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 11:14:47 +0900 Subject: [PATCH 069/380] docs: fix return type for lang() --- system/Common.php | 2 +- system/Language/Language.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Common.php b/system/Common.php index 9ad7fe5b842b..2d876564846e 100644 --- a/system/Common.php +++ b/system/Common.php @@ -755,7 +755,7 @@ function is_windows(?bool $mock = null): bool * A convenience method to translate a string or array of them and format * the result with the intl extension's MessageFormatter. * - * @return string + * @return list|string */ function lang(string $line, array $args = [], ?string $locale = null) { diff --git a/system/Language/Language.php b/system/Language/Language.php index 32eee39f2a13..8633f8a2dd9c 100644 --- a/system/Language/Language.php +++ b/system/Language/Language.php @@ -88,7 +88,7 @@ public function getLocale(): string * Parses the language string for a file, loads the file, if necessary, * getting the line. * - * @return string|string[] + * @return list|string */ public function getLine(string $line, array $args = []) { From 1b0d777eefab1191fc243932668cb64539a36edc Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 13:06:09 +0900 Subject: [PATCH 070/380] docs: add warning about Cookie based CSRF protection --- user_guide_src/source/libraries/security.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 6c39cbefdb5e..407b99725103 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -71,6 +71,12 @@ Config for CSRF CSRF Protection Methods ----------------------- +.. warning:: If you use :doc:`Session <./sessions>`, be sure to use Session based + CSRF protection. Cookie based CSRF protection will not prevent Same-site attacks. + See + `GHSA-5hm8-vh6r-2cjq `_ + for details. + By default, the Cookie based CSRF Protection is used. It is `Double Submit Cookie `_ on OWASP Cross-Site Request Forgery Prevention Cheat Sheet. From d389049d031550e776ad99ab033b16b075448d65 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 13:37:48 +0900 Subject: [PATCH 071/380] docs: add explanation about redirect and Cookies/Headers --- user_guide_src/source/outgoing/response.rst | 35 +++++++++++++++++-- .../source/outgoing/response/031.php | 6 ---- .../source/outgoing/response/034.php | 4 +++ .../source/outgoing/response/035.php | 4 +++ 4 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 user_guide_src/source/outgoing/response/034.php create mode 100644 user_guide_src/source/outgoing/response/035.php diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index d5785756d461..539c99180eaa 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -64,8 +64,15 @@ parameter. This is not case-sensitive. Redirect ======== -If you want to create a redirect, use the :php:func:`redirect()` function. It -returns a ``RedirectResponse`` instance. +If you want to create a redirect, use the :php:func:`redirect()` function. + +It returns a ``RedirectResponse`` instance. It is a different instance from the +global response instance that ``Services::response()`` returns. + +.. warning:: If you set Cookies or Response Headers before you call ``redirect()``, + they are set to the global response instance, and they are not automatically + copied to the ``RedirectResponse`` instance. To send them, you need to call + the ``withCookies()`` or ``withHeaders()`` method manually. .. important:: If you want to redirect, an instance of ``RedirectResponse`` must be returned in a method of the :doc:`Controller <../incoming/controllers>` or @@ -113,6 +120,30 @@ When you want to redirect back, use ``redirect()->back()``: It takes a visitor to "the last page viewed during the Session" when the Session is available. If the Session hasn't been loaded, or is otherwise unavailable, then a sanitized version of HTTP_REFERER will be used. +Redirect with Cookies +--------------------- + +If you set Cookies before you call ``redirect()``, they are set to the global +response instance, and they are not automatically copied to the ``RedirectResponse`` +instance. + +To send the Cookies, you need to call the ``withCookies()`` method manually. + +.. literalinclude:: ./response/034.php + :lines: 2- + +Redirect with Headers +--------------------- + +If you set Response Headers before you call ``redirect()``, they are set to the +global response instance, and they are not automatically copied to the +``RedirectResponse`` instance. + +To send the Headers, you need to call the ``withHeaders()`` method manually. + +.. literalinclude:: ./response/035.php + :lines: 2- + .. _response-redirect-status-code: Redirect Status Code diff --git a/user_guide_src/source/outgoing/response/031.php b/user_guide_src/source/outgoing/response/031.php index 28b73d6c267c..bd24e1512f09 100644 --- a/user_guide_src/source/outgoing/response/031.php +++ b/user_guide_src/source/outgoing/response/031.php @@ -8,9 +8,3 @@ // Set a flash message. return redirect()->back()->with('foo', 'message'); - -// Copies all cookies from global response instance. -return redirect()->back()->withCookies(); - -// Copies all headers from the global response instance. -return redirect()->back()->withHeaders(); diff --git a/user_guide_src/source/outgoing/response/034.php b/user_guide_src/source/outgoing/response/034.php new file mode 100644 index 000000000000..32c56afe6da6 --- /dev/null +++ b/user_guide_src/source/outgoing/response/034.php @@ -0,0 +1,4 @@ +back()->withCookies(); diff --git a/user_guide_src/source/outgoing/response/035.php b/user_guide_src/source/outgoing/response/035.php new file mode 100644 index 000000000000..3ac3578d21f0 --- /dev/null +++ b/user_guide_src/source/outgoing/response/035.php @@ -0,0 +1,4 @@ +back()->withHeaders(); From fc169d94ec1cfeb8efdd617393d89c34ae5c93df Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 13:53:05 +0900 Subject: [PATCH 072/380] docs: update outdated description --- user_guide_src/source/libraries/security.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 6c39cbefdb5e..a901e74c80a0 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -101,7 +101,9 @@ Token Regeneration ------------------ Tokens may be either regenerated on every submission (default) or -kept the same throughout the life of the CSRF cookie. The default +kept the same throughout the life of the Session or CSRF cookie. + +The default regeneration of tokens provides stricter security, but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You From 79ec2699677ae685d414396725702207e59fc8b4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 13:54:04 +0900 Subject: [PATCH 073/380] docs: add warning on redirect() --- user_guide_src/source/libraries/security.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index a901e74c80a0..d1cdb52194c8 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -112,6 +112,10 @@ may alter this behavior by editing the following config parameter value in .. literalinclude:: security/004.php +.. warning:: If you use Cookie based CSRF protection, and :php:func:`redirect()` + after the submission, you must call ``withCookie()`` to send the regenerated + CSRF cookie. See :ref:`response-redirect` for details. + .. note:: Since v4.2.3, you can regenerate CSRF token manually with the ``Security::generateHash()`` method. From fe5db1837b775215150296ef5ad510658611cd8f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Nov 2023 20:35:37 +0900 Subject: [PATCH 074/380] fix: replace {locale} with default locale in SampleURIGenerator --- system/Commands/Utilities/Routes/SampleURIGenerator.php | 9 +++++++++ .../Commands/Utilities/Routes/SampleURIGeneratorTest.php | 2 ++ 2 files changed, 11 insertions(+) diff --git a/system/Commands/Utilities/Routes/SampleURIGenerator.php b/system/Commands/Utilities/Routes/SampleURIGenerator.php index 38b333fd33c2..43d1934438bb 100644 --- a/system/Commands/Utilities/Routes/SampleURIGenerator.php +++ b/system/Commands/Utilities/Routes/SampleURIGenerator.php @@ -13,6 +13,7 @@ use CodeIgniter\Config\Services; use CodeIgniter\Router\RouteCollection; +use Config\App; /** * Generate a sample URI path from route key regex. @@ -51,6 +52,14 @@ public function get(string $routeKey): string { $sampleUri = $routeKey; + if (strpos($routeKey, '{locale}') !== false) { + $sampleUri = str_replace( + '{locale}', + config(App::class)->defaultLocale, + $routeKey + ); + } + foreach ($this->routes->getPlaceholders() as $placeholder => $regex) { $sample = $this->samples[$placeholder] ?? '::unknown::'; diff --git a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php index 4f7d6221665d..5f490be437e1 100644 --- a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php +++ b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php @@ -40,6 +40,8 @@ public static function provideGet(): iterable 'placeholder num' => ['shop/product/([0-9]+)', 'shop/product/123'], 'placeholder segment' => ['shop/product/([^/]+)', 'shop/product/abc_123'], 'placeholder any' => ['shop/product/(.*)', 'shop/product/123/abc'], + 'locale' => ['{locale}/home', 'en/home'], + 'locale segment' => ['{locale}/product/([^/]+)', 'en/product/abc_123'], 'auto route' => ['home/index[/...]', 'home/index/1/2/3/4/5'], ]; } From 71a1558cb774a35c6e62315a602e7e4e00938cc6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 08:51:10 +0900 Subject: [PATCH 075/380] docs: add sub section titles --- user_guide_src/source/incoming/incomingrequest.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index d3b04bd0c698..95c2b570dc6a 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -99,6 +99,9 @@ With CodeIgniter's built-in methods you can simply do this: Getting Data ============ +getVar() +-------- + The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data from ``$_GET``, ``$POST``, or ``$_COOKIE`` (depending on php.ini `request-order `_). .. warning:: If you want to validate POST data only, don't use ``getVar()``. @@ -109,6 +112,9 @@ The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data fr .. note:: If the incoming request has a ``Content-Type`` header set to ``application/json``, the ``getVar()`` method returns the JSON data instead of ``$_REQUEST`` data. +get*() +------ + While this is convenient, you will often need to use a more specific method, like: From 4647fe3046ed4b469d4571ed6381265fe50546f8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 08:59:09 +0900 Subject: [PATCH 076/380] docs: add missing $_COOKIE --- user_guide_src/source/incoming/incomingrequest.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 95c2b570dc6a..26ee9857ed76 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -76,7 +76,8 @@ You can also check if the request was made through and HTTPS connection with the Retrieving Input **************** -You can retrieve input from ``$_SERVER``, ``$_GET``, ``$_POST``, and ``$_ENV`` through the Request object. +You can retrieve input from ``$_GET``, ``$_POST``, ``$_COOKIE``, ``$_SERVER`` +and ``$_ENV`` through the Request object. The data is not automatically filtered and returns the raw input data as passed in the request. .. note:: It is bad practice to use global variables. Basically, it should be avoided From 2032f7d50b53bc6c407d185e1c5488f7538c6c7e Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 08:59:25 +0900 Subject: [PATCH 077/380] docs: fix incorrect sample code getVar() is not guaranteed to get POST data. --- user_guide_src/source/incoming/incomingrequest/008.php | 2 +- user_guide_src/source/incoming/incomingrequest/014.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest/008.php b/user_guide_src/source/incoming/incomingrequest/008.php index c1ee739bf50c..1f75ce279958 100644 --- a/user_guide_src/source/incoming/incomingrequest/008.php +++ b/user_guide_src/source/incoming/incomingrequest/008.php @@ -1,3 +1,3 @@ getVar('foo'); +$something = $request->getPost('foo'); diff --git a/user_guide_src/source/incoming/incomingrequest/014.php b/user_guide_src/source/incoming/incomingrequest/014.php index 564fc543143b..8455402e59b9 100644 --- a/user_guide_src/source/incoming/incomingrequest/014.php +++ b/user_guide_src/source/incoming/incomingrequest/014.php @@ -1,3 +1,3 @@ getVar('email', FILTER_SANITIZE_EMAIL); +$email = $request->getPost('email', FILTER_SANITIZE_EMAIL); From 4e48de908d41241476aecde49936d85626067241 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:01:36 +0900 Subject: [PATCH 078/380] docs: move getVar() section down The method is not recommended. --- .../source/incoming/incomingrequest.rst | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 26ee9857ed76..f111fa44c22d 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -100,37 +100,67 @@ With CodeIgniter's built-in methods you can simply do this: Getting Data ============ -getVar() +getGet() -------- -The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data from ``$_GET``, ``$POST``, or ``$_COOKIE`` (depending on php.ini `request-order `_). - -.. warning:: If you want to validate POST data only, don't use ``getVar()``. - Newer values override older values. POST values may be overridden by the - cookies if they have the same name, and you set "C" after "P" in - `request-order `_. +The ``getGet()`` method will pull from ``$_GET``. -.. note:: If the incoming request has a ``Content-Type`` header set to ``application/json``, - the ``getVar()`` method returns the JSON data instead of ``$_REQUEST`` data. +* ``$request->getGet()`` -get*() ------- +getPost() +--------- -While this -is convenient, you will often need to use a more specific method, like: +The ``getPost()`` method will pull from ``$_POST``. -* ``$request->getGet()`` * ``$request->getPost()`` + +getCookie() +----------- + +The ``getCookie()`` method will pull from ``$_COOKIE``. + * ``$request->getCookie()`` + +getServer() +----------- + +The ``getServer()`` method will pull from ``$_SERVER``. + * ``$request->getServer()`` + +getEnv() +-------- + +The ``getEnv()`` method will pull from ``$_ENV``. + * ``$request->getEnv()`` +getPostGet() +------------ + In addition, there are a few utility methods for retrieving information from either ``$_GET`` or ``$_POST``, while maintaining the ability to control the order you look for it: * ``$request->getPostGet()`` - checks ``$_POST`` first, then ``$_GET`` + +getGetPost() +------------ + * ``$request->getGetPost()`` - checks ``$_GET`` first, then ``$_POST`` +getVar() +-------- + +The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data from ``$_GET``, ``$POST``, or ``$_COOKIE`` (depending on php.ini `request-order `_). + +.. warning:: If you want to validate POST data only, don't use ``getVar()``. + Newer values override older values. POST values may be overridden by the + cookies if they have the same name, and you set "C" after "P" in + `request-order `_. + +.. note:: If the incoming request has a ``Content-Type`` header set to ``application/json``, + the ``getVar()`` method returns the JSON data instead of ``$_REQUEST`` data. + .. _incomingrequest-getting-json-data: Getting JSON Data From ed117dccbdeec230cfb01e85d4edb38cfff31f1f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:06:12 +0900 Subject: [PATCH 079/380] docs: fix indent --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index f111fa44c22d..659861fd4595 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -417,7 +417,7 @@ The methods provided by the parent classes that are available are: :returns: ``$_POST`` if no parameters supplied, otherwise the POST value if found, or null if not :rtype: array|bool|float|int|object|string|null - This method is identical to ``getVar()``, only it fetches POST data. + This method is identical to ``getVar()``, only it fetches POST data. .. php:method:: getPostGet([$index = null[, $filter = null[, $flags = null]]]) From d46f10a2413aa979dd678ae32ac699a0325bc8e7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:07:39 +0900 Subject: [PATCH 080/380] docs: fix incorrect descriptions getVar() does not return POST items. --- user_guide_src/source/incoming/incomingrequest.rst | 6 +++--- user_guide_src/source/incoming/incomingrequest/029.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 659861fd4595..31894ce50e4c 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -378,15 +378,15 @@ The methods provided by the parent classes that are available are: .. literalinclude:: incomingrequest/028.php - To return an array of all POST items call without any parameters. + To return an array of all REQUEST items call without any parameters. - To return all POST items and pass them through the filter, set the + To return all REQUEST items and pass them through the filter, set the first parameter to null while setting the second parameter to the filter you want to use: .. literalinclude:: incomingrequest/029.php - To return an array of multiple POST parameters, pass all the required keys as an array: + To return an array of multiple REQUEST parameters, pass all the required keys as an array: .. literalinclude:: incomingrequest/030.php diff --git a/user_guide_src/source/incoming/incomingrequest/029.php b/user_guide_src/source/incoming/incomingrequest/029.php index 62390522b9b6..98da556e20a8 100644 --- a/user_guide_src/source/incoming/incomingrequest/029.php +++ b/user_guide_src/source/incoming/incomingrequest/029.php @@ -1,4 +1,4 @@ getVar(null, FILTER_SANITIZE_FULL_SPECIAL_CHARS); -// returns all POST items with string sanitation +// returns all REQUEST items with string sanitation From d0c1d5b6e5d08e4997492ab15a1e823fc1a50956 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:16:07 +0900 Subject: [PATCH 081/380] docs: add explanations to getGet() getVar() is not recommended. --- .../source/incoming/incomingrequest.rst | 29 ++++++++++++++++++- .../source/incoming/incomingrequest/041.php | 3 ++ .../source/incoming/incomingrequest/042.php | 3 ++ .../source/incoming/incomingrequest/043.php | 4 +++ .../source/incoming/incomingrequest/044.php | 3 ++ .../source/incoming/incomingrequest/045.php | 3 ++ 6 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 user_guide_src/source/incoming/incomingrequest/041.php create mode 100644 user_guide_src/source/incoming/incomingrequest/042.php create mode 100644 user_guide_src/source/incoming/incomingrequest/043.php create mode 100644 user_guide_src/source/incoming/incomingrequest/044.php create mode 100644 user_guide_src/source/incoming/incomingrequest/045.php diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 31894ce50e4c..714446ee66e6 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -405,7 +405,34 @@ The methods provided by the parent classes that are available are: :returns: ``$_GET`` if no parameters supplied, otherwise the GET value if found, or null if not :rtype: array|bool|float|int|object|string|null - This method is identical to ``getVar()``, only it fetches GET data. + The first parameter will contain the name of the GET item you are looking for: + + .. literalinclude:: incomingrequest/041.php + + The method returns null if the item you are attempting to retrieve + does not exist. + + The second optional parameter lets you run the data through the PHP's + filters. Pass in the desired filter type as the second parameter: + + .. literalinclude:: incomingrequest/042.php + + To return an array of all GET items call without any parameters. + + To return all REQUEST items and pass them through the filter, set the + first parameter to null while setting the second parameter to the filter + you want to use: + + .. literalinclude:: incomingrequest/043.php + + To return an array of multiple GET parameters, pass all the required keys as an array: + + .. literalinclude:: incomingrequest/044.php + + Same rule applied here, to retrieve the parameters with filtering, set the second parameter to + the filter type to apply: + + .. literalinclude:: incomingrequest/045.php .. php:method:: getPost([$index = null[, $filter = null[, $flags = null]]]) diff --git a/user_guide_src/source/incoming/incomingrequest/041.php b/user_guide_src/source/incoming/incomingrequest/041.php new file mode 100644 index 000000000000..b05ea2336c45 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/041.php @@ -0,0 +1,3 @@ +getGet('some_data'); diff --git a/user_guide_src/source/incoming/incomingrequest/042.php b/user_guide_src/source/incoming/incomingrequest/042.php new file mode 100644 index 000000000000..567b26454336 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/042.php @@ -0,0 +1,3 @@ +getGet('some_data', FILTER_SANITIZE_FULL_SPECIAL_CHARS); diff --git a/user_guide_src/source/incoming/incomingrequest/043.php b/user_guide_src/source/incoming/incomingrequest/043.php new file mode 100644 index 000000000000..4bd67d42046c --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/043.php @@ -0,0 +1,4 @@ +getGet(null, FILTER_SANITIZE_FULL_SPECIAL_CHARS); +// returns all GET items with string sanitation diff --git a/user_guide_src/source/incoming/incomingrequest/044.php b/user_guide_src/source/incoming/incomingrequest/044.php new file mode 100644 index 000000000000..3e482e7a8ad4 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/044.php @@ -0,0 +1,3 @@ +getGet(['field1', 'field2']); diff --git a/user_guide_src/source/incoming/incomingrequest/045.php b/user_guide_src/source/incoming/incomingrequest/045.php new file mode 100644 index 000000000000..b0b0de81e1cd --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/045.php @@ -0,0 +1,3 @@ +getGet(['field1', 'field2'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); From 66b8e26fed143536cd1039dbdcc6347b0eeedc5e Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:20:15 +0900 Subject: [PATCH 082/380] docs: remove detailed explanations in getVar() getVar() is not recommended. --- .../source/incoming/incomingrequest.rst | 31 ++----------------- .../source/incoming/incomingrequest/027.php | 3 -- .../source/incoming/incomingrequest/028.php | 3 -- .../source/incoming/incomingrequest/029.php | 4 --- .../source/incoming/incomingrequest/030.php | 3 -- .../source/incoming/incomingrequest/031.php | 3 -- 6 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 user_guide_src/source/incoming/incomingrequest/027.php delete mode 100644 user_guide_src/source/incoming/incomingrequest/028.php delete mode 100644 user_guide_src/source/incoming/incomingrequest/029.php delete mode 100644 user_guide_src/source/incoming/incomingrequest/030.php delete mode 100644 user_guide_src/source/incoming/incomingrequest/031.php diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 714446ee66e6..d7a268dfec24 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -366,34 +366,7 @@ The methods provided by the parent classes that are available are: :returns: ``$_REQUEST`` if no parameters supplied, otherwise the REQUEST value if found, or null if not :rtype: array|bool|float|int|object|string|null - The first parameter will contain the name of the REQUEST item you are looking for: - - .. literalinclude:: incomingrequest/027.php - - The method returns null if the item you are attempting to retrieve - does not exist. - - The second optional parameter lets you run the data through the PHP's - filters. Pass in the desired filter type as the second parameter: - - .. literalinclude:: incomingrequest/028.php - - To return an array of all REQUEST items call without any parameters. - - To return all REQUEST items and pass them through the filter, set the - first parameter to null while setting the second parameter to the filter - you want to use: - - .. literalinclude:: incomingrequest/029.php - - To return an array of multiple REQUEST parameters, pass all the required keys as an array: - - .. literalinclude:: incomingrequest/030.php - - Same rule applied here, to retrieve the parameters with filtering, set the second parameter to - the filter type to apply: - - .. literalinclude:: incomingrequest/031.php + This method is identical to ``getGet()``, only it fetches REQUEST data. .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) @@ -444,7 +417,7 @@ The methods provided by the parent classes that are available are: :returns: ``$_POST`` if no parameters supplied, otherwise the POST value if found, or null if not :rtype: array|bool|float|int|object|string|null - This method is identical to ``getVar()``, only it fetches POST data. + This method is identical to ``getGet()``, only it fetches POST data. .. php:method:: getPostGet([$index = null[, $filter = null[, $flags = null]]]) diff --git a/user_guide_src/source/incoming/incomingrequest/027.php b/user_guide_src/source/incoming/incomingrequest/027.php deleted file mode 100644 index aa4f01787b4b..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/027.php +++ /dev/null @@ -1,3 +0,0 @@ -getVar('some_data'); diff --git a/user_guide_src/source/incoming/incomingrequest/028.php b/user_guide_src/source/incoming/incomingrequest/028.php deleted file mode 100644 index 3bc49822b301..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/028.php +++ /dev/null @@ -1,3 +0,0 @@ -getVar('some_data', FILTER_SANITIZE_FULL_SPECIAL_CHARS); diff --git a/user_guide_src/source/incoming/incomingrequest/029.php b/user_guide_src/source/incoming/incomingrequest/029.php deleted file mode 100644 index 98da556e20a8..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/029.php +++ /dev/null @@ -1,4 +0,0 @@ -getVar(null, FILTER_SANITIZE_FULL_SPECIAL_CHARS); -// returns all REQUEST items with string sanitation diff --git a/user_guide_src/source/incoming/incomingrequest/030.php b/user_guide_src/source/incoming/incomingrequest/030.php deleted file mode 100644 index 9e555a2f3143..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/030.php +++ /dev/null @@ -1,3 +0,0 @@ -getVar(['field1', 'field2']); diff --git a/user_guide_src/source/incoming/incomingrequest/031.php b/user_guide_src/source/incoming/incomingrequest/031.php deleted file mode 100644 index 98c6f35e367d..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/031.php +++ /dev/null @@ -1,3 +0,0 @@ -getVar(['field1', 'field2'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); From 79e517dbcfdf2e71ae32d43804ab2ad0b9d0ae3a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:22:56 +0900 Subject: [PATCH 083/380] docs: fix replacement mistake --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index d7a268dfec24..91fd26fcb6aa 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -492,7 +492,7 @@ The methods provided by the parent classes that are available are: :rtype: array|bool|float|int|object|string|null This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` - methods, only it fetches getServer data (``$_SERVER``): + methods, only it fetches Server data (``$_SERVER``): .. literalinclude:: incomingrequest/036.php From 9f46435d4f9f3c9c88e4078a966a44d9d1fc40e3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:24:12 +0900 Subject: [PATCH 084/380] docs: fix outdated description --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 91fd26fcb6aa..45336f3397e4 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -508,7 +508,7 @@ The methods provided by the parent classes that are available are: :returns: The User Agent string, as found in the SERVER data, or null if not found. :rtype: CodeIgniter\\HTTP\\UserAgent - This method returns the User Agent string from the SERVER data: + This method returns the User Agent instance from the SERVER data: .. literalinclude:: incomingrequest/038.php From 76789fd495307a3fc7571b848c7b2ba0271a5655 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:26:31 +0900 Subject: [PATCH 085/380] docs: add () after function name --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 45336f3397e4..ffcd68e1e14a 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -177,7 +177,7 @@ By default, this will return any objects in the JSON data as objects. If you wan arrays, pass in ``true`` as the first parameter. The second and third parameters match up to the ``depth`` and ``options`` arguments of the -`json_decode `_ PHP function. +`json_decode() `_ PHP function. If the incoming request has a ``Content-Type`` header set to ``application/json``, you can also use ``getVar()`` to get the JSON stream. Using ``getVar()`` in this way will always return an object. From e6faa70e51ed3b6e7f1d43235d2d2d919110b48b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:31:34 +0900 Subject: [PATCH 086/380] docs: remove description getVar() is not recommended. --- user_guide_src/source/incoming/incomingrequest.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index ffcd68e1e14a..fe7d46859ba7 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -179,9 +179,6 @@ arrays, pass in ``true`` as the first parameter. The second and third parameters match up to the ``depth`` and ``options`` arguments of the `json_decode() `_ PHP function. -If the incoming request has a ``Content-Type`` header set to ``application/json``, you can also use ``getVar()`` to get -the JSON stream. Using ``getVar()`` in this way will always return an object. - Getting Specific Data from JSON =============================== From 1e07684cfbd2d450a589d16808d591ec0b8738df Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:36:27 +0900 Subject: [PATCH 087/380] docs: fix param names --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index fe7d46859ba7..d1fad9b7724f 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -176,7 +176,7 @@ You can grab the contents of ``php://input`` as a JSON stream with ``getJSON()`` By default, this will return any objects in the JSON data as objects. If you want that converted to associative arrays, pass in ``true`` as the first parameter. -The second and third parameters match up to the ``depth`` and ``options`` arguments of the +The second and third parameters match up to the ``$depth`` and ``$flags`` arguments of the `json_decode() `_ PHP function. Getting Specific Data from JSON From 099a884e925be54351da62f8b88b03741fca41b3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:39:46 +0900 Subject: [PATCH 088/380] docs: replace getVar() with getJsonVar() getVar() is not recommended. --- user_guide_src/source/incoming/incomingrequest.rst | 7 +++---- user_guide_src/source/incoming/incomingrequest/010.php | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index d1fad9b7724f..ab79d6c149d8 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -182,14 +182,13 @@ The second and third parameters match up to the ``$depth`` and ``$flags`` argume Getting Specific Data from JSON =============================== -You can get a specific piece of data from a JSON stream by passing a variable name into ``getVar()`` for the +You can get a specific piece of data from a JSON stream by passing a variable name into ``getJsonVar()`` for the data that you want or you can use "dot" notation to dig into the JSON to get data that is not on the root level. .. literalinclude:: incomingrequest/010.php -If you want the result to be an associative array instead of an object, you can use ``getJsonVar()`` instead and pass -true in the second parameter. This function can also be used if you can't guarantee that the incoming request will have the -correct ``Content-Type`` header. +If you want the result to be an associative array instead of an object, you can +pass true in the second parameter: .. literalinclude:: incomingrequest/011.php diff --git a/user_guide_src/source/incoming/incomingrequest/010.php b/user_guide_src/source/incoming/incomingrequest/010.php index a199c91bffe2..cf9824d8cd6e 100644 --- a/user_guide_src/source/incoming/incomingrequest/010.php +++ b/user_guide_src/source/incoming/incomingrequest/010.php @@ -10,8 +10,8 @@ * } */ -$data = $request->getVar('foo'); +$data = $request->getJsonVar('foo'); // $data = "bar" -$data = $request->getVar('fizz.buzz'); +$data = $request->getJsonVar('fizz.buzz'); // $data = "baz" From e3c0edcda4cd10bf9f523cc5585078e7b4af4c0c Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:44:24 +0900 Subject: [PATCH 089/380] docs: replace `here` with meaningful text The anchor text `here` is not recommened. --- .../source/incoming/incomingrequest.rst | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index ab79d6c149d8..f2d8d02f8cf2 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -355,10 +355,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getVar([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be found - `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_REQUEST`` if no parameters supplied, otherwise the REQUEST value if found, or null if not :rtype: array|bool|float|int|object|string|null @@ -367,10 +367,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_GET`` if no parameters supplied, otherwise the GET value if found, or null if not :rtype: array|bool|float|int|object|string|null @@ -418,10 +418,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getPostGet([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_POST`` and ``$_GET`` combined if no parameters specified (prefer POST value on conflict), otherwise looks for POST value, if nothing found looks for GET value, if no value found returns null :rtype: array|bool|float|int|object|string|null @@ -438,10 +438,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getGetPost([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_GET`` and ``$_POST`` combined if no parameters specified (prefer GET value on conflict), otherwise looks for GET value, if nothing found looks for POST value, if no value found returns null :rtype: array|bool|float|int|object|string|null @@ -458,10 +458,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getCookie([$index = null[, $filter = null[, $flags = null]]]) :param array|string|null $index: COOKIE name - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_COOKIE`` if no parameters supplied, otherwise the COOKIE value if found or null if not :rtype: array|bool|float|int|object|string|null @@ -480,10 +480,10 @@ The methods provided by the parent classes that are available are: .. php:method:: getServer([$index = null[, $filter = null[, $flags = null]]]) :param array|string|null $index: Value name - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. - :param int $flags: Flags to apply. A list of flags can be found - `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. + :param int $flags: Flags to apply. A list of flags can be found in + `Filter flags `__. :returns: ``$_SERVER`` item value if found, null if not :rtype: array|bool|float|int|object|string|null @@ -499,8 +499,8 @@ The methods provided by the parent classes that are available are: .. php:method:: getUserAgent([$filter = null]) - :param int $filter: The type of filter to apply. A list of filters can be - found `here `__. + :param int $filter: The type of filter to apply. A list of filters can be found in + `Types of filters `__. :returns: The User Agent string, as found in the SERVER data, or null if not found. :rtype: CodeIgniter\\HTTP\\UserAgent From 99538c553c789d5b2415b18a7fdf2541927272c2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:45:38 +0900 Subject: [PATCH 090/380] docs: fix incorrect param There is no param in getUserAgent(). --- user_guide_src/source/incoming/incomingrequest.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index f2d8d02f8cf2..c3f5f7495073 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -497,10 +497,8 @@ The methods provided by the parent classes that are available are: .. literalinclude:: incomingrequest/037.php - .. php:method:: getUserAgent([$filter = null]) + .. php:method:: getUserAgent() - :param int $filter: The type of filter to apply. A list of filters can be found in - `Types of filters `__. :returns: The User Agent string, as found in the SERVER data, or null if not found. :rtype: CodeIgniter\\HTTP\\UserAgent From fb0af42345619fec3f2f76c3b1f0370b9a037f5f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 09:56:59 +0900 Subject: [PATCH 091/380] docs: add note to not recommended method --- user_guide_src/source/incoming/incomingrequest.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index c3f5f7495073..479e64e18278 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -151,6 +151,10 @@ getGetPost() getVar() -------- +.. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + another, more appropriate method. + The ``getVar()`` method will pull from ``$_REQUEST``, so will return any data from ``$_GET``, ``$POST``, or ``$_COOKIE`` (depending on php.ini `request-order `_). .. warning:: If you want to validate POST data only, don't use ``getVar()``. @@ -362,6 +366,10 @@ The methods provided by the parent classes that are available are: :returns: ``$_REQUEST`` if no parameters supplied, otherwise the REQUEST value if found, or null if not :rtype: array|bool|float|int|object|string|null + .. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + another, more appropriate method. + This method is identical to ``getGet()``, only it fetches REQUEST data. .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) From 9399b61bbb56a681c5afbd64412919f31789d382 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 10:05:20 +0900 Subject: [PATCH 092/380] docs: add note to not recommened methods --- 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 0fa702ff10d2..7db0eaf36e0b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -290,6 +290,10 @@ routes defined within this closure are only accessible from the given environmen Routes with any HTTP verbs ========================== +.. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + another, more appropriate method. + .. warning:: While the ``add()`` method seems to be convenient, it is recommended to always use the HTTP-verb-based routes, described above, as it is more secure. If you use the :doc:`CSRF protection `, it does not protect **GET** requests. If the URI specified in the ``add()`` method is accessible by the GET method, the CSRF protection @@ -307,6 +311,10 @@ You can use the ``add()`` method: Mapping Multiple Routes ======================= +.. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + another, more appropriate method. + .. warning:: The ``map()`` method is not recommended as well as ``add()`` because it calls ``add()`` internally. From 6b78a75c431fc3495b0ae030a3401c2790f944bf Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 11:22:32 +0900 Subject: [PATCH 093/380] docs: use validateData() instead of validate() validate() is not recommended. --- .../source/tutorial/create_news_items.rst | 13 ++++++++++++- .../source/tutorial/create_news_items/005.php | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 6443e674d450..6f2c5f997c6e 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -106,11 +106,22 @@ You're going to do three things here: The code above adds a lot of functionality. +Retrieve the Data +^^^^^^^^^^^^^^^^^ + +First, we use the :doc:`IncomingRequest <../incoming/incomingrequest>` +object ``$this->request``, which is set in the controller by the framework. + +We get the necessary items from the **POST** data by the user and set them in the +``$data`` variable. + Validate the Data ^^^^^^^^^^^^^^^^^ -You'll use the Controller-provided helper function :ref:`validate() ` to validate the submitted data. +Next, you'll use the Controller-provided helper function +:ref:`validateData() ` to validate the submitted data. In this case, the title and body fields are required and in the specific length. + CodeIgniter has a powerful validation library as demonstrated above. You can read more about the :doc:`Validation library <../libraries/validation>`. diff --git a/user_guide_src/source/tutorial/create_news_items/005.php b/user_guide_src/source/tutorial/create_news_items/005.php index 6d565789141a..bf3a3e2b3bb0 100644 --- a/user_guide_src/source/tutorial/create_news_items/005.php +++ b/user_guide_src/source/tutorial/create_news_items/005.php @@ -13,8 +13,10 @@ public function create() { helper('form'); + $data = $this->request->getPost(['title', 'body']); + // Checks whether the submitted data passed the validation rules. - if (! $this->validate([ + if (! $this->validateData($data, [ 'title' => 'required|max_length[255]|min_length[3]', 'body' => 'required|max_length[5000]|min_length[10]', ])) { From 8ba7444083569c692efdfb5b1891f178be0c0fcb Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Nov 2023 07:05:21 +0900 Subject: [PATCH 094/380] fix: add check if valid JSON --- system/HTTP/Exceptions/HTTPException.php | 13 +++++++++++++ system/HTTP/IncomingRequest.php | 10 +++++++++- system/Language/en/HTTP.php | 1 + tests/system/HTTP/IncomingRequestTest.php | 13 +++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/system/HTTP/Exceptions/HTTPException.php b/system/HTTP/Exceptions/HTTPException.php index d22c48bcb9f3..32f9ceabd662 100644 --- a/system/HTTP/Exceptions/HTTPException.php +++ b/system/HTTP/Exceptions/HTTPException.php @@ -72,6 +72,19 @@ public static function forInvalidNegotiationType(string $type) return new static(lang('HTTP.invalidNegotiationType', [$type])); } + /** + * Thrown in IncomingRequest when the json_decode() produces + * an error code other than JSON_ERROR_NONE. + * + * @param string $error The error message + * + * @return static + */ + public static function forInvalidJSON(?string $error = null) + { + return new static(lang('HTTP.invalidJSON', [$error])); + } + /** * For Message * diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 307a78d38b4a..f263ad166d77 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -573,10 +573,18 @@ public function getVar($index = null, $filter = null, $flags = null) * @see http://php.net/manual/en/function.json-decode.php * * @return array|bool|float|int|stdClass|null + * + * @throws HTTPException When the body is invalid as JSON. */ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) { - return json_decode($this->body ?? '', $assoc, $depth, $options); + $result = json_decode($this->body ?? '', $assoc, $depth, $options); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw HTTPException::forInvalidJSON(json_last_error_msg()); + } + + return $result; } /** diff --git a/system/Language/en/HTTP.php b/system/Language/en/HTTP.php index a7861c7188d1..e9082f85d185 100644 --- a/system/Language/en/HTTP.php +++ b/system/Language/en/HTTP.php @@ -19,6 +19,7 @@ // IncomingRequest 'invalidNegotiationType' => '"{0}" is not a valid negotiation type. Must be one of: media, charset, encoding, language.', + 'invalidJSON' => 'Failed to parse JSON string. Error: {0}', // Message 'invalidHTTPProtocol' => 'Invalid HTTP Protocol Version: {0}', diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 9f6114f4875e..af7f650329d3 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -528,6 +528,19 @@ public function testGetJSONReturnsNullFromNullBody(): void $this->assertNull($request->getJSON()); } + public function testGetJSONWithInvalidJSONString(): void + { + $this->expectException(HTTPException::class); + $this->expectExceptionMessage('Failed to parse JSON string. Error: Syntax error'); + + $config = new App(); + $config->baseURL = 'http://example.com/'; + $json = 'Invalid JSON string'; + $request = $this->createRequest($config, $json); + + $request->getJSON(); + } + public function testCanGrabGetRawInput(): void { $rawstring = 'username=admin001&role=administrator&usepass=0'; From 4d2a4ba47ca121a6cb90049104bb8075518c4ef7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Nov 2023 07:07:25 +0900 Subject: [PATCH 095/380] test: add test for Validation::withRequest() --- tests/system/Validation/ValidationTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 7cc6f99c40d5..b2db31ad00b0 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Validation; +use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; @@ -789,6 +790,25 @@ public function testJsonInput(): void unset($_SERVER['CONTENT_TYPE']); } + public function testJsonInputInvalid(): void + { + $this->expectException(HTTPException::class); + $this->expectExceptionMessage('Failed to parse JSON string. Error: Syntax error'); + + $config = new App(); + $json = 'invalid'; + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request->setHeader('Content-Type', 'application/json'); + + $rules = [ + 'role' => 'if_exist|max_length[5]', + ]; + $this->validation + ->withRequest($request->withMethod('POST')) + ->setRules($rules) + ->run(); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/6466 */ From a3a7134a4bf84e2ce8c537b86974ee0e3d833fa1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 11:39:42 +0900 Subject: [PATCH 096/380] fix: if body is null, should return null See IncomingRequestTest::testGetJSONReturnsNullFromNullBody() --- system/HTTP/IncomingRequest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index f263ad166d77..48b9f3f61be4 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -578,7 +578,11 @@ public function getVar($index = null, $filter = null, $flags = null) */ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) { - $result = json_decode($this->body ?? '', $assoc, $depth, $options); + if ($this->body === null) { + return null; + } + + $result = json_decode($this->body, $assoc, $depth, $options); if (json_last_error() !== JSON_ERROR_NONE) { throw HTTPException::forInvalidJSON(json_last_error_msg()); From bfcae8dcb3dbde1e76a32f640fa85fd72c922507 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 11:44:09 +0900 Subject: [PATCH 097/380] test: add test for getJSON() and JSON_THROW_ON_ERROR --- tests/system/HTTP/IncomingRequestTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index af7f650329d3..9c323b8e5639 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -18,6 +18,7 @@ use CodeIgniter\Test\CIUnitTestCase; use Config\App; use InvalidArgumentException; +use JsonException; use TypeError; /** @@ -541,6 +542,19 @@ public function testGetJSONWithInvalidJSONString(): void $request->getJSON(); } + public function testGetJSONWithJsonThrowOnErrorAndInvalidJSONString(): void + { + $this->expectException(JsonException::class); + $this->expectExceptionMessage('Syntax error'); + + $config = new App(); + $config->baseURL = 'http://example.com/'; + $json = 'Invalid JSON string'; + $request = $this->createRequest($config, $json); + + $request->getJSON(false, 512, JSON_THROW_ON_ERROR); + } + public function testCanGrabGetRawInput(): void { $rawstring = 'username=admin001&role=administrator&usepass=0'; From d0bf4bc998774899bc982b4d3f9cf127e70aeb57 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 11:53:36 +0900 Subject: [PATCH 098/380] docs: add changelog --- user_guide_src/source/changelogs/v4.4.4.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index bb4250f1e63f..dfc862d62b62 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -31,6 +31,8 @@ and Traditional rules validate data of non-string types. Message Changes *************** +- Added ``HTTP.invalidJSON`` error message. + ******* Changes ******* From eb908d14f9c5c0e342edd7428787dba0c4d982a5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 13:11:13 +0900 Subject: [PATCH 099/380] fix: Undefined array key error --- system/Commands/Database/ShowTableInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Commands/Database/ShowTableInfo.php b/system/Commands/Database/ShowTableInfo.php index f955c6b27011..4c8f1bfd3865 100644 --- a/system/Commands/Database/ShowTableInfo.php +++ b/system/Commands/Database/ShowTableInfo.php @@ -125,7 +125,7 @@ public function run(array $params) $limitRows = (int) ($params['limit-rows'] ?? 10); $limitFieldValue = (int) ($params['limit-field-value'] ?? 15); - if (! in_array($tableName, $tables, true)) { + while (! in_array($tableName, $tables, true)) { $tableNameNo = CLI::promptByKey( ['Here is the list of your database tables:', 'Which table do you want to see?'], $tables, @@ -133,7 +133,7 @@ public function run(array $params) ); CLI::newLine(); - $tableName = $tables[$tableNameNo]; + $tableName = $tables[$tableNameNo] ?? null; } if (array_key_exists('metadata', $params)) { From 698dbf57f77493c350a9fb72b02e460e68abe0e7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 15:36:49 +0900 Subject: [PATCH 100/380] docs: add notes to not recommened withRequest() --- user_guide_src/source/libraries/validation.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 6fc55822b71a..0e172d575f84 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -343,6 +343,10 @@ For example, data returned by multi select dropdown: withRequest() ============= +.. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + another, more appropriate method. + .. warning:: If you want to validate POST data only, don't use ``withRequest()``. This method uses :ref:`$request->getVar() ` which returns ``$_GET``, ``$_POST`` or ``$_COOKIE`` data in that order From 75676bda3b73aab6511ded0be46089966e0993ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 20:59:29 +0900 Subject: [PATCH 101/380] docs: make it clear these rules accept only ASCII alphabets --- user_guide_src/source/libraries/validation.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 6fc55822b71a..c088198bfc9c 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -829,16 +829,16 @@ The following is a list of all the native rules that are available to use: Rule Parameter Description Example ======================= ========== ============================================= =================================================== alpha No Fails if field has anything other than - alphabetic characters. + alphabetic characters in ASCII. alpha_space No Fails if field contains anything other than - alphabetic characters or spaces. + alphabetic characters or spaces in ASCII. alpha_dash No Fails if field contains anything other than alphanumeric characters, underscores or - dashes. + dashes in ASCII. alpha_numeric No Fails if field contains anything other than - alphanumeric characters. + alphanumeric characters in ASCII. alpha_numeric_space No Fails if field contains anything other than - alphanumeric or space characters. + alphanumeric or space characters in ASCII. alpha_numeric_punct No Fails if field contains anything other than alphanumeric, space, or this limited set of punctuation characters: ``~`` (tilde), From b8871133e0482cebbe83d748f6d64c026d3256c7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 06:52:10 +0900 Subject: [PATCH 102/380] docs: fix description Co-authored-by: Michal Sniatala --- user_guide_src/source/incoming/incomingrequest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 479e64e18278..c6db5b28fe4c 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -396,7 +396,7 @@ The methods provided by the parent classes that are available are: To return an array of all GET items call without any parameters. - To return all REQUEST items and pass them through the filter, set the + To return all GET items and pass them through the filter, set the first parameter to null while setting the second parameter to the filter you want to use: From 757973c76acae3e71277434853a012561f80c5d7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 07:36:21 +0900 Subject: [PATCH 103/380] docs: make note more accurate --- user_guide_src/source/incoming/filters.rst | 7 ++++--- user_guide_src/source/incoming/routing.rst | 8 +++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 29462ccc6538..cee8515dcd54 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -204,7 +204,7 @@ filter:check .. versionadded:: 4.3.0 -Check the filters for the route ``/`` with **GET** method: +For example, check the filters for the route ``/`` with **GET** method: .. code-block:: console @@ -220,8 +220,9 @@ The output is like the following: | GET | / | | toolbar | +--------+-------+----------------+---------------+ -You can also see the routes and filters by the ``spark routes`` command. -See :ref:`URI Routing `. +You can also see the routes and filters by the ``spark routes`` command, +but it might not show accurate filters when you use regular expressions for routes. +See :ref:`URI Routing ` for details. **************** Provided Filters diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 0fa702ff10d2..8cb3e37718b8 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -907,7 +907,13 @@ The *Route* column shows the route path to match. The route of a defined route i Since v4.3.0, the *Name* column shows the route name. ``»`` indicates the name is the same as the route path. -.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. If you want to check filters for a route, you can use :ref:`spark filter:check ` command. +.. important:: The system is not perfect. + For routes containing regular expression patterns like ``([^/]+)`` or ``{locale}``, + the *Filters* displayed might not be correct (if you set complicated URI pattern + for the filters in **app/Config/Filters.php**), or it is displayed as ````. + + The :ref:`spark filter:check ` command can be used to check + for 100% accurate filters. Auto Routing (Improved) ----------------------- From e063cbe1be98f6a1830a2a4b889d55e8a3b1d575 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 10:55:32 +0900 Subject: [PATCH 104/380] docs: add about difference in redirec() --- user_guide_src/source/installation/upgrade_4xx.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index bf7ba85fece6..9e8ac1dbe7aa 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -142,7 +142,12 @@ Helpers - In CI4, ``redirect()`` is completely changed from CI3's. - `redirect() Documentation CodeIgniter 3.X `_ - `redirect() Documentation CodeIgniter 4.X <../general/common_functions.html#redirect>`_ - - In CI4, ``redirect()`` returns a ``RedirectResponse`` instance instead of redirecting and terminating script execution. You must return it. + - In CI4, :php:func:`redirect()` returns a ``RedirectResponse`` instance instead of + redirecting and terminating script execution. You must return it from Controllers + or Controller Filters. + - Cookies and Headers you set before calling ``redirect()`` are not automatically + carried over to a ``RedirectResponse``. You need to call ``withCookies()`` + or ``withHeaders()`` manually if you want to send them. - You need to change CI3's ``redirect('login/form')`` to ``return redirect()->to('login/form')``. Hooks From 6ead627af963c0c5e076d515e6f00d8d5332c44d Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 10:56:30 +0900 Subject: [PATCH 105/380] docs: add notes and descriptions for setting cookies --- user_guide_src/source/helpers/cookie_helper.rst | 12 +++++++++++- user_guide_src/source/outgoing/response.rst | 6 +++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 10002e2a9eb5..813025adb185 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -42,6 +42,11 @@ The following functions are available: a description of its use, as this function is an alias for :php:meth:`CodeIgniter\\HTTP\\Response::setCookie()`. + .. note:: This helper function just sets browser cookies to the global response + instance that ``Services::response()`` returns. So, if you create and + return another response instance (e.g., if you call :php:func:`redirect()`), + the cookies set here will not be sent automatically. + .. php:function:: get_cookie($index[, $xssClean = false[, $prefix = '']]) :param string $index: Cookie name @@ -78,6 +83,9 @@ The following functions are available: This function is otherwise identical to :php:func:`set_cookie()`, except that it does not have the ``value`` and ``expire`` parameters. + This also just sets browser cookies for deleting the cookies to the global + response instance that ``Services::response()`` returns. + .. note:: When you use :php:func:`set_cookie()`, if the ``value`` is set to empty string and the ``expire`` is set to ``0``, the cookie will be deleted. If the ``value`` is set to non-empty string and the ``expire`` is set to ``0``, the cookie will only last as long as the browser is open. @@ -95,4 +103,6 @@ The following functions are available: :param string $prefix: Cookie prefix :rtype: bool - Checks if a cookie exists by name. This is an alias of ``Response::hasCookie()``. + Checks if a cookie exists by name in the global response instance that + ``Services::response()`` returns. This is an alias of + :php:meth:`CodeIgniter\\HTTP\\Response::hasCookie()`. diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 539c99180eaa..7dca22dda53a 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -384,7 +384,9 @@ The methods provided by the parent class that are available are: .. note:: Prior to v4.2.7, the default values of ``$secure`` and ``$httponly`` were ``false`` due to a bug, and these values from **app/Config/Cookie.php** were never used. - Sets a cookie containing the values you specify. There are two ways to + Sets a cookie containing the values you specify to the Response instance. + + There are two ways to pass information to this method so that a cookie can be set: Array Method, and Discrete Parameters: @@ -439,6 +441,8 @@ The methods provided by the parent class that are available are: Delete an existing cookie. + .. note:: This also just sets browser cookie for deleting the cookie. + Only the ``name`` is required. The ``prefix`` is only needed if you need to avoid name collisions with From cc15903bc2a80ca128e93a8578c3e84097189f31 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 10:58:22 +0900 Subject: [PATCH 106/380] docs: add explanation for "global response instance" --- user_guide_src/source/outgoing/response.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 7dca22dda53a..ad37311fb6e8 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -12,8 +12,11 @@ a server responding to the client that called it. Working with the Response ========================= -A Response class is instantiated for you and passed into your controllers. It can be accessed through -``$this->response``. Many times you will not need to touch the class directly, since CodeIgniter takes care of +A Response class is instantiated for you and passed into your controllers. It can +be accessed through ``$this->response``. It is the same instance that +``Services::response()`` returns. We call it the global response instance. + +Many times you will not need to touch the class directly, since CodeIgniter takes care of sending the headers and the body for you. This is great if the page successfully created the content it was asked to. When things go wrong, or you need to send very specific status codes back, or even take advantage of the powerful HTTP caching, it's there for you. From d7cbe6f04b05ba48e300bb2bd12abe4ca25e1913 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 10:58:54 +0900 Subject: [PATCH 107/380] docs: make it more readable --- user_guide_src/source/outgoing/response.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index ad37311fb6e8..4cf1c196edbb 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -44,13 +44,16 @@ Setting Headers --------------- Often, you will need to set headers to be set for the response. The Response class makes this very simple to do, -with the ``setHeader()`` method. The first parameter is the name of the header. The second parameter is the value, +with the ``setHeader()`` method. + +The first parameter is the name of the header. The second parameter is the value, which can be either a string or an array of values that will be combined correctly when sent to the client. -Using these functions instead of using the native PHP functions allows you to ensure that no headers are sent -prematurely, causing errors, and makes testing possible. .. literalinclude:: response/004.php +Using these functions instead of using the native PHP functions allows you to ensure that no headers are sent +prematurely, causing errors, and makes testing possible. + If the header exists and can have more than one value, you may use the ``appendHeader()`` and ``prependHeader()`` methods to add the value to the end or beginning of the values list, respectively. The first parameter is the name of the header, while the second is the value to append or prepend. From 8778a7c2fcae7a3f17ed089df84e92023d51e051 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 11:01:09 +0900 Subject: [PATCH 108/380] docs: add sub section titles --- user_guide_src/source/outgoing/response.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 4cf1c196edbb..3d7b81c6970d 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -43,6 +43,9 @@ You can set format an array into either JSON or XML and set the content type hea Setting Headers --------------- +setHeader() +^^^^^^^^^^^ + Often, you will need to set headers to be set for the response. The Response class makes this very simple to do, with the ``setHeader()`` method. @@ -54,12 +57,18 @@ which can be either a string or an array of values that will be combined correct Using these functions instead of using the native PHP functions allows you to ensure that no headers are sent prematurely, causing errors, and makes testing possible. +appendHeader() +^^^^^^^^^^^^^^ + If the header exists and can have more than one value, you may use the ``appendHeader()`` and ``prependHeader()`` methods to add the value to the end or beginning of the values list, respectively. The first parameter is the name of the header, while the second is the value to append or prepend. .. literalinclude:: response/005.php +removeHeader() +^^^^^^^^^^^^^^ + Headers can be removed from the response with the ``removeHeader()`` method, which takes the header name as the only parameter. This is not case-sensitive. From b0ac56d2baf4c5fb60b2d612b6ea7c954375096b Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 11:03:42 +0900 Subject: [PATCH 109/380] docs: add note to setting headers --- user_guide_src/source/outgoing/response.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 3d7b81c6970d..ee115350763f 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -57,6 +57,10 @@ which can be either a string or an array of values that will be combined correct Using these functions instead of using the native PHP functions allows you to ensure that no headers are sent prematurely, causing errors, and makes testing possible. +.. note:: This method just sets headers to the response instance. So, if you create + and return another response instance (e.g., if you call :php:func:`redirect()`), + the headers set here will not be sent automatically. + appendHeader() ^^^^^^^^^^^^^^ From dcc6467b55672dd39d67edd1627976567b323003 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 11:29:59 +0900 Subject: [PATCH 110/380] chore: workaround for UndefinedClass UndefinedClass: Class, interface or enum named SimpleConfig does not exist (see https://psalm.dev/019) --- psalm_autoload.php | 1 + 1 file changed, 1 insertion(+) diff --git a/psalm_autoload.php b/psalm_autoload.php index d0f0c9af46e6..d42636a11fef 100644 --- a/psalm_autoload.php +++ b/psalm_autoload.php @@ -25,6 +25,7 @@ $dirs = [ 'tests/_support/Controllers', + 'tests/system/Config/fixtures', ]; foreach ($dirs as $dir) { From 1cf6cb8a418b19c657e5af9906305b3a21fa6c7e Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Nov 2023 17:39:32 +0900 Subject: [PATCH 111/380] docs: fix @var for $validator --- system/Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Controller.php b/system/Controller.php index 45fe0e499565..c040e1d20a4f 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -65,7 +65,7 @@ class Controller /** * Once validation has been run, will hold the Validation instance. * - * @var ValidationInterface + * @var ValidationInterface|null */ protected $validator; From 98ed457543360c2c36c633dd7b88c1e9dd67cc46 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 07:39:06 +0900 Subject: [PATCH 112/380] docs: add warning to validate() --- .../source/incoming/controllers.rst | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 8bc9e90d581f..e4fa3caafc60 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -87,15 +87,44 @@ modify this by passing the duration (in seconds) as the first parameter: Validating Data *************** +.. _controller-validatedata: + +$this->validateData() +===================== + +.. versionadded:: 4.2.0 + +To simplify data checking, the controller also provides the convenience method +``validateData()``. + +The method accepts an array of data to validate in the first parameter, and an +array of rules in the second parameter, and in the optional third parameter, +an array of custom error messages to display if the items are not valid. + +The :doc:`Validation Library docs ` have details on +rule and message array formats, as well as available rules: + +.. literalinclude:: controllers/006.php + .. _controller-validate: $this->validate() ================= -To simplify data checking, the controller also provides the convenience method ``validate()``. +The controller also provides the convenience method ``validate()``. + +.. warning:: Instead of ``validate()``, use ``validateData()`` to validate POST + data only. ``validate()`` uses ``$request->getVar()`` which returns + ``$_GET``, ``$_POST`` or ``$_COOKIE`` data in that order (depending on php.ini + `request-order `_). + Newer values override older values. POST values may be overridden by the + cookies if they have the same name. + The method accepts an array of rules in the first parameter, and in the optional second parameter, an array of custom error messages to display -if the items are not valid. Internally, this uses the controller's +if the items are not valid. + +Internally, this uses the controller's ``$this->request`` instance to get the data to be validated. The :doc:`Validation Library docs ` have details on @@ -123,19 +152,6 @@ the ``$rules`` array with the name of the group as defined in **app/Config/Valid .. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. -.. _controller-validatedata: - -$this->validateData() -===================== - -.. versionadded:: 4.2.0 - -Sometimes you may want to check the controller method parameters or other custom data. -In that case, you can use the ``$this->validateData()`` method. -The method accepts an array of data to validate in the first parameter: - -.. literalinclude:: controllers/006.php - Protecting Methods ****************** From 37472711c788a3728aff6a6c475f777f91b6e72a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 07:41:54 +0900 Subject: [PATCH 113/380] docs: replace getVar() with getPost() getVar() is not recommended. --- user_guide_src/source/incoming/controllers/006.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers/006.php b/user_guide_src/source/incoming/controllers/006.php index 555a8c98d570..8bf7045411f1 100644 --- a/user_guide_src/source/incoming/controllers/006.php +++ b/user_guide_src/source/incoming/controllers/006.php @@ -8,7 +8,7 @@ public function product(int $id) { $data = [ 'id' => $id, - 'name' => $this->request->getVar('name'), + 'name' => $this->request->getPost('name'), ]; $rule = [ From 71c18481c53a26a907f12a8f91d2c2e63c58ce7f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Nov 2023 11:29:37 +0900 Subject: [PATCH 114/380] docs: add note to not recommened validate() --- user_guide_src/source/incoming/controllers.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index e4fa3caafc60..a901c9fd58eb 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -111,6 +111,10 @@ rule and message array formats, as well as available rules: $this->validate() ================= +.. important:: This method exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + the ``validateData()`` method instead. + The controller also provides the convenience method ``validate()``. .. warning:: Instead of ``validate()``, use ``validateData()`` to validate POST From 04505c74ffe0c49fc45f756473c8780e03953ebe Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 06:29:03 +0900 Subject: [PATCH 115/380] docs: add about missing fourth parameter --- user_guide_src/source/incoming/controllers.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index a901c9fd58eb..bf5a747cb462 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -97,9 +97,9 @@ $this->validateData() To simplify data checking, the controller also provides the convenience method ``validateData()``. -The method accepts an array of data to validate in the first parameter, and an -array of rules in the second parameter, and in the optional third parameter, -an array of custom error messages to display if the items are not valid. +The method accepts (1) an array of data to validate, (2) an array of rules, +(3) an optional array of custom error messages to display if the items are not valid, +(4) an optional database group to use. The :doc:`Validation Library docs ` have details on rule and message array formats, as well as available rules: From f9da010d0ad73edd50d327e8de83ad69b688cf4c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 08:35:42 +0900 Subject: [PATCH 116/380] docs: add note to not recommended Auto Routing (Legacy) --- user_guide_src/source/incoming/controllers.rst | 4 ++++ user_guide_src/source/incoming/routing.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index bf5a747cb462..113e9a50d5df 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -422,6 +422,10 @@ CodeIgniter also permits you to map your URIs using its :ref:`Defined Route Rout Auto Routing (Legacy) ********************* +.. important:: This feature exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + the :ref:`auto-routing-improved` instead. + This section describes the functionality of Auto Routing (Legacy) that is a routing system from CodeIgniter 3. It automatically routes an HTTP request, and executes the corresponding controller method without route definitions. The auto-routing is disabled by default. diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 7db0eaf36e0b..ce753e929c0d 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -801,6 +801,10 @@ will be routed to ``Acme\Blog\Controllers\Foo::getBar()``. Auto Routing (Legacy) ********************* +.. important:: This feature exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you use + the :ref:`auto-routing-improved` instead. + Auto Routing (Legacy) is a routing system from CodeIgniter 3. It can automatically route HTTP requests based on conventions and execute the corresponding controller methods. From b2d99264472e8052331a2e26775d6c6bfbbbb6da Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 08:39:40 +0900 Subject: [PATCH 117/380] docs: add note to not recommended $shareOptions --- user_guide_src/source/libraries/curlrequest.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index f029efc4f883..ebfd1934c88f 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -28,9 +28,11 @@ Config for CURLRequest Sharing Options =============== -.. note:: Since v4.4.0, the default value has been changed to ``false``. This - setting exists only for backward compatibility. New users do not need to - change the setting. +.. important:: This setting exists only for backward compatibility. Do not use it + in new projects. Even if you are already using it, we recommend that you disable + it. + +.. note:: Since v4.4.0, the default value has been changed to ``false``. If you want to share all the options between requests, set ``$shareOptions`` to ``true`` in **app/Config/CURLRequest.php**: From a555953360fb6a545a28a58e3aef34de40c87399 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 08:42:45 +0900 Subject: [PATCH 118/380] docs: add note to not recommended Traditional Rules --- user_guide_src/source/libraries/validation.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index a3dcfa52a817..42782751653c 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -221,6 +221,10 @@ and the new classes (**Strict Rules**) have ``CodeIgniter\Validation\StrictRules Traditional Rules ----------------- +.. important:: Traditional Rules exist only for backward compatibility. Do not + use them in new projects. Even if you are already using, we recommend that + you switch to Strict Rules. + .. warning:: When validating data that contains non-string values, such as JSON data, it is recommended to use **Strict Rules**. The **Traditional Rules** implicitly assume that string values are validated, From 0d518babe9f20820fc67583f3c1d3b1567a21533 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Nov 2023 05:32:42 +0900 Subject: [PATCH 119/380] docs: add missing core classes --- .../source/extending/core_classes.rst | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index efb42c53034e..a1731e7e460a 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -22,26 +22,41 @@ System Class List The following is a list of the core system classes that are invoked every time CodeIgniter runs: * ``CodeIgniter\Autoloader\Autoloader`` +* ``CodeIgniter\Autoloader\FileLocator`` +* ``CodeIgniter\Cache\CacheFactory`` +* ``CodeIgniter\Cache\Handlers\BaseHandler`` +* ``CodeIgniter\Cache\Handlers\FileHandler`` +* ``CodeIgniter\Cache\ResponseCache`` * ``CodeIgniter\CodeIgniter`` +* ``CodeIgniter\Config\BaseService`` * ``CodeIgniter\Config\DotEnv`` +* ``CodeIgniter\Config\Factories`` * ``CodeIgniter\Config\Services`` * ``CodeIgniter\Controller`` +* ``CodeIgniter\Cookie\Cookie`` +* ``CodeIgniter\Cookie\CookieStore`` * ``CodeIgniter\Debug\Exceptions`` * ``CodeIgniter\Debug\Timer`` * ``CodeIgniter\Events\Events`` * ``CodeIgniter\Filters\Filters`` -* ``CodeIgniter\HTTP\ContentSecurityPolicy`` * ``CodeIgniter\HTTP\CLIRequest`` (if launched from command line only) +* ``CodeIgniter\HTTP\ContentSecurityPolicy`` +* ``CodeIgniter\HTTP\Header`` * ``CodeIgniter\HTTP\IncomingRequest`` (if launched over HTTP) +* ``CodeIgniter\HTTP\Message`` +* ``CodeIgniter\HTTP\OutgoingRequest`` * ``CodeIgniter\HTTP\Request`` * ``CodeIgniter\HTTP\Response`` -* ``CodeIgniter\HTTP\Message`` +* ``CodeIgniter\HTTP\SiteURI`` +* ``CodeIgniter\HTTP\SiteURIFactory`` * ``CodeIgniter\HTTP\URI`` +* ``CodeIgniter\HTTP\UserAgent`` (if launched over HTTP) * ``CodeIgniter\Log\Logger`` * ``CodeIgniter\Log\Handlers\BaseHandler`` * ``CodeIgniter\Log\Handlers\FileHandler`` * ``CodeIgniter\Router\RouteCollection`` * ``CodeIgniter\Router\Router`` +* ``CodeIgniter\Superglobals`` * ``CodeIgniter\View\View`` Replacing Core Classes From d07c73cca4b85bd25f3c49d047d77865ba053153 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Nov 2023 07:54:56 +0900 Subject: [PATCH 120/380] docs: fix by proofreading Co-authored-by: Michal Sniatala --- user_guide_src/source/libraries/validation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 42782751653c..df48ce2ed55b 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -222,8 +222,8 @@ Traditional Rules ----------------- .. important:: Traditional Rules exist only for backward compatibility. Do not - use them in new projects. Even if you are already using, we recommend that - you switch to Strict Rules. + use them in new projects. Even if you are already using them, we recommend + switching to Strict Rules. .. warning:: When validating data that contains non-string values, such as JSON data, it is recommended to use **Strict Rules**. From 1a25f1bfd80e47a29da995cfeed2f9ec05be410a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 09:16:28 +0900 Subject: [PATCH 121/380] refactor: replace non bool if conditions --- phpstan-baseline.php | 7 +------ system/BaseModel.php | 14 +++++++------- system/Model.php | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 3cbe5a4732fc..beb2d85a4d84 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -56,11 +56,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/BaseModel.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in &&, string given on the right side\\.$#', - 'count' => 7, - 'path' => __DIR__ . '/system/BaseModel.php', -]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in a ternary operator condition, array\\|null given\\.$#', 'count' => 1, @@ -2628,7 +2623,7 @@ ]; $ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in &&, string given on the right side\\.$#', - 'count' => 3, + 'count' => 2, 'path' => __DIR__ . '/system/Model.php', ]; $ignoreErrors[] = [ diff --git a/system/BaseModel.php b/system/BaseModel.php index 80baaf3fb024..e8e746e64c25 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -770,11 +770,11 @@ public function insert($data = null, bool $returnID = true) // Set created_at and updated_at with same time $date = $this->setDate(); - if ($this->useTimestamps && $this->createdField && ! array_key_exists($this->createdField, $data)) { + if ($this->useTimestamps && $this->createdField !== '' && ! array_key_exists($this->createdField, $data)) { $data[$this->createdField] = $date; } - if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $data)) { + if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, $data)) { $data[$this->updatedField] = $date; } @@ -857,11 +857,11 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch // Set created_at and updated_at with same time $date = $this->setDate(); - if ($this->useTimestamps && $this->createdField && ! array_key_exists($this->createdField, $row)) { + if ($this->useTimestamps && $this->createdField !== '' && ! array_key_exists($this->createdField, $row)) { $row[$this->createdField] = $date; } - if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $row)) { + if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, $row)) { $row[$this->updatedField] = $date; } } @@ -929,7 +929,7 @@ public function update($id = null, $data = null): bool throw DataException::forEmptyDataset('update'); } - if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $data)) { + if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, $data)) { $data[$this->updatedField] = $this->setDate(); } @@ -1014,7 +1014,7 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc $row[$index] = $updateIndex; } - if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $row)) { + if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, $row)) { $row[$this->updatedField] = $this->setDate(); } } @@ -1147,7 +1147,7 @@ public function replace(?array $data = null, bool $returnSQL = false) return false; } - if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, (array) $data)) { + if ($this->useTimestamps && $this->updatedField !== '' && ! array_key_exists($this->updatedField, (array) $data)) { $data[$this->updatedField] = $this->setDate(); } diff --git a/system/Model.php b/system/Model.php index e53c0aae4bd1..1873804a3c2d 100644 --- a/system/Model.php +++ b/system/Model.php @@ -435,7 +435,7 @@ protected function doDelete($id = null, bool $purge = false) $set[$this->deletedField] = $this->setDate(); - if ($this->useTimestamps && $this->updatedField) { + if ($this->useTimestamps && $this->updatedField !== '') { $set[$this->updatedField] = $this->setDate(); } From 698a30569d65d5ac03356828e945ca4c060e60c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 09:17:17 +0900 Subject: [PATCH 122/380] docs: clarify what "empty" is --- 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 db4ecd80b59d..43fdbb9d6f18 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -180,13 +180,13 @@ $createdField ^^^^^^^^^^^^^ Specifies which database field to use for data record create timestamp. -Leave it empty to avoid updating it (even if ``$useTimestamps`` is enabled). +Leave it empty (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Leave it empty to avoid update it (even ``$useTimestamps`` is enabled). +Leave it empty (``''``) to avoid update it (even ``$useTimestamps`` is enabled). $deletedField ^^^^^^^^^^^^^ From 72e769562557207ccdcf69f746d1d39869608981 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 09:20:16 +0900 Subject: [PATCH 123/380] docs: fix typo --- 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 43fdbb9d6f18..6a2700520fd0 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -186,7 +186,7 @@ $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Leave it empty (``''``) to avoid update it (even ``$useTimestamps`` is enabled). +Leave it empty (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). $deletedField ^^^^^^^^^^^^^ From 064b8b0060f1b062c83f9a052337120fc2fecd51 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 17:32:34 +0900 Subject: [PATCH 124/380] test: add test for classname filter --- tests/system/Test/FilterTestTraitTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index bebec3857030..c05ea29ed340 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -73,6 +73,14 @@ public function testCallerSupportArray(): void $this->assertSame('http://hellowworld.com', $result->getBody()); } + public function testCallerSupportClassname(): void + { + $caller = $this->getFilterCaller(Customfilter::class, 'before'); + $result = $caller(); + + $this->assertSame('http://hellowworld.com', $result->getBody()); + } + public function testCallerUsesClonedInstance(): void { $caller = $this->getFilterCaller('test-customfilter', 'before'); From 0dc64cd66b8aa1a5c9c8e8833e9cea3c6571549d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 17:33:01 +0900 Subject: [PATCH 125/380] fix: ErrorException : Undefined variable $filterClasses --- system/Test/FilterTestTrait.php | 37 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 084a6cd082fc..523717e54679 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -125,6 +125,10 @@ protected function getFilterCaller($filter, string $position): Closure throw new InvalidArgumentException('Invalid filter position passed: ' . $position); } + if ($filter instanceof FilterInterface) { + $filterInstances = [$filter]; + } + if (is_string($filter)) { // Check for an alias (no namespace) if (strpos($filter, '\\') === false) { @@ -132,28 +136,31 @@ protected function getFilterCaller($filter, string $position): Closure throw new RuntimeException("No filter found with alias '{$filter}'"); } - $filterClasses = $this->filtersConfig->aliases[$filter]; + $filterClasses = (array) $this->filtersConfig->aliases[$filter]; + } else { + // FQCN + $filterClasses = [$filter]; } - $filterClasses = (array) $filterClasses; - } + $filterInstances = []; - foreach ($filterClasses as $class) { - // Get an instance - $filter = new $class(); + foreach ($filterClasses as $class) { + // Get an instance + $filter = new $class(); - if (! $filter instanceof FilterInterface) { - throw FilterException::forIncorrectInterface(get_class($filter)); + if (! $filter instanceof FilterInterface) { + throw FilterException::forIncorrectInterface(get_class($filter)); + } + + $filterInstances[] = $filter; } } $request = clone $this->request; if ($position === 'before') { - return static function (?array $params = null) use ($filterClasses, $request) { - foreach ($filterClasses as $class) { - $filter = new $class(); - + return static function (?array $params = null) use ($filterInstances, $request) { + foreach ($filterInstances as $filter) { $result = $filter->before($request, $params); // @TODO The following logic is in Filters class. @@ -177,10 +184,8 @@ protected function getFilterCaller($filter, string $position): Closure $response = clone $this->response; - return static function (?array $params = null) use ($filterClasses, $request, $response) { - foreach ($filterClasses as $class) { - $filter = new $class(); - + return static function (?array $params = null) use ($filterInstances, $request, $response) { + foreach ($filterInstances as $filter) { $result = $filter->after($request, $response, $params); // @TODO The following logic is in Filters class. From 7dc70874518006c7946c19aaa46fc8e1a351dd84 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 18:55:42 +0900 Subject: [PATCH 126/380] test: add test for Filter instance --- tests/system/Test/FilterTestTraitTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index c05ea29ed340..300bc2b47425 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -81,6 +81,14 @@ public function testCallerSupportClassname(): void $this->assertSame('http://hellowworld.com', $result->getBody()); } + public function testCallerSupportsFilterInstance(): void + { + $caller = $this->getFilterCaller(new Customfilter(), 'before'); + $result = $caller(); + + $this->assertSame('http://hellowworld.com', $result->getBody()); + } + public function testCallerUsesClonedInstance(): void { $caller = $this->getFilterCaller('test-customfilter', 'before'); From e7bd962eaa59f9431e286f72b487b24394d08aa1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 18:56:36 +0900 Subject: [PATCH 127/380] test: fix test method names --- tests/system/Test/FilterTestTraitTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index 300bc2b47425..dda0ca0d3265 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -63,7 +63,7 @@ public function testGetCallerInvalidPosition(): void $this->getFilterCaller('test-customfilter', 'banana'); } - public function testCallerSupportArray(): void + public function testCallerSupportsArray(): void { $this->filtersConfig->aliases['test-customfilter'] = [Customfilter::class]; @@ -73,7 +73,7 @@ public function testCallerSupportArray(): void $this->assertSame('http://hellowworld.com', $result->getBody()); } - public function testCallerSupportClassname(): void + public function testCallerSupportsClassname(): void { $caller = $this->getFilterCaller(Customfilter::class, 'before'); $result = $caller(); From 396dca92c0c8e9f16c35665e5f4d58761905a3f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 10:47:36 +0900 Subject: [PATCH 128/380] test: update tests to use SiteURI --- tests/system/API/ResponseTraitTest.php | 15 +-- tests/system/Cache/ResponseCacheTest.php | 4 +- tests/system/CommonFunctionsTest.php | 8 +- tests/system/ControllerTest.php | 4 +- tests/system/Filters/InvalidCharsTest.php | 4 +- .../HTTP/IncomingRequestDetectingTest.php | 3 +- tests/system/HTTP/IncomingRequestTest.php | 7 +- tests/system/Helpers/CookieHelperTest.php | 4 +- tests/system/Pager/PagerTest.php | 7 +- .../system/RESTful/ResourceControllerTest.php | 6 +- .../SecurityCSRFCookieRandomizeTokenTest.php | 5 +- .../SecurityCSRFSessionRandomizeTokenTest.php | 51 +++++------ .../Security/SecurityCSRFSessionTest.php | 43 ++++----- tests/system/Security/SecurityTest.php | 91 +++++-------------- tests/system/Validation/ValidationTest.php | 16 ++-- 15 files changed, 110 insertions(+), 158 deletions(-) diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index c867f1b4a94e..708235e9fbd9 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -15,7 +15,7 @@ use CodeIgniter\Format\FormatterInterface; use CodeIgniter\Format\JSONFormatter; use CodeIgniter\Format\XMLFormatter; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockIncomingRequest; @@ -42,7 +42,7 @@ protected function setUp(): void $this->formatter = new JSONFormatter(); } - protected function makeController(array $userConfig = [], string $uri = 'http://example.com', array $userHeaders = []) + protected function makeController(array $userConfig = [], string $routePath = '', array $userHeaders = []) { $config = new App(); @@ -73,7 +73,7 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// Factories::injectMock('config', 'Cookie', $cookie); if ($this->request === null) { - $this->request = new MockIncomingRequest($config, new URI($uri), null, new UserAgent()); + $this->request = new MockIncomingRequest($config, new SiteURI($config, $routePath), null, new UserAgent()); $this->response = new MockResponse($config); } @@ -115,7 +115,7 @@ public function resetFormatter(): void public function testNoFormatterJSON(): void { $this->formatter = null; - $controller = $this->makeController([], 'http://codeigniter.com', ['Accept' => 'application/json']); + $controller = $this->makeController([], '', ['Accept' => 'application/json']); $this->invoke($controller, 'respondCreated', [['id' => 3], 'A Custom Reason']); @@ -133,7 +133,7 @@ public function testNoFormatterJSON(): void public function testNoFormatter(): void { $this->formatter = null; - $controller = $this->makeController([], 'http://codeigniter.com', ['Accept' => 'application/json']); + $controller = $this->makeController([], '', ['Accept' => 'application/json']); $this->invoke($controller, 'respondCreated', ['A Custom Reason']); @@ -484,8 +484,9 @@ private function tryValidContentType($mimeType, $contentType): void $original = $_SERVER; $_SERVER['CONTENT_TYPE'] = $mimeType; - $this->makeController([], 'http://codeigniter.com', ['Accept' => $mimeType]); + $this->makeController([], '', ['Accept' => $mimeType]); $this->assertSame($mimeType, $this->request->getHeaderLine('Accept'), 'Request header...'); + $this->response->setContentType($contentType); $this->assertSame($contentType, $this->response->getHeaderLine('Content-Type'), 'Response header pre-response...'); @@ -554,7 +555,7 @@ public function testFormatByRequestNegotiateIfFormatIsNotJsonOrXML(): void } Factories::injectMock('config', 'Cookie', $cookie); - $request = new MockIncomingRequest($config, new URI($config->baseURL), null, new UserAgent()); + $request = new MockIncomingRequest($config, new SiteURI($config), null, new UserAgent()); $response = new MockResponse($config); $controller = new class ($request, $response) { diff --git a/tests/system/Cache/ResponseCacheTest.php b/tests/system/Cache/ResponseCacheTest.php index 12eaeb1a2d23..b34cfce95c37 100644 --- a/tests/system/Cache/ResponseCacheTest.php +++ b/tests/system/Cache/ResponseCacheTest.php @@ -15,7 +15,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use Config\App as AppConfig; @@ -53,7 +53,7 @@ private function createIncomingRequest( $appConfig ??= $this->appConfig; - $siteUri = new URI($appConfig->baseURL . $uri); + $siteUri = new SiteURI($appConfig, $uri); if ($query !== []) { $_GET = $_REQUEST = $query; $siteUri->setQueryArray($query); diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index b6702c5a7376..228a24e9a26f 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -18,7 +18,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Session\Handlers\FileHandler; @@ -411,7 +411,7 @@ public function testOldInput(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); // setup & ask for a redirect... @@ -446,7 +446,7 @@ public function testOldInputSerializeData(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); // setup & ask for a redirect... @@ -481,7 +481,7 @@ public function testOldInputArray(): void $this->routes = $this->createRouteCollection(); Services::injectMock('routes', $this->routes); - $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + $this->request = new MockIncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); Services::injectMock('request', $this->request); $locations = [ diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 668cf9b1bc68..14756039c161 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -16,7 +16,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Validation\Exceptions\ValidationException; @@ -58,7 +58,7 @@ protected function setUp(): void parent::setUp(); $this->config = new App(); - $this->request = new IncomingRequest($this->config, new URI('https://somwhere.com'), null, new UserAgent()); + $this->request = new IncomingRequest($this->config, new SiteURI($this->config), null, new UserAgent()); $this->response = new Response($this->config); $this->logger = Services::logger(); } diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 6289ae755ce0..a7c40ebe8b20 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -13,7 +13,7 @@ use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; @@ -53,7 +53,7 @@ protected function tearDown(): void private function createRequest(): IncomingRequest { $config = new MockAppConfig(); - $uri = new URI(); + $uri = new SiteURI($config); $userAgent = new UserAgent(); $request = $this->getMockBuilder(IncomingRequest::class) ->setConstructorArgs([$config, $uri, null, $userAgent]) diff --git a/tests/system/HTTP/IncomingRequestDetectingTest.php b/tests/system/HTTP/IncomingRequestDetectingTest.php index 481821dd922b..9984e8d825b3 100644 --- a/tests/system/HTTP/IncomingRequestDetectingTest.php +++ b/tests/system/HTTP/IncomingRequestDetectingTest.php @@ -32,8 +32,7 @@ protected function setUp(): void $_POST = $_GET = $_SERVER = $_REQUEST = $_ENV = $_COOKIE = $_SESSION = []; // The URI object is not used in detectPath(). - $origin = 'http://www.example.com/index.php/woot?code=good#pos'; - $this->request = new IncomingRequest(new App(), new URI($origin), null, new UserAgent()); + $this->request = new IncomingRequest(new App(), new SiteURI(new App(), 'woot?code=good#pos'), null, new UserAgent()); } public function testPathDefault(): void diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 9f6114f4875e..f9000d90001f 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -223,7 +223,7 @@ public function testSetValidLocales() $config->defaultLocale = 'es'; $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), null, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $request->setValidLocales(['ja']); $request->setLocale('ja'); @@ -901,7 +901,7 @@ public function testExtensionPHP($path, $detectPath): void $_SERVER['REQUEST_URI'] = $path; $_SERVER['SCRIPT_NAME'] = $path; - $request = new IncomingRequest($config, new URI($path), null, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config, $path), null, new UserAgent()); $this->assertSame($detectPath, $request->detectPath()); } @@ -914,7 +914,8 @@ public function testGetPath(): void public function testSetPath(): void { - $request = new IncomingRequest(new App(), new URI(), null, new UserAgent()); + $config = new App(); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $this->assertSame('', $request->getPath()); $request->setPath('foobar'); diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index 45796658fecc..73f05123ab88 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -15,7 +15,7 @@ use CodeIgniter\Cookie\Exceptions\CookieException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockResponse; @@ -49,7 +49,7 @@ protected function setUp(): void Services::injectMock('response', new MockResponse(new App())); $this->response = Services::response(); - $this->request = new IncomingRequest(new App(), new URI(), null, new UserAgent()); + $this->request = new IncomingRequest(new App(), new SiteURI(new App()), null, new UserAgent()); Services::injectMock('request', $this->request); helper('cookie'); diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 63ae20d3cd0c..f5059f082b53 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Pager\Exceptions\PagerException; @@ -53,7 +54,7 @@ private function createPager(string $requestUri): void $request = new IncomingRequest( $config, - new URI($config->baseURL . ltrim($requestUri, '/')), + new SiteURI($config, ltrim($requestUri, '/')), 'php://input', new UserAgent() ); @@ -70,7 +71,7 @@ public function testSetPathRemembersPath(): void $details = $this->pager->getDetails(); - $this->assertSame('foo/bar', $details['uri']->getPath()); + $this->assertSame('foo/bar', $details['uri']->getRoutePath()); } public function testGetDetailsRecognizesPageQueryVar(): void @@ -474,7 +475,7 @@ public function testBasedURI(): void $request = new IncomingRequest( $config, - new URI(), + new SiteURI($config, 'x/y'), 'php://input', new UserAgent() ); diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index bd52bd0d31a5..284754280929 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -17,7 +17,7 @@ use CodeIgniter\Format\XMLFormatter; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Model; use CodeIgniter\Router\RouteCollection; @@ -312,7 +312,7 @@ public function testJSONFormatOutput(): void $resource = new MockResourceController(); $config = new App(); - $uri = new URI(); + $uri = new SiteURI($config); $agent = new UserAgent(); $request = new IncomingRequest($config, $uri, '', $agent); @@ -340,7 +340,7 @@ public function testXMLFormatOutput(): void $resource = new MockResourceController(); $config = new App(); - $uri = new URI(); + $uri = new SiteURI($config); $agent = new UserAgent(); $request = new IncomingRequest($config, $uri, '', $agent); diff --git a/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php index b0c1ef8ec707..a5c014814035 100644 --- a/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFCookieRandomizeTokenTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Cookie\Cookie; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockAppConfig; @@ -74,7 +74,8 @@ public function testCSRFVerifySetNewCookie(): void $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = $this->randomizedToken; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $config = new MockAppConfig(); + $request = new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); $security = new Security($this->config); diff --git a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php index 7c8af63040f4..e16093b76418 100644 --- a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Handlers\ArrayHandler; @@ -25,6 +25,7 @@ use CodeIgniter\Test\Mock\MockSecurity; use CodeIgniter\Test\Mock\MockSession; use CodeIgniter\Test\TestLogger; +use Config\App; use Config\Cookie; use Config\Logger as LoggerConfig; use Config\Security as SecurityConfig; @@ -136,13 +137,19 @@ public function testCSRFVerifyPostNoToken(): void $_SERVER['REQUEST_METHOD'] = 'POST'; unset($_POST['csrf_test_name']); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); } + private function createIncomingRequest(?App $config = null): IncomingRequest + { + $config ??= new MockAppConfig(); + + return new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); + } + public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void { $this->expectException(SecurityException::class); @@ -151,8 +158,7 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); @@ -166,8 +172,7 @@ public function testCSRFVerifyPostInvalidToken(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '!'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); @@ -179,8 +184,7 @@ public function testCSRFVerifyPostReturnsSelfOnMatch(): void $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = $this->randomizedToken; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -192,9 +196,8 @@ public function testCSRFVerifyPOSTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -208,9 +211,8 @@ public function testCSRFVerifyPOSTHeaderReturnsSelfOnMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', $this->randomizedToken); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -222,9 +224,8 @@ public function testCSRFVerifyPUTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -237,9 +238,8 @@ public function testCSRFVerifyPUTHeaderReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', $this->randomizedToken); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -250,9 +250,8 @@ public function testCSRFVerifyPUTBodyReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody("csrf_test_name={$this->randomizedToken}&foo=bar"); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -266,9 +265,8 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}'); - $security = $this->createSecurity(); $security->verify($request); @@ -278,9 +276,8 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"' . $this->randomizedToken . '","foo":"bar"}'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -298,9 +295,8 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void $config->regenerate = false; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - - $security = new MockSecurity($this->config); + $request = $this->createIncomingRequest(); + $security = new MockSecurity($config); $oldHash = $security->getHash(); $security->verify($request); @@ -319,8 +315,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void $config->regenerate = true; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php index 1d701520488c..cc5b56eae33a 100644 --- a/tests/system/Security/SecurityCSRFSessionTest.php +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Handlers\ArrayHandler; @@ -24,6 +24,7 @@ use CodeIgniter\Test\Mock\MockAppConfig; use CodeIgniter\Test\Mock\MockSession; use CodeIgniter\Test\TestLogger; +use Config\App; use Config\Cookie; use Config\Logger as LoggerConfig; use Config\Security as SecurityConfig; @@ -125,21 +126,26 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $security->verify($request); } + private function createIncomingRequest(?App $config = null): IncomingRequest + { + $config ??= new MockAppConfig(); + + return new IncomingRequest($config, new SiteURI($config), null, new UserAgent()); + } + public function testCSRFVerifyPostReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -151,9 +157,8 @@ public function testCSRFVerifyPOSTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -165,9 +170,8 @@ public function testCSRFVerifyPOSTHeaderReturnsSelfOnMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -179,9 +183,8 @@ public function testCSRFVerifyPUTHeaderThrowsExceptionOnNoMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); - $security = $this->createSecurity(); $this->expectException(SecurityException::class); @@ -192,9 +195,8 @@ public function testCSRFVerifyPUTHeaderReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -205,9 +207,8 @@ public function testCSRFVerifyPUTBodyReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'PUT'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a&foo=bar'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -220,9 +221,8 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}'); - $security = $this->createSecurity(); $security->verify($request); @@ -232,9 +232,8 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = $this->createIncomingRequest(); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}'); - $security = $this->createSecurity(); $this->assertInstanceOf(Security::class, $security->verify($request)); @@ -251,8 +250,7 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void $config->regenerate = false; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); @@ -271,8 +269,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void $config->regenerate = true; Factories::injectMock('config', 'Security', $config); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - + $request = $this->createIncomingRequest(); $security = $this->createSecurity(); $oldHash = $security->getHash(); diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index ae4953607662..f10c79e5fb7c 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -14,7 +14,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; @@ -101,17 +101,24 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $this->expectException(SecurityException::class); $security->verify($request); } + private function createIncomingRequest(): IncomingRequest + { + $config = new MockAppConfig(); + + return new IncomingRequest( + $config, + new SiteURI($config), + null, + new UserAgent() + ); + } + public function testCSRFVerifyPostReturnsSelfOnMatch(): void { $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -120,12 +127,7 @@ public function testCSRFVerifyPostReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -139,12 +141,7 @@ public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -159,12 +156,7 @@ public function testCSRFVerifyHeaderReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -180,12 +172,7 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a"}' @@ -201,12 +188,7 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}' @@ -224,12 +206,7 @@ public function testCSRFVerifyPutBodyThrowsExceptionOnNoMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a' @@ -245,12 +222,7 @@ public function testCSRFVerifyPutBodyReturnsSelfOnMatch(): void $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = $this->createMockSecurity(); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $request->setBody( 'csrf_test_name=8b9218a55906f9dcc1dc263dce7f005a&foo=bar' @@ -282,12 +254,7 @@ public function testRegenerateWithFalseSecurityRegenerateProperty(): void Factories::injectMock('config', 'Security', $config); $security = new MockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); @@ -307,12 +274,7 @@ public function testRegenerateWithFalseSecurityRegeneratePropertyManually(): voi Factories::injectMock('config', 'Security', $config); $security = $this->createMockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); @@ -333,12 +295,7 @@ public function testRegenerateWithTrueSecurityRegenerateProperty(): void Factories::injectMock('config', 'Security', $config); $security = $this->createMockSecurity($config); - $request = new IncomingRequest( - new MockAppConfig(), - new URI('http://badurl.com'), - null, - new UserAgent() - ); + $request = $this->createIncomingRequest(); $oldHash = $security->getHash(); $security->verify($request); diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 7cc6f99c40d5..fbc8f2ace5f6 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Validation; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\SiteURI; use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Validation\Exceptions\ValidationException; @@ -748,7 +748,7 @@ public function testRawInput(): void $rawstring = 'username=admin001&role=administrator&usepass=0'; $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $rawstring, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $rawstring, new UserAgent()); $rules = [ 'role' => 'required|min_length[5]', @@ -772,7 +772,7 @@ public function testJsonInput(): void $json = json_encode($data); $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $json, new UserAgent()); $rules = [ 'role' => 'required|min_length[5]', @@ -809,7 +809,7 @@ public function testJsonInputObjectArray(): void $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $json, new UserAgent()); $rules = [ 'p' => 'required|array_count[2]', @@ -995,7 +995,7 @@ public function testRulesForArrayField(array $body, array $rules, array $results $config = new App(); $config->baseURL = 'http://example.com/'; - $request = new IncomingRequest($config, new URI(), http_build_query($body), new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), http_build_query($body), new UserAgent()); $this->validation->setRules($rules); $this->validation->withRequest($request->withMethod('post'))->run($body); @@ -1074,7 +1074,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnNoError(): void ], ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user.*' => 'numeric', @@ -1108,7 +1108,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError(): void ], ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user.*' => 'numeric', @@ -1144,7 +1144,7 @@ public function testRulesForSingleRuleWithSingleValue(): void 'id_user' => 'gh', ]; - $request = new IncomingRequest($config, new URI(), 'php://input', new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), 'php://input', new UserAgent()); $this->validation->setRules([ 'id_user' => 'numeric', From ee7020f2185de2a9ccfca915631643e6b41eebf4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 06:49:06 +0900 Subject: [PATCH 129/380] docs: add missing `get` in method name --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 92daf06b7be6..3ba27117468f 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -763,7 +763,7 @@ when a controller is found that matches the URI, but no segment exists for the m ``index``. In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the -``Products::listAll()`` method would be executed: +``Products::getListAll()`` method would be executed: .. literalinclude:: routing/048.php From 0cdd2996588e3f0c5383d35ece4c5e55a3fb601e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 07:05:13 +0900 Subject: [PATCH 130/380] docs: add about Controller returns string/Response --- user_guide_src/source/incoming/controllers.rst | 4 +++- user_guide_src/source/installation/upgrade_controllers.rst | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index bf5a747cb462..eda94fcf447a 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -11,7 +11,9 @@ Controllers are the heart of your application, as they determine how HTTP reques What is a Controller? ********************* -A Controller is simply a class file that handles a HTTP request. :doc:`URI Routing ` associates a URI with a controller. +A Controller is simply a class file that handles a HTTP request. +:doc:`URI Routing ` associates a URI with a controller. It returns a +view string or ``Response`` object. Every controller you create should extend ``BaseController`` class. This class provides several features that are available to all of your controllers. diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index cd5f17fd3d22..1a2dc9a9b4ce 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -20,6 +20,8 @@ What has been changed - CI4 provides :doc:`Request ` and :doc:`Responses ` objects for you to work with - more powerful than the CI3-way. - If you want a base controller (``MY_Controller`` in CI3), use **app/Controllers/BaseController.php**. +- Calling ``echo`` within Controllers, as in CI3, is still supported, but + it is recommended that a string or Response object be returned from Controllers. Upgrade Guide ============= From fbd0ebe7e6c82340ef4cb1ac0db74f8944a8cb2a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 08:33:27 +0900 Subject: [PATCH 131/380] docs: change expressions --- 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 6a2700520fd0..d8cefa02c1cb 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -180,13 +180,13 @@ $createdField ^^^^^^^^^^^^^ Specifies which database field to use for data record create timestamp. -Leave it empty (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Leave it empty (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). $deletedField ^^^^^^^^^^^^^ From ac4430863401c15882b33fc7fa6625391ef85690 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:04:53 +0900 Subject: [PATCH 132/380] docs: change model event order Place batch methods after. --- user_guide_src/source/models/model.rst | 47 +++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index d8cefa02c1cb..e6b6ec448b16 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -244,18 +244,10 @@ $beforeInsert ^^^^^^^^^^^^^ $afterInsert ^^^^^^^^^^^^ -$beforeInsertBatch -^^^^^^^^^^^^^^^^^^ -$afterInsertBatch -^^^^^^^^^^^^^^^^^ $beforeUpdate ^^^^^^^^^^^^^ $afterUpdate ^^^^^^^^^^^^^ -$beforeUpdateBatch -^^^^^^^^^^^^^^^^^^ -$afterUpdateBatch -^^^^^^^^^^^^^^^^^ $beforeFind ^^^^^^^^^^^ $afterFind @@ -264,6 +256,14 @@ $beforeDelete ^^^^^^^^^^^^^ $afterDelete ^^^^^^^^^^^^ +$beforeInsertBatch +^^^^^^^^^^^^^^^^^^ +$afterInsertBatch +^^^^^^^^^^^^^^^^^ +$beforeUpdateBatch +^^^^^^^^^^^^^^^^^^ +$afterUpdateBatch +^^^^^^^^^^^^^^^^^ These arrays allow you to specify callback methods that will be run on the data at the time specified in the property name. @@ -718,10 +718,17 @@ Model Events ************ There are several points within the model's execution that you can specify multiple callback methods to run. -These methods can be used to normalize data, hash passwords, save related entities, and much more. The following -points in the model's execution can be affected, each through a class property: ``$beforeInsert``, ``$afterInsert``, -``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdate``, ``$afterUpdate``, ``$beforeUpdateBatch``, -``$afterUpdateBatch``, ``$afterFind``, and ``$afterDelete``. +These methods can be used to normalize data, hash passwords, save related entities, and much more. + +The following +points in the model's execution can be affected, each through a class property: + +- `$beforeInsert`_, `$afterInsert`_ +- `$beforeUpdate`_, `$afterUpdate`_ +- `$beforeFind`_, `$afterFind`_ +- `$beforeDelete`_, `$afterDelete`_ +- `$beforeInsertBatch`_, `$afterInsertBatch`_ +- `$beforeUpdateBatch`_, `$afterUpdateBatch`_ .. note:: ``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdateBatch`` and ``$afterUpdateBatch`` can be used since v4.3.0. @@ -769,20 +776,12 @@ beforeInsert **data** = the key/value pairs that are being inserted. If an afterInsert **id** = the primary key of the new row, or 0 on failure. **data** = the key/value pairs being inserted. **result** = the results of the insert() method used through the Query Builder. -beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the - insertBatch method, it is first converted to an array. -afterInsertBatch **data** = the associative array of values being inserted. - **result** = the results of the insertbatch() method used through the Query Builder. beforeUpdate **id** = the array of primary keys of the rows being updated. **data** = the key/value pairs that are being updated. If an object or Entity class is passed to the update method, it is first converted to an array. afterUpdate **id** = the array of primary keys of the rows being updated. **data** = the key/value pairs being updated. **result** = the results of the update() method used through the Query Builder. -beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the - updateBatch method, it is first converted to an array. -afterUpdateBatch **data** = the key/value pairs being updated. - **result** = the results of the updateBatch() method used through the Query Builder. beforeFind The name of the calling **method**, whether a **singleton** was requested, and these additional fields: - first() No additional fields - find() **id** = the primary key of the row being searched for. @@ -796,6 +795,14 @@ afterDelete **id** = primary key of row being deleted. **purge** = boolean whether soft-delete rows should be hard deleted. **result** = the result of the delete() call on the Query Builder. **data** = unused. +beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the + insertBatch method, it is first converted to an array. +afterInsertBatch **data** = the associative array of values being inserted. + **result** = the results of the insertbatch() method used through the Query Builder. +beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the + updateBatch method, it is first converted to an array. +afterUpdateBatch **data** = the key/value pairs being updated. + **result** = the results of the updateBatch() method used through the Query Builder. ================= ========================================================================================================= Modifying Find* Data From ab2d13de0e474cc214834130c20cb79295094cfc Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:15:05 +0900 Subject: [PATCH 133/380] docs: make property names links --- user_guide_src/source/models/model.rst | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index e6b6ec448b16..a83ca4082130 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -111,12 +111,12 @@ is used with methods like ``find()`` to know what column to match the specified $useAutoIncrement ----------------- -Specifies if the table uses an auto-increment feature for ``$primaryKey``. If set to ``false`` +Specifies if the table uses an auto-increment feature for `$primaryKey`_. If set to ``false`` then you are responsible for providing primary key value for every record in the table. This feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. The default value is ``true``. -.. note:: If you set ``$useAutoIncrement`` to ``false``, then make sure to set your primary +.. note:: If you set `$useAutoIncrement`_ to ``false``, then make sure to set your primary key in the database to ``unique``. This way you will make sure that all of Model's features will still work the same as before. @@ -142,8 +142,8 @@ part of a security trail. If true, the **find*()** methods will only return non- the ``withDeleted()`` method is called prior to calling the **find*()** method. This requires either a DATETIME or INTEGER field in the database as per the model's -``$dateFormat`` setting. The default field name is ``deleted_at`` however this name can be -configured to any name of your choice by using ``$deletedField`` property. +`$dateFormat`_ setting. The default field name is ``deleted_at`` however this name can be +configured to any name of your choice by using `$deletedField`_ property. .. important:: The ``deleted_at`` field must be nullable. @@ -155,7 +155,7 @@ This array should be updated with the field names that can be set during ``save( against just taking input from a form and throwing it all at the model, resulting in potential mass assignment vulnerabilities. -.. note:: The ``$primaryKey`` field should never be an allowed field. +.. note:: The `$primaryKey`_ field should never be an allowed field. Dates ----- @@ -164,29 +164,29 @@ $useTimestamps ^^^^^^^^^^^^^^ This boolean value determines whether the current date is automatically added to all inserts -and updates. If true, will set the current time in the format specified by ``$dateFormat``. This +and updates. If ``true``, will set the current time in the format specified by `$dateFormat`_. This requires that the table have columns named **created_at**, **updated_at** and **deleted_at** in the appropriate data type. $dateFormat ^^^^^^^^^^^ -This value works with ``$useTimestamps`` and ``$useSoftDeletes`` to ensure that the correct type of +This value works with `$useTimestamps`_ and `$useSoftDeletes`_ to ensure that the correct type of date value gets inserted into the database. By default, this creates DATETIME values, but -valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using **useSoftDeletes** or -**useTimestamps** with an invalid or missing **dateFormat** will cause an exception. +valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using `$useSoftDeletes`_ or +`$useTimestamps`_ with an invalid or missing `$dateFormat`_ will cause an exception. $createdField ^^^^^^^^^^^^^ Specifies which database field to use for data record create timestamp. -Set to an empty string (``''``) to avoid updating it (even if ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even if `$useTimestamps`_ is enabled). $updatedField ^^^^^^^^^^^^^ Specifies which database field should use for keep data record update timestamp. -Set to an empty string (``''``) to avoid updating it (even ``$useTimestamps`` is enabled). +Set to an empty string (``''``) to avoid updating it (even `$useTimestamps`_ is enabled). $deletedField ^^^^^^^^^^^^^ @@ -284,7 +284,7 @@ Returns a single row where the primary key matches the value passed in as the fi .. literalinclude:: model/006.php -The value is returned in the format specified in ``$returnType``. +The value is returned in the format specified in `$returnType`_. You can specify more than one row to return by passing an array of primaryKey values instead of just one: @@ -329,7 +329,7 @@ Returns the first row in the result set. This is best used in combination with t withDeleted() ------------- -If ``$useSoftDeletes`` is true, then the **find*()** methods will not return any rows where ``deleted_at IS NOT NULL``. +If `$useSoftDeletes`_ is true, then the **find*()** methods will not return any rows where ``deleted_at IS NOT NULL``. To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** method. .. literalinclude:: model/013.php @@ -351,7 +351,7 @@ insert() The first parameter is an associative array of data to create a new row of data in the database. If an object is passed instead of an array, it will attempt to convert it to an array. -The array's keys must match the name of the columns in the ``$table``, while the array's values are the values to save for that key. +The array's keys must match the name of the columns in the `$table`_, while the array's values are the values to save for that key. The optional second parameter is of type boolean, and if it is set to false, the method will return a boolean value, which indicates the success or failure of the query. @@ -376,15 +376,15 @@ You can enable the check again by calling ``allowEmptyInserts(false)``. update() -------- -Updates an existing record in the database. The first parameter is the ``$primaryKey`` of the record to update. +Updates an existing record in the database. The first parameter is the `$primaryKey`_ of the record to update. An associative array of data is passed into this method as the second parameter. The array's keys must match the name -of the columns in a ``$table``, while the array's values are the values to save for that key: +of the columns in a `$table`_, while the array's values are the values to save for that key: .. literalinclude:: model/016.php .. important:: Since v4.3.0, this method raises a ``DatabaseException`` if it generates an SQL statement without a WHERE clause. - In previous versions, if it is called without ``$primaryKey`` specified and + In previous versions, if it is called without `$primaryKey`_ specified and an SQL statement was generated without a WHERE clause, the query would still execute and all records in the table would be updated. @@ -440,7 +440,7 @@ Takes a primary key value as the first parameter and deletes the matching record .. literalinclude:: model/023.php -If the model's ``$useSoftDeletes`` value is true, this will update the row to set ``deleted_at`` to the current +If the model's `$useSoftDeletes`_ value is true, this will update the row to set ``deleted_at`` to the current date and time. You can force a permanent delete by setting the second parameter as true. An array of primary keys can be passed in as the first parameter to delete multiple records at once: @@ -481,13 +481,13 @@ prior to saving to the database with the ``insert()``, ``update()``, or ``save() Setting Validation Rules ------------------------ -The first step is to fill out the ``$validationRules`` class property with the fields and rules that should -be applied. If you have custom error message that you want to use, place them in the ``$validationMessages`` array: +The first step is to fill out the `$validationRules`_ class property with the fields and rules that should +be applied. If you have custom error message that you want to use, place them in the `$validationMessages`_ array: .. literalinclude:: model/027.php If you'd rather organize your rules and error messages within the Validation configuration file, you can do that -and simply set ``$validationRules`` to the name of the validation rule group you created: +and simply set `$validationRules`_ to the name of the validation rule group you created: .. literalinclude:: model/034.php @@ -614,7 +614,7 @@ Protecting Fields ================= To help protect against Mass Assignment Attacks, the Model class **requires** that you list all of the field names -that can be changed during inserts and updates in the ``$allowedFields`` class property. Any data provided +that can be changed during inserts and updates in the `$allowedFields`_ class property. Any data provided in addition to these will be removed prior to hitting the database. This is great for ensuring that timestamps, or primary keys do not get changed. @@ -629,7 +629,7 @@ Runtime Return Type Changes =========================== You can specify the format that data should be returned as when using the **find*()** methods as the class property, -``$returnType``. There may be times that you would like the data back in a different format, though. The Model +`$returnType`_. There may be times that you would like the data back in a different format, though. The Model provides methods that allow you to do just that. .. note:: These methods only change the return type for the next **find*()** method call. After that, @@ -674,7 +674,7 @@ You can get access to the **shared** instance of the Query Builder any time you .. literalinclude:: model/043.php -This builder is already set up with the model's ``$table``. +This builder is already set up with the model's `$table`_. .. note:: Once you get the Query Builder instance, you can call methods of the :doc:`Query Builder <../database/query_builder>`. @@ -748,13 +748,13 @@ must return the original $data array so other callbacks have the full informatio Specifying Callbacks To Run =========================== -You specify when to run the callbacks by adding the method name to the appropriate class property (``$beforeInsert``, ``$afterUpdate``, +You specify when to run the callbacks by adding the method name to the appropriate class property (`$beforeInsert`_, `$afterUpdate`_, etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can use the same callback in multiple events: .. literalinclude:: model/051.php -Additionally, each model may allow (default) or deny callbacks class-wide by setting its ``$allowCallbacks`` property: +Additionally, each model may allow (default) or deny callbacks class-wide by setting its `$allowCallbacks`_ property: .. literalinclude:: model/052.php From de0f67fc1ca86a8680d1599d261b335c183a7c26 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Nov 2023 09:16:27 +0900 Subject: [PATCH 134/380] docs: add references in page --- user_guide_src/source/models/model.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index a83ca4082130..5481265231e9 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -166,7 +166,7 @@ $useTimestamps This boolean value determines whether the current date is automatically added to all inserts and updates. If ``true``, will set the current time in the format specified by `$dateFormat`_. This requires that the table have columns named **created_at**, **updated_at** and **deleted_at** in the appropriate -data type. +data type. See also `$createdField`_, `$updatedField`_, and `$deletedField`_. $dateFormat ^^^^^^^^^^^ @@ -238,7 +238,7 @@ Callbacks $allowCallbacks ^^^^^^^^^^^^^^^ -Whether the callbacks defined below should be used. +Whether the callbacks defined below should be used. See :ref:`model-events`. $beforeInsert ^^^^^^^^^^^^^ @@ -266,7 +266,7 @@ $afterUpdateBatch ^^^^^^^^^^^^^^^^^ These arrays allow you to specify callback methods that will be run on the data at the -time specified in the property name. +time specified in the property name. See :ref:`model-events`. Working with Data ***************** @@ -714,6 +714,8 @@ and specify the model's method at the end of the method chaining. .. literalinclude:: model/046.php +.. _model-events: + Model Events ************ From aed2800f94d9914192dc136893e2b46548eb33a5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 13 Nov 2023 17:08:06 +0700 Subject: [PATCH 135/380] [Rector] Fix deprecated dynamic pull phpDocInfoFactory from AbstractRector on UnderscoreToCamelCaseVariableNameRector --- utils/Rector/UnderscoreToCamelCaseVariableNameRector.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php index 3cadde86d3f7..4af0be534e61 100644 --- a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php +++ b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php @@ -21,6 +21,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Namespace_; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Core\Php\ReservedKeywordAnalyzer; use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace; use Rector\Core\Rector\AbstractRector; @@ -39,12 +40,15 @@ final class UnderscoreToCamelCaseVariableNameRector extends AbstractRector private const PARAM_NAME_REGEX = '#(?@param\s.*\s+\$)(?%s)#ms'; private ReservedKeywordAnalyzer $reservedKeywordAnalyzer; + private PhpDocInfoFactory $phpDocInfoFactory; private bool $hasChanged = false; public function __construct( - ReservedKeywordAnalyzer $reservedKeywordAnalyzer + ReservedKeywordAnalyzer $reservedKeywordAnalyzer, + PhpDocInfoFactory $phpDocInfoFactory ) { $this->reservedKeywordAnalyzer = $reservedKeywordAnalyzer; + $this->phpDocInfoFactory = $phpDocInfoFactory; } public function getRuleDefinition(): RuleDefinition From 6ca37592f7a868d1e41a7941fe04ebc6d33e6884 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:16:41 +0000 Subject: [PATCH 136/380] chore(deps-dev): update rector/rector requirement from 0.18.6 to 0.18.7 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/0.18.6...0.18.7) --- 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 9e0288c26f6b..7f00c4c6efa0 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.18.6", + "rector/rector": "0.18.7", "vimeo/psalm": "^5.0" }, "suggest": { From 59649ea661281fee653d31613acb5a628866cc9f Mon Sep 17 00:00:00 2001 From: webalchemist Date: Tue, 14 Nov 2023 01:53:10 +0000 Subject: [PATCH 137/380] Update 002.php Updated RouteCollection constructor parameters --- user_guide_src/source/extending/core_classes/002.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/extending/core_classes/002.php b/user_guide_src/source/extending/core_classes/002.php index 68d22ff508b8..40d7342686a0 100644 --- a/user_guide_src/source/extending/core_classes/002.php +++ b/user_guide_src/source/extending/core_classes/002.php @@ -12,7 +12,7 @@ public static function routes(bool $getShared = true) return static::getSharedInstance('routes'); } - return new \App\Libraries\RouteCollection(static::locator(), config('Modules')); + return new \App\Libraries\RouteCollection(static::locator(), config(Modules::class), config(Routing::class) ); } // ... From e56e4606a66cffb6ed0fe6545c77900aa7969aa2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Nov 2023 21:37:59 +0900 Subject: [PATCH 138/380] test: add test for baseURL with subfolder --- tests/system/CommonFunctionsTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 228a24e9a26f..a097cb2a81a0 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -612,6 +612,7 @@ public function testViewNotSaveData(): void public function testForceHttpsNullRequestAndResponse(): void { $this->assertNull(Services::response()->header('Location')); + Services::response()->setCookie('force', 'cookie'); Services::response()->setHeader('Force', 'header'); Services::response()->setBody('default body'); @@ -634,6 +635,25 @@ public function testForceHttpsNullRequestAndResponse(): void force_https(); } + public function testForceHttpsWithBaseUrlSubFolder(): void + { + $config = config(App::class); + $config->baseURL = 'https://example.jp/codeIgniter/'; + $uri = new SiteURI($config, 'en/home?foo=bar'); + $request = new IncomingRequest($config, $uri, '', new UserAgent()); + Services::injectMock('request', $request); + + try { + force_https(); + } catch (Exception $e) { + $this->assertInstanceOf(RedirectException::class, $e); + $this->assertSame( + 'https://example.jp/codeIgniter/index.php/en/home?foo=bar', + $e->getResponse()->header('Location')->getValue() + ); + } + } + /** * @dataProvider provideCleanPathActuallyCleaningThePaths * From d59fdaad5ab207d61fff9c0c4a98141c730b6af3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Nov 2023 19:59:39 +0900 Subject: [PATCH 139/380] fix: force_https() redirects to wrong URL --- system/Common.php | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/system/Common.php b/system/Common.php index 2d876564846e..451e6c601a63 100644 --- a/system/Common.php +++ b/system/Common.php @@ -502,27 +502,11 @@ function force_https( Services::session()->regenerate(); // @codeCoverageIgnore } - $baseURL = config(App::class)->baseURL; - - if (strpos($baseURL, 'https://') === 0) { - $authority = substr($baseURL, strlen('https://')); - } elseif (strpos($baseURL, 'http://') === 0) { - $authority = substr($baseURL, strlen('http://')); - } else { - $authority = $baseURL; - } - - $uri = URI::createURIString( - 'https', - $authority, - $request->getUri()->getPath(), // Absolute URIs should use a "/" for an empty path - $request->getUri()->getQuery(), - $request->getUri()->getFragment() - ); + $uri = $request->getUri()->withScheme('https'); // Set an HSTS header $response->setHeader('Strict-Transport-Security', 'max-age=' . $duration) - ->redirect($uri) + ->redirect((string) $uri) ->setStatusCode(307) ->setBody('') ->getCookieStore() From b25ff87a8e748807863d11256b508170e9cc9fd4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 13:14:46 +0900 Subject: [PATCH 140/380] docs: add @phpstan-param --- system/View/RendererInterface.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/View/RendererInterface.php b/system/View/RendererInterface.php index 409a5a76d3ba..a0f093b67326 100644 --- a/system/View/RendererInterface.php +++ b/system/View/RendererInterface.php @@ -46,6 +46,7 @@ public function renderString(string $view, ?array $options = null, bool $saveDat * * @param string $context The context to escape it for: html, css, js, url * If 'raw', no escaping will happen + * @phpstan-param null|'html'|'js'|'css'|'url'|'attr'|'raw' $context * * @return RendererInterface */ @@ -57,6 +58,7 @@ public function setData(array $data = [], ?string $context = null); * @param mixed $value * @param string $context The context to escape it for: html, css, js, url * If 'raw' no escaping will happen + * @phpstan-param null|'html'|'js'|'css'|'url'|'attr'|'raw' $context * * @return RendererInterface */ From 8fbeb9364be142060a9a0d1a57f2444fc21836b2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 13:15:41 +0900 Subject: [PATCH 141/380] refactor: replace empty() --- system/View/Cell.php | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/system/View/Cell.php b/system/View/Cell.php index f654e97a376d..de9bbe636e4e 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -84,11 +84,9 @@ public function render(string $library, $params = null, int $ttl = 0, ?string $c $params = $this->prepareParams($params); // Is the output cached? - $cacheName = ! empty($cacheName) - ? $cacheName - : str_replace(['\\', '/'], '', $class) . $method . md5(serialize($params)); + $cacheName ??= str_replace(['\\', '/'], '', $class) . $method . md5(serialize($params)); - if (! empty($this->cache) && $output = $this->cache->get($cacheName)) { + if ($output = $this->cache->get($cacheName)) { return $output; } @@ -105,7 +103,7 @@ public function render(string $library, $params = null, int $ttl = 0, ?string $c : $this->renderSimpleClass($instance, $method, $params, $class); // Can we cache it? - if (! empty($this->cache) && $ttl !== 0) { + if ($ttl !== 0) { $this->cache->save($cacheName, $output, $ttl); } @@ -119,11 +117,14 @@ public function render(string $library, $params = null, int $ttl = 0, ?string $c * * @param array|string|null $params * - * @return array|null + * @return array */ public function prepareParams($params) { - if (empty($params) || (! is_string($params) && ! is_array($params))) { + if ( + ($params === null || $params === '' || $params === []) + || (! is_string($params) && ! is_array($params)) + ) { return []; } @@ -139,7 +140,7 @@ public function prepareParams($params) unset($separator); foreach ($params as $p) { - if (! empty($p)) { + if ($p !== '') { [$key, $val] = explode('=', $p); $newParams[trim($key)] = trim($val, ', '); @@ -175,7 +176,7 @@ protected function determineClass(string $library): array [$class, $method] = explode(':', $library); - if (empty($class)) { + if ($class === '') { throw ViewException::forNoCellClass(); } @@ -187,7 +188,7 @@ protected function determineClass(string $library): array throw ViewException::forInvalidCellClass($class); } - if (empty($method)) { + if ($method === '') { $method = 'index'; } @@ -274,7 +275,7 @@ final protected function renderSimpleClass($instance, string $method, array $par $refParams = $refMethod->getParameters(); if ($paramCount === 0) { - if (! empty($params)) { + if ($params !== []) { throw ViewException::forMissingCellParameters($class, $method); } From 6ddc920f0a368b1157bfae16c2ec6353900943ce Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 13:15:58 +0900 Subject: [PATCH 142/380] chore: phpstan-baseline.php --- phpstan-baseline.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index beb2d85a4d84..7f9182eeeeda 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -3951,16 +3951,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/View/Cell.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 8, - 'path' => __DIR__ . '/system/View/Cell.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property CodeIgniter\\\\View\\\\Cell\\:\\:\\$cache \\(CodeIgniter\\\\Cache\\\\CacheInterface\\) in empty\\(\\) is not falsy\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/system/View/Cell.php', -]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 1, @@ -4006,16 +3996,6 @@ 'count' => 3, 'path' => __DIR__ . '/system/View/View.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#2 \\$context \\(\'attr\'\\|\'css\'\\|\'html\'\\|\'js\'\\|\'raw\'\\|\'url\'\\|null\\) of method CodeIgniter\\\\View\\\\View\\:\\:setData\\(\\) should be contravariant with parameter \\$context \\(string\\|null\\) of method CodeIgniter\\\\View\\\\RendererInterface\\:\\:setData\\(\\)$#', - 'count' => 1, - 'path' => __DIR__ . '/system/View/View.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#3 \\$context \\(\'attr\'\\|\'css\'\\|\'html\'\\|\'js\'\\|\'raw\'\\|\'url\'\\|null\\) of method CodeIgniter\\\\View\\\\View\\:\\:setVar\\(\\) should be contravariant with parameter \\$context \\(string\\|null\\) of method CodeIgniter\\\\View\\\\RendererInterface\\:\\:setVar\\(\\)$#', - 'count' => 1, - 'path' => __DIR__ . '/system/View/View.php', -]; $ignoreErrors[] = [ 'message' => '#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#', 'count' => 2, From e113ff1360b4d9b96921a0a150df667ce9ec8256 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 16:47:16 +0900 Subject: [PATCH 143/380] fix: Image::save() causes error with webp imagewebp(): Palette image not supported by webp --- system/Images/Handlers/GDHandler.php | 1 + tests/_support/Images/rocket.png | Bin 0 -> 56947 bytes tests/system/Images/GDHandlerTest.php | 9 +++++++++ 3 files changed, 10 insertions(+) create mode 100644 tests/_support/Images/rocket.png diff --git a/system/Images/Handlers/GDHandler.php b/system/Images/Handlers/GDHandler.php index 15bb97b6b839..6620dcac431a 100644 --- a/system/Images/Handlers/GDHandler.php +++ b/system/Images/Handlers/GDHandler.php @@ -227,6 +227,7 @@ public function save(?string $target = null, int $quality = 90): bool // for png and webp we can actually preserve transparency if (in_array($this->image()->imageType, $this->supportTransparency, true)) { + imagepalettetotruecolor($this->resource); imagealphablending($this->resource, false); imagesavealpha($this->resource, true); } diff --git a/tests/_support/Images/rocket.png b/tests/_support/Images/rocket.png new file mode 100644 index 0000000000000000000000000000000000000000..07ca8e212637901c2f4f1f430721047408607cf8 GIT binary patch literal 56947 zcmWh!cQ~7G7e;ppyi|`BO_zbM5`K*kpZCpe}I7NFB?UN z=450PM|uw*t6jg&?O**nzM9^>oSt1<+&Y??T>iVVGo}4vV{57al0_@{#T)o5-V`ps3r!|j8!tLj%*ZNYtmWmjdEKg2X9dg2Bb zcb0a~e$Vb552S8YK7Q}xxBKS9U(#84+?Rz0$A9~0n?(D~;n1-r%;4f)YDSiK0KVu) z-s0xb+RpL(#=-XfDM{RL42+Aug(3lE`HU>;iI&_ zXIB}@S96h9HCn~R#a9j59Rlh(IXPKb*^P~jS6>v}{_K1jJ89-cjxO!SCnQ~szl|O} zPD=igGJPHs8$UceT+1bQ)uMAX|EUcIzZ!MS%gftAI9x3zrKY9-nc7%~+kc(ANSHYN zJat+;f7&}s%9}lH;#L?DM7OM+{k;9(g0gM-;@SNE`ONP5z}DF&{Q2+Szw1}duKws& zEuUQt+pZj5bZ?xElgV80Ctp3TR-1{h)KcrfRl9my zb5ncY^i_}jDmEpzs=2nclQ_S(;1E3M@p0ijVQqSO{d4hX&adB(UN$6V<+t=Kr2SYa zs7q-bZE2`$sHsY-@9li%v+U(q=pLLLgg^L&$$IL%{rUY#R|K)Rw!h-fk>^yH~;y)n2NZ(QW6M))aYj{FeXuwgZ0tA?I(! zW$@_ElTla>a8FTw|CdcRk=3SX#lU-C*ZiHGK_B@y7TO&tY4d)xRxS3QzU0-};@4ZH zx0eSrU2YX=uiSL95l^{NZ~S`sTwq8_BUte6KWn#%+idEw@j88Titt$Wx0)bz?{m6D z4ai0fuE=7o_Q=V+=--(QSoQ4}^85TMLEBQ$$YALHOSekKwYOm&5%H?&#poeU;jXd3t8v8+SZKk%KPjtwPy8 z5e02C`frZTE;v>H{E!8%ox$^Y-ZUPkN$)kMA5av)^&)ne&p%ZV01rYOBjBlafh*uo zJiZdUBGpl0{4bHZ&c{CuF>>>(NI(^oBgK1kFdEb$opX#2?zuuSRX4)#!A~cZ}|z- zFIP3|)R>I7AA(KZjljhXH4)WZdApw8zSw~UowZ^-s5E+oM&)^^bnvhHgQEMDDUdjE zAeAQ1BPWi4frak13?N;GbN0D}9s`-5S@c3Cge^X*kc5~UW&a~2{h~ikl&{iTt&?tk zT=IcBd<3*cL#1xH9i8b(!DC}+DrT+m-(REyCxPcTsX3YyEcQryj;cel3_7d!Q49Kr z8HU?OC1#W)$;Af5-_SuSaK5HAG#aF8&v-|QK5snJet!cx9k7x)h(a;hRV6kP)Yfcn zee>$EE@)nqU7Kr})8Xq%ycr{eN#`2?**BU)qa2uQFFbJlX@ZIEbLm(nx5((nTyT?FMKN%g#a?WU|W9Q)qjtPnfnMt>yjHqs0KrIMg0sY%wxU??i$?x`Y+# zZr-wF%9ksEX<^cu9 z`8vy{)H)`=-(D$&{BcaYSvfkoBuvWiaJ3}tk!v&Ag@IticYAH6^rxeGIZPONU1Q9u zsZ4{;TOMfTT!bx79G?s+q4_UuGr2Sub4&e}3crN;$G>uJwBx;BxhxSTXH`57Qgu_>JMDyq_7-r<^cAjq~bv+#9*h=y4Rh?8z@b#YA ztKY8sv452kQ*ILB&|e`xp2}vX(Ss=hCOus+x*a~T6E*Ub3!JM&zIeKuWC;5;^g5co zs0ja3j-f+43$Wb8@RXyw0@D*f!k66TUbJujE6)aNeYI(xy(D_jbpF*S%~rz?1nZ}# zbjkkMC&0x5$N2w~eu#V``%69ZXSL!)s{e>2g!>*TgCZiH)vFCVUp0%e2V0RDTzuMU zu2QN#o>l6hinlU*OVNKEPRA4)M6DuUGQP<%gh2^8DikB=& z%sWkVf?CSuCwUWhrgeH=>2E%@jHEnU@}Xv7zPT%x{Yuzz2L*zDZ@=w@|GN_+k}_bq z*TI}p!#h#!`sAt1$tAy=Fg5I<0iD>ERUi`(12j_jTC*G{U|v~Trr@v-7o+AD;^QAj z9mk{%;g#=_^fy0k4dA%Vt9L5B=B$U(s2M*Q3uU9`nqaD7lO{iSgHe*-Pg-3Q|%=4|8Q{_Rzdr{6F)|2PG(K0mwi;z0(qM`Vu8 zvU%W{{>W2g$^j2qMJHA)-41P@-uyRO54ypIhcL79W*=MkI5=lTJ?C+ws*C#}3fOS1$|`JnmzIAFt_UXs;|+ zU>tlOcmq@vRSjujZ42c3xSNUPk?u6?G9~hcjPtLi3w!=9-tZ_GDR(sKiQ3un1v7(T zy%LfeLU;MtA5!tiBZM2e$yE11e}Lrg7NHMB@85A-n<{578u7Sso3IRHcx=|R_wgfY zqn3q7z!SF&@vLmBVNXl{cNx6_t$#=O&ZX_~!*xMkw7H$^Fat;v1m7ckY|-E7?*7z8 zN4xq(g;{rug7AT@V6}y9GY3Nii(XmzmK*>3MGl4 zqGB>Uj-J`u#*`dB<7;4I>dYH-mO&xz#!#ZlQ#(;3)6_r7G=KApQL2 z*cB)D11{-;wihpdebzw(0=Sq4?v)jPKH$8AS!FJ$bOl3agM^@jZ8gu?QV95_3cb^b zCK)jF2hCjeQ(A6EZ(U5^-P+k;F@DL^`;bP!qsnI|Qt=8L_NLmI)$7PRSW0gLe-F}E zDDN#olBnsa&&Vyp28L116RnQvB!4??*<$W1`|`2P_PT^94*t=hSQ!ixC=xE}cGcus z*{ck0ggaZUxVN|lBV`)`+*R{t7bHNikEzf_OEYX&38)_XAghT^5+afn40_YP?Eci` zDaY_Yp%p57FR$)U6?xej<6R6JqJ#;YP~Qd?3+JSu{PQe>;>hq1-V(TdM!hUOMhnD; zk2G-Rlpr{eMukcy+Z&qgqL{va-h_cavDS3QN9ne<^XFL5<0q$O@+J!1CFLNUR=zjT znK(S;Gpk8B;Q=(;4v;|>Q=Lw{TVMxQ?EN)^m?BMmv4&(F*%n#~sT!L}s*c#lvF-FL z1Ocqn7*EUxu!Or zohd4oi8=xaFX8Wc6f+-___^mMf5pq=7h19%J)Wu_!su1`_!AewB4y@2I20S4|BepW z;1>7&+qKfLCx&&RCsCVOcblNf^7V^+QZX*yUe6V0T8K-2A8xzIH@_}p6-;R6##L z^xd<|fY+1>Kh;XiQ93U3<#qqetMkoHAyZZNp?GcT4)ttAj2R{DLx(jU+x5E*JT2SM z_7n{Lt$GFR>)N=gsVNl&~Z(|{dK6aUxEHgan_z=Gf%TP68q4=r}V)Q z!3Pw|8$sZIXuJ%2a6r#ean(-)PM>p26o%7YL0_fG!7*MH>XyE5oMNW0Bo(o<0b-ye zbe#KkKlrdoJ~RmX-w?f%cIwg#-{@TQd z{Zp!+oA4zJiw!JXqUq;0^^`fK9($3JnR{Xlf4`lIfQuh*#T={+C?LcPu({c~9)72b zP0;{if0yPuk{JHJuMJ^No}qo$is9|>DK%M@@8@IL;DF=JsDm|%IFq*@@>2=WyL-`; zn%?KLeU<{rN|VgUW;;!1pz;wyI#2av60_ZBQ{Kj z_@hu7AWRg%;-3pyytKYU3G3u4EmRDSG`Zt9rm(7KPxt0FbRIIMsUm9hapjq1^RmX1 zJD&+Yp;->yCGxeS zYza*PLty5IEIPzBNYqUQcrJU1IqtksbqLjm+q?{H`FVr;%;Tt+7OL!DpdnmLlK#S} zV>^oS1cAQ`*b%5AsnYz8?4BaseA}=A%oZJr`}8cb=-ZImAot%~t@pNzbP~Gy@~M;u zc4_i_G?oIQ`CX07_E?ZEx8yuYOB(^EF0eJO zunITi1f&7zQy`y@Yyy#6-w^ZQchuOfHXKi;aC+{Ir{vkCfhNa&0aMQv$KXA!VaUIJ z72=k@7RQN+quJ}!z(C)=2w>IWBgcbsQ4pd@rDZg}psYN2tQRqgDv^eeW!JS}6FhH# z;bnD~O>Zyv+b7&^d=5Sl&Gmxe&(F{!I{7q7a+_S*Ebo5&M3s66>ydF(FB$#2#F6x$ zHt{MSjxyp`p1o>bu1b$iqEepa_HShTUVw5PwZG6|hrMug05M&`8LQs=>mwVfA9KSw zC$#q|*c(>Eu~EkGS%?D}xVJsoZHLOlWRZ!3<^0`@9`=T`;m)eC6$b^(xDnlo!ZWZd z+U;Z)L0r?B`a#}BkD$CCsrO(3&MhiH0?zf3$I)deQ}rp&MpGG>j{ZE^KPG1_FYier z6F4)rdP8=0g&9l6IGgbmf*PYlFECj!;GaRyT$L{y_ex>jo7_RDFIiYB*=Vc5(L{1^ zOlSQ8%Ob(Qs5>;b$YpqmU&Q7MU}XzdH|}Mvz*|#_pXXk%IH1v`HN>PZalr` z>2y!Y2f=&bC##S8Jq37n^>vA(j||BvYu48;obDfu&1`)AmICZ|TWwbqg_GgHQUxl( z${Rr7LbMQg;7PCW{$(jm_4(7%Gjc95>N~e-=WIlkltjFUzt%^nVZWTaNfmNRsvN*) zwxm_XHg1etFGR1ZapJ*5Dm8c;@;P1m4WFOgy#yKzvof=gimBWpX~xjwE}aqkYfUwL z2TVn!$Uc}sRr^;We!>Ho^&ajC$j&YC^F0`-irmFGhZfb|hlTl&ZeI~VLBsS!>_jB}k{JQ<_^GY;~xOn5-^ z5v)VcW3Gu@=?ekBVkE+TP2?BY?Q;Ov>KpSnQD^NGs1iyL884kFJ@IxzuX}tir0!-i z%ii=(;vew8^e9O{i_@=2q})}8B7b%wBT`o$97D;#6U1lW9qu#9bmv7q%#;&cR2)D} zwl=2u@BfkCQO}d>e+NDx`as;7k*%oa)?GqLGJ&7+R>)0;tsxfM9sOScOXXGn+QA}c zFBqX^c>D8Ua<7Xg54^6%$ogkh^F2ld0VZF}v|^cYgoUBE$!qCB1jvtK0ehtK1%kyu zZsD5^KoyV)iDjXIzM^Voq)=WaYu&rvEY)BZqwS(wxW>$ErA0K5L-}ouZjKSp?razX zGe^g4BroL&YDeF<slg^_U}G6VlLwZsSEU@ptW_AmAQH&+jF_%S`q+(X|!<$JcW0J1<_ z*w8+O6RA3X9k^p$pE}E83lLVuA?&ieP@6vPuY>r{r|g9mX$FaG-v+ZYrS(2dO(dj)OQ>;@P7W}DekfKuR(smqVn zhg})2lPsX5R$IjQ-Pg)yhd&S-iEqdV0v@Qj(eMDP`bFhk6N;#qJxnLJ*y|MK!~@7Y zd7+4`?4w}E1{?eb1x&*yRlv`$%@a0C&fZ$pE6)IKN(z`Bz111f^Y8~-%O){)v7Asf z^i%sa1!+F)PJk3hpS&(5Dnl8WxF?_Hzp?dt5<^D#sms#PIO${wRepTgXu%ODYl@V; ziss9V^+p3Ki1)>&lkKsTHa*mei#Io6n{=ktH2HgAG1#*QJ_);8WG~mGcNhfgMsCa~ zuWZ14g1Xu$wWU^AD$I3Fvsfc zp`89D>Xkjz$Hzw}MX9VGK)(2)Le^Y^wEzUPx5M%y_XVDge z;GjL80_cl9@C$w(UJGoz@6dbF#Nc}9^gq!?gePH33X)luQkU@gkmiCV+q)otoAd`^ z&r_y-t3Y>cBusPOz+UHT0zVBPuk3e)5xXTHZ)<`5Fk_P=_k!|k&5PkAna*rS}*;9^;NjtUpc09=;J3yg@x0_C#tuqmFa#gQ&@EKoBi$+yo*m6PO$ z#<4)Xf$;$JD8v4{kdP%y;;}}Ha)wpo`VR?3NkPS-%2v;~rMOgkW;Hbf|Njz0#hwfM z&U+FQ6&KCWR>5BIIXunF+d=Nq+4=8@j~>9w12;_B%YK;DJX(DKKNVYm2q@Z76hA>Q z7r+P7ZEJ(_3xsQ)3uWE8`0pA3{6-_P4K`um1sGp7HaaS=gBLmR{JebIzZ?RSE`B&E z@ZX_a;D%DcB-IX`snUp3ZZSQN<4O3vg6<+MO>s~3OZ65S*fUCH==ZX4f;e{8iHe?G zad8oBIz*mHR}gvM&yCE+>;!=6v$zPf@TaW%RbAiKqV`G{8+$BA&K#Os77l<`9^4%_ z8ZiZCoWqb-BP&8tY>-XzY;JHjb?4JYURBalpV^V9#`XN%x)e&qPp+-xWq-oQ1CYdr zj`-tCEKV4ytK%i}8v?|B$SDCKusJb)6rendnPH49p?tp7X|I$)5gXM7Usta=V{DsQ zm*1rp!|vhQXmnGBvWLl;F5o|{&7-}Xs zp@X{{!DbSmsYsceGUWl} z$Zl8Z`7I6;vM}wmy^^3+0lMA?8>-Vc7i z$Sv|4o;%r8BTb?Y@#UYuFzWuX_>&21N@O!;=@wR4d58n~qOy^rc{*l;BH|=>=Kt&K z*p3Ouft?egA51zlR>Px!2666im?}`S^VMc>K?m}*1URmxZyh3aanS<7gSq?2(Xqj9 zo3m`MI;nuvVDy{d2LUYPB%D9{?@L1LX_IURM-t7o2=%jja3Kv3 zjt5IIQ2$mjwb8eiyYJ`7oozuq@|ppfS@&f48QTRD;puv_MG45DZHoCxglO~wd!7@O zgrlx+f2{g%y%O4h8Ef z7q^ZirkqIN=NEed%7X+| zknvR4Pdo>V-&FLB8=a=wA+P(^aU$F-TLQivW>WWER7;xMCX?o*9V{invI_#1ZdvWg z{Q3!iwdBA|TS7vw%go`|`tN2-2MSmvwjJ_qGQJ)@6|#r59rl)&*avqvVavXU1B0wP z0D`rKgb=^T*594Y-~>4SE2#eLiz4M()=TW4X3<(Q)ln1gxKZl;daYeA=QPEYt$h0u zLWfAHt=uJNe^wlrs7Rfh3#Nfls*8hzG7tlxXU0Bh+&p2vFR1Sf+5e6bDFOEz!A_#TNKs*wV5isfWwFI$V(6v5CIqb2;sKJ8h_Z%-6D9@Ncw$(u4zR$JPe6TcQ#!^b z3LZ{^F9R{b_(#oO^0mC4$rC^VhJxo0ZDy5TOaQo+(+=r%Y9$@JP+=A)KpTzHvv`TT z1@<&O9tU~A@mi}XIBOb6kv}@{D=)G0tI<;k{PcV0gP_C{VW}$V9cKAnhjH3B2W|v) zOsF34ZGHjyNLc{x#Z4^wrADU6KSN&Cl_)mn0KyYMw9!l^^DcSzuWHX=Xu!sSXb%5V zv->p|S_%mRhR|ocYbHeiCiBR^@4twhcefA$1BTVjg%j<)nI zHEfZOmoM4cw?>VffmoIWyPeg!jl>6E8Fgsxt#g8!wAip*LGuyhe}Ehc_VFj2Bw_NC zac)CDn{^f+M9=OthlhAZ^ke;7zjrv&gu|mk-Y`7~5^b^?!-osrj-Dx}LP|q{(V;zwISw}L!64S1!rZJ%_qi(n zl<%(FN(Za08r2z>-;0XM`JN>` zAN*uVOYjv0p&dZ1Ml#jA3bW8a#wX4;3@~>8J{du5`n&&dSA_Fm-RQ?=nKX~h=Ai-s ztivWW&~VW3chis7A2SOsE#2RF_>^18mj^G>*}2fttZ_bP4su_O#PMTX3~#>5J;-RG zo_3A<)v4TQnj;`9PHs6LX4 z%NJ59P56P5j(2w~_K|*=&!Z*@M)xDydF4yLGZjR$?#wNNQg2P|_0%}pXnd09?MN)* z*$#2#|1%ZZQf)*5`;%333S~0LANT*yi}>G93kPL5-t(Hc1HD#;&aR9DE8@*;s%k`x zBY+yZ30`*vq%;!Cx7E*5_Xy7|!I^A*W)XkK6kSNS8*YMwgl_UQTd}1u8}NbNrate0 z4U)j^O+21+0IU<_iR{lF^XMp7`;e~7kL9cB1&378krKAsi%moGzt z1wiwJI4G~|s?Dz{6QdXo6vNZlta!>Lll=I`h%oJ6h+5ewsE0UHqff)$6{_+q^;~Vb zi}Bvv7((dJ)bG8euHY8xq97{quo3^pQ;_`H4G?*<%$8u@tAeysm*ITe$kq~~tWk0=qv6{zDqkZ(#&gT`6WrAda^!rou?W1Wm+9&?>#gxoq_FF) zXgi{js^};3DJ*W0V0BGbc^*dor|T=b`Oy*li#c80t!>8j5_!pygV+QUzS^wZAKP%(8uNh2mc^*1cpAsAZAK{3MjVkh&!=+1 z_}v1SSy#f)Hx+gDUX?opd#^?0sG?FaZZyH~APPeI%7 zVskB1x&h!YnCY9c2k?LpEm$ZhS)-V?pnovwf#zii7bR020a(g7s_bb25yep6;eK~J zG4@^%*6{f_gz`hEF~IyPaMT|iwY4ZieLj!*cHt}O^``tIqO72+a9O+zVNOXl4Fb*w!~rydW7^4fKQcdgCsnP4{E z0(Qek1Q{^1EP|4ULh%rU&sU=a4>U~t^LuU&y^0dgqCt-Pn~)lx5bKlOo%CiZ+0@+z zts^}$P&#QXaNSz@f;D+ayAJVX!)mgUceTyxNwyWLbjOv zy^&Kc5VWFAeIwd;OL23KY3!E^QwCqFO%<+%b`01R{Y_#sSlV@&1SV2`FpNI^-fP7T zO3Hrb{;@!i-XKZ}t4M}CoCy3%9+(JvaT0TFPG*Nv{<|nN=r-o(H!n~{)}tIBJ<8Jd z!Z9v4v6Ulu>Xb9=JbN&fMDQ_0Dxdqc!1(FI2o*97vJ;o#z`&qmw!RnJbjL-hzGU-- zFf2O@oW1wEF;iq>BTm{niSB7=5|_B5JT&#*Xh4Yrn1djT>w@P7PA}dS&H<#4D?C-e zTHlP_9!JevF(QcT$w$`3IoRy4Tui$ok3{@m$aXN;MfQA(iWBWEx;7f$XB{KwU;pj7 z<;GXOPBm7(b6Pte(OI%PSLnY0+tz5F8J*AAHGWv$n{S^Bi(j+A2F}pTNI@8^_4^{6 z$OkzuKjHveUUxots1eKdi!i~yK{l*0W0R15zLK7C)#syGz4>0xQ$BP8P1(B%W`I49 zmiH*sllUtq9~)b}L(sdFHY~q`Tz&od9sUB>UkH9zY(T{`NP+JpW|9zt*z4RgkU!I1 z&Jx6ulx!sQii?sZ6Yel7d4^c54Y7@5T|~b9vK9DzL`tHa-dsboFi9;ub|v>B?kDf5 z_$?CNE4WRCDJ~YKQ5}M&L%v=F%d_?7F`o*reNf1&x0N?gPE34gzrWt$`~Cq9FYwp; zyJN6CMp-ryMATTkPyoVAVfMQG2fsu2I~E>UT`ewhDs{c57H48sEA=4BsK&`yM`U{8 zq#@Z@(E8&7+5-KUBxrfVLV$kLVWurdygM0K>5D}@f`$Z?^^u?vV?%1i%B5NbqV7mw zT|5*N`Nv#@IuSs@p;w?2W&AC$u_r_^dkn56gb)LmRplg8a0pnw|6Fm3>JVLPV21A- zfbc4LOJHWxh^}_ebQ%9(<|je#{v%1vDW-LOBy$3qP5zC1MYtEn32pUn?k>Jj^f0dN zcJE6?H;N>KXSLEL3PR>p*-`|i0XB~&_{NB+l3&}0#YaH)Ci1LD*8&mn-i- zzs-rTGH;hNUfygQ0J9Vsr@ly}38DX(L=y85NY;OJUUhzD&oe5Hiv z#+APmOE9zthb`OF+B;42A_wGL!Sh9SQ8Y<*rF72zH;;LwY`zx^+bVB#`zZpL;C*=a z=hqeNLr;)@r4@uN8cKy)oNQ}W630^arxc&YD_fSSl|9_v(3#W(|F$OnV*(o4}tyM;XS-=@!B}I zL=tpFU|6bIzkmEzBL$N#Rbb!?IEJ-MB>x;3qZs2Ro!vSi1hEkgIHtX&!P9*MrW>~; zR!#dr+5gRLP~~;)e-**F14ioTfa5uU$0fYPDkCI>iMzV$x&IaP9uym*daX3f+!MW; z<323f*nI_vX{Y{%Y6letw6div(*L-8b{A&%ZkV%^*7RQ*6RZREvo^a2>$wznACO6& zt?*In(HdgK%Nuqlkz12_pZFOR+Zc-IREu1pMq#K%yo(v-kJ^Zkl-*4(Y2N5 zWYWf$c-^`6Go05uC@f-ndfLyQW`h52+xpSkUSVM=^aH1GU3$}L2DPggg4^wPaQs~| zK0-NgeXpL~)Qx|?#p3Scs&m&%pu_;$e>{?jI-bbRx@PuzE)BZ6Bg}QQ*TW8aqik!tFcCk7<05 z)hrS#wc*bPF0>!l#5q3iHD(oXY2`uK-4c1eH?+P_FXSxX?j5P!1&FcLeHalXVS;$J zFsg|H@~n)ZnwykV_XBwORRX)r0JQ^n_du`O>kw?nV;N`cn1G*wevdKu#3*y)`#yFB zEsu??0WY$lUF^BT>+a-_o%sPL8nY+V{^0O(T)B>i0?&Gv2;Juv1?@M(qopZqfA z#XI07h+$;lEqE=k%(b)XIc=8KDyj&TgVLv0MdJBgFO0eyQA%lf9{b~R-b!QY+Ksai zbBvuAO@ZAXTmG(qmPaczU)PjLYFZwSiPE-6q{rj{J?I1`ly{%~#{WkgiiJ;ZYHWO` zajLYZDzPKc-V+1DlrekPV!c{$wf?gYb-`Z%&bI`tXN3ouPKRfnbD?R~e;}!&I8BW8 z$a%;cim&9WeuIAgfu$At`0HA**!q2he|Io8YeShv5G*Y-nyY1h26Vtf&2P=Rn}7y1 zZ|0x`K*s;^Sk$m{yGd~WcZ;>>PJst4hg`GzK=0j(vgf=hZzPAxd}=)7UhS?n93^$Y z!oim^#;g49y>eZhg(YreW>1y9#iIs{QMD+s!3<)JaED;H8$_n#^SHbC_8W?*ryoLR z=VZ~N*&kjrau!92y*l)0zt8NG7^j$xl6_=6Kn;uK?|^ykkJhOmfK1wB^`B^LhQkP> ze+7|Gu3SzMQGxauO#vHEJg8I_hr!#Vb!SSqH%WId7GKGCKV`n7%pa=y*rIK@U*A)f zalnH2fYIaKW^m*p<9}r}Uuj<2eSDHpIe^W51EyJnQj|d0Q=QcCMP=aXZy#{j@aw71 zvHe>R1bmCAee>IbUR)r3p=a3Ln`Wiatr%5yNNo*U-HI@;V*Hc65?7Di&}a9Tv;KNN z%tEv??L}G)ndA9tp0V>DKnre!xdO$!EcYH#74do!-|Sk`!TjQ6LSn@q0)5a*Oh#rT zaQ~-U_{AtMBb#Zz_%6H0mbIwwPD={FrO)t2+_@-%3FT@Q3RG3xSJ`}73u zen8ao{9%4^EI|;4e5(XcY_!AOcNQ3F`eq&Y3lj+5Av_X8O7M;GP{SI7EwPG=u3!pk zCeYlUqdN~W|DDnXxP%Bi@{a4n={dOKY_Dgo$e4RIpH6n?Nj7XIU|}){uEv(zn3o)q z;s9}!~GTBVwu` zq+$gUQ-%{QrnLnIA_CLvJ1FdKJTtY0U85p}aeDE_{scX1H2qERqz0kt|D-8XPCJO| zc(qqK$APMQ?6JpT(n1g}kbL{|Y_K?;&U>(Omv7X10h!LuEMR2rwOcnXw^nrQ56meX ze0{YH+oQTCGzWtNsAIg5L{`%>5ixH=4Cz*U_NHT`%c|QeTdqbv{fYG3YMv{<-&*Xt z-YqJsjTR-NP+l$T8^B6Kymyc9Ka#o?8SK_XO_n6%iPwAK{@~1_b_zw(vr-o5cm}u$ zvzvsqUev5Vw%;uAFZnQxsc*vY%Pj_uhJYiYoB=RyrOt@SYwwc8Z)-cKtfE7bwIZKz zoB=)LFz9_k=@U|aTF9dps*Egb69{3)fGEFz92BkZ!HomXKdYs$uc>BL+rmV$6E?F2 zu(d19%tP*R_8h=>crddBuPPb`oU62@cH4v)*o1LEeznyiK)V_glG|j()9BFcxI|)$ z_9eFB5@f1FK?AXL9q`A}H;q>rG0r?z1ccbAs<#AFC~q7I=KKkeX)^AJT!$H%{Y~bY z2Vy07q~Z^jzD^qICHbR61lSGS?=Z%8G3U|SY{~`(nv7^EXo(e))>lFcNSf3mlMKDexSODl|CN+X!C7Z$&s{r;>*3_0?T7aSx)$IiF& zOt<()ib8cQrnAbir&tS$%D&%klgW=V2?-yp;_hLQ=F*cd#HIQQcgndqDyA=^=-Sf| z6mR=qm6LR4DXc}2H7izslC1N-n|kvWKq0;GR~{m7d8V~uA*X}q2p z+8&C^5`EpdA5}J8Xsft7yBn^cwL7X(p(tTWuelqmO~Dd8$V`+FdWbFa=F4Ak^yj@b zB@$78ha0koaKu3=JB0WX;RcV$llI)C=KyT+yV&c4M0LeF3ev4X1FaZBOPurrC@dW{ zx4k)3MFr>nS^1qT?XL}{m954rADZ^`KBxDvY zuSLlqkpA{`FiPd}Sgw#|Uoy~E!UituE1aQIuRy1)_xz*2{ta}vR&HP=IqXn=zv7RT z7r8tm*kB%pMB`|7s7o5D-S)pYo8;2l-Evb`C(G+zeEnL@x$o6!oSqGrO7&aIkc_GE zWkHdwC$h>H`>n15r^gGAXkza9^;SeZr^aw?fw{m8u^%6F2z7Om^-pgqa_h=riD0dV zaTWK;U<<0m69weC_M?h`V^%2d{~xgo1*b2fC2 zk%NH(z<*Ur9@2V>K`g6a#Xfb(sw$o*Te$_s-Rv@( zI^Ho$#qiNGE$-@&5SF`iBrqitXV(C5!|Ea46AhGic}vseGLk8`vNrnRO=1F*B?KP# z)uFG6`sGsmkKGT~a0T4#P9J@u8~`NK`wYL&?}-wOY}9CXtV&kX&>Y+r&gkg)3b4lP zlML@EU#&Y8nEdsa@rwVGavwDyCb`RDDH`Y*)`04vAaNj152s3 zPaNjG2TC^rx12#{cA#;&8%VL~qtgdgm$fa1SbFLVgl8+;$iWF+`gh8ACC&6U-Q7I< z@f9&B|EyhuQahe-Grp z2xB%elO)X3yrpofJ+0ily=)uF zrF0=(_tf_o`w`#WZ1dxT9XaN_28-^2>U*3q?jee~)qvl{GJ?0*Z_dHkAuKElN0Zn9 zMk>3dLsz=|Zyj((^ozL)Em5%Tf3plz+h8m~X-WXi@L}85b2Ldxqd3eCq`3@H0?AW? zYS~s_LU)f#R|d`hEm$QtKwft2j6K5z;vS(*mDiej{q@7zMh{Jqz@H!^Eahg}iw&)E zGzIKGXgn?;QjUD__x!hpYqSn>?9h8tQ0pRso}!n)&y~Lj%zSJlHJt!%Mn5(QYHum_ zGUFPhkVmWHt88xDsQNv?OR#&6V)xry%G{pbV}!mVlpw?7)?iRok~MOsfDVGhZ)6iu zroXIAnHxm`a>AAhhR+m>y=e`qGPjH;E3Blb% z46)d{w!FQ_9kRaP9-*D@&B%eIPV?LYCS4WH^zhpCQ($L2R!4!10HA158BxiOd0KV9 zY^A{*?FntB&uF6XbODEDQqpd)HoxS)oD;KVKrW+*eTPlMaZL+r54aS`G^%__IzdE3 zAp@2>#8T0zmKSBf04#W>l#$`{Bol7t%V*QGlqX1!|V22gUsed3BGl2#ko0WlP{q zrkDlp(p~ZmEwk8Df1+vUC|x5*KVWi2Hk;N0WU(qZe0P9 zcxl7?7|Kh=wd-Fp>H_LR)F&{Sr^l-@GAxN)dQ?KN*0>a#H?fY)7soH*UU-$Xfp8J`^HTA`; zjCe2Hi&=Z+5<%47TX{|T;`Ok1-VEzJLBvwiM=DoLLeX4OtBqcEg96z-4$pUI^A{QA zumt&oE!|V25l<0bySJ%b03oN>OA4}hywajDAV_jXid$qCkBSRCe^4Fd&=+wG4auZx z@Fa6G{O{q0eVhs5dl6Vkt5dW#0vk0Nsh`qjZ@dR$z#X(WH}KGMpM0Mb`>^M;%NZ;O zUw!SN$X`w)X*BXi$YVgniS{3L7~%BuB3C$pm2jJy<5j@~>y=f8n&e?5dI$Emht&`k z!`w*;p36cxNj>(8bAnVdruHD(or<}&RYP}QZ|FiE`1iVi<;-jB`=4Nf?>$@QO}l14 z<*%qSCJ%*FiM*6(QrnlmI<-klu&}@{_x19PhI5V^XlqC#ykOq4Gmk-ps0jljbnSE^ zF=}RDE~kxJy;%3wS>HHdwCt32+rWnVhaEaF%mv(UjgNDCk5bb>h(Cb4Y!ISeef%|v z1p00_rCDsgWqL;xT5)9z41|mNzaD-?hhX$N>18AB47dmDm>Mx%__I-GXq*gbfgsZ8<+5Cx40`h!+>Lq-nmXRpFLJr>2Hz3gJEe2O-to_wZin?(X96*J5{_ z>9VW;8VFQ&Pc5K%M>D~#l^9o-RpM|fmondeMay3%44^lBMnY|u&} z+B(;IeSzS7erZ4M;a2htE|9OzeP*$HgQ-0jD-A&U9mUE^G5tC>zH<|`@uBEt;>}Ro zTz;pqB|?I@#X6KyuGJIIZc0gMWK5%3=L{St6#g8qmVCo}8C88kPURK_roNHVGM$H^ z*Z5ZW-m{$8_JvFM)R)-)X__jozNB@&Nr4>1EG2+_v6b6X2p=2p)c@QHK>({^A?1;B z{xW%Id&VhB+2E}!GO83sELIqr*jK@0z>X}}OneFR3OQ(4qw+xm&H+@+IV3lvcy=Q* z@=5n!&rSQkD(ue30o92$13hxvs>*005)NETuWTXU>>fOQ4$S+{u4t5u7o@qg+ju{Y zaShmU2|_XpWkaz*$kbsImw^G&T96#pFw^heS}&QlQ0KkIEcPb$ZmVZe+UGywC68Y} z`t5X21R}0@&!c9mBNTMI`!0l6-CYIOMFSBvqG;yrq;7R(tT`8<13_oE%h*77Jb89E zQ_`#i!49yPp}-I;dnLbTAgh(G&sdXt3{YjLR3Y8hJ@SM*jquv~^v;%#5@`*(+>tEq`(imrHdD77uY(DFV2J_E@SiE_GUffR{}01DwvIdhumV%8wKXw&>S~hmdGPS-$FX}DNys= zM(7qWweTCzi#B%6K%GJQ<$pugE$y+M`We>@QeZN2>ItFEH454K>(?0cx#N9-tUDK& z^znfEJU`2J@P&oo$tM-b5VCL&(WZxb8VpV*>hOvW5!OA~|B>VL7arcUbkE_4{oAfz zR^&U#`H2Jq-l6JB$%D!>7&=^GLkIWU2QB2&Zsm}~YON>W!ZA$Q-+6hg>!^Y`P;}6^ zAS~?W)ZgzOeP`8BBtM4MkUIU`uCn!ceQ-$g*;5uDh|LkC4oj$plF?a+)VbB8A4|O@ z+@FNQI!h@W{_@(!_^o{1|NLAUyu!x>xklNeJbDNZvgWfk#okY+?0mt$lz;YMdN2}H zxY1n6!<)?ZORLq=@8kF9V)%tH@DiL7G==CiZcK&LNAWE`-sa(Fze5pE0YxFT1voYJ zzTSO65SeIJ(OF3=o)DRJiOLIqf2MJ@e)2mfbS~&jADL;L3CQanM)nki_IDqSZnYY* z4$Vuvz?cvFHG216bT}a?Abt=~Fdw4&6C6Q@Kx>$^-_@EF>)HjgWyQgWjdWR?e_Lm)2yp@;{N#Wlk4u|zxdgl5C6_4 z;}9l=H%yg5jThTQLu?+eZ~RxqQ57+1Z0O`S z-v61mm5a}u6-+>&i6&lYV&@Q)x`sfw{t<+2w3W)^^gpj@YVRI$v##mJ=w+61;f| zPC8X&-uz1C{W0IVrn59EkpljBupo>3%QE$AM_bcZD{m{{i?Zen>b`rsdfPWqevb&N z3}^=(>wj1hNkKHb0O`R~UmB5)NDt9U)~{32LcSemXpsc)xJe^6hmU#xCJ%5%JRZ4o z#hZvlnmG9dnZ_}!wEl2qe3iVb(v9a^P6icEhMah;A(;EbX1vX;6j_r^%}hTw@^=18 zCvhNZo?jV01yZ5p2lVs?^RqAhMT)iEYt4%rZ=he>K$r5=q=2L$R`0vWc>P$-U$Swk z-k_n6=p>^kf}a?bmSS=D*AWp|h~e_J&(966Gq@%!&*Nq#S#XbZbV#)R1BukdpE6@8 z{wRM}mjT9>8d&Y{2K#0u;I~GuSGhU$rx9J$T$KfN5FVcZqxy2`Az|kbJg-0Zr|b@D0BMb|k}x zls+Bxl-O9T{fu9H@ydhCSLwCp3S$xt)mcttj-^a9OBI2mQ`M$Cg=s;bWbpaY1Jaf`?SDGnoTh zs??L@^I^nLCFV>yiq$af{ca&4<2UFr{i;*eYLn>_2e3qFZx2=zw&S`*D602Kwi|x*1Z}CTT z9ZrWv^3`jvOxfx{Vcm#bAb&9fwny`6=*vGfqh7-*A8aACNxSeL$`D2ucT7QKFn>oP z;)k=q_rsj#l|u^J z&$;FG4uHElct}~^Q>ER3m(oUTQJF0_nk1u}3hs zZP;uS{!nENoAk<_cN=^B_*N%s0Q)AtAvdy`L3JOugGZ$t@3?WLw=Y(A5C{(ZufI&+ zNZk1B{XrejY$=Y5>5<`u5DuJI8;?^KZa^H2-htlU$bXrfKqk#Q?*>NkI#v%ami5(W ztJF-Q1>2tCN@a3C;fZ>OX=XhQhxpr`Apwj{N(r$HdEp{48vMnsWK}pKLgf$23yer? zP1f`IMod|T&~NQzKe%6@G5NiGknI5VZ-eg6fRgzIlUhs_m@)U3#a#R?Eo^O%27XxBPQh<4@bFClFW(D}m}CMz3_?_H z)%f-zp}OZb)ooc6wC}^>&+l>9p_{vAB%kAt+G1W&o7+<(FlAoZ%t7#s{q_TUx~So$ zH~Q33UpzG&HREKXw1Qv8M{Vob8&t4&SwYeSZ9B6+chzT1ut@QmD`bEaBYXbffH&o~ z`r?iN;I*6)HD_>fNz{!R!wJn(XLK`2(|@>Kd|AQItltX);slyzRK~g&=+6r*=~M0I z&r(3AX@KIzWnpx0Kr@u)Z;c6(TaLskTmPuatdRSBze(Y1cfM(m4|D!_L%;g@+Mb91 ztLKEkew?k}Y|0^ow1AsL(rd!cTKHe-4$C8FG!L_(gRc=QlUmfN-@K>W(S7RjmNRaHtm7&U_oyNneC-t@o$3ZC4strQ zAI|9`w1-_Pn%PmhwO0JLu*-O(b20XFV&!7*8Jbkh`YX&a2Ct*_?ymzSL&s~Dac3>2 zChL#*I(^HZyFB5EkAxAd4Ah%)X)6$~sQ87hyXIxHQ-d>I!t*U31>f9xyok;0u6c4h zeTnU;zNDjuU($7@K~rZ$8rx=F`?$24n{&Q>W7x9%hqUIRFg*%jbc?6?kzhbVbWWQ$ zgMy#;gB_(8u~5LYfxIaEx5St`&d7X3taM(TM0Uni{ElA38%<|b_xq2eZG#fSIxNB| z1rVg5EqE%}diF6mSF^|EE=9rFyk7&AR$8Id7%7mZ)Ja}$ohiAQE#VpiZzbj86GluAmSk>h1>Bx8uLL))+ha zpsLIavZO_RU%oXpsWx!N377z~irriuNl=0r?F-8cukzWCA>v-Q5RXr1{H)8B8K0rI zB)~M3CW;srHi|Iz44NOl1ID_e7wNNda*!nOBVdddVWCCUSJ#A=p}BdQ0@_WADDRSV zl8BUuI(uV^q`w$5^&{{jV}2O4s%SHy;1EM6)L@}AK>LB>YPCiM#uq0X9hdT^fQD8> zy5Ja@$^ID1wd@#-M+@;n`FSo8uWpyj1C`xsv`-;o@9nkj{B1{#pi>bY+QGb2%AWov zcPl|iVKivBJr(AS2b4A!5J?nd*tpqjew_{i+9Ty{vjSmt$VtSo=uc zs4pgA^EbHlqjDB&HU9StYIISmb;7Z!Gjes9+Fn!7Dz-@PX2bDo#*?R=P)xU8gNLUT z@u}T=&EgaAjZ~~MfQ~;2zn%KkU9gF@klcYH<08i~;OV*krIK4sfGQ6+2d#m?sftA_ zHD>;q{SpabaP%ns0dorT zYUmOW#lRnfy$4YztbplY!W;Rq`=mtRQ&Ij%i0fG98TxpSkK#+3g->ZRn8vlaTyYSFi-j6YR) ztG5q&y9-TT@(%|>tv?>}zpgYiAoXHnK)|yF4(<0{#LIVh4BmZ<)c@3>EmCceF85Dh9~M`7gKG>&Ceu-^_Od-<$8 z>$SPB-1Nc-p0L1jQbvn)e)5s9xjXRu_52BpeERT5+T=+&09#8WxJTgd|J-C;0cFx- z5w_`}lkrWmpEqYR3fQX;Xq7T4jJ5jDu+H^T2%s;+^5bLm8t=!E1&R}hH|#?9#=+pT zYT_S2W1(1mwoJ_J+#_;7TvOSqZ@a>bZ?EnBry1yb#0`z_Lu;G17+z%LNYX2uHnP>deQ!NT(&DmiSl z*A7(WIsIIyYTQCZAbg9kLVV+@WH)qZOCxzYSnFO}+sN-*-R_*OHfqSCUe}K(QNQ(} zkiaxDmb{U|)=ca9T;KR5@5>=ruW1AL?Jf@|?R*#=?C;Nm>Thyhn6VeP$bgD3-d#x7 z2)=0;T`k7~ur!3TH_i94@DH%ks;z}y6Vq->?D2*liKO0L|FIYM-n4Zu>v?pM<8lj} zmF&1*(?Cesiyh9_{_oZM@Y5FeJMy51cKLU^$(Rdr5 zR1}BC@rwp)xJ9qquZ&g=&A2(*UL0DcuVt|rSCDRxW?uCIR5x0luJ?f80)c?b)#UMn zuI{+gRjepovU>jIEEuAPN8izVOsyGtT~+OE5IpgBs;tA}gRXof z&#>czPr8qAUA}ZFdvHLIu6VunF<2EJX%d`W?2*sF8`g5#(%rvN!$z+30+wijbUKRC zAOY@5(yLZNZt{F=zd`^BhtTXn<+9I(Mqs1-v@y{syK*(kI{KD;s(-a$nCRz#^@%YG zd~>rke9?gM-Dc<0645E-M~-C|HPUxd}Xm%Lgxt!%+eNtI}jM3no$F?8%;l`vL zCjc?n6lp>HJ6@J0Oax66>I)$jlQyQb@eJySLSDN8_|J-9q@O7>A2!stgg&nrM=6<< z1&K-qZX1wkv5%fhKzXAGNjM7p?D5h^N2^qZ@W>jLJiz*VA;UV{O$y~Sw>fqW5RxT@ zKmG-d%i@gQ-5rqaJ199ctppbmlD*_9Zm89J$(*9Ik0h>l=sc9AdBcFbKEM2J%WO`l z-|?{8h?O&e4NOu#YGtK4^A?q{_O|UO3v|Rm-3X-n1*J6VTlYv%y1P~_iV=q_kva$8 zNb(G20w2Mjo+vbNh~%|8=fr9pvR)`{q~1yazXFPUh7_a&urfUXx<*+Twl(y9l+u8_ zQhL8LC0L+?epoO&Br9doNW<+H-6RR97tPHVh`U`MIjU*-#O33o)p~WLcyYx~z-v;; z->y>l0lNi6u#a|&{tD%I*v6^`b&R~EbsiV3m-Dq%2?sSi+>65Dhy-eY(gb{n0JxR{ z5u1o-#r{6CYWStMFTX`SpZ!(lra$c74epcs6sce1GZrn9Fku5C70#$J31$ZtzKW%y zMu;v^P<-EpB;&8%XSXKz-vEP~KkLWlF>nIQ>6Ch?M!Ny7mXCwjZ4zqI=+xqsg5@p22zUa|KO zt~G2)o97F`${+dQ#(*AYGT@66zc4Q?;6jTEsR6i(R&Pwz1^!Mvu(UkytM+o_@RHEA zR~FfMi>}hZs=`kKn6dy%+4!{0-eNsd{yj=wurHC$h3tDkxU^Xtrzj4TJf?idN!6#B zMul%y2Kdv_WVYRrKM@zG>F~qTKbQqwZeFH?>y#fqWaE9sHsBR=6PwhNADydcdK6-gk`%yQZyvbGKA@CNrv z^^35B0!7U)QCE@pF9Y*=n05kd9*y31P1ulZ#4XeX8eCE)7s+cyyj8uby^(XkdSNGQ zwTx6h{-7vl%}lbt4hbe#GGTL8G>gP(jv>*PS{;XwM?iM-Alh<=B|aO zqT@sYZSIiVoy!G{(89kYn2{hjcx$Ot{-t}~GYc0yh*SsYfcsd5(@o z8at6@fFwrOEKlNsIG7=~o$=;h!?w#C*IVPFZtAh@3Sj_oHB~i0ZurZPlZywhv2wUe zQuyCYEVEfot4G#2`LZS6{6n3*JGgI1%vKrQ9kjPxizSRIqTErkg;8FNC=8 zh(YTFa?qN4uQ><@<=&=4nPs^QiYgzGFkOrL?X?3t$YIK!f9&~q^!t^c&B6A@k^MQ4 z0qOK7YDx%SVji>yf6gIfpY*T=qI7#|c!rTzhd2n8q);6uOeoG;l$zrc(xc}eCm^^* zD`mhsk%MTye~6B!feTgCPNWuoVjTbi!z4h4J5-R))+@2UDw4Rv zMD%IXTL2+^ta*yG1I6SP+#xeOE$06KM5Z(oLg=ii@uM42PGVT%&C-oR&vWQ(eVt_J z0jLnoGCOY}|Na-YZEr62e!Wtnrm~U*aQ@>Q>qQ74G2Cobeo5j*!7S_r7V3!5d%>%S z^RJAuj?zc>yCCA|jZ60t-!s)H2tu5g5=Md`0S>znW|56jdAGU$ss~!=hgh^Hkp&f( zIG)B1uCw~h^mXSFz3Qi}(lg1R6ckGAfY$s}8cp*I+^wYQP;KtCO$P{s;ZM3UwEqDE z=&d_O>8f4f_B@}lmrT=GZUG%-c!yg9iwyId7sq;axBjxD=MCLB*bq?5S{@YbR3?i& z(UCstx^>;l>G2PTBmo-Yw~aCPj~M1771m3H%XBwiW-*u8!Qwu=d8M< zQ=#$E-=UKKtgdCuY^iv1k?mEAKW603H~G!8U{@)-7j|M`!DG5DelVa<~Hn5bN&9eN77NGrZxqu3-2Ih||wgf9h8X zOj<4)qL;ErLt+5<{QBBAu4uZ4gw0nX0 zzxM+7(<5f?+-FXvD`5*omv28w+JN)Qc33}tMgZ(m>#iRhprJ}skNocj>gzc_ppae8 zePR|!?})zLs5@ID#M27qLI_m~;la5bwJH=zHRfg-LeDX!U3s#3-M>G{CL8&D{gCR{ z1o!r}o2UG*=`~ib4?OsB+?bk!e>q>3nwCt{%q}{P`B1=&T=2uPxc1zpJ;tG4LTbAa za81@b<8rpRY#|**{?0v;?XhE)SOmBW!ZlupiN@9c)~@tyi))Hb0Dl2Su7`hYKDih3 zEt(q|Fih^NPqKW69D5~8gZmVJM8``;@ir$nH0s{Z-YVLB{vS@gnQkr%Ix6^kR((Z^#?Z(o?P{&YP(7hq>MyER{MKV@u zva|{$!YyQYO&oBOLR68A00RnB<_BZy2LH%z8oQUPO_$$1xE_ekHF*5EBVo3@bpGM8 zc`p%8opAIs9h{@T1Q&+$^jrS?IYUZRF$= z@W&1UC&PNR#?0{9g;n}rv=z8mO><3_O0;Xp_z5ruXCv9?2AwQaW@f48orQ;}jN8sH`dhuGZf%j; z^Lc#}#zku1yZB9Yz7FLsXBjvUe=CEl!)F9+`F2p{vEn#-j@_`t&`DZ8W^=gHJa(fO_Cmw~!2x^wqQu$uc7OqoV;kTVFC`D2 z8hoz7TTA_2TB!%{FH-u)bceDI8UlNJ28Z5-{ojm2kz_KF1#)uv<#YYXoM>SB+cfX0 zlQyoI>^7N*Kx)|1aC-?2!W@Z?r8p#k1~9~8j(VDl+@nb7=W}PPOSce8{mKO-xCIH$ zTNv(_x57&Oq+ZFu5;_5DR&%?u64k1h1Tc?tGIIN-onTZFff-Nth_Z%eUE18~qg5C>EwfiYw zym4bmD{AfXyhoX5MJwyI;{E|Il{+~65Z#(GzR=)o0#DrN6UriF*D~cG4 zHSVe}Z`q>kOx0eN)R$?MW@z`yIVefKp0NE%i98z;U-;|ccQo7$_36KR>q+5LKS^Ki z5WnptXDb#W9Dch@@H&SoKt3SlYH~RoH=ZhsUgYQ9z!@GHB6&pp4_=h`raRbfE{j_?a`#Wse7=`sn z&w$IFI@|t@-doue{B<*a6WG1bt4>!fT8gluras2pcS_G+LYs()f}>{lq;K?hbbFPg zW=no+W0anMzk1&8n1x=RGsg2!pzSQ!Xx?Sw=(%6zT1Bta#NaX0PTCzYWJL*($3Y@~wPh^>}(^5p5;UjFBlISc;%+8dQ2J@?iFG}eYv7^Tyo&f@KVL5I<(!7h@G&~q#dTzF zl>4B0C$)yFzkOT98~xVE%(ZD!pW?H#3Z_SyBK8bemx>QH(#ZSpbs1$wHH^Oc0MBiu zjlo2|Oz-H%?qSY{nU?-!Vr=h?O9jK6Um$XQ(DO0VXKl3yaq3-++903UcF`@;3jdT z)ZiTv_`fmcUs`L~0W|qt3bGtfKcWW_1B&aehW`T+ZoxKh}g=4Q-uSAF-bPK1^z64S}IQ3#0han zBGBwP%Tn%wniBFB`+#!J$6GOn^rKjky8%c#!U@ag?`}M~r6^;T$(D_M0!cR@oTjby z9T9hi{?`p)l!*tQCS$z=jBj`eI9iZKPd`E0WE&n>QCVMWc$O0+5x89YkO7gAQOY(R z9>s%C@kO>pn|{b!v1Z5l6Kde4_Zk%06f&ufrclUIJ+xP&M!W4q)mm22$(uLD#gmE@ z-GI+N^WsQ(I1Kr3)O7<&|C$~1L*DKE(u=oaEXL+i+rs5F=$Cn2WK30&kT-S+CiyFh z)D)A22q&l;npdd<_{w(@!TAh!T;>BCb_AHe>$xpjXJUFl+RP3XIC_PT`JS8qSnjk< z-!zskh=^&CA3=^7y*{%GfCLE2E@ehDrmUrFmBRjBl$OR65m%5TftG zidmZwl%jQEfl2dqjJ8M|JaVtJO`AS127H(pK`m;- zSW^MH{$&)hnNeKI&o*Gs^FYH1{V%7Zo2M=qJ)KrDM=OP1FDqP6D4M5FaA+7J=D?eU z-sg02lE&dc<~@-QJMT5hc(uA>_v7mCBA8u87FxTjPm%HhnQexD`0V*??Ry_?9so9k zj=@X$S@VBIIlRn%eEisK_YqsUFnt&n8aB-zEZcLb_wBePff{}~M{}M~=ru09OSK8PCF39_`RNINWF$>9 z;Sv+vX?K0}bvhs^3YeUh>x`Np*B_ELRMPGfdDn4p;sx`+ObY5z_5|w^E}ufwTQLEV zl_L*X+1^+_Y<;KzWwX{iEc!^!J|l`MUJQr=FkVzt%%%73alamp2md)BLX#7O9>k1?|lW(FuxG-Nk~3hI1wFITeW}E_#hm%VES4x5$r-G!rEwJQ|5{9oa^C^a%KH>fg|Fq zRTtgO8&hStIigosJa!FAm~Z{}6+6T0#|J?TE6LHoFcQ=$iDyFeFm_LdgW>y1pGKZ{ zEO|j~o&R-_N4SZhx>eusQTEFJVGlV8T$LKQ$gf%yy7aF%TXQ(J% z{pvjH#a2wWcOt~f32{cna|p885kIdHP}{g_)&b9wa2)k$oD!APQhDX_1GHmt8EK*Y zDP)o&;RdyfG^>dFEm{K)(1VBJd>TDiMDCxE3Rz%*QHY8#Un)XK z7Rad1!?PG^Awf$Dx2)}6?1P&+Q68Gvj+3D~3Gd@_YLiJc%(uAtl8F#L_Lt!WoNiMw zUXRG{5uo%@O8so+nyGk)`-bEh^w-0?xiU9%eA>JDGSR)EiUIWg=k3x)L&@#eQP;nB zXyAGI&yR$B2^mZZT!tr4ToB65QDBm4x3Ec_)P?X?5u&GZRG8@Avvtp@nFcIx;4eB8 zR)UHxh(cM0YV>Ms!;yvDt4*86vVTn)S1OJ)T(S#!%vmAp&p6RBw1eEkx_DCnDG zFV^<`H*tQ$5_*j3L76-->FHij$?Y(tYw+N)=px~IDAR5>XxWoU9FiVb?}~72+fw)d zgu8NxB?QjsSDg|`e1*b`RD?`CwO3(2`b|G?j)*s^xpu-(97W&Kd*MR*4XT;a_Tqs1>Y3Bxe`GvdE5t04hU8gkkyc8hTwal-*T^1Turuhl@@?nc}UL4tpiX66p5aW-#wj!vAEK9mGN*aN6*1% z=bZ9NTFpcO*xrHE8jYqW=8gSLl{b9qDk6KM?GS*(#VFX0ic35%J`^vVU)lk4^HhVy zT-RnVHQo`u)001W7TclC{c^5FCNxRA~6NP0nO;_^SVSWAcyk*-xBmE~2@8fE)^5O_qt7PU! z6@*9a(G-j93*&D*!X{343q=B)csj=4hk@x_6owd5qqM;sP!xtPYty9X<;!9LJ6s@`5&!s=TY)SN7Ecbs?I zQbaxdz3tglSEVigK2nLlL!JV+?J`%ayfxFzV$7sybb}14R^%RFQN{NzSuSk9B|$L| zZX*2%e0Q*)bns>Sp>nV=`DZQYoU*D0AFbDa_FeA`*Y>YH0j6dEp zT+f~ON$he{I*;iZJ6Q;6AIyN|^+-xKMY1Cr?L}nAOd1Y~y$_0Mz+s_E2}kA8s3Cc&wCZO`TWd9%3nbJs`|v&X=OnIS^4Dsjapn+uJWzaCRNKaoU9&D z+^1dd^nNM@#U!pHq{p#M1)~ZwdI>u~9mb)lt5t9fm=oE9>!M6f3V=$b<5naEoCeXr@6mu$qx-B@h< zG}hKCnOtD8om^6RnSPtOn|dxNj#LZF7yZt1Sc|jI>(+BIiFXKWfKY0LiSD16B60HJ z?G$$5eLO%!rJ=PIeLY-vmwh8EGQKpgW%KO0$SVa#!)MN3u~+R-7R4N0CGUVOn697A z!hy&X*0}(fcyTVWF)*l2w;XdD&?|r6n3OYM7d=aX$mfR5+Eg^&Mxh`L9uu8DLFEBk zSFOJfUSm|zc5Y@iE)4FEG2{jFQ69t$Q||v3+dmRInQyZ35Xzn-%-MKOTJ~&>r7ZLV z;Xw%I=8dooI0F|n-e|vT`w20;{UH`Wr^X7L!jW+7L{FSuFxfy1Ng@f#zbTs%{AQ><^xR+}WF_%n ztrG@T`*1KAm-nDx?R}i)DCuG=lURDM16@*R{7W_fX*F|SsXw*)_F9 zLB^#>`V7ss?xEC;3yxCC#a7-Q`O2a_H$;;iveVCJ^_8jMP9LbvOURtb@4xeX9i`!z zgW~b@x4yR)6J_005)NYw1B}mF_dT9rbGalx7hMFMqz1yAB=Gagn7yFk5L5l z%$g>13V{uNfBK{enfVZqgncig0Bd47XuZd}8rXgLeAR4|1GY2=A5t#MjGamACj9yu&4ND@+$zR3R!5c9ekMXC%oTk=wFFB>Uib zFNw|I1^ZvW>L_(vQ@rNM+r;VLP?sXSDl+YGFOsMW{?fFq${i&0B9TH%?H=OA zzjn|zdDz=mu8IRH2_z59`Exl314AXZ3&eX#jhl6p=LI-nIys5#=oh z3iQ=N&}yoT`qEwEOo%3v*?*Z|9VQ&ZHTk=8sY?yTBy;O9QWFMi->h3SbT5du38O{- z5aiT*Q-%@wU5W)94|!PcZ%_UGyG7rT`CgGrz95Zvct>2}NS_si*IeTHd^`>Z_e-Qvlgm- z65Dw9K{x-Q(BH@p!@s7nlA2CT<-g1dbs5^4!fCVHJaI$n@eFmm!|owV$sO|F#O{H) zdDSqU2Q;?;qzKkGyE$_#1vH$|_T+C)M27xdkac#8u%_V{Or4B9KCthH?|0p)nA23s ztF=>&c2-$2E{iOB-&eQzZZm`t#ZRFToxsjV!aJ$?bUl3taR`A9C_5m(JbM7QXN1Z) zuscj~)r!HMh)I0j0?{N^ub9&RhlK>(RD0a$Jvy%yWOg`RyWAz29su86_H>ohEhD%n zBH8W?0uiJXtmAPU2<{J{q88mH4JZNkC# z`gHd)KgF*3k0|e6#Zy~{q2*<0`c(#vpE>j@{tN%J;R@|4k~B=Lj)&Xz2z8MMCL0ROoC0MVPFFU})< zbza}5yM6xI@w^EWQn%u$opmWkD9WDubwX$J>s{Q73vDJd34%w9#*owN-uWSeV~v-C z0-(j2A`Z@}Y$wCG_64RT6}$PAqlwF?h*iX`USO%xqum`PSpUSyc{ne>&39U4JZOdv zB74JM3q>o9A#cHUsJx!sSK2hSjZOSr2e>z|upLQ-Le8BFOGCts6 zQlAHzvWi!u@$Ijm3VOAeNqe0(^OknZHJVQNTst=?&MUBt>wV zxR{${k6yXo1bF5o4c}Mt8y+K@8DOjMr&PQ$-aBCEfFit!Dw$og^)(|8<${$S_l?f; z>ob>Xt|6U-Nc}9O9yIfNl*QKGN86Kzve2Idgz+NjK7s^=Bzk+$^}JGC;M1{Q(3#TY ziE=&@I3wyR(+u;)*M7Tr$JB&Rt5f7=?Ho0gS>eXPpy1m(44)F3t{h%94lsYk&TCQ$ zAeT{zaq1w+CBOEzzobc#yB2gk={G>~;c$C1otQL_KnUUP`Q+kP>y1W;;w}I{xBdc5 zCB?2Gp@iLEpeE&9NS~c~c^Ua+WBsPUcjg(zd^o)Q(}&a{vxzFtL{017P#u*u^nt~* zZArI6zC8m0UWBEsnj1KH>ed3mRCHf7?dRgx+Vk}=Onf7lzQFi*_uo|6FFE}3)jO@Z z*Vwg4PtO2{Y1n&p4eNu8C5L>>nriWSiC3G7qtfo%&`J$<<_Zl_w}5ntX!qN=Gf0Z* zt|K?soU)OrfdQoTUw1c_gUNjBX5y%oa8cH2n=~cJ6A0%rcND^D$+MqLQBuHUkGj)` z5+amUo5`+;;86!k)lHrN3P;tJRibd<;UrKuKs-SH1@NwXsYVf53BU0AoevMzcsA6Y zSm>Y6c&04t8fO9!Qc2Pb5kr*^eurpE3FW<0U?x^Y=|*)~ig-hwKliQl9|~H}Z3>p~ z_GQ$4=J)4DJ`W@G_FnLil0@h9MYq(~x0Xgh$R?T-vAdcD$>R;{gxzn`b9_2gL`&R2 zyxY6CLD;qQB-BR*;`8(Ad6D{~4;DVZ~&Y;oAs@*uIv-;kswtP=837;e#rC z!(%upVMyM{S~#r!D))2AJP-QiAH{5w?rtVCi;xwBu%Q_2BUPT7ph0_k1C_uYkq^e9 zog6PA;#NN>#p?XuS@l8Egl`0PF2->v37?~yK4FQeScQQ{_~+Gv`vM@ z_Vv# zwC^-|Nt6CeP(9-qP$mg)Q1!PwvEPijctJ}>$%5`dKC4O2`qL$=C#X{uYPM_l{3)n< za`(=~tsv(EPIDG@FYK!pbFa1lvbsgsJc^R#4g0&rln#m)45*&AX4?OH2T~}r5{4jh znOWjd_nqDp(E26W@rixO6Iztd5fb-X@Yf5j7--xJI-R{N?wfshs=J}i(2w^S{JSeL z&NvN(aesS#TAus^HplTz-cXttJj6n2;V&P{Q|D6kgqrTSz1KN%IV=6vPR_ z9{vz|Rr-y!JwFX>p$uZM`V{%GaLilBln7z@yA+#>-%o>lS_VIU#1Av_{`dNg&SsFQ zzEEad-$sLl6i>uTXyIqeD_>;t3a*rvciV=6AWaPa36ag%oG1sF6RbCj?yB zJ$;zZxl!JPn%o1Vf#sslb4I?JE-y7_(Yh1rULoG**>S$@!e)$_x$BPoQumwXM?ZC{ z)RZami{03(XcNEyTGzOENO+n^$n zDp}Dk`#k^Y|NVl0tT`{7TNYJ30tiw;b6&P+NWxwjP5k>I=y_HUkF++Xz+syIGc3=b zrE+zx_?rAjq)QoP5feZHwmw|&Tvt7_lgd`J42xv`^&xalXQDv>{@3O2OgC=?z}OXj z7-R~jdiap-L*Q>8I;J8q?s({PGyyb9GQ|%XQTtAdJ9-}nPbe*4I1S~mkFvIb_OHbK z3Hj7?Oz}F=A@|t3K@@RLp|+w@qd%hlqnn?lErbP@J7tO%^!RWSGTV?eoGlCw3=C{t zb*4T@d1Ftrx-bOUvEFCYrJ&+bB}oDo(&38mqT<7v#N4h{e-uSMOKPqC6GkYw zr`WZnW$3CN(!8zfJg)p& zJARD(t4BY&>)*wnL~iBlTo3udTJ!Ti0C?FEkIBuyN6VB!%>i8ZTr%wg$Qi3Q zr{Y)JINK%{1_T4vcVIj#_Z$)vlS_1P>_EmIN$RQ^w`?YTLLz`6BWK-U1HN3a)rcKx zt{N#4{)AfMxE4<%~`Rd%e*5c5O8=Om(Dc3FUTXDn*J1Y^$4QkIFHg&V7uW zyh6A+!QoD7)B*PiNZwe4M5QYkJ)8>+mIKoB-*feQHJIyfE=5%P+OHZhV;Gt@Vt^x)MQXnd^UV=cbr-DOk?Ld zHU__{q46^VBfjrAAaL_dIJE*m6&R4YF+*o5-L3K&?!&Zr!vhl}8R`AQ!{f?m5;Iz$ zdH~>q`}Wi9aXeXPj{{$5{NHXG6Ge&e(~OHLQ-Sl<{n%KT_Y+yT1ALzE0ff=v*4qwA zzZ_>Z=?dy`IZZyl+spsdKIzQ{axPdxfvYbO@@J2urkf0@N#ZFODJ`IUal8AJISr4n<_;!+b0& zz1AIw=95ik@0Jmv#&!>?iwnxpV8xuxa}bu&k;|!wd2F<+KPH}Ha=zppk$g@%Y&@5n zaG)9YfIj%g83^zI9P$Jpn$&YO$7Ax|6`Ji}p*2y_F}j%t3p~OAA`CbKAs-Rq}W^B|s2rK4snSRwl zrWcydUx$X)ArBaZH4s`zIv>=-?eNw3yI>hUfQPk@w8J^=-tB&YkpA(qGmv2kWSI`4 z9&*%8FI7wq2i1)_2=O2Wb#P?Gr@Znj0}=cyuz~DR^bLe{uTkZEt}m;*+u_}Dbj3Zp zW`!*Y3E2mlCxTIxK!67x9w2kMfvhrpKuXA(5Rx80;&4pGLAsIGRCf6}Zw(}VbQDDAh-^+xJk&tua|2QDz=MPg5>@W4YN@x+KarXlN%?j1NfoXoq*l(Y0@f1G-#|&yIRN zJh@%omJc@RA(QZtKo?U*)IlbwdicQuTzDF8-h&Dv2(Zm2bMjG_&3ke`+zww& zyohi&xqoG=AK{~;z(;N(6l^es zgITyp7HC#F(Cc>e37H2b_O_dsOy0pdXO~BX?4zjEqoXVy9Ks?P>pmVSgmmiwX+EYK zc91FzQi~p0#?Dp-Fr2*6T{RDBQ9$C|D+1D!{LyY+GT|brKKTd@@4nDz@5H!&%y9^7 zu&VxH@sJyY)DAaIC70JYh$wCtwR`}K1NaDNAQq!+9ts|43QoX3$cIsHc=q5U?c%|4 zN3hN@fJE00;vE2lGU+^OAUn$;E#k4ZG+;ci9iu7W(TzCB_(czf4=58cnhym$4rUI5 z=Ak8XX;ot9%9sb@hb$g!`x!i;GG~mAb%V;^|hT!Tbe_9*t&{sB?gcZkE?P=o)_0 zjjVzVJcJA+r@~JjJ$)=ZapfhgCLY1++u6IOE{H2~_D4kr%jORPf@!?#K{VXEKuEXZ z_dAh}W?4Ntn>}7KSLZmummVI7OPeakBM1mORw4OEs(B6qJbLnItLGDsVD+migjUhD zgGQnFfj4R(*Bb*dn21P-8L}M{k8W-f_;+rf*?v;qRy2?JLO~}y5y(fJxR!Zybn_4Q zsZ_WtK#1^R5OL4|59SZwJ=_g#w0mDoR3gMGLIx0%KZr(r?YX5x$FItK&_BWkvY5AA z%Z`waNeq+u2k2{ zpOX%GEj-aK{+Mi)t@=m5E`Cth0E_WFKD>)N$cL;%uTJQTRiLaa!9xhh#CSM5&RqE8 z$D20y_qTpOQ)M3Gja#8uuFnpBoxMJluBJUeEH9`Mk6Aoy#|kf(&)L1wq9E;K;o&xZ zOx(c&ALogOjUSM;kEHTP9Ur3KK6LBQEgrsqu$Q$n3o=xbMi0T`%WrPl7kwZ{FNlX& zKoZy>9^e6q!`TRXR~dLf0~|c4IfV~V$wsPkk8Rb$ZCO*vFKm`m%i2KKW=@xzxBcM*qH0{GaejX_~@jWN2U)| zcN9J-brbi@Y5 z@YsiY;Qmqp8LML6<(QQ`(aJSJ>;k9JBdZZCBLfb!5Ce#Jc2ut{N$Ty^qLb-FepF|l z9jsvdun8n(>vp_V77x)y8i=ia5De=fnOUgbG@EySzvM`FEbKVj%7w3W{DzN5vitY9D|l0tgAwRtt#80Mbt0 zox&WGerb+7?SptE9UWy?e^6onID~W|35wJ${6Bh5cf zzI^o#mPu6z-VsDZPS#kT;nwb{qJ4ZWBfAAW=JEL8^(X85Q}mNkDi=O7&e%mb_ZE3L zGX2JT^wvLGn?K9~*7_m|Qn-1Pf&7qg**xrSmbD!Uu$vwyOmw*a8l+B2Atk zL_9>2^f)tiVIP~|!`u7x@0p|o(lN^NTf0|`9m6ku`FL1J${R3HHGo+E*pSv%2dA^o z4|FcP{6oD1350y4k6+EthwVe|vtJ$U1pGrC#G1ztkrfa!UI$Ck2YOeA;9s_z^P!78 zh8`jf(Y(AI3J=V-O3mg0I0%V1r@ibSy>@5n$%PUKJ6N<2v-m?4%pNchyL2$>AJCy1 zh>ah3)Zj5BWStemknA?0Pd@#-Ngu;yTi3stKHVzQx6alzBf13(!8Kb0M*s@LhK=W# zlW6(4yPcdkrF~40(RWQiCnNFvf%0JUd=3ja`;SZL#Dn$`bdVK!425162}$MT%!MEK z9UrKD_<;QK7Sefo)dP_OwQ}9;&5Pp-3dlj_uL6qzAX+~U0K(Z1L+*;L%G01UNDeTGfy{- z9=HUROfF7C^yad2nIOfz+Q~;+?+Sn5*r0!G5RP{8)wCxm`XgA4rYCZA*Yd&mVY^q< z$NwOKkPRmW^U6*Z=+KvxLmVOW5P$i2#h-3>f8Hu~uKm_-I>rl}~Y{eW{pcJBTkdUZ#@H?Odxwzy*n1GMu zYR^5NmTuhC3J6X@x8a-*2z1!;M)5s+TdK=9s}Z6}vZ zN0*Ok=)1I!gxy8SM&s$b1Vs5bdHUjqW{5Z9AV8vo$l5DWLU35xcJ~{XK9mpB!FuoO z?@nbwIP5w>k+;wsPXL07d65eKPzMM(sa0P4!1P3j{i}_3XSk`)ai z<#Xa85(C*8tP>4Z2d!uxbP#F@gmf6qt-3CLeE+G>$Gl31c)vpg=~UB^X&xVD5ce}U zDd&#jz%7ZeT`V7nbU?V^9DwvZJ{BHpm!403qo4B}y^3z!9vi+gsxF^{54ojCxLR2| zx084E4VCa%6Dc7z8+8xsQJ70{!5Cz{Q#Qu$B=Ieqrefmb~z7iBz{J8NzhmA}y5Md9OAXy<8|hLFK}AS;424?SK`eS)r`4b#`1!5j~t4$dxN2dk%A zc%t2ScdA3Yt_IR~d{j>^i5(q9_ehT)E#dA;orp?2;i`gteE+;79<3h*&+G z81cjKar)$MgW}k3#6j?|`J4`t6OvW8Ab3Nq=uq)!Br6#tNy^$!AaaZr)Z?dWcB^h)6%BFrI9dHMXw?Tf%;pEGyM z?79*m0P)SEt9z92Jag`DrIc{z=}H6P?pC()ftDuru0RI9a_^A4T^coI-GGEHI&Y3P zh|k`IVn;{C;s?ffztRK}j_2wiHKSK_5E9Z8Lb&zS_Uw-uKf?cQ^Zy7Rq76HfJ@*fR zK=H``4tU_5Suw1Gk1X9g^iS>ZE<`}`ec{?;qo66*2r85{(BT=<@ocLOtv4`qZGni-kJfnNT)j`H?a z`VruRtDY$SU}HFcwjv)2NN=R}SR82TH9`#WnpIKmqyFd*JHOpXfAgyO;219rBofc* z9Mqa|5byy)mOgtr6Ay8ajE1k!xvCyoJH!YtB8aM+(LCTCT}&i^p~LUF%m4 z?WP@#Lp0Dj{u`AE5e?<8(_Q4(& z-NOguB{#;q>TS)SvTFw|9$>;6$Px%a%X?Yde{6w|=ZOaecr}2i+-loAo8x9lkd=?& zI`V^Ad2&*T6`VpH#3&ZaX&gg7DB6eU?sn%0l0FZA_;!)!e#kpGch?}Y7D(rCkb;M7cVu|iNw-XdcTl5EBTf+z4ISOg zHPBJ=4vbr&WS+M3^sKcIt1urT;e&uU(;y%1q0aw@uG@6oE0N^`pW*aTy?XHYSXh`l zd&lh$JaFf|s)ru9|Is^ce);riz(PD|A*av&#i_d%kD9d~fWsPy#t(UtkZ(R9AM=o{ zTpnr#L?ei1^85%-TLUwFCOk4o-SC(OL86luquFrH}|Qno+}&1 zKopUoUU}nhmOsM#I)3~w_{gguunu{7+xO5xGHH^`16a7r8VDJQ2M$<99FUE+I5>TA zmSP{W@m%h-t$pV3_~iKH&G+AM-HF)wRVS{y_J;fKxcS9*5BGqF)9H_YTdx_t3a|Yj z94j6jbP(0rtJf2U7NkRoa-UJ(*uv@HoXb&r^RRtlq#|9+du0-*mHlApww*No6c5@g&&RI6n&p!X; z_~kq9yt28&Uvc8vJ8ymTnvW!zz(5E`;@S@%4(lM~6t4sHbCBoUQ8@ z%|%W5VDY0y>{(GXkcA39?rv8O{!hC6)^omrB+tGgBFD!!-%9Ujtjn*v@uA!ASPKsD zLdH2DcCQQ`zScZGLU_nfGXuI##F~MaJMymsRs_?~;3~nyDtTb-d6A5E>h9EK6G$K0 zwVRjN#UEw}3+AzR#|;zP`(;<$vR1J)imi}AqO%iO|DbtLs}us)8|YZ1Mme?V)N$(>(Awl+dZ*-f*8dJZ`^XD*t;feb5nN z6=<~x@VjT}6@{PCyqQLyND0UdPetV`(3AD~0?M?udc zfX8+LAs#9MlEm_=tx^M7+605{(F_n~kJZS z+38nA#ODK(+kwZ*ab%Bn5JK5t&UCI0;?v>t0sjy@MB&y4@EGF&RyKlsqNBN3Vve3* zXvpAJ4IabKS{tH1FjwBffu6prBfC{$O6IPYio2|1TNLW>9O>=HT% zgfGfRaC8@RNdDjq6Gjjx;Gt7>agq-oklik>INrgrgVtiAu7?S9yJ4*7g25RdY4KlP6=AC8cP(SN?X{D?-rf>#KwPeeKfTw?;sJ30%bRE7^bvi-9HAH9Xh*QchB*b_5Xn6`o3FRx;BGs`A*>}B zi02@55Bb>i@&55P{OTefwc2Oi#-e4`4szk3$nx=F)9MO*T&6h4tNsu=!hnqID0*ID9A2irqP91x`>0&2!zg(%?#s{-iGeIhg|*@JKM07G@Ub$`*FNnRKAh^) z(-WWO26WP4n}fmWyMb^{KCs7+(OL2laFCGz8#{;|$R5PQR9Fs}7vt2cj%eT0GK3|B z&^?+>-^KpatFN{5SJ(b`CcsB+YElR(S6aF7t{e1U@m_$a_*Y~kMWa)yxk z>}p#fp)-@&(;;0ieptnK8gxi+ZVB=Dm?R*fEL-Y`8q+oZe zozK;^16PoNBXNUQ(LOq>{yE`84W!`J1}9bzb!zD3$lD4Bt1J+5-U=+>67-Mvo0nIk z3*^Ik$UO5$fQ_94l8lrsuj15_4(rKbMDz`_cF=BpwZ4jY-WlzCb5igiACqDs%k})p ziMSN>2Z@ITWbBUeVLfDC&X3HCZ;Xm42xoIxM_D}1#C3xm*S^Is9U#^|?Bv}K2l_gw zy+R1&KoNnEDLb}n93;etr9*ei9=-E`Y}llpgo-PDQ}YhZ!wSuiBo1CxLocKT;=v&w z+dV(l*FljG@G(U~!ttY+58^>Y#!i!uyc~i8tA)9`CD+l072xAc+;g`J+W+j2+5>4e zyenFJ{+Yf`iG)yMBuYqe{J2Oy#zK7XjaCcbBS^^nj#hd!o2#p5j`HwG;>^TuXh035 z=*_ijgB=Zr^bk34Q3)ZRohynT5~coo$lL%eh3$4w9QbqJ4By zY!a%0H17_scWQVy>>*n@goK3Rhw+afA7UR10v{xVqK9zTl5qdLAf1aw7w)m9n)V*2ryU`)m*-&?R@(<7 z7(L?PRpqpA(Iya6VYRq8suP4vUIZM(BUE46-Uo$uy#WL;fdhB&p&l|mfAUP3XkK=A zD>=*B2WMWz^wBMCHVH#~K*GmRUl$c7L>1&i0U;fRj~|2&M}=O12kF31ZhU%DGe#-% zD3!|j9Pp3$I_HXL@8Fj(knq}b;bW}3e1r+H{&CUd4{IMF0~hcyO)Bt=2LR))a;yEG zNY)lUz)1@&4+_A*KAOw05x3m!vR?KL#Jt)7d~~RNUY?L?;~~NP5h|{f4-lZIqXTH@ z5B2NhMD6#Jz`&XZz8AugzHrl(SKeWpA6Bo#^wCA_IZOlL;wXQCt+da(uPh(#L5<1ohQ{zXbr=1zp4Y(WKkmQK~FgA8kLI zJO3!^ok#nqoc29U1F@?I!N-xls%XC>1Z+%CgAYf@^muUnd7$;786AB1enCHRVuj_T zgp}Tz1UQ(L9;NU|^d9%T>b{0(Ag~a-y0$uexV_}2)j`0Ch=dqEjCs&O=pTxP?;iYu zdrbk6u`DT&l#epeoT~&&@_`}Vv=MSM?s?UH$zBaK5F5{BdSbN(;Kf74JK!F;X9&Rn zZ>B#eEs*fw)hPL}0v41+5E3$yFqRhsQc~=FB>3Rz=D)*nQ=hKuU?Y=2JgsAI>cdqV zVRVGRJ=_6-5Yr!|Y;zD=xMTQm$mM7Xcqkz!nL`QzDK9&Ab@SH;S6+(+R=4$pi|CEq zS4Uy`?$PQEp$H+c508-Laj_4d53R5)9VPjoTm(_oYF{Kt@j?%XD?Q4m58B5+uilz@ zwR->c|8K%HtPMN7tFJvjTE$;sAVdQQJ!Ce^M=+hshxsFng{`pYA)m{i`QoN|Qfg93 z&_3=yxOHphQUs*y8roQzYuNfq{o{BQ`OqrM&kUkj@{u>TyHMmGlm0i}CxOOzN=W^j zyp6mW8!aS{bZVlUdO)ML|3{pB z*Z^|c`Ugn>Xq?oq}qId z5QRgP>3=|`bMEuu2MqwidQ0KZW((0EA?IB;Pl(u=eVFR%stf1jW2QNEP(tp~l>tpU&5X650K#C-}h3MZ<>;=W?TgfDbhbz36v- zh0 zbPwf&u921hO$`OA89elkDl5^R;kG)1tgaBwRhOuliVr0|-g@$IW3G`k4}JMZPpx2+ zD(k-RagF{#I^5w&>Z_^AY|79JZXr!rJSN;RFNvuUHD=AW6Bx^6#lV^AQS2zB&4N*UGkwZ{hMrcC459cs-mF{&p_UD z!&jBqy`&ZG8QxrfK1x0q&ux9xqJ*cqNgudv$`LXTLK4h+FES4sKfcLSS6AemiGWl^ zPaVEKw?RD8mw)t@_6*-vK8Ob)@$@a~t1?u0_nLK(6pvYW$hZ(vl+-O7I>`HntFF{L z-1T*jj|*Q#K)R=Wi(()I1jD;MH}yyOkoxM{sF_;g<8kWLsfBWU@bA%AT4mRQ;Bb6o zJfvP9|Fy8n(yn>1y1Jr_%qSSqK`Nl31`Gs3{8+8v>cIjH-M+Rcga8jYsaE-z!bS1W zXMCyK(JT5#hLEHnc~}EUP+g^^6>c+t;{vX@MF;7ExEEd&YxB8v3QG%QBM6wl4RA1rH1iM}Js?(BY992D)I=g6UDe*frH%Ip$l6M;#dGH$ zVjtimcUdi`U!77uyaLMDhyKieW$1)&Aml<3At8x_!LXqVJ}e%0?=yVJNj~5n?iMph zSM|(dBU4^gYxAp;e5|B=G%v5T{{ayXWrC!*M_eHNo2H0I>KmSeXbzb&RaQdf;lb)k zj*Nd?02k3gDxhOOZ#X(Mehl|q{OB845jxaA#;k!@|L{mqOj1-JJW=xeXarH;pqSL> z(c>T>P57AC>I&WgJlu_imAiwL2uK$-1U^J3POPo;T6ZwR2k;2Hhvp9_FJBOYoF`gI z&1-)!o%^cUq)s+09>3r7Yb&Q2!jU?N1Elxr-p5A6?{4zZLz8zs16*0W=J?2>kq3zQ z#~t#Kg}|UfMkr)*Kcrj#kdsvwJLdWN?(Tyttgg0%(h5h$K`vbCy~6jg(Q%oX2s{o9 z^xEi^^5OD_X?|Ef;2-1xmweN(^4sVtACa1$Ly||Ef(fq-A0#974;3B6-69}e)W90> z`0!{C+DBjiN<;HGCnnmlUGVYo!{xMSlB28$h&l-4xlzp>OzL1EP+eXA=bpmh*@xzH zPysOH8Ug9D_CCM1CU{hS>3J?6&x4OU(m*#0qeut%IPl9azbyMngU?NgVFYOw&$k?8 ztI8r9HhkQ_VrnbRA9|z@>9@EZqZ0O_Wc_9K4)uN6JHc(%&`(gPIKt#d^@PL-?kNXq?#!A846d&0OJtmE7SO8O0JSs`V+Bw-+5BW8g#O;{hoja^eFI$+HZS zLO5{2N&ldOFqqRmsEN8(StfkYJ&4E5SHM6IcRK&Lz*~Gj$j;P*9ljm%aaj1!e4fQ) zlzga#q>ktVaOdJ9P7?=C!KU8(NT#Xqaeu$!A&rW8NrZ<`X3mfp~004 zS8+%}FCuAY(>REj%!uwJ!L7ImA~Yx>%t8Xa2yU_z1edP;UU}c?TRHW-^`_F*PW9OR zPQ7|n(@{{&&vVbauc}#J0h99_lAKBdF8H(FDk@Gwg&P(M9x7X9ed;Q#Pm#?n9_|1i z6kG!)0z@Jp|A{8Yi;x+QkA^L;6p*8hJ4>%PD1e4saexq_k&pluaKk(O0rw{6u3uR~ z&a=5MumKMNAFvCn#75$mcn%22L}iRLy`cHr#&gCGTu+uBth`7%Fsp|s3N#ViGMwWh z72xR4K1fI}n_D=vyaFGz4oo`B=&99xZoK{v_}{DgzwCq;$1%q&SYPqx3 z>MmBIifeM5V*2E>;vXWx!lsWj9?FLj0ud1q;)!f19~6KH>2Ch<-j_ZeLInoZZYM@T z&89zViKN83kH01If1n9>j){dhK3oGNue?$|NC?QFNC+*%pDCpC{P4mE?1erNd#ozC9Lsjg^10}ZaDCMi0jD z4ltp!OoT)0tF&#*wgd6Ns;{%0-MKUHveyRN7&R0&S+;x@1 zM}QD2NXU)Utz|=$$p>Z+4;-F%V4%Db$;4_(D=KFnPRb67tfjb_x45d6F##mu1M9o} z@nH%1R*oJaBmsxs;ELhnkz9h={P**fUB!dO!TAvJ19(tLE^n#Mk!dyKR;&RuF(x|} z=N?r)P+axR2MGZhdZmYu3f|yit1CAfvGJkiq0!uLdteeiTIwH&8|f27K>9=6JXwh< zCNx0C!b0Yr{2qJ&kG}aJA)rHM9VCQCLRj2k;K;`VbQl4T!w=hs!UszzTyUb&!UsJ% z$V&IQN>pJ$#$(4~?NRXYJ^aJak;?}OL3L#bVQob?WMn%?_R%fLjdu1UK#&bgpcNV2oX_2Km;a5CHbR|2L70b2Zk-K z+HwdWZG;bn0n)oVXH6ffxYOjn*v323+f8a(U)h)X7(OO)*8HAw9s(QrR!$5hMA!fo zGUMn?7iyj>9>zJ?^#B|)seL#?;1KomjtBFIOgLJix;whDPgs17cN`v@nt2XQB_C&xT2m<= zj*rbS8-Rh?qy8_4>Bcrl;V$~fzaZ=K1?#I#tc3RGA;iOah$;}z-xWNTKFopxr{e+z zmZlHd2ckE@zyzb%Od!FJle2{%cOR=n6>Nfx`U|oy^)@Kx^MQrXzCDDDC?O_gkPkna zFIhU!>i`ps9_?GceSi_gBS8bcfjj+NRZk@0DympSAN9AJ6yT#sl@%n!_y^qM{Xds% z?hwm3)ZCHc19;qOZ!&2hS76p=$Ee(=A#Sj^w@>7qN<|I^wVC zO*Xja`N!;Bg<U^h%ZH^AsK*01p-Mz^X3n1GeF)aMxQ->2#jBh6a&l(+!A3;0E_P z&&H=g3LD5MTgZdD0V_-gbTa!?g<US6+P?WH=f3Kv&Q#>K+1*-cCe0v3%8&^1-Dl zZIRUp8SU5f*2sq{pO3)_d1b0H_cEyP%PV&y3s*iEnmphf$R0q% zIR{L{#{>4^PW%ZX4ZK*L#P^OCjOZi%RR~iT^p7R*F)$(IqXI${5AyNJZ%gQxlMYN+ zvcjsa#`1&=@}V>!ZtICZGH|pwQ*jY%KvhTjP46>LczkRG`9OdjoDlM%g!p*8??(^9 zfeFTenRNK+qprJjkw1JCG<}4$QQwU3{3&K2qx>Fg-JsZ^dj$BXRj9!TAs-|JbbRzK zqKC%@4mU6<9k<#@%A(Z!=!_`-e9-HTQ7!WKTmJ^?slla{r zg#fw#zL2dtGgX^gURhsXU0qu{+u#4u*XL(vYip~k>+9<)%X77+gOqe-8lN!&Ln zWO8c$>eZLl&VJli7=HXbApBHxw)WD>)vNPU6TuBwVLkxJ$)X`_5JJ8-tHqNGzIW)H zTCvj9;bvL~1Tv^5u*h=^9}UpqBFJWZoUniEct<5j5udRK)C%^go`|_(Vr`4Gy z1*oj8t*=PwRW%#1I$=EOGLFsbuLdLpeE7QjnJKLxZedqAs7)=ejA0lgaKX@fgN6)j zG>fktEwsjaUwo(M^wj*y`n3cNH*h5*hLf|iFTS{aQ?#?Q?Jl>!_~K05WPN@4ajm)L zdT)qp9EJG6(r5QsFm+FLP!23d%_0vIYz>UMMSvR+1lOxSoEEYls-P#-QKx*`{w%ca;@@IkB`$pZ%|tU zCuO`zZRUA@RabXeInN*-BtvD8xKLT;xrW~K)P1@V)t^{G4R57atYhsO;Gke0G8+du z`$^C^I1n%>fZ`77V0Y{9)n5`m=pQ~Pj*n&;d{icvfCtrvg9sWp(jp$s94r{cX%w9F zn!w?%&6v@Pt?>@gLT2VxR>eB@(rnN^bizg9NQgM_=)mj{q5giL$A^QW5%7FJ$wjNRcARIP;;PLZPbj1NesddQ3!U47JY8(`?pr`bR@bN%Kk9*w*F_6-mg;Q77 zuNgYDt`h0hA@bwr;vEN+!z9~6h{&%U^^a^coMd}@X?yn`Omzfd9hqWvm4^naC|o$m z2JiKQllb21!b@1?TS#qX^&LkC5%EDu4jE^+w+{|>4?IHTkP)_!U)4Vp5F;$=l(@Hb zddc|)2CXAInaj9XF3*HR#apTwxAG3~vY&FBh4U+W@9aUr5=-4<|LmqSk6n=uNrH!= zgnV>_j_~@`$x@lWFbl8`-DV}1Fdr?$0{(do8jRyOJo-6PaVu}}2SG|+$a?&xYrsQg z=wN{bJa(Z2j1(VkczAHt_pc85$TSb|QBqr(DIHr$4g=KfJm_)7U`*ycylVaE2| zGBwpsf(NcX9s2zqv=38a`7I8dzG>h-Bv|Q5{DSmi38c&vG9!4vK8!N#VYfCLx$p@-2jX+%13L@sF}~`4D7)jqWDZOk~{yvx>e!CUR^8 zr!vxLoWvKJ6flqyEo6H6Jbb*9N66mUw&39gPVzw$3FMH2heCXCwY0lft(32a+v*#* zC>vBTjT^}C9yl7jQ9AS*_n8zikdiC}YggCdA9;xEX?eA^rFhsNA|vP^+CUHG5AspE zYO`H`Gl`D}t-_X5bq;GGb$EvQ2C(2w%0lkMZ_X)bAf+s1RhK240}#a{m_x{in~aIj zK^Q~`Nstc!l05!V8Hy$z?b14YDHuK+ICN0fI8JF9ob{%`IaXLj45TaznR50)KthP9 zf!q{0$cNEExTXGA#{ts8F9pfKq~i9(vNidHI!IIGA)@ZV3kF3{0s;c$ff0oB(QJI$ zw#aiJ<)o0gRmTUUY*H!Gqqx1Y+wd ztJ73TKd3V9b`feLx&>b>!=<#D)zezs|?dY{CJyu@?{CiOsrka*O)5B%+(#9glpOV#I2&gqbI!#alyO9oEz z;Z;>8j0Y6=Vf772Ie*)gYu6b-@~f<~?Jak>;n!IHTGqiiBQlha%mzrE0v}H6GnHZK zv2Hz;%d=JY*Qsb19JCDbk)t~cm8kvQ=m@=3+I5$W}u3m2(9mj`lOX`YOC;Q>!?dy4j$d%gJ+TK=1 zFcXoSr7Si;LVz@X{Z6$tybyA^oAhJCYM4MyBGU6I*~sJL^~RkikE6teuL z14I$IZUMpU1rUdaR#-NtgASQ3AZ(ypJjjRYV0a!AKC!1y+Kt|_@LIND?`#80AbRwQWShY z@tYf%E{q5CMvUnFX`+nv;VWt%VM2WE?`%UPLvGBb6H5pdcwGW%1k0=XU*Dy4bG|Yp zJ=M%a;uI4-BX#&6Vd{qrb&xypYja9S=QY{vGm>M+gfnufE#$JOpRvQr1I0 zA6OQG*gp5(+q<(etVd6$>Y=8%H4U9l8&Cl@sQ9dH0Smate}C-CiR;H zq&IB85R(RV5+Vz{9r9rSX?FhBHgs0QTf51jV z&m$Rc97h8wVTre|l)v)U+t)8l2o1y!A$pS))X9e|@H$yIl#gEz)IZ#r0P@93rCbpZ zKc)ZsAr5G8;}9s0aC!ZWH(r0^n}vx=REY+X--w@g{vjie5F#Q5vXdr+4gwFc7P6&$ zJb(Z~_pp3qy!`$4`jCEQX8vLC3|iZ`qA0AyN*q!rAvlfQMX?)b8`@^oY(m-}Pz=CSLBLBxmd1-L0$pfhvM_}r41%aTgZ_jeq^sU{bfu%$JL8cQ zYb2F-X6B7bp@p_z&pr3Pnfdlj)Ep4Ei(%s#Tm#CvLvFtX14$vF_hKQRKNLWqZV7>b zc!=;c`?9b!5s?P3(~0Fn$AjKWN!x%FAE!Pyvl)b=@r&?{XW+tD4v>TyNV*9<`7e`w z3_iLiWY-x8@Ss>^$r%^bH*N?W(!hFZ`Oxv8_eMD^?#v$yX;hfK{>C$pi}8(UGO);X z5@sOj%m|Z>hyf%45F<5^yhjKTiSZC=@H#-ihb^xPF};x zcoeDH@1vhS>=r>A+$XVIcW@-dG3@+cm8MEwaID zySoJ$f4qu%v2}CZK6pHwy%*X2i)mE(Sl|E{@<&TKF%EY)R&rsJN$Lrmnn)@}dEfhBszcRo{FGX4M`vKl<(5t}W!W6!0=fPB9LMM`KQEU@Sx?FN=1qyRo5Khx%ibO*>V>hoLgo^=~E z6b^tOY=}Sv5dkf1=mH;PcID&iFab$*1d^Q7Cm#Wjo~kTXSY*S=rVu?vA6tCb_SKog zL-}y4wGcYUFxpu6A}TD43_Zi$6asBixk))0VO^zMxErp@?JqJxX^udWo#}^V0@6bc zDH;c9dkEFh%4!C5)4(dYm;1al@05#1WLp3k#&*S-cX6gc*T``ej%Jm%Z*_&VpKApF zz*V^(_!x--tE0%8dO*p(p)<*r{bO_rOC$I14 zV(>7mC>6@ef8}$bzH|~K_3YRXh5atbB z>MX3P@JBh^=pLeK;A4~uEdA?eAFi(ULC9J?UnCv!yHRiCi3sqZ5YSBntKc3!-v%Ir z1ZYH6S#3bl-|&8Q-`dAgj^hoit!5P`;}Kb$VE9@L`D1iOgdQQTh1C}!4F?ERZq!S= zm>Uuglvz~18PFphuH8QGd+N5zDheR=sZ7e6edj&Hky9>YAs)^yVgd(G!eIzm4E^0v zE3jJ65sLaCr0je{*}&ki?8kKmk*EMt(A`&phseCQ_oW^IXB?R0Ca0GLkkp?Dxg-^q zDkp+_Xa&XU%CZ4Etc5_vKo+ZkkC7{|oTl9jq&Gs=+_lqavmqzOhKwS(QwSjB19!Bq zHn&@J#C$)*j0_vX$7$MtO#Oz;0RaxBM91Px9V+FAEvoaiC<=Ux$R=LH;CE7C_2(h2 z-_4!9CDZT4+6*8J=uiPmLE2aROq=>g!aQWVo+cpdVYS%EnMa%Shnf1R*wBi{Bh*); zHzI6n3VifI2(<$hJwC87fRGPPKO~-;ue8ZYJctM(**F*iAXjeZD6gK<8q0%$KXD{E zhsg0U6W$Rwf(c#pJpk#K5W6pnh%k$sMe%|7VF+;-WdYd)ASrLgy7`9wfu*hJxS_q> zBrQ^vnXo@`#72aw?EN+zSP~G4eX(`j;K6wa1Bf?0-%kFVy6t5ZhXBZ>xk@fV3>TdK zA$W8RhU@L(R=FGa7|8&V$$ax1czkk|r9(rCvyczhJU);sVaM!a2F z#iob{89@Ny) ztxV9U29V5UOwoNscYD_&qSSF5Y$;(N%A4n7L4@``Fh;xQ84%W`KqeL&`6 zAT2udyeK}x_XNqJ>I7j5v+o0*4f zqr!qt(*xv-KPp7x0>B_23yYO+!+3CXx0tjlEE1BC)CmZ+E=Nh(z~Kk=;x+J503TZ@ zuk5={aQckIwX!x3R6nKG_?fG9Zx~Bm!-1tT7v4|ZXNNbXfBjdr!14%D|L8ucH|QVq z5GM4KW^Y&aCZ2WBp|==9;2$=Jpu$SGi}ls<#rX#DSa7P`3**7j-NOt0_t!7Ug$(KO%rg`uOdv<5Rdk9h%iCG6Fs*MD%n4 zxqRn15{jjs0C6V{29RoKUyXhM$z-I$QV|eJEyO4~fp|e(E#yr2C`fg6P3(hT5Akyd z7E@`Nho_)M33R0NJO~o{;swMF9xa94?fvU=dVEaY2Oz8JA_k8nKp-)YvK&+%i~y0d zlda$XDzxxuE+SxJy1ho4)JX{pBuzlFGt$E97ZGIvV7Qa2 zyAmD5BC@huBpp5@uEaX|?d0r(;9#DivhTHK$Cq^A@C~GtCLr^lVjv58E>J*4c3*{f zKI&Vr*yL3_)Jf#*#zZ^=DHrJ>`TvYV8Xp=S9a#0SNo2#0Lp%dfI#PRS!&h&QKP8dl zw5ra8mzRu10Le@|unq!3k{>aoft1S%hpe`lMR|-+bP+m;$45sPX`DI(DWwKT_S#X; zY%q|=s8*c|@q7#>AWm0(JaC$*p3v;A7ljZyh;JkLC_-Q!w$QRBLJI*NFY_hGhN?7p zKqltiANPVs^MZB6t5&%;kqH|0EsAXN%IPDbfGiV`a|l`4DXW7RM%eGQl$ePjQ%IDF zXi~42L@f(>IF%W+W{+O?mc@xitc6tn2-EZNn1D1NwpBj-Ru-sPTkmGu$x2h?`1CaDt*pAQhC3BBYlM36^=o+C`o9GzQW(KotQExh|` zd;&Tm2$1N2V_DevW-2@3ziknU1Z1ToXyA~$Rh~JdXtTNv>JVdyPf5LWpod#de;)8Z ztIPB6V+};f&>zX-^drQN@d+R@1$jX9QQH);3#np`_= zKCr41a|kWOXN1E-^ZZnicwiayR;QctnDifP2TS+gvPXrp8xatw zRtwKYjnM=h%8GAHPsVslS8qCzh)xUf&@hPD6r!uaBeL789bS?4u}%lNSNzJI_j|{R zgj@CKTfci12e(#7C zRZnQJtWxuEw@_Y>Yjy^ zODg)vV47GA=u%+ymo=(yJB;$axRpx*^D+PY27am|m}a^*d+kw#s6C zMLKYu{+Jn*uFOdQ>6(ZnKB`Z`qfz76;O(NoLX8z!XSEGvC&EBH2eCFnd5oy+JOq5~ z8Uq>RSJEfu-%9{VsHez6>z4&&0esAaH#3Z3gSWc^OYtx!(ota@;-oZ&C?j@ruWum5 zx?7`%>bM*qz{6+&8J!I*ba=b2rD|9s_3Pq%cyZ#md%C#!ChI3NMqOgEUqF#|By3Z2Od@f%IMhQetrO9^^~MqN`6-4eWf!g2U6sMzORjiUMR%8%@5rcC@z_iG`sgN%CaW zC{+eytC6a&+#W38K}uo@H$4XdBuwcIfkO!~HP&Dr zJGy#9_~>AvCT9(9P{R+=0**xeTAd5c-Tz$!%f02q&>=@8AnS@p^N1K3p0~BPvE%sI z)fd1=z6?k#27E+X$fJQ|-^sf!pvQOxe<#!NYxVf%X#I;FSB)4SQ_I#suv$V~g(Ye( zrpPimM8phI6#EdZBcnt1rHc)~5rfEJ9tN4XBmQxuqYcx$?H&)|<8FAcb{ro;Pts+K zKnx+U5u-ZrfQ3XMLNd%$9rhuo0zwlZ9!0SaNFnjctJBi%AR@@6`S-#H(?+jsu(~># z4O_3q@e%Z{6S_4K>mh50P#KFYvUvDH`dHtA*uZ{l2 zSM}~0PVO$}-*0b@R#`Bo8?kP^6+n(jL^2Nm2QqXBBx@)xncM{F;O>&eQ4qmFD7XnCwAlpz z70>(TwBKCMeQi>&kayqxzUNK+0fP0D@A;l{-)(_4Z~jra4Fgd^yywYnQa$>IzVU8- z#|=tk-P;m82uM%5ypDhe`0$E++z=#6Hr_t4bxtC#0ZSr=x5z zh^TB1X}uyDyx}3L2xsa}D@$&K5AZ=idT3%DAo6za72r@n{B@QB68b;l^2N{D4#gSZ zu=@TjJyt7<@(C%Z-tRz$4?_qeh!+xyB^K~7`VBrn2h79RhY|4jb?;u_6F*6|4 zD24OL`KUDdWB*V>{4T;xC;JiPHyy-mT!aLVt*)qN3CWsR^4p}tAtZ;C43MzfIF>R# zcJtXVTv$Aw-%8;;>imHjp^zaLlov(V$}$y}zs5o|Z+BIH1M>E_ItzNPA_1bk=$p@A@?d*>motq=JYqW-b>s!Kd_39*3qa|r9Kuo3;z z?r`{Z79_|2p0>4@fsd1`jOde`=pua#wW zFWf(2E#qVA?2)0NmsD3z(|No9LDl)>11&7aK>!99Gg5yAIQFnoLPwi){Hurf`RFym z@p0<&@ar^S&^Yvx$;a6=INw*)^FgRF=oklqe-IJ;pxzks_`Ub0%cI|CBP4Ge;xmzO zL&D{Y86Qs%2ZNd8i3-{L=A3>di>-O(qpAjCAps@67y>%>aN*tFRvU2S0@6N?hj=o2 z?@qWAevE&3DWQOh;E}TVzRJPJcpGoOW6LaD-c2WDL*S5k2lk(k4nxSXa|lFGwt^YR z68M+~i}9t4w5~3t!Qg>Pkk4r#) zk<+fyt}Cicd@Qc^MSugV&p~`o;PQ>Nkbg_+mXg3N-qWYHg^w2iKvv%c9T-T4#~gnN zi>^64pBkdp#|Z>rV6jp{6cKLjRXTho0z^Xgve4qK1{)CWvaX_2II)B8N6(UbSjBt( zuH9vlImq||CDuWViO@yz0SO&Lwl-?v284h?Z^uOljIN`n2@j+4_=oH==|jLH*FoqX zK17V#xj}tqM3_T*>w%uI6+YOi!fIVZ^;kMrm*@HOt@xUAK29_T85?@>o2G| zMA`u+hEy-m2;`OwK@K=RRFXF7)O9H+xZF1!?eZ z580ez1|cO7#)6-&Bs{!|_;_kxkCzrAc;MBAgGt>bg^XA}+PNNb%xzhLI#_4l4TrmC z++oc_@VJ;Zl^muBzrVBhQFN`apiZ8PFsS=&M8mp^$W(;zF?E*{TVS0C)4BO5;l(Vhk~exFJOOa2-T%qkr*`zxcSf7-$FY_GepCshG@1D``V} zo=P$vWJI5kMTCqfA6y_J;w!WMrOI;o*a#B_t{|X;58=R>f>5JpD`yiP9+i)eN^Rg8 z2ocGzvb<-%6A`Nby{te1ex7WsWU5E&- za2`THx{m@K(XhS!!wDP~k8|myl0#IU@yA3&Cn8w=QJo_ZqCq^A4qsBo`j3Qk?^ePE z5F;AN=x0jihpR;GT}E`Ob0{7VQwSNc{oYp4c}VwRm_%?x3#>fzcyax75kA$T&|L4n zq7cz7A-M84_S%UdxX`6#_rCvImDRl$CZL}lZV!Lt<8kgrtr%al2sGcj6RG76*)TZ- zOI}u|k(g;nc8Bct_U?z_WAWk+3M_A1_vzJCTOFzrmRF*6sjvopH-^we{5yN~CLSh- z7!S#Rg32&r@#t+_s01#sY~Sko*|{HBMWjNsuQFBFlns3$BQz2t9^rshUl>7f8TUA@ zhinDo#Vd4 z!t3bgsat8c?hz_6A4_W(Ph9&|N`OcT_JNE`j#AX>b-v!l)d zK4i1*rDPsQtIT{zg#|FMSP2^5qfS_6$(qR#sMSTsxa$ z`7A1D_iDewf_(rF_y}&x2oUj(L;Oz|QdxP`7$1&3DMI_+iAdh&EC&-`w-@%oDrwz3WOxW6?Yk*QN2TJW4``hR!muv4XCA`u z&z2X}O+rUHXEirHAe+*?N{UDY8xB&eu===7N(Uc&Ascx~ouEiMcV^&dVjV#UzJFnR z^I_Wm5tWLV&Y|W0fa;qVk{i_f-lR@8K+0<4gd2A(AhK9(N^>_UA{B4=ai9hagoJ>P zyrh1Bhksazl_^B+gIbm@uaz;7&5e{k;?jwtmRH&64uDXHBy|#^E9IU^3Pi*{7Amgl z-2I+A4G~j$SgRyOq(U}#c^;O-2JhUBy;vC5?Y1nnkK5J-8Xe(7Zlei2TKDRO{j^Dn zth^G{zbG26gOHDbx5%95s&Bgu~9K}g)QfHtLfm3E)Ur6Su0H!7N-j&^VE z#89g&zk|qctv0IO^Ra#3DjK)G+gMLKOX5-iw_dq;uMrUcJUut6TPYuXj0U~CB3t&v zMMXrG*2bgM+Ko(wZSL-?Mk*XU@J1Q&cYAYpX7!u(ypA&X@P7-cR%>lN;SrgNoj#z3 z?O}1A&am!1)>`DjW6e`tv55uQ93pr$Quc^V1y3JP)7fX@zGH#qeK^E)d=Wm@51C-B zcl<}ccQ%`Kp=zPL0K|w9T^I79kXQ?`;lnnu4vssaTCLUF^@TVRT@qD| z;?u6?EwCu!VN8Tsgm^3;@lD=3V*_ECC9SVDr*TzHh(w`SKI+!3ftV(*R$2xTcU(B= zH)}`EBs+?RHhVjnc~sp$bRverwd`6b+_4N(?lU1Fl)y3YpSVZ|kzZ(<`M0-;MFSD@ zXf{s9wQnaWvajIDaRfO$hd@3HAs>Rr6dxINjUeO4M5L>`5aHIHq?o>ZwJ%?YhmkqS z!B5D*4nF*9>~DjY;L)g+<0Ghiit1~(u6%eXF*(HcdvOn@aSt}JB(1DA8_U%)w9w0_ zSi-rg2|#3VurRVwy`$>@=lM*jwSH%F?RI^!Tsf~yimAFfIM2i~Vl9L>{R4R1uFdkd zH5;{s(ta3~Kv7j!8bQ8*4#gzbM92p<__8|N*4u@pg&9AO5+X&?pLWhBNkJHh!V-UG z!-&wUJpb9JjJMi3D%eaF$pEx7TKD z6{2(+JKPHgMTMkGE{OESqpc3RC2{JqpEA_$4l3zR3L(!o_7d^V+oxaz?4UAyM6N6k zexwwVRY`dB_FgbY15rPk%e$*7ko1w&20zHZn>-*9^=Os{FBA49WV94QlXJ4zS{-*Q zfS-y8M!EGpbqS=qbPAb95u#gNNjM4=4J}b9ZC#Bsx}U@ldY}$5r;X??>6=1vHcuIy z@wphn;t`|{E90^SOl&2siRt8#)C_>uc9_YA z(y<|rkkLIQk~;W#+msSgIV2(vXQr80QY1x?@IM->^KmB~NaQsjkB_Ow^&?(G>DbEg z>V=U?F9<8x)v@>an|)68ikuS2huwmC6Rug3a-U^_MWPrB<*rqiPmdwHHI0py)p*kQBBRG^1 zOe+AJP`-G#R31PL=5R37FS18#!zcwb0&4|k!T96ufTx{(d<)RZ0JA%_u>3W~6__>v ik|=HlfY*Yv`kY_3eVGuEa?k<*0000assertSame(exif_imagetype($this->start . 'work/ci-logo.png'), IMAGETYPE_PNG); } + public function testImageConvertPngToWebp(): void + { + $this->handler->withFile($this->origin . 'rocket.png'); + $this->handler->convert(IMAGETYPE_WEBP); + $saved = $this->start . 'work/rocket.webp'; + $this->handler->save($saved); + $this->assertSame(exif_imagetype($saved), IMAGETYPE_WEBP); + } + public function testImageReorientLandscape(): void { for ($i = 0; $i <= 8; $i++) { From d45dd5948f8a2d85136eddd6d5251f23cc18e838 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 17:53:37 +0900 Subject: [PATCH 144/380] docs: change phpstan-type names --- system/Config/View.php | 12 ++++++------ system/View/Parser.php | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/system/Config/View.php b/system/Config/View.php index 5a6a6404b69e..101b67f580d0 100644 --- a/system/Config/View.php +++ b/system/Config/View.php @@ -16,8 +16,8 @@ /** * View configuration * - * @phpstan-type ParserCallable (callable(mixed): mixed) - * @phpstan-type ParserCallableString (callable(mixed): mixed)&string + * @phpstan-type parser_callable (callable(mixed): mixed) + * @phpstan-type parser_callable_string (callable(mixed): mixed)&string */ class View extends BaseConfig { @@ -40,7 +40,7 @@ class View extends BaseConfig * @psalm-suppress UndefinedDocblockClass * * @var array - * @phpstan-var array + * @phpstan-var array */ public $filters = []; @@ -52,7 +52,7 @@ class View extends BaseConfig * @psalm-suppress UndefinedDocblockClass * * @var array|callable|string> - * @phpstan-var array|ParserCallableString|ParserCallable> + * @phpstan-var array|parser_callable_string|parser_callable> */ public $plugins = []; @@ -60,7 +60,7 @@ class View extends BaseConfig * Built-in View filters. * * @var array - * @phpstan-var array + * @phpstan-var array */ protected $coreFilters = [ 'abs' => '\abs', @@ -90,7 +90,7 @@ class View extends BaseConfig * Built-in View plugins. * * @var array|callable|string> - * @phpstan-var array|ParserCallableString|ParserCallable> + * @phpstan-var array|parser_callable_string|parser_callable> */ protected $corePlugins = [ 'csp_script_nonce' => '\CodeIgniter\View\Plugins::cspScriptNonce', diff --git a/system/View/Parser.php b/system/View/Parser.php index 120570079d2b..ff729d4837d5 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -20,8 +20,8 @@ /** * Class for parsing pseudo-vars * - * @phpstan-type ParserCallable (callable(mixed): mixed) - * @phpstan-type ParserCallableString (callable(mixed): mixed)&string + * @phpstan-type parser_callable (callable(mixed): mixed) + * @phpstan-type parser_callable_string (callable(mixed): mixed)&string * * @see \CodeIgniter\View\ParserTest */ @@ -64,7 +64,7 @@ class Parser extends View * Stores any plugins registered at run-time. * * @var array|callable|string> - * @phpstan-var array|ParserCallableString|ParserCallable> + * @phpstan-var array|parser_callable_string|parser_callable> */ protected $plugins = []; From 5dccbcc87017b3207e4935c5b786bca3b5f5c45b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Nov 2023 19:01:21 +0900 Subject: [PATCH 145/380] chore: vendor/bin/psalm --set-baseline=psalm-baseline.xml --- psalm-baseline.xml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 379314e5093a..c4240e2b7fc8 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -10,11 +10,6 @@ public $plugins = []; - - - $val - - Memcache @@ -39,9 +34,9 @@ - ]]> - |ParserCallableString|ParserCallable>]]> - |ParserCallableString|ParserCallable>]]> + |parser_callable_string|parser_callable>]]> + |parser_callable_string|parser_callable>]]> + ]]> '\abs', 'capitalize' => '\CodeIgniter\View\Filters::capitalize', @@ -144,8 +139,8 @@ - |ParserCallableString|ParserCallable>]]> - |ParserCallableString|ParserCallable>]]> + |parser_callable_string|parser_callable>]]> + |parser_callable_string|parser_callable>]]> protected $plugins = []; protected $plugins = []; From 0d277665e6dca03a818d3fc6eed31a91a055cda8 Mon Sep 17 00:00:00 2001 From: Thomas Meschke Date: Tue, 14 Nov 2023 11:24:56 +0100 Subject: [PATCH 146/380] replace -1 with E_ALL in error_reporting calls --- app/Config/Boot/development.php | 2 +- app/Config/Boot/testing.php | 2 +- spark | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php index aa8099a46501..a868447a8e37 100644 --- a/app/Config/Boot/development.php +++ b/app/Config/Boot/development.php @@ -10,7 +10,7 @@ | | If you set 'display_errors' to '1', CI4's detailed error report will show. */ -error_reporting(-1); +error_reporting(E_ALL); ini_set('display_errors', '1'); /* diff --git a/app/Config/Boot/testing.php b/app/Config/Boot/testing.php index e84670e972f6..40b6ca83cf3f 100644 --- a/app/Config/Boot/testing.php +++ b/app/Config/Boot/testing.php @@ -14,7 +14,7 @@ | make sure they don't make it to production. And save us hours of | painful debugging. */ -error_reporting(-1); +error_reporting(E_ALL); ini_set('display_errors', '1'); /* diff --git a/spark b/spark index 2ea79d5ccdaf..9daa44034473 100755 --- a/spark +++ b/spark @@ -39,7 +39,7 @@ if (version_compare(PHP_VERSION, $minPhpVersion, '<')) { } // We want errors to be shown when using it from the CLI. -error_reporting(-1); +error_reporting(E_ALL); ini_set('display_errors', '1'); /** From f364cb8a5a0ad7f9a146fbd8174f13edb942ce6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:06:55 +0000 Subject: [PATCH 147/380] chore(deps): bump actions/github-script from 6 to 7 Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/deploy-distributables.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-distributables.yml b/.github/workflows/deploy-distributables.yml index 3d4b31f289e6..f28a62544fa5 100644 --- a/.github/workflows/deploy-distributables.yml +++ b/.github/workflows/deploy-distributables.yml @@ -66,7 +66,7 @@ jobs: run: ./source/.github/scripts/deploy-framework ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/framework ${GITHUB_REF##*/} - name: Release - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.ACCESS_TOKEN}} script: | @@ -116,7 +116,7 @@ jobs: run: ./source/.github/scripts/deploy-appstarter ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/appstarter ${GITHUB_REF##*/} - name: Release - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.ACCESS_TOKEN}} script: | @@ -172,7 +172,7 @@ jobs: run: ./source/.github/scripts/deploy-userguide ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/userguide ${GITHUB_REF##*/} - name: Release - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{secrets.ACCESS_TOKEN}} script: | From ee5d2a344aefc90943e4f4bdcb4663a5ea113548 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:36:32 +0000 Subject: [PATCH 148/380] chore(deps-dev): update rector/rector requirement from 0.18.7 to 0.18.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/0.18.7...0.18.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 7f00c4c6efa0..d762dea8e0bb 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.18.7", + "rector/rector": "0.18.8", "vimeo/psalm": "^5.0" }, "suggest": { From 535405241324aa387fcce24bee6e993f77f08156 Mon Sep 17 00:00:00 2001 From: Cole Thorsen <959538+colethorsen@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:47:14 -0800 Subject: [PATCH 149/380] fix issue where running getClassName on a directory would cause a PHP error --- system/Autoloader/FileLocator.php | 4 ++++ tests/system/Autoloader/FileLocatorTest.php | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 744567a3bcc0..7cd2a5e60135 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -119,6 +119,10 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' */ public function getClassname(string $file): string { + if(is_dir($file)) { + return ''; + } + $php = file_get_contents($file); $tokens = token_get_all($php); $dlm = false; diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 1cf32cfa5ad1..8df13094ef7a 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -312,4 +312,12 @@ public function testGetClassNameFromNonClassFile(): void $this->locator->getClassname(SYSTEMPATH . 'bootstrap.php') ); } + + public function testGetClassNameFromDirectory(): void + { + $this->assertSame( + '', + $this->locator->getClassname(SYSTEMPATH) + ); + } } From b53f049553ccfa88e6c63cb3d3b526e447583663 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 19:02:33 +0900 Subject: [PATCH 150/380] docs: add types for PHPStan --- system/BaseModel.php | 11 +++++++++++ system/Model.php | 11 ++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index e8e746e64c25..f9eed92b1d49 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -41,6 +41,16 @@ * - ensure validation is run against objects when saving items * - process various callbacks * - allow intermingling calls to the db connection + * + * @phpstan-type row_array array + * @phpstan-type event_data_beforeinsert array{data: row_array} + * @phpstan-type event_data_afterinsert array{id: int|string, data: row_array, result: bool} + * @phpstan-type event_data_beforefind array{id?: int|string, method: string, singleton: bool, limit?: int, offset?: int} + * @phpstan-type event_data_afterfind array{id: int|string|null|list, data: row_array|list|object|null, method: string, singleton: bool} + * @phpstan-type event_data_beforeupdate array{id: null|list, data: row_array} + * @phpstan-type event_data_afterupdate array{id: null|list, data: row_array|object, result: bool} + * @phpstan-type event_data_beforedelete array{id: null|list, purge: bool} + * @phpstan-type event_data_afterdelete array{id: null|list, data: null, purge: bool, result: bool} */ abstract class BaseModel { @@ -539,6 +549,7 @@ abstract public function chunk(int $size, Closure $userFunc); * @param array|int|string|null $id One primary key or an array of primary keys * * @return array|object|null The resulting row of data, or null. + * @phpstan-return ($id is int|string ? row_array|object|null : list) */ public function find($id = null) { diff --git a/system/Model.php b/system/Model.php index 1873804a3c2d..d2f531998fef 100644 --- a/system/Model.php +++ b/system/Model.php @@ -84,6 +84,8 @@ * @method $this where($key, $value = null, ?bool $escape = null) * @method $this whereIn(?string $key = null, $values = null, ?bool $escape = null) * @method $this whereNotIn(?string $key = null, $values = null, ?bool $escape = null) + * + * @phpstan-import-type row_array from BaseModel */ class Model extends BaseModel { @@ -178,6 +180,7 @@ public function setTable(string $table) * @param array|int|string|null $id One primary key or an array of primary keys * * @return array|object|null The resulting row of data, or null. + * @phpstan-return ($singleton is true ? row_array|null|object : list) */ protected function doFind(bool $singleton, $id = null) { @@ -224,6 +227,7 @@ protected function doFindColumn(string $columnName) * @param int $offset Offset * * @return array + * @phpstan-return list */ protected function doFindAll(int $limit = 0, int $offset = 0) { @@ -244,6 +248,7 @@ protected function doFindAll(int $limit = 0, int $offset = 0) * This method works only with dbCalls. * * @return array|object|null + * @phpstan-return row_array|object|null */ protected function doFirst() { @@ -411,7 +416,7 @@ protected function doUpdateBatch(?array $set = null, ?string $index = null, int * @param array|int|string|null $id The rows primary key(s) * @param bool $purge Allows overriding the soft deletes setting. * - * @return bool|string + * @return bool|string SQL string when testMode * * @throws DatabaseException */ @@ -450,7 +455,7 @@ protected function doDelete($id = null, bool $purge = false) * through soft deletes (deleted = 1) * This method works only with dbCalls. * - * @return bool|string Returns a string if in test mode. + * @return bool|string Returns a SQL string if in test mode. */ protected function doPurgeDeleted() { @@ -491,7 +496,7 @@ protected function doReplace(?array $data = null, bool $returnSQL = false) * ['source' => 'message'] * This method works only with dbCalls. * - * @return array + * @return array */ protected function doErrors() { From 76757983726bb457c2df92581a025ea22797c261 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Nov 2023 19:03:12 +0900 Subject: [PATCH 151/380] docs: update PHPDoc types --- system/Database/BaseBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 12bd14f73ab1..badf2d35cdfc 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -2738,9 +2738,9 @@ public function getCompiledDelete(bool $reset = true): string /** * Compiles a delete string and runs the query * - * @param mixed $where + * @param array|RawSql|string $where * - * @return bool|string Returns a string if in test mode. + * @return bool|string Returns a SQL string if in test mode. * * @throws DatabaseException */ From 279e1358fdbed35192c53b9d6d52739b63699374 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Nov 2023 09:24:47 +0900 Subject: [PATCH 152/380] docs: make note stand out --- user_guide_src/source/libraries/validation.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index df48ce2ed55b..ff449c9e6fb9 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -978,7 +978,13 @@ valid_cc_number Yes Verifies that the credit card number matches Rules for File Uploads ====================== -These validation rules enable you to do the basic checks you might need to verify that uploaded files meet your business needs. +When you validate uploaded files, you must use the rules specifically created for +file validation. + +.. important:: Only rules that listed in the table below can be used to validate + files. Therefore, adding any general rules, like ``permit_empty``, to file + validation rules array or string, the file validation will not work correctly. + Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, the name of the input field will need to be used twice. Once to specify the field name as you would for any other rule, but again as the first parameter of all file upload related rules:: @@ -1020,7 +1026,3 @@ is_image Yes Fails if the file cannot be determined to be ======================= ========== ============================================= =================================================== The file validation rules apply for both single and multiple file uploads. - -.. note:: Only rules specifically created for file validation (like the ones listed in the table above) can be used to validate files. - Therefore, adding any general rules, like ``permit_empty``, to file validation rules array or string, the file validation will not - work correctly. From f5135041c57be0dd326357edf8fba971719c32f7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Nov 2023 10:09:43 +0900 Subject: [PATCH 153/380] chore: use MySQL 8.0 by default --- .github/workflows/test-phpunit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index c6deb546bb7d..f0cc346617f6 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -99,11 +99,11 @@ jobs: - SQLSRV - SQLite3 mysql-version: - - '5.7' + - '8.0' include: - php-version: '7.4' db-platform: MySQLi - mysql-version: '8.0' + mysql-version: '5.7' - php-version: '8.3' composer-option: '--ignore-platform-req=php' From 7d758d8522f595cc84fae5cc209b504536444595 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Nov 2023 10:10:00 +0900 Subject: [PATCH 154/380] chore: set empty string as name It should be boolean/number/string --- .github/workflows/test-phpunit.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index f0cc346617f6..53124f695162 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -109,7 +109,7 @@ jobs: uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: - job-name: + job-name: '' php-version: ${{ matrix.php-version }} job-id: database-live-tests db-platform: ${{ matrix.db-platform }} @@ -141,7 +141,7 @@ jobs: uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo with: - job-name: + job-name: '' php-version: ${{ matrix.php-version }} job-id: separate-process-tests group-name: SeparateProcess From 3ba7ef65cd6d1b5dca7b97bc1b93d95a4139c9ab Mon Sep 17 00:00:00 2001 From: Cole Thorsen <959538+colethorsen@users.noreply.github.com> Date: Wed, 15 Nov 2023 07:51:19 -0800 Subject: [PATCH 155/380] fix style --- system/Autoloader/FileLocator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 7cd2a5e60135..92381a7ee25b 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -119,7 +119,7 @@ public function locateFile(string $file, ?string $folder = null, string $ext = ' */ public function getClassname(string $file): string { - if(is_dir($file)) { + if (is_dir($file)) { return ''; } From eafda29a27553a821c5625c1ca12432d28fdbadc Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 08:35:38 +0900 Subject: [PATCH 156/380] docs: add note for migrations table --- user_guide_src/source/dbmgmt/migration.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 4af207164b73..fd816e551c02 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -66,7 +66,7 @@ Database Groups =============== A migration will only be run against a single database group. If you have multiple groups defined in -**app/Config/Database.php**, then it will run against the ``$defaultGroup`` as specified +**app/Config/Database.php**, then by default it will run against the ``$defaultGroup`` as specified in that same configuration file. There may be times when you need different schemas for different @@ -79,6 +79,9 @@ match the name of the database group exactly: .. literalinclude:: migration/003.php +.. note:: The **migrations** table that tracks which migrations have already been + run will be always created in the default database group. + Namespaces ========== From 0b47dfea28cbaf8e09ebc3cb31e5346d119242bc Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 08:45:15 +0900 Subject: [PATCH 157/380] docs: clarify that $db is for testing purposes --- system/Database/MigrationRunner.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index 241a9e6da5fa..a466a91462dc 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -122,14 +122,11 @@ class MigrationRunner protected $groupSkip = false; /** - * Constructor. + * The migration can manage multiple databases. So it should always use the + * default DB group so that it creates the `migrations` table in the default + * DB group. Therefore, passing $db is for testing purposes only. * - * When passing in $db, you may pass any of the following to connect: - * - group name - * - existing connection instance - * - array of database configuration values - * - * @param array|ConnectionInterface|string|null $db + * @param array|ConnectionInterface|string|null $db DB group. For testing purposes only. * * @throws ConfigException */ From 0f9b27b57d4a4a560719486f850ff1653e2ce64b Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 09:09:33 +0900 Subject: [PATCH 158/380] docs: update outdated sample code --- user_guide_src/source/helpers/filesystem_helper/010.php | 2 +- user_guide_src/source/helpers/filesystem_helper/011.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/helpers/filesystem_helper/010.php b/user_guide_src/source/helpers/filesystem_helper/010.php index 51db194b6d63..3b88fda2a77b 100644 --- a/user_guide_src/source/helpers/filesystem_helper/010.php +++ b/user_guide_src/source/helpers/filesystem_helper/010.php @@ -1,3 +1,3 @@ Date: Thu, 16 Nov 2023 09:28:41 +0900 Subject: [PATCH 159/380] docs: update outdated description --- user_guide_src/source/helpers/filesystem_helper.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 75062ae054a3..eb70a3cc5406 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -2,8 +2,8 @@ Filesystem Helper ################# -The Directory Helper file contains functions that assist in working with -directories. +The Filesystem Helper file contains functions that assist in working with +files and directories. .. contents:: :local: From 0304689e95c3ac4dbc1d95b1b2942b3b9f07f7d7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 09:29:01 +0900 Subject: [PATCH 160/380] docs: fix incorrect parameter in sample code --- user_guide_src/source/helpers/filesystem_helper/004.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/filesystem_helper/004.php b/user_guide_src/source/helpers/filesystem_helper/004.php index 6b1e065cc0a5..418ecd7640fc 100644 --- a/user_guide_src/source/helpers/filesystem_helper/004.php +++ b/user_guide_src/source/helpers/filesystem_helper/004.php @@ -1,3 +1,3 @@ Date: Thu, 16 Nov 2023 09:30:09 +0900 Subject: [PATCH 161/380] docs: add text decration --- .../source/helpers/filesystem_helper.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index eb70a3cc5406..728ce3997cd2 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -24,7 +24,7 @@ The following functions are available: .. php:function:: directory_map($sourceDir[, $directoryDepth = 0[, $hidden = false]]) :param string $sourceDir: Path to the source directory - :param int $directoryDepth: Depth of directories to traverse (0 = fully recursive, 1 = current dir, etc) + :param int $directoryDepth: Depth of directories to traverse (``0`` = fully recursive, ``1`` = current dir, etc) :param bool $hidden: Whether to include hidden paths :returns: An array of files :rtype: array @@ -33,17 +33,17 @@ The following functions are available: .. literalinclude:: filesystem_helper/002.php - .. note:: Paths are almost always relative to your main index.php file. + .. note:: Paths are almost always relative to your main **index.php** file. Sub-folders contained within the directory will be mapped as well. If you wish to control the recursion depth, you can do so using the second - parameter (integer). A depth of 1 will only map the top level directory: + parameter (integer). A depth of ``1`` will only map the top level directory: .. literalinclude:: filesystem_helper/003.php By default, hidden files will not be included in the returned array and hidden directories will be skipped. To override this behavior, you may - set a third parameter to true (boolean): + set a third parameter to ``true`` (boolean): .. literalinclude:: filesystem_helper/004.php @@ -99,7 +99,7 @@ The following functions are available: :param string $path: File path :param string $data: Data to write to file :param string $mode: ``fopen()`` mode - :returns: true if the write was successful, false in case of an error + :returns: ``true`` if the write was successful, ``false`` in case of an error :rtype: bool Writes data to the file specified in the path. If the file does not exist then the @@ -120,7 +120,7 @@ The following functions are available: be set such that it is writable. If the file does not already exist, then the directory containing it must be writable. - .. note:: The path is relative to your main site index.php file, NOT your + .. note:: The path is relative to your main site **index.php** file, NOT your controller or view files. CodeIgniter uses a front controller so paths are always relative to the main site index. @@ -132,7 +132,7 @@ The following functions are available: :param bool $delDir: Whether to also delete directories :param bool $htdocs: Whether to skip deleting .htaccess and index page files :param bool $hidden: Whether to also delete hidden files (files beginning with a period) - :returns: true on success, false in case of an error + :returns: ``true`` on success, ``false`` in case of an error :rtype: bool Deletes ALL files contained in the supplied path. @@ -141,7 +141,7 @@ The following functions are available: .. literalinclude:: filesystem_helper/008.php - If the second parameter is set to true, any directories contained within the supplied + If the second parameter is set to ``true``, any directories contained within the supplied root path will be deleted as well. Example: From 4ed2bfe33b8eed5ad7e1b1937fb03538aed273ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 09:30:34 +0900 Subject: [PATCH 162/380] docs: add links to PHP manual --- user_guide_src/source/helpers/filesystem_helper.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 728ce3997cd2..99230f2d4c94 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -204,7 +204,7 @@ The following functions are available: :returns: Symbolic permissions string :rtype: string - Takes numeric permissions (such as is returned by ``fileperms()``) and returns + Takes numeric permissions (such as is returned by `fileperms() `_) and returns standard symbolic notation of file permissions. .. literalinclude:: filesystem_helper/012.php @@ -215,7 +215,7 @@ The following functions are available: :returns: Octal permissions string :rtype: string - Takes numeric permissions (such as is returned by ``fileperms()``) and returns + Takes numeric permissions (such as is returned by `fileperms() `_) and returns a three character octal notation of file permissions. .. literalinclude:: filesystem_helper/013.php From fd07f4fa870c3eba07989415f7aee4a7f815e274 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Nov 2023 09:30:50 +0900 Subject: [PATCH 163/380] docs: change anchor text --- user_guide_src/source/helpers/filesystem_helper.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 99230f2d4c94..e122660959c5 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -113,7 +113,7 @@ The following functions are available: .. literalinclude:: filesystem_helper/007.php - The default mode is 'wb'. Please see the `PHP user guide `_ + The default mode is ``'wb'``. Please see `fopen() `_ in the PHP manual for mode options. .. note:: In order for this function to write data to a file, its permissions must From d4fc50d35f3c470637829095ad76e75f137047fd Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 17 Nov 2023 00:50:53 +0700 Subject: [PATCH 164/380] Remove unused use statements on system/Common.php --- system/Common.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/Common.php b/system/Common.php index 451e6c601a63..56e1c07b6e3e 100644 --- a/system/Common.php +++ b/system/Common.php @@ -25,9 +25,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RequestInterface; -use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; -use CodeIgniter\HTTP\URI; use CodeIgniter\Model; use CodeIgniter\Session\Session; use CodeIgniter\Test\TestLogger; From 001339b291264d4a910c304c9b6e791c9dbddba7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:50:49 +0000 Subject: [PATCH 165/380] chore(deps-dev): update rector/rector requirement from 0.18.8 to 0.18.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/0.18.8...0.18.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 d762dea8e0bb..4ff56944a3b1 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.18.8", + "rector/rector": "0.18.10", "vimeo/psalm": "^5.0" }, "suggest": { From c6aa4426a8b6bcf651d4f6c544ccb2794fab7dfe Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Nov 2023 07:05:37 +0900 Subject: [PATCH 166/380] docs: fix incorrect code --- user_guide_src/source/database/results/013.php | 2 +- user_guide_src/source/database/results/014.php | 2 +- user_guide_src/source/database/results/015.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/database/results/013.php b/user_guide_src/source/database/results/013.php index d0b1e445f01f..bb476f84eb80 100644 --- a/user_guide_src/source/database/results/013.php +++ b/user_guide_src/source/database/results/013.php @@ -6,7 +6,7 @@ class User public $email; public $username; - protected $last_login; + protected $lastLogin; public function lastLogin($format) { diff --git a/user_guide_src/source/database/results/014.php b/user_guide_src/source/database/results/014.php index f0845bf55ac3..fe88c6f0529e 100644 --- a/user_guide_src/source/database/results/014.php +++ b/user_guide_src/source/database/results/014.php @@ -7,5 +7,5 @@ foreach ($rows as $row) { echo $row->id; echo $row->email; - echo $row->last_login('Y-m-d'); + echo $row->lastLogin('Y-m-d'); } diff --git a/user_guide_src/source/database/results/015.php b/user_guide_src/source/database/results/015.php index 247d5d8b5313..31bc816a8472 100644 --- a/user_guide_src/source/database/results/015.php +++ b/user_guide_src/source/database/results/015.php @@ -6,5 +6,5 @@ if (isset($row)) { echo $row->email; // access attributes - echo $row->last_login('Y-m-d'); // access class methods + echo $row->lastLogin('Y-m-d'); // access class methods } From 745381c8393a3e41bcd3e97da2a75d533dfa8d2e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Nov 2023 07:06:33 +0900 Subject: [PATCH 167/380] docs: add namespace to User class --- user_guide_src/source/database/results/003.php | 4 ++-- user_guide_src/source/database/results/007.php | 2 +- user_guide_src/source/database/results/013.php | 2 ++ user_guide_src/source/database/results/014.php | 2 +- user_guide_src/source/database/results/015.php | 2 +- user_guide_src/source/database/results/016.php | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/database/results/003.php b/user_guide_src/source/database/results/003.php index da55c19717c1..d3fc78cc8d77 100644 --- a/user_guide_src/source/database/results/003.php +++ b/user_guide_src/source/database/results/003.php @@ -2,7 +2,7 @@ $query = $db->query('SELECT * FROM users;'); -foreach ($query->getResult('User') as $user) { - echo $user->name; // access attributes +foreach ($query->getResult(\App\Entities\User::class) as $user) { + echo $user->name; // access attributes echo $user->reverseName(); // or methods defined on the 'User' class } diff --git a/user_guide_src/source/database/results/007.php b/user_guide_src/source/database/results/007.php index 6a6c309efb4f..460857242adb 100644 --- a/user_guide_src/source/database/results/007.php +++ b/user_guide_src/source/database/results/007.php @@ -1,7 +1,7 @@ query('SELECT * FROM users LIMIT 1;'); -$row = $query->getRow(0, 'User'); +$row = $query->getRow(0, \App\Entities\User::class); echo $row->name; // access attributes echo $row->reverse_name(); // or methods defined on the 'User' class diff --git a/user_guide_src/source/database/results/013.php b/user_guide_src/source/database/results/013.php index bb476f84eb80..baef2cd97d99 100644 --- a/user_guide_src/source/database/results/013.php +++ b/user_guide_src/source/database/results/013.php @@ -1,5 +1,7 @@ query('YOUR QUERY'); -$rows = $query->getCustomResultObject('User'); +$rows = $query->getCustomResultObject(\App\Entities\User::class); foreach ($rows as $row) { echo $row->id; diff --git a/user_guide_src/source/database/results/015.php b/user_guide_src/source/database/results/015.php index 31bc816a8472..7fff4e037bf4 100644 --- a/user_guide_src/source/database/results/015.php +++ b/user_guide_src/source/database/results/015.php @@ -2,7 +2,7 @@ $query = $db->query('YOUR QUERY'); -$row = $query->getCustomRowObject(0, 'User'); +$row = $query->getCustomRowObject(0, \App\Entities\User::class); if (isset($row)) { echo $row->email; // access attributes diff --git a/user_guide_src/source/database/results/016.php b/user_guide_src/source/database/results/016.php index ed5ac68c4b1a..f6d0e2325ce6 100644 --- a/user_guide_src/source/database/results/016.php +++ b/user_guide_src/source/database/results/016.php @@ -1,3 +1,3 @@ getCustomRowObject(0, 'User'); +$row = $query->getCustomRowObject(0, \App\Entities\User::class); From 63fc2c04c9cfea49d13aa7b3de8fd95f5c4e204c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Nov 2023 07:06:54 +0900 Subject: [PATCH 168/380] docs: align comments --- user_guide_src/source/database/results/007.php | 2 +- user_guide_src/source/database/results/015.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/results/007.php b/user_guide_src/source/database/results/007.php index 460857242adb..ed1550836aab 100644 --- a/user_guide_src/source/database/results/007.php +++ b/user_guide_src/source/database/results/007.php @@ -3,5 +3,5 @@ $query = $db->query('SELECT * FROM users LIMIT 1;'); $row = $query->getRow(0, \App\Entities\User::class); -echo $row->name; // access attributes +echo $row->name; // access attributes echo $row->reverse_name(); // or methods defined on the 'User' class diff --git a/user_guide_src/source/database/results/015.php b/user_guide_src/source/database/results/015.php index 7fff4e037bf4..7cc9b7996e3b 100644 --- a/user_guide_src/source/database/results/015.php +++ b/user_guide_src/source/database/results/015.php @@ -5,6 +5,6 @@ $row = $query->getCustomRowObject(0, \App\Entities\User::class); if (isset($row)) { - echo $row->email; // access attributes + echo $row->email; // access attributes echo $row->lastLogin('Y-m-d'); // access class methods } From 247e7407a05c8e57c67d41d4861ec006b52088e5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Nov 2023 08:53:01 +0900 Subject: [PATCH 169/380] docs: change sample code to be more practical --- user_guide_src/source/database/events.rst | 4 +++- user_guide_src/source/database/events/001.php | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/events.rst b/user_guide_src/source/database/events.rst index 08fe73b09081..8cefcad22dbf 100644 --- a/user_guide_src/source/database/events.rst +++ b/user_guide_src/source/database/events.rst @@ -21,6 +21,8 @@ DBQuery This event is triggered whenever a new query has been run, whether successful or not. The only parameter is a :doc:`Query ` instance of the current query. You could use this to display all queries in STDOUT, or logging to a file, or even creating tools to do automatic query analysis to help you spot -potentially missing indexes, slow queries, etc. An example usage might be: +potentially missing indexes, slow queries, etc. + +An example usage might be: .. literalinclude:: events/001.php diff --git a/user_guide_src/source/database/events/001.php b/user_guide_src/source/database/events/001.php index 4461b715af19..ed2bb1fcec43 100644 --- a/user_guide_src/source/database/events/001.php +++ b/user_guide_src/source/database/events/001.php @@ -1,4 +1,18 @@ Date: Sun, 19 Nov 2023 09:05:23 +0900 Subject: [PATCH 170/380] test: fix failed test --- tests/system/Validation/ValidationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 85b504ca1cd7..889338a09f41 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -797,7 +797,7 @@ public function testJsonInputInvalid(): void $config = new App(); $json = 'invalid'; - $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + $request = new IncomingRequest($config, new SiteURI($config), $json, new UserAgent()); $request->setHeader('Content-Type', 'application/json'); $rules = [ From 7c0024a10002b3d0532ea4a03ac8a6cf5a49c06e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Nov 2023 09:42:07 +0900 Subject: [PATCH 171/380] docs: add space after comma --- app/Config/Publisher.php | 2 +- system/Config/Publisher.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php index 47475112c080..bf03be1db7e0 100644 --- a/app/Config/Publisher.php +++ b/app/Config/Publisher.php @@ -19,7 +19,7 @@ class Publisher extends BasePublisher * result in a PublisherException. Files that do no fit the * pattern will cause copy/merge to fail. * - * @var array + * @var array */ public $restrictions = [ ROOTPATH => '*', diff --git a/system/Config/Publisher.php b/system/Config/Publisher.php index fa04e24cd28f..d5f938e09be3 100644 --- a/system/Config/Publisher.php +++ b/system/Config/Publisher.php @@ -26,7 +26,7 @@ class Publisher extends BaseConfig * result in a PublisherException. Files that do no fit the * pattern will cause copy/merge to fail. * - * @var array + * @var array */ public $restrictions = [ ROOTPATH => '*', From ad6e3e141b6201788cce9b0d351411bf47e19669 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Nov 2023 09:42:30 +0900 Subject: [PATCH 172/380] config: update system/Config/Routing This should be the same as Config\Routing. --- system/Config/Routing.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/system/Config/Routing.php b/system/Config/Routing.php index 409bcf099f65..e6d25138f8f0 100644 --- a/system/Config/Routing.php +++ b/system/Config/Routing.php @@ -24,7 +24,7 @@ class Routing extends BaseConfig * Default: APPPATH . 'Config/Routes.php' */ public array $routeFiles = [ - APPPATH . 'Routes.php', + APPPATH . 'Config/Routes.php', ]; /** @@ -95,4 +95,17 @@ class Routing extends BaseConfig * Default: false */ public bool $prioritize = false; + + /** + * Map of URI segments and namespaces. For Auto Routing (Improved). + * + * The key is the first URI segment. The value is the controller namespace. + * E.g., + * [ + * 'blog' => 'Acme\Blog\Controllers', + * ] + * + * @var array [ uri_segment => namespace ] + */ + public array $moduleRoutes = []; } From a841e1de3d1841ebb3ce0329b1392f4716ec9026 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Nov 2023 09:21:39 +0900 Subject: [PATCH 173/380] refactor: rename param names --- system/HTTP/RequestTrait.php | 45 +++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 52ffa812a315..0acfbe184b43 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -35,10 +35,9 @@ trait RequestTrait protected $ipAddress = ''; /** - * Stores values we've retrieved from - * PHP globals. + * Stores values we've retrieved from PHP globals. * - * @var array + * @var array{get?: array, post?: array, request?: array, cookie?: array, server?: array} */ protected $globals = []; @@ -213,13 +212,15 @@ public function getEnv($index = null, $filter = null, $flags = null) /** * Allows manually setting the value of PHP global, like $_GET, $_POST, etc. * + * @param string $name Supergrlobal name (lowercase) + * @phpstan-param 'get'|'post'|'request'|'cookie'|'server' $name * @param mixed $value * * @return $this */ - public function setGlobal(string $method, $value) + public function setGlobal(string $name, $value) { - $this->globals[$method] = $value; + $this->globals[$name] = $value; return $this; } @@ -234,19 +235,18 @@ public function setGlobal(string $method, $value) * * http://php.net/manual/en/filter.filters.sanitize.php * - * @param string $method Input filter constant + * @param string $name Supergrlobal name (lowercase) + * @phpstan-param 'get'|'post'|'request'|'cookie'|'server' $name * @param array|string|null $index * @param int|null $filter Filter constant * @param array|int|null $flags Options * * @return array|bool|float|int|object|string|null */ - public function fetchGlobal(string $method, $index = null, ?int $filter = null, $flags = null) + public function fetchGlobal(string $name, $index = null, ?int $filter = null, $flags = null) { - $method = strtolower($method); - - if (! isset($this->globals[$method])) { - $this->populateGlobals($method); + if (! isset($this->globals[$name])) { + $this->populateGlobals($name); } // Null filters cause null values to return. @@ -257,9 +257,9 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, if ($index === null) { $values = []; - foreach ($this->globals[$method] as $key => $value) { + foreach ($this->globals[$name] as $key => $value) { $values[$key] = is_array($value) - ? $this->fetchGlobal($method, $key, $filter, $flags) + ? $this->fetchGlobal($name, $key, $filter, $flags) : filter_var($value, $filter, $flags); } @@ -271,7 +271,7 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, $output = []; foreach ($index as $key) { - $output[$key] = $this->fetchGlobal($method, $key, $filter, $flags); + $output[$key] = $this->fetchGlobal($name, $key, $filter, $flags); } return $output; @@ -279,7 +279,7 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, // Does the index contain array notation? if (($count = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $index, $matches)) > 1) { - $value = $this->globals[$method]; + $value = $this->globals[$name]; for ($i = 0; $i < $count; $i++) { $key = trim($matches[0][$i], '[]'); @@ -297,7 +297,7 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, } if (! isset($value)) { - $value = $this->globals[$method][$index] ?? null; + $value = $this->globals[$name][$index] ?? null; } if (is_array($value) @@ -326,20 +326,23 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, } /** - * Saves a copy of the current state of one of several PHP globals + * Saves a copy of the current state of one of several PHP globals, * so we can retrieve them later. * + * @param string $name Supergrlobal name (lowercase) + * @phpstan-param 'get'|'post'|'request'|'cookie'|'server' $name + * * @return void */ - protected function populateGlobals(string $method) + protected function populateGlobals(string $name) { - if (! isset($this->globals[$method])) { - $this->globals[$method] = []; + if (! isset($this->globals[$name])) { + $this->globals[$name] = []; } // Don't populate ENV as it might contain // sensitive data that we don't want to get logged. - switch ($method) { + switch ($name) { case 'get': $this->globals['get'] = $_GET; break; From cbb096727367ce8a526d83a2948b679f0b609519 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Nov 2023 09:33:23 +0900 Subject: [PATCH 174/380] docs: make Request::getEnv() deprecated See https://github.com/codeigniter4/CodeIgniter4/commit/b0975ec5dba#diff-fb41662a8e01f56cacc449d12f5d386be73835879b2f49f452cb2aef8ac03466R441-R442 --- system/HTTP/RequestTrait.php | 3 +++ user_guide_src/source/changelogs/v4.4.4.rst | 4 ++++ user_guide_src/source/incoming/incomingrequest.rst | 3 +++ user_guide_src/source/incoming/request.rst | 3 +++ 4 files changed, 13 insertions(+) diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 0acfbe184b43..01ff12c73ca4 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -203,9 +203,12 @@ public function getServer($index = null, $filter = null, $flags = null) * @param array|int|null $flags * * @return mixed + * + * @deprecated 4.4.4 This method does not work from the beginning. Use `env()`. */ public function getEnv($index = null, $filter = null, $flags = null) { + // @phpstan-ignore-next-line return $this->fetchGlobal('env', $index, $filter, $flags); } diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index dfc862d62b62..aca70ba7874e 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -41,6 +41,10 @@ Changes Deprecations ************ +- **Request:** The :php:meth:`CodeIgniter\\HTTP\\Request::getEnv()` method is + deprecated. This method does not work from the beginning. Use :php:func:`env()` + instead. + ********** Bugs Fixed ********** diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index c6db5b28fe4c..ba3f12a0a0ec 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -131,6 +131,9 @@ The ``getServer()`` method will pull from ``$_SERVER``. getEnv() -------- +.. deprecated:: 4.4.4 This method does not work from the beginning. Use + :php:func:`env()` instead. + The ``getEnv()`` method will pull from ``$_ENV``. * ``$request->getEnv()`` diff --git a/user_guide_src/source/incoming/request.rst b/user_guide_src/source/incoming/request.rst index d15da89ec14e..7c00380b9dc9 100644 --- a/user_guide_src/source/incoming/request.rst +++ b/user_guide_src/source/incoming/request.rst @@ -107,6 +107,9 @@ Class Reference .. php:method:: getEnv([$index = null[, $filter = null[, $flags = null]]]) + .. deprecated:: 4.4.4 This method does not work from the beginning. Use + :php:func:`env()` instead. + :param mixed $index: Value name :param int $filter: The type of filter to apply. A list of filters can be found in `PHP manual `__. :param int|array $flags: Flags to apply. A list of flags can be found in `PHP manual `__. From fe64ca018ecfbfac4a68af46777e67c8e0800fa9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Nov 2023 12:06:43 +0900 Subject: [PATCH 175/380] docs: fix typo Co-authored-by: John Paul E. Balandan, CPA --- system/HTTP/RequestTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index 01ff12c73ca4..6db903ddacec 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -332,7 +332,7 @@ public function fetchGlobal(string $name, $index = null, ?int $filter = null, $f * Saves a copy of the current state of one of several PHP globals, * so we can retrieve them later. * - * @param string $name Supergrlobal name (lowercase) + * @param string $name Superglobal name (lowercase) * @phpstan-param 'get'|'post'|'request'|'cookie'|'server' $name * * @return void From 5fbef683589f0e20e3be369d08f2c686f6dabe0f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 06:31:15 +0900 Subject: [PATCH 176/380] chore: disable RemoveVarTagFromClassConstantRector If we want to write @var to constants, we can write. --- rector.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/rector.php b/rector.php index 747cd4ce8bbd..cfc84104456e 100644 --- a/rector.php +++ b/rector.php @@ -45,7 +45,6 @@ use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector; use Utils\Rector\PassStrictParameterToFunctionParameterRector; use Utils\Rector\RemoveErrorSuppressInTryCatchStmtsRector; -use Utils\Rector\RemoveVarTagFromClassConstantRector; use Utils\Rector\UnderscoreToCamelCaseVariableNameRector; return static function (RectorConfig $rectorConfig): void { @@ -134,7 +133,6 @@ $rectorConfig->rule(ChangeArrayPushToArrayAssignRector::class); $rectorConfig->rule(UnnecessaryTernaryExpressionRector::class); $rectorConfig->rule(RemoveErrorSuppressInTryCatchStmtsRector::class); - $rectorConfig->rule(RemoveVarTagFromClassConstantRector::class); $rectorConfig->rule(SimplifyRegexPatternRector::class); $rectorConfig->rule(FuncGetArgsToVariadicParamRector::class); $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class); From 2ec8ff5d9b79f435330db4a5bad0ba4bf41410f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 10:47:24 +0900 Subject: [PATCH 177/380] fix: bug where ExceptionHandler displays incorrect Exception classname It showed the first Exception, but devs must catch the thrown Exception. --- app/Views/errors/cli/error_exception.php | 17 +++++++++++++---- app/Views/errors/html/error_exception.php | 23 +++++++++++++++++++++++ system/Debug/BaseExceptionHandler.php | 9 ++++++++- system/Debug/Exceptions.php | 14 ++++++++------ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/app/Views/errors/cli/error_exception.php b/app/Views/errors/cli/error_exception.php index f24e98fb9a49..98d83b0ed3a6 100644 --- a/app/Views/errors/cli/error_exception.php +++ b/app/Views/errors/cli/error_exception.php @@ -3,17 +3,26 @@ use CodeIgniter\CLI\CLI; // The main Exception -CLI::newLine(); CLI::write('[' . get_class($exception) . ']', 'light_gray', 'red'); -CLI::newLine(); CLI::write($message); -CLI::newLine(); CLI::write('at ' . CLI::color(clean_path($exception->getFile()) . ':' . $exception->getLine(), 'green')); CLI::newLine(); +$last = $exception; + +while ($prevException = $last->getPrevious()) { + $last = $prevException; + + CLI::write(' Caused by:'); + CLI::write(' [' . get_class($prevException) . ']', 'red'); + CLI::write(' ' . $prevException->getMessage()); + CLI::write(' at ' . CLI::color(clean_path($prevException->getFile()) . ':' . $prevException->getLine(), 'green')); + CLI::newLine(); +} + // The backtrace if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) { - $backtraces = $exception->getTrace(); + $backtraces = $last->getTrace(); if ($backtraces) { CLI::write('Backtrace:', 'green'); diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 1c094d728872..406b48ec6772 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -44,6 +44,29 @@
+
+ getPrevious()) { + $last = $prevException; + ?> + +
+    Caused by:
+    getCode() ? ' #' . $prevException->getCode() : '') ?>
+
+    getMessage())) ?>
+    getMessage())) ?>"
+       rel="noreferrer" target="_blank">search →
+    getFile()) . ':' . $prevException->getLine()) ?>
+    
+ + +
+
diff --git a/system/Debug/BaseExceptionHandler.php b/system/Debug/BaseExceptionHandler.php index 0330c53cf97c..8b67d2153f9f 100644 --- a/system/Debug/BaseExceptionHandler.php +++ b/system/Debug/BaseExceptionHandler.php @@ -67,7 +67,14 @@ abstract public function handle( */ protected function collectVars(Throwable $exception, int $statusCode): array { - $trace = $exception->getTrace(); + // Get the first exception. + $firstException = $exception; + + while ($prevException = $firstException->getPrevious()) { + $firstException = $prevException; + } + + $trace = $firstException->getTrace(); if ($this->config->sensitiveDataInTrace !== []) { $trace = $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace); diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index a9887fba15ce..37b0376990de 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -136,11 +136,6 @@ public function exceptionHandler(Throwable $exception) $this->request = Services::request(); $this->response = Services::response(); - // Get the first exception. - while ($prevException = $exception->getPrevious()) { - $exception = $prevException; - } - if (method_exists($this->config, 'handler')) { // Use new ExceptionHandler $handler = $this->config->handler($statusCode, $exception); @@ -325,7 +320,14 @@ protected function render(Throwable $exception, int $statusCode) */ protected function collectVars(Throwable $exception, int $statusCode): array { - $trace = $exception->getTrace(); + // Get the first exception. + $firstException = $exception; + + while ($prevException = $firstException->getPrevious()) { + $firstException = $prevException; + } + + $trace = $firstException->getTrace(); if ($this->config->sensitiveDataInTrace !== []) { $trace = $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace); From 6153d4dffcdbaffdb4e5fe8a1ef86418879c139d Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 13:02:13 +0900 Subject: [PATCH 178/380] chore: remove RemoveVarTagFromClassConstantRector class --- .../RemoveVarTagFromClassConstantRector.php | 82 ------------------- 1 file changed, 82 deletions(-) delete mode 100644 utils/Rector/RemoveVarTagFromClassConstantRector.php diff --git a/utils/Rector/RemoveVarTagFromClassConstantRector.php b/utils/Rector/RemoveVarTagFromClassConstantRector.php deleted file mode 100644 index 2393516f508b..000000000000 --- a/utils/Rector/RemoveVarTagFromClassConstantRector.php +++ /dev/null @@ -1,82 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Utils\Rector; - -use PhpParser\Node; -use PhpParser\Node\Stmt\ClassConst; -use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; -use Rector\Comments\NodeDocBlock\DocBlockUpdater; -use Rector\Core\Rector\AbstractRector; -use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; -use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; - -final class RemoveVarTagFromClassConstantRector extends AbstractRector -{ - private PhpDocInfoFactory $phpDocInfoFactory; - private DocBlockUpdater $docBlockUpdater; - - public function __construct(PhpDocInfoFactory $phpDocInfoFactory, DocBlockUpdater $docBlockUpdater) - { - $this->phpDocInfoFactory = $phpDocInfoFactory; - $this->docBlockUpdater = $docBlockUpdater; - } - - public function getRuleDefinition(): RuleDefinition - { - return new RuleDefinition('Remove @var tag from class constant', [ - new CodeSample( - <<<'CODE_SAMPLE' - class Foo - { - /** @var string */ - const X = 'test'; - } - CODE_SAMPLE, - <<<'CODE_SAMPLE' - class Foo - { - const X = 'test'; - } - CODE_SAMPLE - ), - ]); - } - - /** - * @return string[] - */ - public function getNodeTypes(): array - { - return [ClassConst::class]; - } - - /** - * @param ClassConst $node - */ - public function refactor(Node $node): ?Node - { - $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); - $varTagValueNode = $phpDocInfo->getVarTagValueNode(); - if (! $varTagValueNode instanceof VarTagValueNode) { - return null; - } - - $phpDocInfo->removeByType(VarTagValueNode::class); - - $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); - - return $node; - } -} From 181b93f922959294b5b837e002cbeb9814183f19 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 13:10:45 +0900 Subject: [PATCH 179/380] docs: add upgrade guide --- user_guide_src/source/installation/upgrade_444.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst index b3773947efd9..e21a1850d613 100644 --- a/user_guide_src/source/installation/upgrade_444.rst +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -16,6 +16,14 @@ Please refer to the upgrade instructions corresponding to your installation meth Mandatory File Changes ********************** +Error Files +=========== + +Update the following files to show correct error messages: + +- app/Views/errors/cli/error_exception.php +- app/Views/errors/html/error_exception.php + **************** Breaking Changes **************** From 886aa89de958c7998a82f664cc919bdec0c5bae5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Nov 2023 19:06:27 +0900 Subject: [PATCH 180/380] feat: log exception classname and all previous exceptions --- system/Debug/Exceptions.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 37b0376990de..4b3e5cf3ea3e 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -125,12 +125,26 @@ public function exceptionHandler(Throwable $exception) [$statusCode, $exitCode] = $this->determineCodes($exception); if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) { - log_message('critical', "{message}\nin {exFile} on line {exLine}.\n{trace}", [ + log_message('critical', get_class($exception) . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ 'message' => $exception->getMessage(), 'exFile' => clean_path($exception->getFile()), // {file} refers to THIS file 'exLine' => $exception->getLine(), // {line} refers to THIS line 'trace' => self::renderBacktrace($exception->getTrace()), ]); + + // Get the first exception. + $last = $exception; + + while ($prevException = $last->getPrevious()) { + $last = $prevException; + + log_message('critical', '[Caused by] ' . get_class($prevException) . ": {message}\nin {exFile} on line {exLine}.\n{trace}", [ + 'message' => $prevException->getMessage(), + 'exFile' => clean_path($prevException->getFile()), // {file} refers to THIS file + 'exLine' => $prevException->getLine(), // {line} refers to THIS line + 'trace' => self::renderBacktrace($prevException->getTrace()), + ]); + } } $this->request = Services::request(); From 1aee162bde6c5f66cce86c36bf3263da5283027c Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 23 Nov 2023 04:10:44 -0800 Subject: [PATCH 181/380] Fix code style --- user_guide_src/source/extending/core_classes/002.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/extending/core_classes/002.php b/user_guide_src/source/extending/core_classes/002.php index 40d7342686a0..a176459afc60 100644 --- a/user_guide_src/source/extending/core_classes/002.php +++ b/user_guide_src/source/extending/core_classes/002.php @@ -12,7 +12,7 @@ public static function routes(bool $getShared = true) return static::getSharedInstance('routes'); } - return new \App\Libraries\RouteCollection(static::locator(), config(Modules::class), config(Routing::class) ); + return new \App\Libraries\RouteCollection(static::locator(), config(Modules::class), config(Routing::class)); } // ... From 49ac6640665ff71499d7a3b2d98b85dc26e137a6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 23 Nov 2023 21:12:06 +0900 Subject: [PATCH 182/380] docs: fix incorrect PHPDoc types --- system/Database/BaseResult.php | 6 ++++-- system/Database/ResultInterface.php | 5 +++-- system/Email/Email.php | 2 +- system/HTTP/Files/FileCollection.php | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index c5f603a28127..6f6399cfb2fd 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -254,14 +254,16 @@ public function getResultObject(): array * * If row doesn't exist, returns null. * - * @param int $n The index of the results to return - * @param string $type The type of result object. 'array', 'object' or class name. + * @param int|string $n The index of the results to return, or column name. + * @param string $type The type of result object. 'array', 'object' or class name. + * @phpstan-param class-string|'array'|'object' $type * * @return array|object|stdClass|null * @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null)) */ public function getRow($n = 0, string $type = 'object') { + // $n is a column name. if (! is_numeric($n)) { // We cache the row data for subsequent uses if (! is_array($this->rowData)) { diff --git a/system/Database/ResultInterface.php b/system/Database/ResultInterface.php index c959a7cb2292..b06de85ad3be 100644 --- a/system/Database/ResultInterface.php +++ b/system/Database/ResultInterface.php @@ -57,8 +57,9 @@ public function getResultObject(): array; * * If row doesn't exist, returns null. * - * @param int $n The index of the results to return - * @param string $type The type of result object. 'array', 'object' or class name. + * @param int|string $n The index of the results to return, or column name. + * @param string $type The type of result object. 'array', 'object' or class name. + * @phpstan-param class-string|'array'|'object' $type * * @return array|object|stdClass|null * @phpstan-return ($type is 'object' ? stdClass|null : ($type is 'array' ? array|null : object|null)) diff --git a/system/Email/Email.php b/system/Email/Email.php index 0adb3e6eb5e6..37a5b56be98d 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -731,7 +731,7 @@ public function setHeader($header, $value) } /** - * @param string $email + * @param array|string $email * * @return array */ diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index f01cc69f5902..8cb1f913e8dc 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -77,7 +77,7 @@ public function getFile(string $name) /** * Verify if a file exist in the collection of uploaded files and is have been uploaded with multiple option. * - * @return array|null + * @return list|null */ public function getFileMultiple(string $name) { @@ -245,7 +245,7 @@ protected function fixFilesArray(array $data): array * @param array $index The index sequence we are navigating down * @param array $value The portion of the array to process * - * @return UploadedFile|null + * @return list|UploadedFile|null */ protected function getValueDotNotationSyntax(array $index, array $value) { From 6bb7c52c70313ae248a8dc0913145d5be25e27a6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Nov 2023 17:43:36 +0900 Subject: [PATCH 183/380] docs: fix PHPDoc types for Model --- phpstan-baseline.php | 5 ----- system/BaseModel.php | 6 ++++-- system/Model.php | 6 ++++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 7f9182eeeeda..1322685d6fd2 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2641,11 +2641,6 @@ 'count' => 1, 'path' => __DIR__ . '/system/Model.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Return type \\(int\\|object\\|string\\|false\\) of method CodeIgniter\\\\Model\\:\\:insert\\(\\) should be covariant with return type \\(bool\\|int\\|string\\) of method CodeIgniter\\\\BaseModel\\:\\:insert\\(\\)$#', - 'count' => 1, - 'path' => __DIR__ . '/system/Model.php', -]; $ignoreErrors[] = [ 'message' => '#^Accessing offset mixed directly on \\$_GET is discouraged\\.$#', 'count' => 1, diff --git a/system/BaseModel.php b/system/BaseModel.php index f9eed92b1d49..1d854256a63c 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -740,10 +740,12 @@ public function getInsertID() * Inserts data into the database. If an object is provided, * it will attempt to convert it to an array. * - * @param array|object|null $data Data - * @param bool $returnID Whether insert ID should be returned or not. + * @param array|object|null $data Data + * @phpstan-param row_array|object|null $data + * @param bool $returnID Whether insert ID should be returned or not. * * @return bool|int|string insert ID or true on success. false on failure. + * @phpstan-return ($returnID is true ? int|string|false : bool) * * @throws ReflectionException */ diff --git a/system/Model.php b/system/Model.php index d2f531998fef..3a055531cb5b 100644 --- a/system/Model.php +++ b/system/Model.php @@ -697,9 +697,11 @@ protected function shouldUpdate($data): bool * it will attempt to convert it to an array. * * @param array|object|null $data - * @param bool $returnID Whether insert ID should be returned or not. + * @phpstan-param row_array|object|null $data + * @param bool $returnID Whether insert ID should be returned or not. * - * @return BaseResult|false|int|object|string + * @return false|int|object|string + * @phpstan-return ($returnID is true ? int|string|false : bool) * * @throws ReflectionException */ From fb0348366ab28d174e772f19f47fb63f1236b0eb Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 13:42:44 +0900 Subject: [PATCH 184/380] docs: add missing Time::setTestNow() --- user_guide_src/source/testing/overview.rst | 17 +++++++++++++ .../source/testing/overview/021.php | 24 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 user_guide_src/source/testing/overview/021.php diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index d969f73cdc41..2dd63d4eed9e 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -267,6 +267,23 @@ component name: .. note:: All component Factories are reset by default between each test. Modify your test case's ``$setUpMethods`` if you need instances to persist. +Testing and Time +================ + +Testing time-dependent code can be challenging. However, when using the +:doc:`Time <../libraries/time>` class, the current time can be fixed or changed +at will during testing. + +Below is a sample test code that fixes the current time: + +.. literalinclude:: overview/021.php + +You can fix the current time with the ``Time::setTestNow()`` method. +Optionally, you can specify a locale as the second parameter. + +Don't forget to reset the current time after the test with calling it without +parameters. + .. _testing-cli-output: Testing CLI Output diff --git a/user_guide_src/source/testing/overview/021.php b/user_guide_src/source/testing/overview/021.php new file mode 100644 index 000000000000..7a8c7a026afd --- /dev/null +++ b/user_guide_src/source/testing/overview/021.php @@ -0,0 +1,24 @@ +assertSame('2023-11-25 12:00:00', (string) Time::now()); + } +} From f3fd116da2a138e642de10e00368f1ecf34b5330 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 13:14:20 +0900 Subject: [PATCH 185/380] test: add tests for Model timestamp --- tests/_support/Models/UserTimestampModel.php | 29 +++ tests/system/Models/TimestampModelTest.php | 254 +++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 tests/_support/Models/UserTimestampModel.php create mode 100644 tests/system/Models/TimestampModelTest.php diff --git a/tests/_support/Models/UserTimestampModel.php b/tests/_support/Models/UserTimestampModel.php new file mode 100644 index 000000000000..1cc66d334e37 --- /dev/null +++ b/tests/_support/Models/UserTimestampModel.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Models; + +use CodeIgniter\Model; + +class UserTimestampModel extends Model +{ + protected $table = 'user'; + protected $allowedFields = [ + 'name', + 'email', + 'country', + 'deleted_at', + ]; + protected $returnType = 'array'; + protected $useSoftDeletes = true; + protected $useTimestamps = true; + protected $dateFormat = 'datetime'; +} diff --git a/tests/system/Models/TimestampModelTest.php b/tests/system/Models/TimestampModelTest.php new file mode 100644 index 000000000000..b44461a8a3c9 --- /dev/null +++ b/tests/system/Models/TimestampModelTest.php @@ -0,0 +1,254 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Models; + +use CodeIgniter\I18n\Time; +use Tests\Support\Entity\User; +use Tests\Support\Models\UserTimestampModel; + +/** + * @group DatabaseLive + * + * @internal + */ +final class TimestampModelTest extends LiveModelTestCase +{ + protected $migrate = true; + protected $migrateOnce = true; + protected $refresh = false; + protected $seed = ''; + + protected function tearDown(): void + { + parent::tearDown(); + + // Reset current time. + Time::setTestNow(); + } + + /** + * @return int|string Insert ID + */ + private function allowDatesPrepareOneRecord(array $data) + { + $this->createModel(UserTimestampModel::class); + $this->db->table('user')->truncate(); + + $this->model->setAllowedFields([ + 'name', + 'email', + 'country', + 'created_at', + 'updated_at', + 'deleted_at', + ]); + + return $this->model->insert($data, true); + } + + /** + * @return int|string Insert ID + */ + private function doNotAllowDatesPrepareOneRecord(array $data) + { + $this->createModel(UserTimestampModel::class); + $this->db->table('user')->truncate(); + + $this->model->setAllowedFields([ + 'name', + 'email', + 'country', + // no 'created_at', + // no 'updated_at', + 'deleted_at', + ]); + + return $this->model->insert($data, true); + } + + public function testDoNotAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + // no created_at + // no updated_at + ]; + $id = $this->doNotAllowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $this->assertSame('2023-11-25 12:00:00', $user['created_at']); + $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + } + + public function testDoNotAllowDatesInsertArrayWithDatesSetsTimestamp(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->doNotAllowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $this->assertSame('2023-11-25 12:00:00', $user['created_at']); + $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + } + + public function testDoNotAllowDatesUpdateArrayUpdatesUpdatedAt(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->doNotAllowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $user['country'] = 'CA'; + $this->model->update($user['id'], $user); + + $user = $this->model->find($id); + + $this->assertSame('2023-11-25 12:00:00', $user['created_at']); + $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + } + + public function testDoNotAllowDatesUpdateEntityUpdatesUpdatedAt(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->doNotAllowDatesPrepareOneRecord($data); + $this->setPrivateProperty($this->model, 'returnType', User::class); + $this->setPrivateProperty($this->model, 'tempReturnType', User::class); + + $user = $this->model->find($id); + + $user->country = 'CA'; + $this->model->update($user->id, $user); + + $user = $this->model->find($id); + + $this->assertSame('2023-11-25 12:00:00', (string) $user->created_at); + $this->assertSame('2023-11-25 12:00:00', (string) $user->updated_at); + } + + public function testAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + // no created_at + // no updated_at + ]; + $id = $this->allowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $this->assertSame('2023-11-25 12:00:00', $user['created_at']); + $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + } + + public function testAllowDatesInsertArrayWithDatesSetsTimestamp(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->allowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $this->assertSame('2000-01-01 12:00:00', $user['created_at']); + $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); + } + + public function testAllowDatesUpdateArrayUpdatesUpdatedAt(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->allowDatesPrepareOneRecord($data); + + $user = $this->model->find($id); + + $user['country'] = 'CA'; + $this->model->update($user['id'], $user); + + $user = $this->model->find($id); + + $this->assertSame('2000-01-01 12:00:00', $user['created_at']); + $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); + } + + public function testAllowDatesUpdateEntityUpdatesUpdatedAt(): void + { + Time::setTestNow('2023-11-25 12:00:00'); + + $data = [ + 'name' => 'John Smith', + 'email' => 'john@example.com', + 'country' => 'US', + 'created_at' => '2000-01-01 12:00:00', + 'updated_at' => '2000-01-01 12:00:00', + ]; + $id = $this->allowDatesPrepareOneRecord($data); + $this->setPrivateProperty($this->model, 'returnType', User::class); + $this->setPrivateProperty($this->model, 'tempReturnType', User::class); + + $user = $this->model->find($id); + + $user->country = 'CA'; + $this->model->update($user->id, $user); + + $user = $this->model->find($id); + + $this->assertSame('2000-01-01 12:00:00', (string) $user->created_at); + // The Entity has `updated_at` value, but it will be discarded because of onlyChanged. + $this->assertSame('2023-11-25 12:00:00', (string) $user->updated_at); + } +} From d690553efc77de7ea9dbf8f90c515e01c14f0f76 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 14:24:59 +0900 Subject: [PATCH 186/380] docs: add comments --- tests/system/Models/TimestampModelTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/system/Models/TimestampModelTest.php b/tests/system/Models/TimestampModelTest.php index b44461a8a3c9..92458449b981 100644 --- a/tests/system/Models/TimestampModelTest.php +++ b/tests/system/Models/TimestampModelTest.php @@ -163,6 +163,10 @@ public function testDoNotAllowDatesUpdateEntityUpdatesUpdatedAt(): void $this->assertSame('2023-11-25 12:00:00', (string) $user->updated_at); } + /** + * We do not recommend to add timestamp fields to $allowedFields. + * If you want to add old data to these fields, use Query Builder. + */ public function testAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void { Time::setTestNow('2023-11-25 12:00:00'); @@ -182,6 +186,10 @@ public function testAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); } + /** + * We do not recommend to add timestamp fields to $allowedFields. + * If you want to add old data to these fields, use Query Builder. + */ public function testAllowDatesInsertArrayWithDatesSetsTimestamp(): void { Time::setTestNow('2023-11-25 12:00:00'); @@ -201,6 +209,10 @@ public function testAllowDatesInsertArrayWithDatesSetsTimestamp(): void $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); } + /** + * We do not recommend to add timestamp fields to $allowedFields. + * If you want to add old data to these fields, use Query Builder. + */ public function testAllowDatesUpdateArrayUpdatesUpdatedAt(): void { Time::setTestNow('2023-11-25 12:00:00'); @@ -225,6 +237,10 @@ public function testAllowDatesUpdateArrayUpdatesUpdatedAt(): void $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); } + /** + * We do not recommend to add timestamp fields to $allowedFields. + * If you want to add old data to these fields, use Query Builder. + */ public function testAllowDatesUpdateEntityUpdatesUpdatedAt(): void { Time::setTestNow('2023-11-25 12:00:00'); From d062b568a5cdebacf750eab7215b4bf85f8e5810 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 18:36:07 +0900 Subject: [PATCH 187/380] test: fix assertions for SQLSRV --- tests/system/Models/TimestampModelTest.php | 48 ++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tests/system/Models/TimestampModelTest.php b/tests/system/Models/TimestampModelTest.php index 92458449b981..6df8b014ba60 100644 --- a/tests/system/Models/TimestampModelTest.php +++ b/tests/system/Models/TimestampModelTest.php @@ -90,8 +90,12 @@ public function testDoNotAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void $user = $this->model->find($id); - $this->assertSame('2023-11-25 12:00:00', $user['created_at']); - $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } public function testDoNotAllowDatesInsertArrayWithDatesSetsTimestamp(): void @@ -109,8 +113,12 @@ public function testDoNotAllowDatesInsertArrayWithDatesSetsTimestamp(): void $user = $this->model->find($id); - $this->assertSame('2023-11-25 12:00:00', $user['created_at']); - $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } public function testDoNotAllowDatesUpdateArrayUpdatesUpdatedAt(): void @@ -133,8 +141,12 @@ public function testDoNotAllowDatesUpdateArrayUpdatesUpdatedAt(): void $user = $this->model->find($id); - $this->assertSame('2023-11-25 12:00:00', $user['created_at']); - $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } public function testDoNotAllowDatesUpdateEntityUpdatesUpdatedAt(): void @@ -182,8 +194,12 @@ public function testAllowDatesInsertArrayWithoutDatesSetsTimestamp(): void $user = $this->model->find($id); - $this->assertSame('2023-11-25 12:00:00', $user['created_at']); - $this->assertSame('2023-11-25 12:00:00', $user['updated_at']); + $expected = '2023-11-25 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } /** @@ -205,8 +221,12 @@ public function testAllowDatesInsertArrayWithDatesSetsTimestamp(): void $user = $this->model->find($id); - $this->assertSame('2000-01-01 12:00:00', $user['created_at']); - $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); + $expected = '2000-01-01 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } /** @@ -233,8 +253,12 @@ public function testAllowDatesUpdateArrayUpdatesUpdatedAt(): void $user = $this->model->find($id); - $this->assertSame('2000-01-01 12:00:00', $user['created_at']); - $this->assertSame('2000-01-01 12:00:00', $user['updated_at']); + $expected = '2000-01-01 12:00:00'; + if ($this->db->DBDriver === 'SQLSRV') { + $expected .= '.000'; + } + $this->assertSame($expected, $user['created_at']); + $this->assertSame($expected, $user['updated_at']); } /** From 11afcc215202c6ba3c80f9553ecdfb3fb5929d54 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 19:58:32 +0900 Subject: [PATCH 188/380] docs: fix incorrect sample code --- user_guide_src/source/incoming/restful.rst | 4 ++++ user_guide_src/source/incoming/restful/003.php | 7 +++++-- user_guide_src/source/incoming/restful/011.php | 7 +++++-- user_guide_src/source/incoming/routing.rst | 2 ++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index 9240ac8b476d..d40f27ff6e9f 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -52,6 +52,8 @@ the controller that should be used: .. literalinclude:: restful/003.php +See also :ref:`controllers-namespace`. + Change the Placeholder Used =========================== @@ -122,6 +124,8 @@ the controller that should be used: .. literalinclude:: restful/011.php +See also :ref:`controllers-namespace`. + Change the Placeholder Used =========================== diff --git a/user_guide_src/source/incoming/restful/003.php b/user_guide_src/source/incoming/restful/003.php index 6610555f0a5f..347fde94c649 100644 --- a/user_guide_src/source/incoming/restful/003.php +++ b/user_guide_src/source/incoming/restful/003.php @@ -1,6 +1,9 @@ resource('photos', ['controller' => 'App\Gallery']); +$routes->resource('photos', ['controller' => 'Gallery']); +// Would create routes like: +$routes->get('photos', '\App\Controllers\Gallery::index'); +$routes->resource('photos', ['controller' => '\App\Gallery']); // Would create routes like: -$routes->get('photos', 'App\Gallery::index'); +$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/011.php b/user_guide_src/source/incoming/restful/011.php index cbb6f13bdf85..fc3a44b14229 100644 --- a/user_guide_src/source/incoming/restful/011.php +++ b/user_guide_src/source/incoming/restful/011.php @@ -1,6 +1,9 @@ presenter('photos', ['controller' => 'App\Gallery']); +$routes->presenter('photos', ['controller' => 'Gallery']); +// Would create routes like: +$routes->get('photos', '\App\Controllers\Gallery::index'); +$routes->presenter('photos', ['controller' => '\App\Gallery']); // Would create routes like: -$routes->get('photos', 'App\Gallery::index'); +$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index c509f807be87..646b66bd4ffc 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -83,6 +83,8 @@ You can supply multiple verbs that a route should match by passing them in as an Specifying Route Handlers ========================= +.. _controllers-namespace: + Controller's Namespace ---------------------- From b09f85eb9b1f366b2e37e368dd92c208c1d8c210 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 20:49:20 +0900 Subject: [PATCH 189/380] test: remove unneeded `deleted_at` in $allowedFields --- tests/_support/Models/UserTimestampModel.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/_support/Models/UserTimestampModel.php b/tests/_support/Models/UserTimestampModel.php index 1cc66d334e37..b3772112379b 100644 --- a/tests/_support/Models/UserTimestampModel.php +++ b/tests/_support/Models/UserTimestampModel.php @@ -20,7 +20,6 @@ class UserTimestampModel extends Model 'name', 'email', 'country', - 'deleted_at', ]; protected $returnType = 'array'; protected $useSoftDeletes = true; From f55cb2e44f602cf7215e872ba66a62466c3ee9a4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Nov 2023 21:10:31 +0900 Subject: [PATCH 190/380] docs: add sample code --- user_guide_src/source/incoming/restful.rst | 8 ++++++++ user_guide_src/source/incoming/restful/003.php | 4 ---- user_guide_src/source/incoming/restful/011.php | 4 ---- user_guide_src/source/incoming/restful/017.php | 5 +++++ user_guide_src/source/incoming/restful/018.php | 7 +++++++ user_guide_src/source/incoming/restful/019.php | 5 +++++ user_guide_src/source/incoming/restful/020.php | 7 +++++++ 7 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 user_guide_src/source/incoming/restful/017.php create mode 100644 user_guide_src/source/incoming/restful/018.php create mode 100644 user_guide_src/source/incoming/restful/019.php create mode 100644 user_guide_src/source/incoming/restful/020.php diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index d40f27ff6e9f..6d111a9302e1 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -52,6 +52,10 @@ the controller that should be used: .. literalinclude:: restful/003.php +.. literalinclude:: restful/017.php + +.. literalinclude:: restful/018.php + See also :ref:`controllers-namespace`. Change the Placeholder Used @@ -124,6 +128,10 @@ the controller that should be used: .. literalinclude:: restful/011.php +.. literalinclude:: restful/019.php + +.. literalinclude:: restful/020.php + See also :ref:`controllers-namespace`. Change the Placeholder Used diff --git a/user_guide_src/source/incoming/restful/003.php b/user_guide_src/source/incoming/restful/003.php index 347fde94c649..6f255282622d 100644 --- a/user_guide_src/source/incoming/restful/003.php +++ b/user_guide_src/source/incoming/restful/003.php @@ -3,7 +3,3 @@ $routes->resource('photos', ['controller' => 'Gallery']); // Would create routes like: $routes->get('photos', '\App\Controllers\Gallery::index'); - -$routes->resource('photos', ['controller' => '\App\Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/011.php b/user_guide_src/source/incoming/restful/011.php index fc3a44b14229..e08078d47e31 100644 --- a/user_guide_src/source/incoming/restful/011.php +++ b/user_guide_src/source/incoming/restful/011.php @@ -3,7 +3,3 @@ $routes->presenter('photos', ['controller' => 'Gallery']); // Would create routes like: $routes->get('photos', '\App\Controllers\Gallery::index'); - -$routes->presenter('photos', ['controller' => '\App\Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/017.php b/user_guide_src/source/incoming/restful/017.php new file mode 100644 index 000000000000..853748f84527 --- /dev/null +++ b/user_guide_src/source/incoming/restful/017.php @@ -0,0 +1,5 @@ +resource('photos', ['controller' => '\App\Gallery']); +// Would create routes like: +$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/018.php b/user_guide_src/source/incoming/restful/018.php new file mode 100644 index 000000000000..6951d07b07b3 --- /dev/null +++ b/user_guide_src/source/incoming/restful/018.php @@ -0,0 +1,7 @@ +resource('photos', ['namespace' => '', 'controller' => Gallery::class]); +// Would create routes like: +$routes->get('photos', '\App\Controllers\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/019.php b/user_guide_src/source/incoming/restful/019.php new file mode 100644 index 000000000000..09885e7f0039 --- /dev/null +++ b/user_guide_src/source/incoming/restful/019.php @@ -0,0 +1,5 @@ +presenter('photos', ['controller' => '\App\Gallery']); +// Would create routes like: +$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/020.php b/user_guide_src/source/incoming/restful/020.php new file mode 100644 index 000000000000..ddd67cc22d93 --- /dev/null +++ b/user_guide_src/source/incoming/restful/020.php @@ -0,0 +1,7 @@ +presenter('photos', ['namespace' => '', 'controller' => Gallery::class]); +// Would create routes like: +$routes->get('photos', '\App\Controllers\Gallery::index'); From 81352d502747e9829bd9d963d4dda2549d566e3f Mon Sep 17 00:00:00 2001 From: Piyush Garg <62426177+il-coder@users.noreply.github.com> Date: Sun, 26 Nov 2023 02:41:12 +0530 Subject: [PATCH 191/380] Fix double prefix for increment in cache FileHandler --- system/Cache/Handlers/FileHandler.php | 4 +-- .../system/Cache/Handlers/FileHandlerTest.php | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index 54cafdc5f35b..0a39c3610ba0 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -150,8 +150,8 @@ public function deleteMatching(string $pattern) */ public function increment(string $key, int $offset = 1) { - $key = static::validateKey($key, $this->prefix); - $tmp = $this->getItem($key); + $prefixedKey = static::validateKey($key, $this->prefix); + $tmp = $this->getItem($prefixedKey); if ($tmp === false) { $tmp = ['data' => 0, 'ttl' => 60]; diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index 11d1c93b9c1c..0bcaccf817c3 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -67,6 +67,10 @@ protected function tearDown(): void chmod($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $key, 0777); unlink($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $key); } + if (is_file($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $this->config->prefix . $key)) { + chmod($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $this->config->prefix . $key, 0777); + unlink($this->config->file['storePath'] . DIRECTORY_SEPARATOR . $this->config->prefix . $key); + } } rmdir($this->config->file['storePath']); @@ -233,6 +237,22 @@ public function testIncrement(): void $this->assertSame(10, $this->handler->increment(self::$key3, 10)); } + public function testIncrementWithDefaultPrefix(): void + { + $this->config->prefix = 'test_'; + $this->handler = new FileHandler($this->config); + $this->handler->initialize(); + + $this->handler->save(self::$key1, 1); + $this->handler->save(self::$key2, 'value'); + + $this->assertSame(11, $this->handler->increment(self::$key1, 10)); + $this->assertSame($this->handler->increment(self::$key1, 10), $this->handler->get(self::$key1)); + $this->assertFalse($this->handler->increment(self::$key2, 10)); + $this->assertSame(10, $this->handler->increment(self::$key3, 10)); + $this->assertSame($this->handler->increment(self::$key3, 10), $this->handler->get(self::$key3)); + } + public function testDecrement(): void { $this->handler->save(self::$key1, 10); @@ -246,6 +266,21 @@ public function testDecrement(): void $this->assertSame(-1, $this->handler->decrement(self::$key3, 1)); } + public function testDecrementWithDefaultPrefix(): void + { + $this->handler->save(self::$key1, 10); + $this->handler->save(self::$key2, 'value'); + + // Line following commented out to force the cache to add a zero entry for key3 + // $this->fileHandler->save(self::$key3, 0); + + $this->assertSame(9, $this->handler->decrement(self::$key1, 1)); + $this->assertSame($this->handler->decrement(self::$key1, 1), $this->handler->get(self::$key1)); + $this->assertFalse($this->handler->decrement(self::$key2, 1)); + $this->assertSame(-1, $this->handler->decrement(self::$key3, 1)); + $this->assertSame($this->handler->decrement(self::$key3, 1), $this->handler->get(self::$key3)); + } + public function testClean(): void { $this->handler->save(self::$key1, 1); From b3f451b30022976e0b72f30226735cb0b15ee4fa Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 09:47:52 +0900 Subject: [PATCH 192/380] docs: remove unneeded comments --- system/Pager/PagerRenderer.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index 454ac9f1cd93..84ba762e5546 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -122,8 +122,6 @@ public function hasPrevious(): bool * page before the current page, but is the page just before the * "first" page. * - * You MUST call hasPrevious() first, or this value may be invalid. - * * @return string|null */ public function getPrevious() @@ -162,8 +160,6 @@ public function hasNext(): bool * page after the current page, but is the page that follows the * "last" page. * - * You MUST call hasNext() first, or this value may be invalid. - * * @return string|null */ public function getNext() From 9fcb679a0e974690ee54f77fa85168cd19b9a610 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 09:48:23 +0900 Subject: [PATCH 193/380] docs: add comment to make things clear --- system/Pager/PagerRenderer.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index 84ba762e5546..274517c4be79 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -25,14 +25,14 @@ class PagerRenderer { /** - * First page number. + * First page number in the current pages being displayed. * * @var int */ protected $first; /** - * Last page number. + * Last page number in the current pages being displayed. * * @var int */ @@ -85,8 +85,11 @@ class PagerRenderer */ public function __construct(array $details) { - $this->first = 1; - $this->last = $details['pageCount']; + // `first` and `last` will be updated by `setSurroundCount()`. + // You must call `setSurroundCount()` after instantiation. + $this->first = 1; + $this->last = $details['pageCount']; + $this->current = $details['currentPage']; $this->total = $details['total']; $this->uri = $details['uri']; @@ -377,7 +380,7 @@ public function getNextPage() } /** - * Returns the page number of the first page. + * Returns the page number of the first page in the current pages being displayed. */ public function getFirstPageNumber(): int { @@ -393,7 +396,7 @@ public function getCurrentPageNumber(): int } /** - * Returns the page number of the last page. + * Returns the page number of the last page in the current pages being displayed. */ public function getLastPageNumber(): int { From 41ae14a0c182543297c52839182a334b47bb5668 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 09:48:58 +0900 Subject: [PATCH 194/380] docs: fix incorrect description --- user_guide_src/source/libraries/pagination.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 3cf6f01dadbb..dad0450cd528 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -299,8 +299,8 @@ These methods return the page number for the previous or next pages in relation getFirstPageNumber() & getLastPageNumber() ------------------------------------------ -These methods return page numbers to the first and last pages in the -result set. +These methods return page numbers to the first and last pages in the current pages +being displayed. getCurrentPageNumber() ---------------------- From 3388114da036d53e5d91364fd2b85e630d95cc56 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 09:49:37 +0900 Subject: [PATCH 195/380] docs: add text decoration --- user_guide_src/source/libraries/pagination.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index dad0450cd528..a910f451bf35 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -239,7 +239,7 @@ Since the first link displayed is page one, ``hasPrevious()`` would return **fal getPrevious() & getNext() ------------------------- -These methods return the URL for the previous or next pages of results on either side of the numbered links. +These methods return the **URL** for the previous or next pages of results on either side of the numbered links. For example, you have the current page set at 5 and you want to have the links before and after (the surroundCount) to be 2 each, that will give you something like this:: @@ -252,7 +252,7 @@ If you want to get page 4 and page 6, use ``getPreviousPage()`` and ``getNextPag getFirst() & getLast() ---------------------- -Much like ``getPrevious()`` and ``getNext()``, these methods return links to the first and last pages in the +Much like ``getPrevious()`` and ``getNext()``, these methods return the **URL** to the first and last pages in the result set. links() @@ -274,14 +274,14 @@ See following an example with these changes: hasPreviousPage() & hasNextPage() --------------------------------- -This method returns a boolean true if there are links to a page before and after, respectively, the current page being displayed. +This method returns a boolean ``true`` if there are links to a page before and after, respectively, the current page being displayed. Their difference to ``hasPrevious()`` and ``hasNext()`` is that they are based on the current page while ``hasPrevious()`` and ``hasNext()`` are based on the set of links to be displayed before and after the current page based on the value passed in ``setSurroundCount()``. getPreviousPage() & getNextPage() --------------------------------- -These methods return a URL for the previous and next pages in relation to the current page being displayed, unlike ``getPrevious()`` and ``getNext()`` that return the URL for the previous or next pages of results on either side of the numbered links. See the previous paragraph for a full explanation. +These methods return a **URL** for the previous and next pages in relation to the current page being displayed, unlike ``getPrevious()`` and ``getNext()`` that return the URL for the previous or next pages of results on either side of the numbered links. See the previous paragraph for a full explanation. For example, you have the current page set at 5 and you want to have the links before and after (the surroundCount) to be 2 each, that will give you something like this:: From be2c2f998b50d1b561315733980c0c80d145764f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 09:50:40 +0900 Subject: [PATCH 196/380] docs: add explanations --- .../source/libraries/pagination.rst | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index a910f451bf35..59aad8e9a562 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -227,14 +227,21 @@ setSurroundCount() In the first line, the ``setSurroundCount()`` method specifies than we want to show two links to either side of the current page link. The only parameter that it accepts is the number of links to show. +.. note:: You must call this method first to generate correct pagination links. + hasPrevious() & hasNext() ------------------------- -These methods return a boolean true if there are more links that can be displayed on either side of the current page, -based on the value passed to ``setSurroundCount()``. For example, let's say we have 20 pages of data. The current -page is page 3. If the surrounding count is 2, then the following links would show up in the list: 1, 2, 3, 4, and 5. -Since the first link displayed is page one, ``hasPrevious()`` would return **false** since there is no page zero. However, -``hasNext()`` would return **true** since there are 15 additional pages of results after page five. +These methods return a boolean ``true`` if there are more links that can be displayed on either side of the current page, +based on the value passed to ``setSurroundCount()``. + +For example, let's say we have 20 pages of data. The current +page is page 3. If the surrounding count is 2, then the following links would show up like this:: + + 1 | 2 | 3 | 4 | 5 + +Since the first link displayed is page one, ``hasPrevious()`` would return ``false`` since there is no page zero. However, +``hasNext()`` would return ``true`` since there are 15 additional pages of results after page five. getPrevious() & getNext() ------------------------- @@ -278,6 +285,14 @@ This method returns a boolean ``true`` if there are links to a page before and a Their difference to ``hasPrevious()`` and ``hasNext()`` is that they are based on the current page while ``hasPrevious()`` and ``hasNext()`` are based on the set of links to be displayed before and after the current page based on the value passed in ``setSurroundCount()``. +For example, let's say we have 20 pages of data. The current +page is page 3. If the surrounding count is 2, then the following links would show up like this:: + + 1 | 2 | 3 | 4 | 5 + +``hasPreviousPage()`` would return ``true`` since there is page 2. And, +``hasNextPage()`` would return ``true`` since there is page 4. + getPreviousPage() & getNextPage() --------------------------------- From b98529c4f17ba6f8ee6e32356d49e0dd16530f29 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 10:00:50 +0900 Subject: [PATCH 197/380] docs: make method names links --- user_guide_src/source/libraries/pagination.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 59aad8e9a562..0a2d243a8a47 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -233,7 +233,7 @@ hasPrevious() & hasNext() ------------------------- These methods return a boolean ``true`` if there are more links that can be displayed on either side of the current page, -based on the value passed to ``setSurroundCount()``. +based on the value passed to `setSurroundCount()`_. For example, let's say we have 20 pages of data. The current page is page 3. If the surrounding count is 2, then the following links would show up like this:: @@ -254,12 +254,12 @@ For example, you have the current page set at 5 and you want to have the links b ``getPrevious()`` returns the URL for page 2. ``getNext()`` returns the URL for page 8. -If you want to get page 4 and page 6, use ``getPreviousPage()`` and ``getNextPage()`` instead. +If you want to get page 4 and page 6, use `getPreviousPage() & getNextPage()`_ instead. getFirst() & getLast() ---------------------- -Much like ``getPrevious()`` and ``getNext()``, these methods return the **URL** to the first and last pages in the +Much like `getPrevious() & getNext()`_, these methods return the **URL** to the first and last pages in the result set. links() @@ -270,9 +270,9 @@ title, which is just the number, and a boolean that tells whether the link is th .. literalinclude:: pagination/013.php -In the code presented for the standard pagination structure, the methods ``getPrevious()`` and ``getNext()`` are used to obtain the links to the previous and next pagination groups respectively. +In the code presented for the standard pagination structure, the methods `getPrevious() & getNext()`_ are used to obtain the links to the previous and next pagination groups respectively. -If you want to use the pagination structure where prev and next will be links to the previous and next pages based on the current page, just replace the ``getPrevious()`` and ``getNext()`` methods with ``getPreviousPage()`` and ``getNextPage()``, and the methods ``hasPrevious()`` and ``hasNext()`` by ``hasPreviousPage()`` and ``hasNextPage()`` respectively. +If you want to use the pagination structure where prev and next will be links to the previous and next pages based on the current page, just replace the `getPrevious() & getNext()`_ methods with `getPreviousPage() & getNextPage()`_, and the methods `hasPrevious() & hasNext()`_ by `hasPreviousPage() & hasNextPage()`_ respectively. See following an example with these changes: @@ -283,7 +283,7 @@ hasPreviousPage() & hasNextPage() This method returns a boolean ``true`` if there are links to a page before and after, respectively, the current page being displayed. -Their difference to ``hasPrevious()`` and ``hasNext()`` is that they are based on the current page while ``hasPrevious()`` and ``hasNext()`` are based on the set of links to be displayed before and after the current page based on the value passed in ``setSurroundCount()``. +Their difference to `hasPrevious() & hasNext()`_ is that they are based on the current page while `hasPrevious() & hasNext()`_ are based on the set of links to be displayed before and after the current page based on the value passed in `setSurroundCount()`_. For example, let's say we have 20 pages of data. The current page is page 3. If the surrounding count is 2, then the following links would show up like this:: @@ -296,7 +296,7 @@ page is page 3. If the surrounding count is 2, then the following links would sh getPreviousPage() & getNextPage() --------------------------------- -These methods return a **URL** for the previous and next pages in relation to the current page being displayed, unlike ``getPrevious()`` and ``getNext()`` that return the URL for the previous or next pages of results on either side of the numbered links. See the previous paragraph for a full explanation. +These methods return a **URL** for the previous and next pages in relation to the current page being displayed, unlike `getPrevious() & getNext()`_ that return the URL for the previous or next pages of results on either side of the numbered links. See the previous paragraph for a full explanation. For example, you have the current page set at 5 and you want to have the links before and after (the surroundCount) to be 2 each, that will give you something like this:: From 552dc9e67ac94fc4b1916115c723c658a64bff13 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 10:13:17 +0900 Subject: [PATCH 198/380] docs: move some descriptions in note --- user_guide_src/source/libraries/pagination.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 0a2d243a8a47..023fbb5af485 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -283,8 +283,6 @@ hasPreviousPage() & hasNextPage() This method returns a boolean ``true`` if there are links to a page before and after, respectively, the current page being displayed. -Their difference to `hasPrevious() & hasNext()`_ is that they are based on the current page while `hasPrevious() & hasNext()`_ are based on the set of links to be displayed before and after the current page based on the value passed in `setSurroundCount()`_. - For example, let's say we have 20 pages of data. The current page is page 3. If the surrounding count is 2, then the following links would show up like this:: @@ -293,10 +291,15 @@ page is page 3. If the surrounding count is 2, then the following links would sh ``hasPreviousPage()`` would return ``true`` since there is page 2. And, ``hasNextPage()`` would return ``true`` since there is page 4. +.. note:: The difference to `hasPrevious() & hasNext()`_ is that they are based + on the current page while `hasPrevious() & hasNext()`_ are based on the set + of links to be displayed before and after the current page based on the value + passed in `setSurroundCount()`_. + getPreviousPage() & getNextPage() --------------------------------- -These methods return a **URL** for the previous and next pages in relation to the current page being displayed, unlike `getPrevious() & getNext()`_ that return the URL for the previous or next pages of results on either side of the numbered links. See the previous paragraph for a full explanation. +These methods return a **URL** for the previous and next pages in relation to the current page being displayed. For example, you have the current page set at 5 and you want to have the links before and after (the surroundCount) to be 2 each, that will give you something like this:: @@ -304,6 +307,9 @@ For example, you have the current page set at 5 and you want to have the links b ``getPreviousPage()`` returns the URL for page 4. ``getNextPage()`` returns the URL for page 6. +.. note:: `getPrevious() & getNext()`_ returns the URL for the previous or next + pages of results on either side of the numbered links. + If you want page numbers instead of URLs, you can use the following methods: getPreviousPageNumber() & getNextPageNumber() @@ -314,9 +320,12 @@ These methods return the page number for the previous or next pages in relation getFirstPageNumber() & getLastPageNumber() ------------------------------------------ -These methods return page numbers to the first and last pages in the current pages +These methods return the page numbers to the first and last pages in the current pages being displayed. +.. note:: Unlike `getFirst() & getLast()`_, these methods return the numbers in + the current pages being displayed. + getCurrentPageNumber() ---------------------- From bb3cff4f51a9ee59bebff446f519fd8fb763ce85 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 10:25:09 +0900 Subject: [PATCH 199/380] docs: add @return --- system/Pager/PagerRenderer.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index 274517c4be79..0e6ff1c5805b 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -259,6 +259,8 @@ public function getCurrent(): string * is represented by another array containing of the URI the link * should go to, the title (number) of the link, and a boolean * value representing whether this link is active or not. + * + * @return list */ public function links(): array { From b5262e74207b5ad905f1c10c68049e7128c62f58 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Nov 2023 10:31:34 +0900 Subject: [PATCH 200/380] docs: change expression --- system/Pager/PagerRenderer.php | 8 ++++---- user_guide_src/source/libraries/pagination.rst | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index 0e6ff1c5805b..9e6d2950caf0 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -25,14 +25,14 @@ class PagerRenderer { /** - * First page number in the current pages being displayed. + * First page number in the set of links to be displayed. * * @var int */ protected $first; /** - * Last page number in the current pages being displayed. + * Last page number in the set of links to be displayed. * * @var int */ @@ -382,7 +382,7 @@ public function getNextPage() } /** - * Returns the page number of the first page in the current pages being displayed. + * Returns the page number of the first page in the set of links to be displayed. */ public function getFirstPageNumber(): int { @@ -398,7 +398,7 @@ public function getCurrentPageNumber(): int } /** - * Returns the page number of the last page in the current pages being displayed. + * Returns the page number of the last page in the set of links to be displayed. */ public function getLastPageNumber(): int { diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 023fbb5af485..364062f04727 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -320,11 +320,11 @@ These methods return the page number for the previous or next pages in relation getFirstPageNumber() & getLastPageNumber() ------------------------------------------ -These methods return the page numbers to the first and last pages in the current pages -being displayed. +These methods return the page numbers to the first and last pages in the set of +links to be displayed. .. note:: Unlike `getFirst() & getLast()`_, these methods return the numbers in - the current pages being displayed. + the set of links to be displayed. getCurrentPageNumber() ---------------------- From 066bbbd4bdfcfe9416549946327921c8be2865c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Nov 2023 05:53:10 +0900 Subject: [PATCH 201/380] docs: add note for how to get the entire dataset's first and last page numbers --- user_guide_src/source/libraries/pagination.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 364062f04727..126388071dc1 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -323,8 +323,9 @@ getFirstPageNumber() & getLastPageNumber() These methods return the page numbers to the first and last pages in the set of links to be displayed. -.. note:: Unlike `getFirst() & getLast()`_, these methods return the numbers in - the set of links to be displayed. +.. note:: If you want to get the page numbers to the first and last pages in the + result set, the first page number is always 1, and use `getPageCount()`_ to + get the last page number. getCurrentPageNumber() ---------------------- From bf6ebaa58f1832fe5bd3f0f944f106b295b42e11 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Nov 2023 09:03:43 +0900 Subject: [PATCH 202/380] docs: remove "in it's database layer" Entity can be used for data from non-database. --- user_guide_src/source/models/entities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index f1f8b42c8a62..1b91bed7b443 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -2,7 +2,7 @@ Using Entity Classes ##################### -CodeIgniter supports Entity classes as a first-class citizen in it's database layer, while keeping +CodeIgniter supports Entity classes as a first-class citizen, while keeping them completely optional to use. They are commonly used as part of the Repository pattern, but can be used directly with the :doc:`Model ` if that fits your needs better. From 2c3ab28430e7f7f2097e3fa734354146a2c826de Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Nov 2023 09:06:16 +0900 Subject: [PATCH 203/380] docs: add note for non-database usage --- user_guide_src/source/models/entities.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 1b91bed7b443..7153c459c2e4 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -16,9 +16,17 @@ Entity Usage At its core, an Entity class is simply a class that represents a single database row. It has class properties to represent the database columns, and provides any additional methods to implement the business logic for -that row. The core feature, though, is that it doesn't know anything about how to persist itself. That's the +that row. + +.. note:: For ease of understanding, the explanation here is based on the case of + using a database. However, Entity can also be used for data that does not come + from a database. + +The core feature, though, is that it doesn't know anything about how to persist itself. That's the responsibility of the model or the repository class. That way, if anything changes on how you need to save the -object, you don't have to change how that object is used throughout the application. This makes it possible to +object, you don't have to change how that object is used throughout the application. + +This makes it possible to use JSON or XML files to store the objects during a rapid prototyping stage, and then easily switch to a database when you've proven the concept works. From 544093acc87bdc50e6dd94f0bebabb4aefacf7e9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Nov 2023 09:06:46 +0900 Subject: [PATCH 204/380] docs: make description more detailed --- user_guide_src/source/models/entities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 7153c459c2e4..072d41e85793 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -78,7 +78,7 @@ access them as if they were public properties. The base class, ``CodeIgniter\Ent well as providing the ability to check the properties with ``isset()``, or ``unset()`` the property, and keep track of what columns have changed since the object was created or pulled from the database. -.. note:: The Entity class stores the data in the property ``$attributes``. +.. note:: The Entity class stores the data in the class property ``$attributes`` internally. When the User is passed to the model's ``save()`` method, it automatically takes care of reading the properties and saving any changes to columns listed in the model's ``$allowedFields`` property. It also knows whether to create From 0ea1c6a47a5178604a47a1dc2da3be31fe93a712 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Nov 2023 13:39:08 +0900 Subject: [PATCH 205/380] docs: fix by proofreading Co-authored-by: Samuel Asor <8720569+sammyskills@users.noreply.github.com> --- user_guide_src/source/libraries/pagination.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 126388071dc1..3871ec72a2e1 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -320,12 +320,16 @@ These methods return the page number for the previous or next pages in relation getFirstPageNumber() & getLastPageNumber() ------------------------------------------ -These methods return the page numbers to the first and last pages in the set of -links to be displayed. +These methods return the page numbers of the first and last pages in the set of +links to be displayed. For example, if the set of links to be displayed is something like this:: -.. note:: If you want to get the page numbers to the first and last pages in the - result set, the first page number is always 1, and use `getPageCount()`_ to - get the last page number. + 3 | 4 | 5 | 6 | 7 + +``getFirstPageNumber()`` will return 3 while ``getLastPageNumber()`` will return 7. + +.. note:: To obtain the page numbers of the first and last pages in the entire + result set, you can use the following approach: The first page number is always 1, and `getPageCount()`_ can be used to + retrieve the last page number. getCurrentPageNumber() ---------------------- From 01727888a020f6ae071614eef60bb6ad432a3584 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 15:27:44 +0000 Subject: [PATCH 206/380] chore(deps-dev): update rector/rector requirement 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/0.18.10...0.18.11) --- 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 4ff56944a3b1..03008c6de3ca 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.18.10", + "rector/rector": "0.18.11", "vimeo/psalm": "^5.0" }, "suggest": { From 7e7821bdf550c42bbb2be0926f32d7f05bc2f7b8 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Sun, 26 Nov 2023 12:53:38 +0000 Subject: [PATCH 207/380] add: skip hostname checks if CURLRequest options 'verify' is set to false. When CURLRequest options 'verify' is set to false, some CURLOPT_SSL_... options should be disabled in such a way as to allow requests to pass through in case the destination is for example on private networks. Avoids SSL errors: SSL: certificate subject name 'CA' does not match target host name 'localhost' --- system/HTTP/CURLRequest.php | 6 ++++++ tests/system/HTTP/CURLRequestTest.php | 3 +++ 2 files changed, 9 insertions(+) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index c8b3b9fe9f92..15e8e65d5579 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -559,6 +559,12 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) $curlOptions[CURLOPT_SSL_VERIFYPEER] = 1; } elseif (is_bool($config['verify'])) { $curlOptions[CURLOPT_SSL_VERIFYPEER] = $config['verify']; + + if ($config['verify'] === false) { + $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; + } else { + $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; + } } } diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 186284da6ba6..25a8c30669d0 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -529,6 +529,9 @@ public function testSSLVerification(): void $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); $this->assertSame(1, $options[CURLOPT_SSL_VERIFYPEER]); + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); + $this->assertSame(2, $options[CURLOPT_SSL_VERIFYHOST]); } public function testSSLWithBadKey(): void From 368523263cfa73d80d2114ddbf3122b6c8235fa2 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Mon, 27 Nov 2023 19:14:21 +0000 Subject: [PATCH 208/380] add: SSL verify options when config.verify is string and boolean --- system/HTTP/CURLRequest.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 15e8e65d5579..2eb4aa388a49 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -555,16 +555,17 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) throw HTTPException::forInvalidSSLKey($config['ssl_key']); } - $curlOptions[CURLOPT_CAINFO] = $file; - $curlOptions[CURLOPT_SSL_VERIFYPEER] = 1; - } elseif (is_bool($config['verify'])) { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = $config['verify']; - - if ($config['verify'] === false) { - $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; - } else { + $curlOptions[CURLOPT_CAINFO] = $file; + if ($config['verify'] === 'yes') { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = 1; $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; + } else { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = 0; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; } + } elseif (is_bool($config['verify'])) { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = $config['verify']; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = $config['verify'] ? 2 : 0; } } From e159bfd8a059c19dc55f58a8ea491e111bcb9df6 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Tue, 28 Nov 2023 07:48:10 +0000 Subject: [PATCH 209/380] fix: CURLOPT_SSL_VERIFYPEER values and tests related with CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST --- system/HTTP/CURLRequest.php | 4 ++-- .../HTTP/CURLRequestDoNotShareOptionsTest.php | 2 +- tests/system/HTTP/CURLRequestTest.php | 17 ++++++++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 2eb4aa388a49..5edd9af6859e 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -557,10 +557,10 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) $curlOptions[CURLOPT_CAINFO] = $file; if ($config['verify'] === 'yes') { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = 1; + $curlOptions[CURLOPT_SSL_VERIFYPEER] = true; $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; } else { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = 0; + $curlOptions[CURLOPT_SSL_VERIFYPEER] = false; $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; } } elseif (is_bool($config['verify'])) { diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index d8e96424dae5..39dc0409afb9 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -545,7 +545,7 @@ public function testSSLVerification(): void $this->assertSame($file, $options[CURLOPT_CAINFO]); $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); - $this->assertSame(1, $options[CURLOPT_SSL_VERIFYPEER]); + $this->assertTrue($options[CURLOPT_SSL_VERIFYPEER]); } public function testSSLWithBadKey(): void diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 25a8c30669d0..a947acee7163 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -528,12 +528,27 @@ public function testSSLVerification(): void $this->assertSame($file, $options[CURLOPT_CAINFO]); $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); - $this->assertSame(1, $options[CURLOPT_SSL_VERIFYPEER]); + $this->assertTrue($options[CURLOPT_SSL_VERIFYPEER]); $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); $this->assertSame(2, $options[CURLOPT_SSL_VERIFYHOST]); } + public function testNoSSL(): void + { + $this->request->request('get', 'http://example.com', [ + 'verify' => false, + ]); + + $options = $this->request->curl_options; + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); + $this->assertFalse($options[CURLOPT_SSL_VERIFYPEER]); + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); + $this->assertSame(0, $options[CURLOPT_SSL_VERIFYHOST]); + } + public function testSSLWithBadKey(): void { $file = 'something_obviously_bogus'; From 50412c771fb52878d8a65cde087639998a8d3d7b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 29 Nov 2023 07:15:04 +0900 Subject: [PATCH 210/380] docs: add about session table change --- user_guide_src/source/installation/upgrade_sessions.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index 888ff5d751c0..ecc27360f310 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -14,6 +14,7 @@ Documentations What has been changed ===================== - Only small things like the method names and the loading of the library have changed. +- The definition of the session table in Database Driver has changed. Upgrade Guide ============= @@ -24,6 +25,7 @@ Upgrade Guide - To set data use ``$session->set($array);`` instead of ``$this->session->set_userdata($array);``. - To remove data use ``unset($_SESSION['some_name']);`` or ``$session->remove('some_name');`` instead of ``$this->session->unset_userdata('some_name');``. - To mark session data as flashdata, which will only be available for the next request, use ``$session->markAsFlashdata('item');`` instead of ``$this->session->mark_as_flash('item');``` +3. If you use Database Driver, you need to recreate the session table. See :ref:`sessions-databasehandler-driver`. Code Example ============ From 84903e0f58b69f62bb978eec2134a42085ab56ae Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 06:57:53 +0900 Subject: [PATCH 211/380] chore: update Kint to 5.1.0 --- system/ThirdParty/Kint/CallFinder.php | 5 +- system/ThirdParty/Kint/Kint.php | 5 +- .../Kint/Parser/BlacklistPlugin.php | 3 +- .../ThirdParty/Kint/Parser/ClosurePlugin.php | 2 +- system/ThirdParty/Kint/Parser/Parser.php | 4 +- .../Kint/Parser/PluginInterface.php | 2 +- system/ThirdParty/Kint/Parser/TablePlugin.php | 6 ++ .../ThirdParty/Kint/Renderer/RichRenderer.php | 76 ++++++++++++------- .../Kint/Renderer/Text/AbstractPlugin.php | 2 +- .../ThirdParty/Kint/Renderer/TextRenderer.php | 18 ++++- system/ThirdParty/Kint/Utils.php | 2 - system/ThirdParty/Kint/Zval/BlobValue.php | 6 +- .../Representation/ColorRepresentation.php | 4 +- .../MicrotimeRepresentation.php | 2 +- .../Zval/Representation/Representation.php | 2 +- .../Representation/SourceRepresentation.php | 2 +- system/ThirdParty/Kint/Zval/Value.php | 8 +- system/ThirdParty/Kint/init.php | 1 + system/ThirdParty/Kint/init_helpers.php | 4 +- .../Kint/resources/compiled/aante-dark.css | 1 + .../Kint/resources/compiled/aante-light.css | 2 +- .../Kint/resources/compiled/original.css | 2 +- .../Kint/resources/compiled/plain.css | 2 +- .../resources/compiled/solarized-dark.css | 2 +- .../Kint/resources/compiled/solarized.css | 2 +- 25 files changed, 101 insertions(+), 64 deletions(-) create mode 100644 system/ThirdParty/Kint/resources/compiled/aante-dark.css diff --git a/system/ThirdParty/Kint/CallFinder.php b/system/ThirdParty/Kint/CallFinder.php index e36e91eac0d0..f85b1ae017a9 100644 --- a/system/ThirdParty/Kint/CallFinder.php +++ b/system/ThirdParty/Kint/CallFinder.php @@ -138,7 +138,7 @@ class CallFinder /** * @psalm-param callable-array|callable-string $function * - * @param mixed $function + * @psalm-return list}> * * @return array List of matching calls on the relevant line */ @@ -187,6 +187,7 @@ public static function getFunctionCalls(string $source, int $line, $function): a $identifier[T_NAME_RELATIVE] = true; } + /** @psalm-var list */ $tokens = \token_get_all($source); $cursor = 1; $function_calls = []; @@ -449,8 +450,6 @@ private static function realTokenIndex(array $tokens, int $index): ?int * for `$token[0]` then "..." will incorrectly match the "." operator. * * @psalm-param PhpToken $token The token to check - * - * @param mixed $token */ private static function tokenIsOperator($token): bool { diff --git a/system/ThirdParty/Kint/Kint.php b/system/ThirdParty/Kint/Kint.php index 47e34abef52b..418c1f3f8789 100644 --- a/system/ThirdParty/Kint/Kint.php +++ b/system/ThirdParty/Kint/Kint.php @@ -133,7 +133,7 @@ class Kint implements FacadeInterface public static $aliases = [ ['Kint\\Kint', 'dump'], ['Kint\\Kint', 'trace'], - ['Kint\\Kint', 'dumpArray'], + ['Kint\\Kint', 'dumpAll'], ]; /** @@ -537,7 +537,7 @@ public static function trace() * * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace()) * - * @param mixed ...$args + * @psalm-param array ...$args * * @return int|string */ @@ -599,6 +599,7 @@ public static function shortenPath(string $file): string $match = '/'; foreach (static::$app_root_dirs as $path => $alias) { + /** @psalm-var string $path */ if (empty($path)) { continue; } diff --git a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php index 90ec3c223327..fa54a3a6743e 100644 --- a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php @@ -29,6 +29,7 @@ use Kint\Zval\InstanceValue; use Kint\Zval\Value; +use Psr\Container\ContainerInterface; class BlacklistPlugin extends AbstractPlugin { @@ -44,7 +45,7 @@ class BlacklistPlugin extends AbstractPlugin * * @var array */ - public static $shallow_blacklist = ['Psr\\Container\\ContainerInterface']; + public static $shallow_blacklist = [ContainerInterface::class]; public function getTypes(): array { diff --git a/system/ThirdParty/Kint/Parser/ClosurePlugin.php b/system/ThirdParty/Kint/Parser/ClosurePlugin.php index 8b199781078e..84ea582646f8 100644 --- a/system/ThirdParty/Kint/Parser/ClosurePlugin.php +++ b/system/ThirdParty/Kint/Parser/ClosurePlugin.php @@ -67,7 +67,7 @@ public function parse(&$var, Value &$o, int $trigger): void } $p = new Representation('Parameters'); - $p->contents = &$o->parameters; + $p->contents = $o->parameters; $o->addRepresentation($p, 0); $statics = []; diff --git a/system/ThirdParty/Kint/Parser/Parser.php b/system/ThirdParty/Kint/Parser/Parser.php index 50642b90a123..f044a9de913f 100644 --- a/system/ThirdParty/Kint/Parser/Parser.php +++ b/system/ThirdParty/Kint/Parser/Parser.php @@ -72,7 +72,7 @@ class Parser * @param int $depth_limit Maximum depth to parse data * @param ?string $caller Caller class name */ - public function __construct(int $depth_limit = 0, ?string $caller = null) + public function __construct(int $depth_limit = 0, string $caller = null) { $this->marker = "kint\0".\random_bytes(16); @@ -83,7 +83,7 @@ public function __construct(int $depth_limit = 0, ?string $caller = null) /** * Set the caller class. */ - public function setCallerClass(?string $caller = null): void + public function setCallerClass(string $caller = null): void { $this->noRecurseCall(); diff --git a/system/ThirdParty/Kint/Parser/PluginInterface.php b/system/ThirdParty/Kint/Parser/PluginInterface.php index ff169fd17d4d..3afb1a77674b 100644 --- a/system/ThirdParty/Kint/Parser/PluginInterface.php +++ b/system/ThirdParty/Kint/Parser/PluginInterface.php @@ -38,7 +38,7 @@ public function getTypes(): array; public function getTriggers(): int; /** - * @param mixed &$var + * @psalm-param mixed &$var */ public function parse(&$var, Value &$o, int $trigger): void; } diff --git a/system/ThirdParty/Kint/Parser/TablePlugin.php b/system/ThirdParty/Kint/Parser/TablePlugin.php index 8d7e155c95cc..5afe75980bc8 100644 --- a/system/ThirdParty/Kint/Parser/TablePlugin.php +++ b/system/ThirdParty/Kint/Parser/TablePlugin.php @@ -30,6 +30,12 @@ use Kint\Zval\Representation\Representation; use Kint\Zval\Value; +// Note: Interaction with ArrayLimitPlugin: +// Any array limited children will be shown in tables identically to +// non-array-limited children since the table only shows that it is an array +// and it's size anyway. Because ArrayLimitPlugin halts the parse on finding +// a limit all other plugins including this one are stopped, so you cannot get +// a tabular representation of an array that is longer than the limit. class TablePlugin extends AbstractPlugin { public function getTypes(): array diff --git a/system/ThirdParty/Kint/Renderer/RichRenderer.php b/system/ThirdParty/Kint/Renderer/RichRenderer.php index f206e560c9c0..b3d86ea1dd5f 100644 --- a/system/ThirdParty/Kint/Renderer/RichRenderer.php +++ b/system/ThirdParty/Kint/Renderer/RichRenderer.php @@ -140,6 +140,13 @@ class RichRenderer extends AbstractRenderer */ public static $sort = self::SORT_NONE; + /** + * Timestamp to print in footer in date() format. + * + * @var ?string + */ + public static $timestamp = null; + public static $needs_pre_render = true; public static $needs_folder_render = true; @@ -465,29 +472,7 @@ public function postRender(): string $output .= ''; } - if (isset($this->call_info['callee']['file'])) { - $output .= 'Called from '.$this->ideLink( - $this->call_info['callee']['file'], - $this->call_info['callee']['line'] - ); - } - - if ( - isset($this->call_info['callee']['function']) && - ( - !empty($this->call_info['callee']['class']) || - !\in_array( - $this->call_info['callee']['function'], - ['include', 'include_once', 'require', 'require_once'], - true - ) - ) - ) { - $output .= ' ['; - $output .= $this->call_info['callee']['class'] ?? ''; - $output .= $this->call_info['callee']['type'] ?? ''; - $output .= $this->call_info['callee']['function'].'()]'; - } + $output .= $this->calledFrom(); if (!empty($this->call_info['trace']) && \count($this->call_info['trace']) > 1) { $output .= '
    '; @@ -497,8 +482,8 @@ public function postRender(): string } $output .= '
  1. '.$this->ideLink($step['file'], $step['line']); // closing tag not required - if (isset($step['function']) - && !\in_array($step['function'], ['include', 'include_once', 'require', 'require_once'], true) + if (isset($step['function']) && + !\in_array($step['function'], ['include', 'include_once', 'require', 'require_once'], true) ) { $output .= ' ['; $output .= $step['class'] ?? ''; @@ -516,8 +501,6 @@ public function postRender(): string /** * @psalm-param Encoding $encoding - * - * @param mixed $encoding */ public function escape(string $string, $encoding = false): string { @@ -559,6 +542,45 @@ public function ideLink(string $file, int $line): string return ''.$path.''; } + protected function calledFrom(): string + { + $output = ''; + + if (isset($this->call_info['callee']['file'])) { + $output .= ' '.$this->ideLink( + $this->call_info['callee']['file'], + $this->call_info['callee']['line'] + ); + } + + if ( + isset($this->call_info['callee']['function']) && + ( + !empty($this->call_info['callee']['class']) || + !\in_array( + $this->call_info['callee']['function'], + ['include', 'include_once', 'require', 'require_once'], + true + ) + ) + ) { + $output .= ' ['; + $output .= $this->call_info['callee']['class'] ?? ''; + $output .= $this->call_info['callee']['type'] ?? ''; + $output .= $this->call_info['callee']['function'].'()]'; + } + + if ('' !== $output) { + $output = 'Called from'.$output; + } + + if (null !== self::$timestamp) { + $output .= ' '.\date(self::$timestamp); + } + + return $output; + } + protected function renderTab(Value $o, Representation $rep): string { if (($plugin = $this->getPlugin(self::$tab_plugins, $rep->hints)) && $plugin instanceof TabPluginInterface) { diff --git a/system/ThirdParty/Kint/Renderer/Text/AbstractPlugin.php b/system/ThirdParty/Kint/Renderer/Text/AbstractPlugin.php index 4d3c7e2a9791..16feccaab6c5 100644 --- a/system/ThirdParty/Kint/Renderer/Text/AbstractPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/AbstractPlugin.php @@ -42,7 +42,7 @@ public function __construct(TextRenderer $r) $this->renderer = $r; } - public function renderLockedHeader(Value $o, ?string $content = null): string + public function renderLockedHeader(Value $o, string $content = null): string { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/TextRenderer.php b/system/ThirdParty/Kint/Renderer/TextRenderer.php index 833320a6c196..2538e4da06af 100644 --- a/system/ThirdParty/Kint/Renderer/TextRenderer.php +++ b/system/ThirdParty/Kint/Renderer/TextRenderer.php @@ -108,6 +108,13 @@ class TextRenderer extends AbstractRenderer */ public static $sort = self::SORT_NONE; + /** + * Timestamp to print in footer in date() format. + * + * @var ?string + */ + public static $timestamp = null; + public $header_width = 80; public $indent_width = 4; @@ -300,7 +307,7 @@ public function filterParserPlugins(array $plugins): array { $return = []; - foreach ($plugins as $index => $plugin) { + foreach ($plugins as $plugin) { foreach (self::$parser_plugin_whitelist as $whitelist) { if ($plugin instanceof $whitelist) { $return[] = $plugin; @@ -319,8 +326,6 @@ public function ideLink(string $file, int $line): string /** * @psalm-param Encoding $encoding - * - * @param mixed $encoding */ public function escape(string $string, $encoding = false): string { @@ -355,6 +360,13 @@ protected function calledFrom(): string $output .= $this->call_info['callee']['function'].'()]'; } + if (null !== self::$timestamp) { + if (\strlen($output)) { + $output .= ' '; + } + $output .= \date(self::$timestamp); + } + return $output; } diff --git a/system/ThirdParty/Kint/Utils.php b/system/ThirdParty/Kint/Utils.php index 78b5a1e8c5ca..545709586dc4 100644 --- a/system/ThirdParty/Kint/Utils.php +++ b/system/ThirdParty/Kint/Utils.php @@ -255,8 +255,6 @@ public static function normalizeAliases(array &$aliases): void /** * @psalm-param Encoding $encoding - * - * @param mixed $encoding */ public static function truncateString(string $input, int $length = PHP_INT_MAX, string $end = '...', $encoding = false): string { diff --git a/system/ThirdParty/Kint/Zval/BlobValue.php b/system/ThirdParty/Kint/Zval/BlobValue.php index ff5a6a24cfc9..5e9f129d1181 100644 --- a/system/ThirdParty/Kint/Zval/BlobValue.php +++ b/system/ThirdParty/Kint/Zval/BlobValue.php @@ -122,8 +122,6 @@ public function transplant(Value $old): void /** * @psalm-param Encoding $encoding - * - * @param mixed $encoding */ public static function strlen(string $string, $encoding = false): int { @@ -142,10 +140,8 @@ public static function strlen(string $string, $encoding = false): int /** * @psalm-param Encoding $encoding - * - * @param mixed $encoding */ - public static function substr(string $string, int $start, ?int $length = null, $encoding = false): string + public static function substr(string $string, int $start, int $length = null, $encoding = false): string { if (\function_exists('mb_substr')) { if (false === $encoding) { diff --git a/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php index 806a800667d4..8853603440c3 100644 --- a/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php @@ -211,7 +211,7 @@ public function __construct(string $value) $this->setValues($value); } - public function getColor(?int $variant = null): ?string + public function getColor(int $variant = null): ?string { if (!$variant) { $variant = $this->variant; @@ -275,7 +275,7 @@ public function getColor(?int $variant = null): ?string return null; } - public function hasAlpha(?int $variant = null): bool + public function hasAlpha(int $variant = null): bool { if (null === $variant) { $variant = $this->variant; diff --git a/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php index d25539b1c7c6..027b0ce21f38 100644 --- a/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php @@ -44,7 +44,7 @@ class MicrotimeRepresentation extends Representation public $mem_peak_real = 0; public $hints = ['microtime']; - public function __construct(int $seconds, int $microseconds, int $group, ?float $lap = null, ?float $total = null, int $i = 0) + public function __construct(int $seconds, int $microseconds, int $group, float $lap = null, float $total = null, int $i = 0) { parent::__construct('Microtime'); diff --git a/system/ThirdParty/Kint/Zval/Representation/Representation.php b/system/ThirdParty/Kint/Zval/Representation/Representation.php index c4680c3d1f75..76d695b8d599 100644 --- a/system/ThirdParty/Kint/Zval/Representation/Representation.php +++ b/system/ThirdParty/Kint/Zval/Representation/Representation.php @@ -36,7 +36,7 @@ class Representation protected $name; - public function __construct(string $label, ?string $name = null) + public function __construct(string $label, string $name = null) { $this->label = $label; diff --git a/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php index d05bf088d46a..2fefc582ccc9 100644 --- a/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php @@ -57,7 +57,7 @@ public function __construct(string $filename, int $line, int $padding = 7) * @param int $start_line The first line to display (1 based) * @param null|int $length Amount of lines to show */ - public static function getSource(string $filename, int $start_line = 1, ?int $length = null): ?array + public static function getSource(string $filename, int $start_line = 1, int $length = null): ?array { if (!$filename || !\file_exists($filename) || !\is_readable($filename)) { return null; diff --git a/system/ThirdParty/Kint/Zval/Value.php b/system/ThirdParty/Kint/Zval/Value.php index facb6cd835e4..01a206d48a9c 100644 --- a/system/ThirdParty/Kint/Zval/Value.php +++ b/system/ThirdParty/Kint/Zval/Value.php @@ -53,8 +53,8 @@ class Value public $reference = false; public $depth = 0; public $size; - public $value; public $hints = []; + public $value; protected $representations = []; @@ -62,7 +62,7 @@ public function __construct() { } - public function addRepresentation(Representation $rep, ?int $pos = null): bool + public function addRepresentation(Representation $rep, int $pos = null): bool { if (isset($this->representations[$rep->getName()])) { return false; @@ -81,7 +81,7 @@ public function addRepresentation(Representation $rep, ?int $pos = null): bool return true; } - public function replaceRepresentation(Representation $rep, ?int $pos = null): void + public function replaceRepresentation(Representation $rep, int $pos = null): void { if (null === $pos) { $this->representations[$rep->getName()] = $rep; @@ -234,7 +234,7 @@ public function transplant(self $old): void /** * Creates a new basic object with a name and access path. */ - public static function blank(?string $name = null, ?string $access_path = null): self + public static function blank(string $name = null, string $access_path = null): self { $o = new self(); $o->name = $name; diff --git a/system/ThirdParty/Kint/init.php b/system/ThirdParty/Kint/init.php index 7605415b6e6e..039489ab43ad 100644 --- a/system/ThirdParty/Kint/init.php +++ b/system/ThirdParty/Kint/init.php @@ -45,6 +45,7 @@ \define('KINT_PHP81', \version_compare(PHP_VERSION, '8.1') >= 0); \define('KINT_PHP82', \version_compare(PHP_VERSION, '8.2') >= 0); \define('KINT_PHP83', \version_compare(PHP_VERSION, '8.3') >= 0); +\define('KINT_PHP84', \version_compare(PHP_VERSION, '8.4') >= 0); // Dynamic default settings if (false !== \ini_get('xdebug.file_link_format')) { diff --git a/system/ThirdParty/Kint/init_helpers.php b/system/ThirdParty/Kint/init_helpers.php index 561425b2a0d6..b4d5f4d9bd86 100644 --- a/system/ThirdParty/Kint/init_helpers.php +++ b/system/ThirdParty/Kint/init_helpers.php @@ -32,7 +32,7 @@ /** * Alias of Kint::dump(). * - * @param mixed ...$args + * @psalm-param mixed ...$args * * @return int|string */ @@ -53,7 +53,7 @@ function d(...$args) * * If run in CLI colors are disabled * - * @param mixed ...$args + * @psalm-param mixed ...$args * * @return int|string */ diff --git a/system/ThirdParty/Kint/resources/compiled/aante-dark.css b/system/ThirdParty/Kint/resources/compiled/aante-dark.css new file mode 100644 index 000000000000..6aa8b702cb23 --- /dev/null +++ b/system/ThirdParty/Kint/resources/compiled/aante-dark.css @@ -0,0 +1 @@ +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(0,0,0,.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#555;color:#e2e1e1}.kint-rich .kint-focused{box-shadow:0 0 3px 2px aqua}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#e2e1e1;float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#070707;border:1px solid #282828;color:#e2e1e1;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#555}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiNBQUEiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjQUFBIi8+PC9zdmc+") no-repeat scroll 0 0/15px 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #282828}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#f90;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:aqua}.kint-rich dfn{font-style:normal;font-family:monospace;color:#e2e1e1}.kint-rich pre{color:#e2e1e1;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #282828;background:#070707;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(226,225,225,.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#070707;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#e2e1e1;background:#070707}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #282828;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#e2e1e1;background:#070707;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#070707;opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#070707}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#070707;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-popup-trigger{background:rgba(0,0,0,0);color:#e2e1e1}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#e2e1e1;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#e2e1e1;border-bottom:1px dotted #e2e1e1}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #282828}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#070707;border:1px solid #282828;border-top:0}.kint-rich ul.kint-tabs>li{background:#070707;border:1px solid #282828;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#555;color:aqua}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#070707;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#555;color:aqua}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #282828;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#555}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #282828;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#070707;color:#e2e1e1}.kint-rich table td{background:#070707;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #555 inset}.kint-rich table tr:hover var{color:aqua}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #070707}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #555;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#070707}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #555,0 1px #555,1px 0 #555,0 -1px #555;color:#070707;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px aqua}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#070707}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#070707;border:1px solid #282828;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #282828;background:#000;font-weight:bold;padding-top:0;border-bottom:1px solid #000 !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #000}.kint-rich ul>li>pre{border:1px solid #282828}.kint-rich dt:hover+dd>ul{border-color:#555}.kint-rich pre{background:#000;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#303}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#000}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#000}.kint-rich table tr:hover>td{box-shadow:none;background:#303} diff --git a/system/ThirdParty/Kint/resources/compiled/aante-light.css b/system/ThirdParty/Kint/resources/compiled/aante-light.css index 832dee718de4..16194736e83c 100644 --- a/system/ThirdParty/Kint/resources/compiled/aante-light.css +++ b/system/ThirdParty/Kint/resources/compiled/aante-light.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-popup-trigger{background:rgba(0,0,0,0);color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} diff --git a/system/ThirdParty/Kint/resources/compiled/original.css b/system/ThirdParty/Kint/resources/compiled/original.css index e3c2bf413adb..331b2c38fb65 100644 --- a/system/ThirdParty/Kint/resources/compiled/original.css +++ b/system/ThirdParty/Kint/resources/compiled/original.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#0092db;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #5cb730}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#e0eaef;border:1px solid #b6cedb;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#0092db}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}input.kint-note-input{width:100%}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#0092db;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #5cb730}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#e0eaef;border:1px solid #b6cedb;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#0092db}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-popup-trigger{background:rgba(0,0,0,0);color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}input.kint-note-input{width:100%}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} diff --git a/system/ThirdParty/Kint/resources/compiled/plain.css b/system/ThirdParty/Kint/resources/compiled/plain.css index ba1eba0ae27f..85a4e739408c 100644 --- a/system/ThirdParty/Kint/resources/compiled/plain.css +++ b/system/ThirdParty/Kint/resources/compiled/plain.css @@ -1 +1 @@ -.kint-plain{background:rgba(255,255,255,0.9);white-space:pre;display:block;font-family:monospace;color:#222}.kint-plain i{color:#d00;font-style:normal}.kint-plain u{color:#030;text-decoration:none;font-weight:bold}.kint-plain .kint-microtime-lap{font-weight:bold;text-shadow:1px 0 #fff, 0 1px #fff, -1px 0 #fff, 0 -1px #fff} +.kint-plain{background:rgba(255,255,255,.9);white-space:pre;display:block;font-family:monospace;color:#222}.kint-plain i{color:#d00;font-style:normal}.kint-plain u{color:#030;text-decoration:none;font-weight:bold}.kint-plain .kint-microtime-lap{font-weight:bold;text-shadow:1px 0 #fff,0 1px #fff,-1px 0 #fff,0 -1px #fff} diff --git a/system/ThirdParty/Kint/resources/compiled/solarized-dark.css b/system/ThirdParty/Kint/resources/compiled/solarized-dark.css index 4ab5e287c54a..2cc125edca72 100644 --- a/system/ThirdParty/Kint/resources/compiled/solarized-dark.css +++ b/system/ThirdParty/Kint/resources/compiled/solarized-dark.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:#073642}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#839496}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#839496;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#002b36;border:1px solid #586e75;color:#839496;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:#073642}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#839496}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#839496;float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#002b36;border:1px solid #586e75;color:#839496;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-popup-trigger{background:rgba(0,0,0,0);color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} diff --git a/system/ThirdParty/Kint/resources/compiled/solarized.css b/system/ThirdParty/Kint/resources/compiled/solarized.css index 952453edc311..8c1a67f08969 100644 --- a/system/ThirdParty/Kint/resources/compiled/solarized.css +++ b/system/ThirdParty/Kint/resources/compiled/solarized.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px rgba(0,0,0,0);cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:rgba(0,0,0,0)}.kint-rich footer>.kint-popup-trigger{background:rgba(0,0,0,0);color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}input.kint-note-input{width:100%}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} From 1c20d682702996b8fbe78cb549f158525a64a1de Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 07:05:18 +0900 Subject: [PATCH 212/380] fix: autoload helpers in test bootstrap --- system/Test/bootstrap.php | 1 + 1 file changed, 1 insertion(+) diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 3145725afe96..fcd3c9498af3 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -75,6 +75,7 @@ // Initialize and register the loader with the SPL autoloader stack. Services::autoloader()->initialize(new Autoload(), new Modules())->register(); +Services::autoloader()->loadHelpers(); // Now load Composer's if it's available if (is_file(COMPOSER_PATH)) { From 31388c84a2dd77a6a6b03490085ad1d62aefa5e9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 11:42:10 +0900 Subject: [PATCH 213/380] docs: fix description for getXMLFromResult() --- user_guide_src/source/database/utilities.rst | 18 +++++++++++------- .../source/database/utilities/001.php | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst index 6bbc99b28ced..43349809b194 100644 --- a/user_guide_src/source/database/utilities.rst +++ b/user_guide_src/source/database/utilities.rst @@ -8,18 +8,17 @@ The Database Utility Class contains methods that help you manage your database. :local: :depth: 2 -******************* -Get XML from Result -******************* -getXMLFromResult() -================== +Export a Query Result as an XML Document +======================================== -This method returns the xml result from database result. You can do like this: +Permits you to generate an XML file from a query result. The first +parameter expects a query result object, the second may contain an +optional array of config parameters. Example: .. literalinclude:: utilities/001.php -and it will get the following xml result:: +and it will get the following xml result when the ``mytable`` has columns ``id`` and ``name``:: @@ -27,3 +26,8 @@ and it will get the following xml result:: bar + +.. important:: This method will NOT write the XML file for you. It + simply creates the XML layout. If you need to write the file + use the :php:func:`write_file()` helper. + diff --git a/user_guide_src/source/database/utilities/001.php b/user_guide_src/source/database/utilities/001.php index 41582ffca023..6cdfacd81834 100644 --- a/user_guide_src/source/database/utilities/001.php +++ b/user_guide_src/source/database/utilities/001.php @@ -1,13 +1,15 @@ query('SELECT * FROM mytable'); -$util = \CodeIgniter\Database\Config::utils(); +$config = [ + 'root' => 'root', + 'element' => 'element', + 'newline' => "\n", + 'tab' => "\t", +]; -echo $util->getXMLFromResult($model->get()); +echo $dbutil->getXMLFromResult($query, $config); From 3e076d3706f3a84b2e2e0dd00bb7e414659f5fdf Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 11:50:12 +0900 Subject: [PATCH 214/380] docs: add "Initializing the Utility Class" --- user_guide_src/source/database/utilities.rst | 28 ++++++++++++++++--- .../source/database/utilities/002.php | 3 ++ .../source/database/utilities/003.php | 3 ++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 user_guide_src/source/database/utilities/002.php create mode 100644 user_guide_src/source/database/utilities/003.php diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst index 43349809b194..8a094cfff549 100644 --- a/user_guide_src/source/database/utilities.rst +++ b/user_guide_src/source/database/utilities.rst @@ -1,6 +1,6 @@ -######### -Utilities -######### +###################### +Database Utility Class +###################### The Database Utility Class contains methods that help you manage your database. @@ -8,6 +8,27 @@ The Database Utility Class contains methods that help you manage your database. :local: :depth: 2 +****************************** +Initializing the Utility Class +****************************** + +Load the Utility Class as follows: + +.. literalinclude:: utilities/002.php + :lines: 2- + +You can also pass another database group to the DB Utility loader, in case +the database you want to manage isn't the default one: + +.. literalinclude:: utilities/003.php + :lines: 2- + +In the above example, we're passing a database group name as the first +parameter. + +**************************** +Using the Database Utilities +**************************** Export a Query Result as an XML Document ======================================== @@ -30,4 +51,3 @@ and it will get the following xml result when the ``mytable`` has columns ``id`` .. important:: This method will NOT write the XML file for you. It simply creates the XML layout. If you need to write the file use the :php:func:`write_file()` helper. - diff --git a/user_guide_src/source/database/utilities/002.php b/user_guide_src/source/database/utilities/002.php new file mode 100644 index 000000000000..895dd88fd58c --- /dev/null +++ b/user_guide_src/source/database/utilities/002.php @@ -0,0 +1,3 @@ + Date: Thu, 30 Nov 2023 16:02:45 +0900 Subject: [PATCH 215/380] docs: fix factory classname --- user_guide_src/source/database/utilities/001.php | 2 +- user_guide_src/source/database/utilities/002.php | 2 +- user_guide_src/source/database/utilities/003.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/database/utilities/001.php b/user_guide_src/source/database/utilities/001.php index 6cdfacd81834..131222efc86b 100644 --- a/user_guide_src/source/database/utilities/001.php +++ b/user_guide_src/source/database/utilities/001.php @@ -1,7 +1,7 @@ query('SELECT * FROM mytable'); diff --git a/user_guide_src/source/database/utilities/002.php b/user_guide_src/source/database/utilities/002.php index 895dd88fd58c..42bbbd63acc6 100644 --- a/user_guide_src/source/database/utilities/002.php +++ b/user_guide_src/source/database/utilities/002.php @@ -1,3 +1,3 @@ Date: Thu, 30 Nov 2023 12:19:43 +0900 Subject: [PATCH 216/380] docs: add missing methods in Database Utility Class --- user_guide_src/source/database/utilities.rst | 78 +++++++++++++++++++ .../source/database/utilities/004.php | 9 +++ .../source/database/utilities/005.php | 7 ++ .../source/database/utilities/006.php | 7 ++ .../source/database/utilities/007.php | 7 ++ .../source/database/utilities/008.php | 9 +++ .../source/database/utilities/009.php | 8 ++ .../source/database/utilities/010.php | 12 +++ 8 files changed, 137 insertions(+) create mode 100644 user_guide_src/source/database/utilities/004.php create mode 100644 user_guide_src/source/database/utilities/005.php create mode 100644 user_guide_src/source/database/utilities/006.php create mode 100644 user_guide_src/source/database/utilities/007.php create mode 100644 user_guide_src/source/database/utilities/008.php create mode 100644 user_guide_src/source/database/utilities/009.php create mode 100644 user_guide_src/source/database/utilities/010.php diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst index 8a094cfff549..eeb88cd1853d 100644 --- a/user_guide_src/source/database/utilities.rst +++ b/user_guide_src/source/database/utilities.rst @@ -30,6 +30,84 @@ parameter. Using the Database Utilities **************************** +Retrieve List of Database Names +================================ + +Returns an array of database names: + +.. literalinclude:: utilities/004.php + :lines: 2- + +Determine If a Database Exists +============================== + +Sometimes it's helpful to know whether a particular database exists. +Returns a boolean ``true``/``false``. Usage example: + +.. literalinclude:: utilities/005.php + :lines: 2- + +.. note:: Replace ``database_name`` with the name of the database you are + looking for. This method is case sensitive. + +Optimize a Table +================ + +Permits you to optimize a table using the table name specified in the +first parameter. Returns ``true``/``false`` based on success or failure: + +.. literalinclude:: utilities/006.php + :lines: 2- + +.. note:: Not all database platforms support table optimization. It is + mostly for use with MySQL. + +Repair a Table +============== + +Permits you to repair a table using the table name specified in the +first parameter. Returns ``true``/``false`` based on success or failure: + +.. literalinclude:: utilities/007.php + :lines: 2- + +.. note:: Not all database platforms support table repairs. + +Optimize a Database +=================== + +Permits you to optimize the database your DB class is currently +connected to. Returns an array containing the DB status messages or +``false`` on failure: + +.. literalinclude:: utilities/008.php + :lines: 2- + +.. note:: Not all database platforms support database optimization. It + it is mostly for use with MySQL. + +Export a Query Result as a CSV File +=================================== + +Permits you to generate a CSV file from a query result. The first +parameter of the method must contain the result object from your +query. Example: + +.. literalinclude:: utilities/009.php + :lines: 2- + +The second, third, and fourth parameters allow you to set the delimiter +newline, and enclosure characters respectively. By default commas are +used as the delimiter, ``"\n"`` is used as a new line, and a double-quote +is used as the enclosure. Example: + +.. literalinclude:: utilities/010.php + :lines: 2- + +.. important:: This method will NOT write the CSV file for you. It + simply creates the CSV layout. If you need to write the file + use the :php:func:`write_file()` helper. + Export a Query Result as an XML Document ======================================== diff --git a/user_guide_src/source/database/utilities/004.php b/user_guide_src/source/database/utilities/004.php new file mode 100644 index 000000000000..4a6b4f673859 --- /dev/null +++ b/user_guide_src/source/database/utilities/004.php @@ -0,0 +1,9 @@ +listDatabases(); + +foreach ($dbs as $db) { + echo $db; +} diff --git a/user_guide_src/source/database/utilities/005.php b/user_guide_src/source/database/utilities/005.php new file mode 100644 index 000000000000..77b0310708e5 --- /dev/null +++ b/user_guide_src/source/database/utilities/005.php @@ -0,0 +1,7 @@ +databaseExists('database_name')) { + // some code... +} diff --git a/user_guide_src/source/database/utilities/006.php b/user_guide_src/source/database/utilities/006.php new file mode 100644 index 000000000000..7fe39efdfdd8 --- /dev/null +++ b/user_guide_src/source/database/utilities/006.php @@ -0,0 +1,7 @@ +optimize_table('table_name')) { + echo 'Success!'; +} diff --git a/user_guide_src/source/database/utilities/007.php b/user_guide_src/source/database/utilities/007.php new file mode 100644 index 000000000000..603b69cc9342 --- /dev/null +++ b/user_guide_src/source/database/utilities/007.php @@ -0,0 +1,7 @@ +repairTable('table_name')) { + echo 'Success!'; +} diff --git a/user_guide_src/source/database/utilities/008.php b/user_guide_src/source/database/utilities/008.php new file mode 100644 index 000000000000..b5f19a33fd9e --- /dev/null +++ b/user_guide_src/source/database/utilities/008.php @@ -0,0 +1,9 @@ +optimizeDatabase(); + +if ($result !== false) { + print_r($result); +} diff --git a/user_guide_src/source/database/utilities/009.php b/user_guide_src/source/database/utilities/009.php new file mode 100644 index 000000000000..054d88afa95e --- /dev/null +++ b/user_guide_src/source/database/utilities/009.php @@ -0,0 +1,8 @@ +query('SELECT * FROM mytable'); + +echo $dbutil->getCSVFromResult($query); diff --git a/user_guide_src/source/database/utilities/010.php b/user_guide_src/source/database/utilities/010.php new file mode 100644 index 000000000000..c2b50a17360f --- /dev/null +++ b/user_guide_src/source/database/utilities/010.php @@ -0,0 +1,12 @@ +query('SELECT * FROM mytable'); + +$delimiter = ','; +$newline = "\r\n"; +$enclosure = '"'; + +echo $dbutil->getCSVFromResult($query, $delimiter, $newline, $enclosure); From e4d390313f85d153980ccd7cbf6580a85da2b3a7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 12:54:57 +0900 Subject: [PATCH 217/380] docs: remove unimplemented repairTable() --- user_guide_src/source/database/utilities.rst | 11 ----------- user_guide_src/source/database/utilities/007.php | 7 ------- 2 files changed, 18 deletions(-) delete mode 100644 user_guide_src/source/database/utilities/007.php diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst index eeb88cd1853d..c8c11e51d864 100644 --- a/user_guide_src/source/database/utilities.rst +++ b/user_guide_src/source/database/utilities.rst @@ -62,17 +62,6 @@ first parameter. Returns ``true``/``false`` based on success or failure: .. note:: Not all database platforms support table optimization. It is mostly for use with MySQL. -Repair a Table -============== - -Permits you to repair a table using the table name specified in the -first parameter. Returns ``true``/``false`` based on success or failure: - -.. literalinclude:: utilities/007.php - :lines: 2- - -.. note:: Not all database platforms support table repairs. - Optimize a Database =================== diff --git a/user_guide_src/source/database/utilities/007.php b/user_guide_src/source/database/utilities/007.php deleted file mode 100644 index 603b69cc9342..000000000000 --- a/user_guide_src/source/database/utilities/007.php +++ /dev/null @@ -1,7 +0,0 @@ -repairTable('table_name')) { - echo 'Success!'; -} From 7e55e4503fca0aef05416cbdf34e0fdeb2a06456 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 12:58:12 +0900 Subject: [PATCH 218/380] docs: fix CI3's method name --- user_guide_src/source/database/utilities/006.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/utilities/006.php b/user_guide_src/source/database/utilities/006.php index 7fe39efdfdd8..6de4d1fdc6a7 100644 --- a/user_guide_src/source/database/utilities/006.php +++ b/user_guide_src/source/database/utilities/006.php @@ -2,6 +2,6 @@ $dbutil = \CodeIgniter\Database\Config::utils(); -if ($dbutil->optimize_table('table_name')) { +if ($dbutil->optimizeTable('table_name')) { echo 'Success!'; } From 4542dd58fbd79a97d36ef510088733e16c7b3a29 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 30 Nov 2023 16:07:28 +0900 Subject: [PATCH 219/380] docs: fix factory method name --- user_guide_src/source/database/utilities/004.php | 2 +- user_guide_src/source/database/utilities/005.php | 2 +- user_guide_src/source/database/utilities/006.php | 2 +- user_guide_src/source/database/utilities/008.php | 2 +- user_guide_src/source/database/utilities/009.php | 2 +- user_guide_src/source/database/utilities/010.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/database/utilities/004.php b/user_guide_src/source/database/utilities/004.php index 4a6b4f673859..3908bb7ad76c 100644 --- a/user_guide_src/source/database/utilities/004.php +++ b/user_guide_src/source/database/utilities/004.php @@ -1,6 +1,6 @@ listDatabases(); diff --git a/user_guide_src/source/database/utilities/005.php b/user_guide_src/source/database/utilities/005.php index 77b0310708e5..92ddaa3487ce 100644 --- a/user_guide_src/source/database/utilities/005.php +++ b/user_guide_src/source/database/utilities/005.php @@ -1,6 +1,6 @@ databaseExists('database_name')) { // some code... diff --git a/user_guide_src/source/database/utilities/006.php b/user_guide_src/source/database/utilities/006.php index 6de4d1fdc6a7..e85a07933798 100644 --- a/user_guide_src/source/database/utilities/006.php +++ b/user_guide_src/source/database/utilities/006.php @@ -1,6 +1,6 @@ optimizeTable('table_name')) { echo 'Success!'; diff --git a/user_guide_src/source/database/utilities/008.php b/user_guide_src/source/database/utilities/008.php index b5f19a33fd9e..726b15a822dd 100644 --- a/user_guide_src/source/database/utilities/008.php +++ b/user_guide_src/source/database/utilities/008.php @@ -1,6 +1,6 @@ optimizeDatabase(); diff --git a/user_guide_src/source/database/utilities/009.php b/user_guide_src/source/database/utilities/009.php index 054d88afa95e..f8bf84f6a499 100644 --- a/user_guide_src/source/database/utilities/009.php +++ b/user_guide_src/source/database/utilities/009.php @@ -1,7 +1,7 @@ query('SELECT * FROM mytable'); diff --git a/user_guide_src/source/database/utilities/010.php b/user_guide_src/source/database/utilities/010.php index c2b50a17360f..7e11cc18019b 100644 --- a/user_guide_src/source/database/utilities/010.php +++ b/user_guide_src/source/database/utilities/010.php @@ -1,7 +1,7 @@ query('SELECT * FROM mytable'); From e601954b35db48ebdd8042d24d1a2e6c6fd5a960 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Thu, 30 Nov 2023 11:18:56 +0000 Subject: [PATCH 220/380] recreate fix: CURLOPT_SSL_VERIFYPEER values and tests related with CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST --- system/HTTP/CURLRequest.php | 25 ++++++++----------- .../HTTP/CURLRequestDoNotShareOptionsTest.php | 9 ++++--- tests/system/HTTP/CURLRequestTest.php | 6 ++--- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 5edd9af6859e..9392e2446b8e 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -548,24 +548,21 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) // SSL Verification if (isset($config['verify'])) { - if (is_string($config['verify'])) { - $file = realpath($config['ssl_key']) ?: $config['ssl_key']; + $configVerify = $config['verify']; + + if (is_string($configVerify)) { + $file = realpath($configVerify) ?: $configVerify; if (! is_file($file)) { - throw HTTPException::forInvalidSSLKey($config['ssl_key']); + throw HTTPException::forInvalidSSLKey($configVerify); } - $curlOptions[CURLOPT_CAINFO] = $file; - if ($config['verify'] === 'yes') { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = true; - $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; - } else { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = false; - $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; - } - } elseif (is_bool($config['verify'])) { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = $config['verify']; - $curlOptions[CURLOPT_SSL_VERIFYHOST] = $config['verify'] ? 2 : 0; + $curlOptions[CURLOPT_CAINFO] = $file; + $curlOptions[CURLOPT_SSL_VERIFYPEER] = true; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; + } elseif (is_bool($configVerify)) { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = $configVerify; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = $configVerify ? 2 : 0; } } diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index 39dc0409afb9..32e60b1418b3 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -535,8 +535,7 @@ public function testSSLVerification(): void $file = __FILE__; $this->request->request('get', 'http://example.com', [ - 'verify' => 'yes', - 'ssl_key' => $file, + 'verify' => $file, ]); $options = $this->request->curl_options; @@ -546,6 +545,9 @@ public function testSSLVerification(): void $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options); $this->assertTrue($options[CURLOPT_SSL_VERIFYPEER]); + + $this->assertArrayHasKey(CURLOPT_SSL_VERIFYHOST, $options); + $this->assertSame(2, $options[CURLOPT_SSL_VERIFYHOST]); } public function testSSLWithBadKey(): void @@ -554,8 +556,7 @@ public function testSSLWithBadKey(): void $this->expectException(HTTPException::class); $this->request->request('get', 'http://example.com', [ - 'verify' => 'yes', - 'ssl_key' => $file, + 'verify' => $file, ]); } diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index a947acee7163..4893266e5009 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -518,8 +518,7 @@ public function testSSLVerification(): void $file = __FILE__; $this->request->request('get', 'http://example.com', [ - 'verify' => 'yes', - 'ssl_key' => $file, + 'verify' => $file, ]); $options = $this->request->curl_options; @@ -555,8 +554,7 @@ public function testSSLWithBadKey(): void $this->expectException(HTTPException::class); $this->request->request('get', 'http://example.com', [ - 'verify' => 'yes', - 'ssl_key' => $file, + 'verify' => $file, ]); } From f8dd0b70b23edd315bfd2bc8640073899cb0bf42 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Thu, 30 Nov 2023 17:49:04 +0000 Subject: [PATCH 221/380] Updated Bugs and Breaking sections Revert to ['verify'] instead of --- CHANGELOG.md | 7 +++++++ system/HTTP/CURLRequest.php | 14 ++++++-------- user_guide_src/source/changelogs/v4.4.4.rst | 6 ++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cf10b0f8372..9dbee6dba64c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [v4.4.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.4) (Unreleased) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.3...v4.4.4) + +### Fixed Bugs + +* fix: [CURLRequest] skip hostname checks if options 'verify' false by @NicolaeIotu in https://github.com/codeigniter4/CodeIgniter4/pull/8258 + ## [v4.4.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.3) (2023-10-26) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.2...v4.4.3) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 9392e2446b8e..500b425d2dc5 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -548,21 +548,19 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) // SSL Verification if (isset($config['verify'])) { - $configVerify = $config['verify']; - - if (is_string($configVerify)) { - $file = realpath($configVerify) ?: $configVerify; + if (is_string($config['verify'])) { + $file = realpath($config['verify']) ?: $config['verify']; if (! is_file($file)) { - throw HTTPException::forInvalidSSLKey($configVerify); + throw HTTPException::forInvalidSSLKey($config['verify']); } $curlOptions[CURLOPT_CAINFO] = $file; $curlOptions[CURLOPT_SSL_VERIFYPEER] = true; $curlOptions[CURLOPT_SSL_VERIFYHOST] = 2; - } elseif (is_bool($configVerify)) { - $curlOptions[CURLOPT_SSL_VERIFYPEER] = $configVerify; - $curlOptions[CURLOPT_SSL_VERIFYHOST] = $configVerify ? 2 : 0; + } elseif (is_bool($config['verify'])) { + $curlOptions[CURLOPT_SSL_VERIFYPEER] = $config['verify']; + $curlOptions[CURLOPT_SSL_VERIFYHOST] = $config['verify'] ? 2 : 0; } } diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index aca70ba7874e..f1123a099308 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -27,6 +27,12 @@ Validation rules matches and differs Bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict and Traditional rules validate data of non-string types. +CURLRequest option 'ssl_key' eliminated +==================================== + +CURLRequest option 'ssl_key' was eliminated. +Please use CURLRequest option 'verify' to indicate the path to a CA bundle. + *************** Message Changes *************** From 25b6d4022758a1b02be28ce4e7693202e3faaced Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Thu, 30 Nov 2023 17:57:03 +0000 Subject: [PATCH 222/380] Fix sphinx-action warning 'Title underline too short' --- user_guide_src/source/changelogs/v4.4.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index f1123a099308..39b74598c92f 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -28,7 +28,7 @@ Bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict and Traditional rules validate data of non-string types. CURLRequest option 'ssl_key' eliminated -==================================== +======================================= CURLRequest option 'ssl_key' was eliminated. Please use CURLRequest option 'verify' to indicate the path to a CA bundle. From edd31c0971c68f4483df04b62a9f994798b3e308 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Dec 2023 15:12:27 +0900 Subject: [PATCH 223/380] chore: add missing ext-sodium in suggest --- admin/framework/composer.json | 1 + composer.json | 1 + 2 files changed, 2 insertions(+) diff --git a/admin/framework/composer.json b/admin/framework/composer.json index f93daa275b1d..04b46a3b667c 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -43,6 +43,7 @@ "ext-readline": "Improves CLI::input() usability", "ext-redis": "If you use Cache class RedisHandler", "ext-simplexml": "If you format XML", + "ext-sodium": "If you Encryption SodiumHandler", "ext-sqlite3": "If you use SQLite3", "ext-sqlsrv": "If you use SQL Server", "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" diff --git a/composer.json b/composer.json index 03008c6de3ca..98e5c32cf10d 100644 --- a/composer.json +++ b/composer.json @@ -52,6 +52,7 @@ "ext-readline": "Improves CLI::input() usability", "ext-redis": "If you use Cache class RedisHandler", "ext-simplexml": "If you format XML", + "ext-sodium": "If you Encryption SodiumHandler", "ext-sqlite3": "If you use SQLite3", "ext-sqlsrv": "If you use SQL Server", "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" From ab25092599263f316fe7b185bf08053e55b2ea83 Mon Sep 17 00:00:00 2001 From: IOTU Nicolae Date: Fri, 1 Dec 2023 07:17:56 +0000 Subject: [PATCH 224/380] Update user_guide_src/source/changelogs/v4.4.4.rst Co-authored-by: Michal Sniatala --- user_guide_src/source/changelogs/v4.4.4.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index 39b74598c92f..98415f303990 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -27,11 +27,11 @@ Validation rules matches and differs Bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict and Traditional rules validate data of non-string types. -CURLRequest option 'ssl_key' eliminated -======================================= +The use of the `ssl_key` option in CURLRequest was removed +========================================================== -CURLRequest option 'ssl_key' was eliminated. -Please use CURLRequest option 'verify' to indicate the path to a CA bundle. +Due to a bug, we were using the undocumented `ssl_key` config option to define the CA bundle in CURLRequest. +This was fixed and is now working according to documentation. You can define your CA bundle via the `verify` option. *************** Message Changes From 6df07b00acba0379440270feffb9c14c4fd66623 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Fri, 1 Dec 2023 07:39:46 +0000 Subject: [PATCH 225/380] Added the summary of the bug --- user_guide_src/source/changelogs/v4.4.4.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.4.4.rst b/user_guide_src/source/changelogs/v4.4.4.rst index 98415f303990..7ee96a53556f 100644 --- a/user_guide_src/source/changelogs/v4.4.4.rst +++ b/user_guide_src/source/changelogs/v4.4.4.rst @@ -55,6 +55,8 @@ Deprecations Bugs Fixed ********** +- **CURLRequest:** Fixed a bug where the hostname was checked even if options 'verify' was set to *false*. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. From bfb9ab4ef7dcaf43bd9ce1ca0f091e2935a39b33 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Fri, 1 Dec 2023 07:51:44 +0000 Subject: [PATCH 226/380] Revert manual changes to CHANGELOG.md --- CHANGELOG.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dbee6dba64c..9cf10b0f8372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,5 @@ # Changelog -## [v4.4.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.4) (Unreleased) -[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.3...v4.4.4) - -### Fixed Bugs - -* fix: [CURLRequest] skip hostname checks if options 'verify' false by @NicolaeIotu in https://github.com/codeigniter4/CodeIgniter4/pull/8258 - ## [v4.4.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.3) (2023-10-26) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.2...v4.4.3) From 5b4482c86dd7b50af8c67901095bda7f9fc20979 Mon Sep 17 00:00:00 2001 From: Nicolae Iotu Date: Fri, 1 Dec 2023 08:58:51 +0000 Subject: [PATCH 227/380] Added upgrading instructions --- user_guide_src/source/installation/upgrade_444.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst index b3773947efd9..77026be6673e 100644 --- a/user_guide_src/source/installation/upgrade_444.rst +++ b/user_guide_src/source/installation/upgrade_444.rst @@ -50,6 +50,15 @@ changed (fixed). Note that Traditional Rules should not be used to validate data that is not a string. +The use of the `ssl_key` option in CURLRequest was removed +========================================================== + +CURLRequest option `ssl_key` it's not recognized anymore. +If in use, option `ssl_key` must be replaced with option `verify` in order to define the path +to a CA bundle for CURLRequest. + +CURLRequest option `verify` can also take *boolean* values as usual. + ********************* Breaking Enhancements ********************* From 2ee497943d2eb32e7dedaf25ac97be5a0c1a8ded Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Dec 2023 17:42:04 +0900 Subject: [PATCH 228/380] test: add test for Model and Entity with cast primaryKey --- tests/_support/Entity/Cast/CastUUID.php | 43 +++++++++++++++++++++++++ tests/_support/Entity/UUID.php | 25 ++++++++++++++ tests/_support/Models/UUIDPkeyModel.php | 25 ++++++++++++++ tests/system/Models/UpdateModelTest.php | 36 +++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 tests/_support/Entity/Cast/CastUUID.php create mode 100644 tests/_support/Entity/UUID.php create mode 100644 tests/_support/Models/UUIDPkeyModel.php diff --git a/tests/_support/Entity/Cast/CastUUID.php b/tests/_support/Entity/Cast/CastUUID.php new file mode 100644 index 000000000000..42cbb23b2670 --- /dev/null +++ b/tests/_support/Entity/Cast/CastUUID.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Entity\Cast; + +use CodeIgniter\Entity\Cast\BaseCast; + +class CastUUID extends BaseCast +{ + /** + * Get + * + * @param string $binary Binary UUID + * + * @return string String UUID + */ + public static function get($binary, array $params = []): string + { + $string = unpack('h*', $binary); + + return preg_replace('/([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})/', '$1-$2-$3-$4-$5', $string[1]); + } + + /** + * Set + * + * @param string $string String UUID + * + * @return string Binary UUID + */ + public static function set($string, array $params = []): string + { + return pack('h*', str_replace('-', '', $string)); + } +} diff --git a/tests/_support/Entity/UUID.php b/tests/_support/Entity/UUID.php new file mode 100644 index 000000000000..1c124656458f --- /dev/null +++ b/tests/_support/Entity/UUID.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Entity; + +use CodeIgniter\Entity\Entity; +use Tests\Support\Entity\Cast\CastUUID; + +class UUID extends Entity +{ + protected $casts = [ + 'id' => 'uuid', + ]; + protected $castHandlers = [ + 'uuid' => CastUUID::class, + ]; +} diff --git a/tests/_support/Models/UUIDPkeyModel.php b/tests/_support/Models/UUIDPkeyModel.php new file mode 100644 index 000000000000..be4a3c750093 --- /dev/null +++ b/tests/_support/Models/UUIDPkeyModel.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Models; + +use CodeIgniter\Model; +use Tests\Support\Entity\UUID; + +class UUIDPkeyModel extends Model +{ + protected $table = 'uuid'; + protected $useAutoIncrement = false; + protected $returnType = UUID::class; + protected $allowedFields = [ + 'value', + ]; +} diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 78ee2c945631..c18a30f7fc9a 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -14,12 +14,15 @@ use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\Entity\Entity; +use Config\Database; use InvalidArgumentException; use stdClass; +use Tests\Support\Entity\UUID; use Tests\Support\Models\EventModel; use Tests\Support\Models\JobModel; use Tests\Support\Models\SecondaryModel; use Tests\Support\Models\UserModel; +use Tests\Support\Models\UUIDPkeyModel; use Tests\Support\Models\ValidModel; use Tests\Support\Models\WithoutAutoIncrementModel; @@ -375,6 +378,39 @@ public function testUpdateWithEntityNoAllowedFields(): void $this->model->update($id, $entity); } + public function testUpdateEntityWithPrimaryKeyCast(): void + { + $this->createUuidTable(); + + $this->createModel(UUIDPkeyModel::class); + + $entity = new UUID(); + $entity->id = '550e8400-e29b-41d4-a716-446655440000'; + $entity->value = 'test1'; + + $id = $this->model->insert($entity); + $entity = $this->model->find($id); + + $entity->value = 'id'; + $result = $this->model->save($entity); + + $this->assertTrue($result); + + $entity = $this->model->find($id); + + $this->assertSame('id', $entity->value); + } + + private function createUuidTable(): void + { + $forge = Database::forge($this->DBGroup); + $forge->dropTable('uuid', true); + $forge->addField([ + 'id' => ['type' => 'BINARY', 'constraint' => 16], + 'value' => ['type' => 'VARCHAR', 'constraint' => 400, 'null' => true], + ])->addKey('id', true)->createTable('uuid', true); + } + public function testUseAutoIncrementSetToFalseUpdate(): void { $key = 'key'; From b8330e904ac467fff90d4b4e82640ab5dfa1c52b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Dec 2023 18:58:12 +0900 Subject: [PATCH 229/380] fix: processing in Model of Entity for which primary key is cast --- system/Model.php | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/system/Model.php b/system/Model.php index 3a055531cb5b..0a8cd9dbec59 100644 --- a/system/Model.php +++ b/system/Model.php @@ -534,6 +534,21 @@ protected function idValue($data) public function getIdValue($data) { if (is_object($data) && isset($data->{$this->primaryKey})) { + // Get the raw primary key value of the Entity. + if ($data instanceof Entity) { + $cast = $data->cast(); + + // Disable Entity casting, because raw primary key value is needed for database. + $data->cast(false); + + $primaryKey = $data->{$this->primaryKey}; + + // Restore Entity casting setting. + $data->cast($cast); + + return $primaryKey; + } + return $data->{$this->primaryKey}; } @@ -796,37 +811,7 @@ public function update($id = null, $data = null): bool */ protected function objectToRawArray($data, bool $onlyChanged = true, bool $recursive = false): ?array { - $properties = parent::objectToRawArray($data, $onlyChanged); - - $primaryKey = null; - - if ($data instanceof Entity) { - $cast = $data->cast(); - - // Disable Entity casting, because raw primary key data is needed for database. - $data->cast(false); - - $primaryKey = $data->{$this->primaryKey}; - - // Restore Entity casting setting. - $data->cast($cast); - } - - // Always grab the primary key otherwise updates will fail. - if ( - // @TODO Should use `$data instanceof Entity`. - method_exists($data, 'toRawArray') - && ( - ! empty($properties) - && ! empty($this->primaryKey) - && ! in_array($this->primaryKey, $properties, true) - && ! empty($primaryKey) - ) - ) { - $properties[$this->primaryKey] = $primaryKey; - } - - return $properties; + return parent::objectToRawArray($data, $onlyChanged); } /** From 7f7be9a2ed59f4c5ab48805f83222182c2ce510e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Dec 2023 19:05:58 +0900 Subject: [PATCH 230/380] chore: update phpstan-baseline --- phpstan-baseline.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 1322685d6fd2..039eedaaccdc 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2608,7 +2608,7 @@ ]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 21, + 'count' => 18, 'path' => __DIR__ . '/system/Model.php', ]; $ignoreErrors[] = [ From c0a86fd6424938b506257e9f739b992853817125 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Dec 2023 06:53:59 +0900 Subject: [PATCH 231/380] test: skip test on OCI8, Postgre, SQLSRV --- tests/system/Models/UpdateModelTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index c18a30f7fc9a..89d3768dc8d1 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -380,6 +380,14 @@ public function testUpdateWithEntityNoAllowedFields(): void public function testUpdateEntityWithPrimaryKeyCast(): void { + if ( + $this->db->DBDriver === 'OCI8' + || $this->db->DBDriver === 'Postgre' + || $this->db->DBDriver === 'SQLSRV' + ) { + $this->markTestSkipped($this->db->DBDriver . ' does not work with binary data as string data.'); + } + $this->createUuidTable(); $this->createModel(UUIDPkeyModel::class); From 87a706ca6a228d074488629c596b66d63df993c3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Dec 2023 07:23:51 +0900 Subject: [PATCH 232/380] test: skip SQLite3 SQLite3::escapeString() is not binary safe. https://www.php.net/manual/en/sqlite3.escapestring.php --- tests/system/Models/UpdateModelTest.php | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 89d3768dc8d1..0a2013b52a49 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -384,6 +384,7 @@ public function testUpdateEntityWithPrimaryKeyCast(): void $this->db->DBDriver === 'OCI8' || $this->db->DBDriver === 'Postgre' || $this->db->DBDriver === 'SQLSRV' + || $this->db->DBDriver === 'SQLite3' ) { $this->markTestSkipped($this->db->DBDriver . ' does not work with binary data as string data.'); } @@ -409,6 +410,51 @@ public function testUpdateEntityWithPrimaryKeyCast(): void $this->assertSame('id', $entity->value); } + public function testUpdateBatchEntityWithPrimaryKeyCast(): void + { + if ( + $this->db->DBDriver === 'OCI8' + || $this->db->DBDriver === 'Postgre' + || $this->db->DBDriver === 'SQLSRV' + || $this->db->DBDriver === 'SQLite3' + ) { + $this->markTestSkipped($this->db->DBDriver . ' does not work with binary data as string data.'); + } + + $this->createUuidTable(); + + $this->createModel(UUIDPkeyModel::class); + + $entity1 = new UUID(); + $entity1->id = '550e8400-e29b-41d4-a716-446655440000'; + $entity1->value = 'test1'; + $id1 = $this->model->insert($entity1); + + $entity2 = new UUID(); + $entity2->id = 'bd59cff1-7a24-dde5-ac10-7b929db6da8c'; + $entity2->value = 'test2'; + $id2 = $this->model->insert($entity2); + + $entity1 = $this->model->find($id1); + $entity2 = $this->model->find($id2); + + $entity1->value = 'update1'; + $entity2->value = 'update2'; + + $data = [ + $entity1, + $entity2, + ]; + $this->model->updateBatch($data, 'id'); + + $this->seeInDatabase('uuid', [ + 'value' => 'update1', + ]); + $this->seeInDatabase('uuid', [ + 'value' => 'update2', + ]); + } + private function createUuidTable(): void { $forge = Database::forge($this->DBGroup); From c357e4c43889b5fde01ec60b46d8aaacfbe1bac3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Dec 2023 10:25:46 +0900 Subject: [PATCH 233/380] test: skip test for batchUpdate() that does not work --- tests/system/Models/UpdateModelTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 0a2013b52a49..4e30763a4073 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -421,6 +421,11 @@ public function testUpdateBatchEntityWithPrimaryKeyCast(): void $this->markTestSkipped($this->db->DBDriver . ' does not work with binary data as string data.'); } + // See https://github.com/codeigniter4/CodeIgniter4/pull/8282#issuecomment-1836974182 + $this->markTestSkipped( + 'batchUpdate() is currently not working due to data type issues in the generated SQL statement.' + ); + $this->createUuidTable(); $this->createModel(UUIDPkeyModel::class); From 6df976b54556405873909a19d6d89b6d06294644 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Dec 2023 18:52:17 +0900 Subject: [PATCH 234/380] test: fix test Entity name --- .../_support/Entity/Cast/{CastUUID.php => CastBinaryUUID.php} | 2 +- tests/_support/Entity/UUID.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/_support/Entity/Cast/{CastUUID.php => CastBinaryUUID.php} (96%) diff --git a/tests/_support/Entity/Cast/CastUUID.php b/tests/_support/Entity/Cast/CastBinaryUUID.php similarity index 96% rename from tests/_support/Entity/Cast/CastUUID.php rename to tests/_support/Entity/Cast/CastBinaryUUID.php index 42cbb23b2670..ddf5a80c202f 100644 --- a/tests/_support/Entity/Cast/CastUUID.php +++ b/tests/_support/Entity/Cast/CastBinaryUUID.php @@ -13,7 +13,7 @@ use CodeIgniter\Entity\Cast\BaseCast; -class CastUUID extends BaseCast +class CastBinaryUUID extends BaseCast { /** * Get diff --git a/tests/_support/Entity/UUID.php b/tests/_support/Entity/UUID.php index 1c124656458f..d88fa25505f9 100644 --- a/tests/_support/Entity/UUID.php +++ b/tests/_support/Entity/UUID.php @@ -12,7 +12,7 @@ namespace Tests\Support\Entity; use CodeIgniter\Entity\Entity; -use Tests\Support\Entity\Cast\CastUUID; +use Tests\Support\Entity\Cast\CastBinaryUUID; class UUID extends Entity { @@ -20,6 +20,6 @@ class UUID extends Entity 'id' => 'uuid', ]; protected $castHandlers = [ - 'uuid' => CastUUID::class, + 'uuid' => CastBinaryUUID::class, ]; } From b1b7d169d523106159970d95765375b017a3b512 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Dec 2023 05:36:02 +0900 Subject: [PATCH 235/380] docs: add missing "use" Co-authored-by: MGatner --- admin/framework/composer.json | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/framework/composer.json b/admin/framework/composer.json index 04b46a3b667c..245091e5d256 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -43,7 +43,7 @@ "ext-readline": "Improves CLI::input() usability", "ext-redis": "If you use Cache class RedisHandler", "ext-simplexml": "If you format XML", - "ext-sodium": "If you Encryption SodiumHandler", + "ext-sodium": "If you use Encryption SodiumHandler", "ext-sqlite3": "If you use SQLite3", "ext-sqlsrv": "If you use SQL Server", "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" diff --git a/composer.json b/composer.json index 98e5c32cf10d..99a7dc676d56 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,7 @@ "ext-readline": "Improves CLI::input() usability", "ext-redis": "If you use Cache class RedisHandler", "ext-simplexml": "If you format XML", - "ext-sodium": "If you Encryption SodiumHandler", + "ext-sodium": "If you use Encryption SodiumHandler", "ext-sqlite3": "If you use SQLite3", "ext-sqlsrv": "If you use SQL Server", "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" From 67335ecd4900a4da64ff8f27763cd123de0dc6ab Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Dec 2023 10:07:24 +0900 Subject: [PATCH 236/380] style: composer cs-fix --- system/Debug/BaseExceptionHandler.php | 2 +- system/Debug/Exceptions.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Debug/BaseExceptionHandler.php b/system/Debug/BaseExceptionHandler.php index 8b67d2153f9f..d4f045797366 100644 --- a/system/Debug/BaseExceptionHandler.php +++ b/system/Debug/BaseExceptionHandler.php @@ -239,7 +239,7 @@ protected function render(Throwable $exception, int $statusCode, $viewFile = nul exit(1); } - echo(function () use ($exception, $statusCode, $viewFile): string { + echo (function () use ($exception, $statusCode, $viewFile): string { $vars = $this->collectVars($exception, $statusCode); extract($vars, EXTR_SKIP); diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 4b3e5cf3ea3e..145474c6c633 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -316,7 +316,7 @@ protected function render(Throwable $exception, int $statusCode) exit(1); } - echo(function () use ($exception, $statusCode, $viewFile): string { + echo (function () use ($exception, $statusCode, $viewFile): string { $vars = $this->collectVars($exception, $statusCode); extract($vars, EXTR_SKIP); From 705a695119e5e9418904be8f86cd7e72be1addf9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:40:52 +0000 Subject: [PATCH 237/380] chore(deps-dev): update rector/rector requirement 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/0.18.11...0.18.12) --- 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 03008c6de3ca..4cdf0137b36a 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.18.11", + "rector/rector": "0.18.12", "vimeo/psalm": "^5.0" }, "suggest": { From 37a0406fe300055c6c6f431e111a017c741a9647 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Dec 2023 06:10:46 +0900 Subject: [PATCH 238/380] test: fix UndefinedVariable Error: tests/system/Test/TestCaseTest.php:57:56: UndefinedVariable: Cannot find referenced variable $result (see https://psalm.dev/024) --- tests/system/Test/TestCaseTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index e5e1ed8cb3f6..2bb19999de39 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -54,6 +54,8 @@ public function testAssertLogContains(): void public function testEventTriggering(): void { + $result = ''; + Events::on('foo', static function ($arg) use (&$result): void { $result = $arg; }); @@ -61,6 +63,7 @@ public function testEventTriggering(): void Events::trigger('foo', 'bar'); $this->assertEventTriggered('foo'); + $this->assertSame('bar', $result); } public function testStreamFilter(): void From 8dae2a8f20a873d0d68b5c2fa2fac64a899707fd Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Dec 2023 06:17:37 +0900 Subject: [PATCH 239/380] test: move class in TestCase file $ vendor/bin/phpunit tests/system/Test/TestCaseTest.php PHPUnit 9.6.15 by Sebastian Bergmann and contributors. Runtime: PHP 8.1.26 Configuration: /.../CodeIgniter4/phpunit.xml E........ 9 / 9 (100%) Time: 00:00.086, Memory: 16.00 MB There was 1 error: 1) CodeIgniter\Test\TestCaseTest::testGetPrivatePropertyWithObject Error: Class "CodeIgniter\Test\__TestForReflectionHelper" not found /.../CodeIgniter4/tests/system/Test/TestCaseTest.php:38 ERRORS! Tests: 9, Assertions: 19, Errors: 1. --- .../_support/Test/TestForReflectionHelper.php | 38 ++++++++++++++++ tests/system/Test/ReflectionHelperTest.php | 44 +++++-------------- tests/system/Test/TestCaseTest.php | 3 +- 3 files changed, 50 insertions(+), 35 deletions(-) create mode 100644 tests/_support/Test/TestForReflectionHelper.php diff --git a/tests/_support/Test/TestForReflectionHelper.php b/tests/_support/Test/TestForReflectionHelper.php new file mode 100644 index 000000000000..6ea9bea597cd --- /dev/null +++ b/tests/_support/Test/TestForReflectionHelper.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Test; + +class TestForReflectionHelper +{ + private string $private = 'secret'; + private static string $static_private = 'xyz'; + + public function getPrivate() + { + return $this->private; + } + + public static function getStaticPrivate() + { + return self::$static_private; + } + + private function privateMethod($param1, $param2) + { + return 'private ' . $param1 . $param2; + } + + private static function privateStaticMethod($param1, $param2) + { + return 'private_static ' . $param1 . $param2; + } +} diff --git a/tests/system/Test/ReflectionHelperTest.php b/tests/system/Test/ReflectionHelperTest.php index 414053b26dc1..86eb65ffbf51 100644 --- a/tests/system/Test/ReflectionHelperTest.php +++ b/tests/system/Test/ReflectionHelperTest.php @@ -11,6 +11,8 @@ namespace CodeIgniter\Test; +use Tests\Support\Test\TestForReflectionHelper; + /** * @internal * @@ -20,14 +22,14 @@ final class ReflectionHelperTest extends CIUnitTestCase { public function testGetPrivatePropertyWithObject(): void { - $obj = new __TestForReflectionHelper(); + $obj = new TestForReflectionHelper(); $actual = $this->getPrivateProperty($obj, 'private'); $this->assertSame('secret', $actual); } public function testGetPrivatePropertyWithObjectStaticCall(): void { - $obj = new __TestForReflectionHelper(); + $obj = new TestForReflectionHelper(); $actual = CIUnitTestCase::getPrivateProperty($obj, 'private'); $this->assertSame('secret', $actual); } @@ -35,7 +37,7 @@ public function testGetPrivatePropertyWithObjectStaticCall(): void public function testGetPrivatePropertyWithStatic(): void { $actual = $this->getPrivateProperty( - __TestForReflectionHelper::class, + TestForReflectionHelper::class, 'static_private' ); $this->assertSame('xyz', $actual); @@ -43,7 +45,7 @@ public function testGetPrivatePropertyWithStatic(): void public function testSetPrivatePropertyWithObject(): void { - $obj = new __TestForReflectionHelper(); + $obj = new TestForReflectionHelper(); $this->setPrivateProperty( $obj, 'private', @@ -55,19 +57,19 @@ public function testSetPrivatePropertyWithObject(): void public function testSetPrivatePropertyWithStatic(): void { $this->setPrivateProperty( - __TestForReflectionHelper::class, + TestForReflectionHelper::class, 'static_private', 'abc' ); $this->assertSame( 'abc', - __TestForReflectionHelper::getStaticPrivate() + TestForReflectionHelper::getStaticPrivate() ); } public function testGetPrivateMethodInvokerWithObject(): void { - $obj = new __TestForReflectionHelper(); + $obj = new TestForReflectionHelper(); $method = $this->getPrivateMethodInvoker( $obj, 'privateMethod' @@ -81,7 +83,7 @@ public function testGetPrivateMethodInvokerWithObject(): void public function testGetPrivateMethodInvokerWithStatic(): void { $method = $this->getPrivateMethodInvoker( - __TestForReflectionHelper::class, + TestForReflectionHelper::class, 'privateStaticMethod' ); $this->assertSame( @@ -90,29 +92,3 @@ public function testGetPrivateMethodInvokerWithStatic(): void ); } } - -class __TestForReflectionHelper -{ - private string $private = 'secret'; - private static string $static_private = 'xyz'; - - public function getPrivate() - { - return $this->private; - } - - public static function getStaticPrivate() - { - return self::$static_private; - } - - private function privateMethod($param1, $param2) - { - return 'private ' . $param1 . $param2; - } - - private static function privateStaticMethod($param1, $param2) - { - return 'private_static ' . $param1 . $param2; - } -} diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index 2bb19999de39..ea71ddd0ac48 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -15,6 +15,7 @@ use CodeIgniter\Events\Events; use CodeIgniter\HTTP\Response; use Config\App; +use Tests\Support\Test\TestForReflectionHelper; /** * @internal @@ -35,7 +36,7 @@ protected function setUp(): void public function testGetPrivatePropertyWithObject(): void { - $obj = new __TestForReflectionHelper(); + $obj = new TestForReflectionHelper(); $actual = $this->getPrivateProperty($obj, 'private'); $this->assertSame('secret', $actual); } From 66ea5298f04a117bd9aefed7df7d6f731f0950e4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Dec 2023 08:02:07 +0900 Subject: [PATCH 240/380] docs: remove space --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index ff449c9e6fb9..1eb0a6873da3 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -222,7 +222,7 @@ Traditional Rules ----------------- .. important:: Traditional Rules exist only for backward compatibility. Do not - use them in new projects. Even if you are already using them, we recommend + use them in new projects. Even if you are already using them, we recommend switching to Strict Rules. .. warning:: When validating data that contains non-string values, such as JSON data, it is recommended to use **Strict Rules**. From 330b27674e62a4acf4cc481109f0d121a08e109a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Dec 2023 08:02:18 +0900 Subject: [PATCH 241/380] docs: improve description --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 1eb0a6873da3..497a682d5f0a 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -525,7 +525,7 @@ replaced by the **value** of the matched incoming field. An example should clari :lines: 2- .. note:: Since v4.3.5, you must set the validation rules for the placeholder - field (``id``). + field (the ``id`` field in the sample code above) for security. In this set of rules, it states that the email address should be unique in the database, except for the row that has an id matching the placeholder's value. Assuming that the form POST data had the following: From ad92ce63280df258af8bee1155333da09a95d400 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Dec 2023 09:47:12 +0900 Subject: [PATCH 242/380] docs: add note for http_errors --- user_guide_src/source/libraries/curlrequest.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index ebfd1934c88f..d2beda913f41 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -83,6 +83,10 @@ a Response instance to you. This takes the HTTP method, the url and an array of .. literalinclude:: curlrequest/005.php +.. important:: By default, CURLRequest will throw ``HTTPException`` if the HTTP + code returned is greater than or equal to 400. If you want to get the response, + see the `http_errors`_ option. + .. note:: When ``$shareOptions`` is false, the options passed to the method will be used for the request. After sending the request, they will be cleared. If you want to use the options to all requests, pass the options in the constructor. Since the response is an instance of ``CodeIgniter\HTTP\Response`` you have all of the normal information From 625db4b99c39dce0643405192e9e245785c1d12a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Dec 2023 09:53:17 +0900 Subject: [PATCH 243/380] docs: remove itailc --- user_guide_src/source/libraries/curlrequest.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index d2beda913f41..bc2a7e3ab36a 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -116,12 +116,12 @@ examples of how the combinations are resolved. ===================== ================ ======================== baseURI URI Result ===================== ================ ======================== - `http://foo.com` /bar `http://foo.com/bar` - `http://foo.com/foo` /bar `http://foo.com/bar` - `http://foo.com/foo` bar `http://foo.com/bar` - `http://foo.com/foo/` bar `http://foo.com/foo/bar` - `http://foo.com` `http://baz.com` `http://baz.com` - `http://foo.com/?bar` bar `http://foo.com/bar` + \http://foo.com /bar \http://foo.com/bar + \http://foo.com/foo /bar \http://foo.com/bar + \http://foo.com/foo bar \http://foo.com/bar + \http://foo.com/foo/ bar \http://foo.com/foo/bar + \http://foo.com \http://baz.com \http://baz.com + \http://foo.com/?bar bar \http://foo.com/bar ===================== ================ ======================== Using Responses From b8166540b4f0a8b78459401fb029eb648da260b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Dec 2023 10:32:14 +0900 Subject: [PATCH 244/380] docs: fix markdown Tags can be used in markdown. So PhpStorm did not render `