diff --git a/.github/mergeable.yml b/.github/mergeable.yml
index 95766c23fcee..d20aa796f5d0 100644
--- a/.github/mergeable.yml
+++ b/.github/mergeable.yml
@@ -32,3 +32,38 @@ mergeable:
Sincerely, the mergeable bot 🤖
- do: close
+
+ - when: pull_request.opened, pull_request.ready_for_review
+ filter:
+ - do: payload
+ pull_request:
+ author_association:
+ must_include:
+ regex: ^NONE|FIRST_TIME_CONTRIBUTOR|FIRST_TIMER$
+ validate: []
+ pass:
+ - do: comment
+ payload:
+ body: |
+ Hi there, @@author! :wave:
+
+ Thank you for sending this PR!
+
+ We expect the following in all Pull Requests (PRs).
+ - PRs must be sent to the [appropriate branch](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#branching)
+ - All git commits must be [GPG-signed](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#signing)
+ - Must follow our [style guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#php-style)
+ - Be [commented](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#comments) in the PHP source file
+ - Be documented in the [user guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#user-guide)
+ - Be [unit tested](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#unit-testing)
+ - Pass all checks in GitHub Actions
+
+ > [!IMPORTANT]
+ > We expect all code changes or bug-fixes to be accompanied by one or more tests added to our test suite to prove the code works.
+
+ If pull requests do not comply with the above, they will likely be closed. Since we are a team of volunteers, we don't have any more time to work
+ on the framework than you do. Please make it as painless for your contributions to be included as possible.
+
+ See https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md
+
+ Sincerely, the mergeable bot 🤖
diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml
index fb9665327578..ca77c6a08c26 100644
--- a/.github/workflows/deploy-apidocs.yml
+++ b/.github/workflows/deploy-apidocs.yml
@@ -49,7 +49,7 @@ jobs:
- name: Download latest phpDocumentor
working-directory: source
- run: phive --no-progress install --trust-gpg-keys 8AC0BAA79732DD42 phpDocumentor
+ run: phive --no-progress install --trust-gpg-keys 6DA3ACC4991FFAE5 phpDocumentor
- name: Prepare API repo
working-directory: api
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 876a767edb70..3556e750e802 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,39 @@
# Changelog
+## [v4.6.1](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.0) (2025-05-02)
+[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.6.0...v4.6.1)
+
+### Fixed Bugs
+* fix(CURLRequest): multiple header sections after redirects by @ducng99 in https://github.com/codeigniter4/CodeIgniter4/pull/9426
+* fix: set headers for CORS by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9437
+* fix: upsert with composite unique index by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9454
+* fix: `getVersion()` for OCI8 and SQLSRV drivers by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9471
+* fix: Toolbar when `maxHistory` is set to `0` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9506
+* fix: `Session::markAsTempdata()` adding wrong TTL by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9536
+* fix: added "application/octet-stream" to the "stl" mime type in the M… by @Franky5831 in https://github.com/codeigniter4/CodeIgniter4/pull/9543
+
+### Refactoring
+* refactor: get upper first protocol only one call in Email by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9449
+* refactor: PHPDocs in `env()` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9468
+* refactor: remove lowercase event name for logging by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9483
+* refactor: OCI8 `limit()` method by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9472
+* refactor: deprecate redundant `FileHandler` cache methods by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9511
+* refactor: fix `variable.undefined` (and other) errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9513
+* refactor: fix `return.unusedType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9514
+* refactor: add `CITestStreamFilter` to phpstan-analysed list and fix errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9515
+* refactor: fix `property.protected` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9517
+* refactor: fix `function.alreadyNarrowedType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9518
+* refactor: fix `empty.property` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9519
+* refactor: import FQCNs by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9520
+* refactor: fix `isset.property` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9522
+* refactor: fix `missingType.return` errors by @warcooft in https://github.com/codeigniter4/CodeIgniter4/pull/9523
+* refactor: fix `nullCoalesce.variable` errors by @warcooft in https://github.com/codeigniter4/CodeIgniter4/pull/9524
+* refactor: fix phpstan errors in `URI` and `SiteURI` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9525
+* refactor: fix `@readonly` property errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9529
+* refactor: fix `missingType.return` errors in system files by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9530
+* refactor: fix `codeigniter.modelArgumentType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9533
+* refactor: fix `Session` and `SessionInterface` code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9535
+
## [v4.6.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.0) (2025-01-19)
[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.8...v4.6.0)
diff --git a/admin/RELEASE.md b/admin/RELEASE.md
index 9ed91e55c183..697af85ff712 100644
--- a/admin/RELEASE.md
+++ b/admin/RELEASE.md
@@ -3,6 +3,7 @@
> Documentation guide based on the releases of `4.0.5` and `4.1.0` on January 31, 2021.
>
> Updated for `4.5.0` on April 7, 2024.
+> Updated for `4.6.0` on January 19, 2025.
>
> -MGatner, kenjis
@@ -33,10 +34,12 @@ git push upstream HEAD
If you release a new minor version.
-* [ ] Create PR to merge `4.y` into `develop` and merge it
+* [ ] Create PR to merge `4.y` into `develop`:
+ * Title: `4.y.0 Merge code`
+ * Description: blank
* [ ] Rename the current minor version (e.g., `4.5`) in Setting > Branches >
- "Branch protection rules" to the next minor version. E.g. `4.5` → `4.6`
-* [ ] Delete the merged `4.y` branch (This closes all PRs to the branch)
+ "Branch protection rules" to the next minor version (e.g. `4.5` → `4.6`).
+* [ ] Delete the merged `4.y` branch (this closes all PRs to the branch).
## Preparation
@@ -60,7 +63,7 @@ Work off direct clones of the repos so the release branches persist for a time.
## Changelog
-When generating the changelog each Pull Request to be included must have one of
+When generating the changelog, each pull request to be included must have one of
the following [labels](https://github.com/codeigniter4/CodeIgniter4/labels):
- **bug** ... PRs that fix bugs
- **enhancement** ... PRs to improve existing functionalities
@@ -72,11 +75,11 @@ PRs with breaking changes must have the following additional label:
### Generate Changelog
-To auto-generate, navigate to the
+To auto-generate the changelog, navigate to the
[Releases](https://github.com/codeigniter4/CodeIgniter4/releases) page,
click the "Draft a new release" button.
-* Tag: `v4.x.x` (Create new tag)
+* Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish)
* Target: `develop`
Click the "Generate release notes" button.
@@ -85,7 +88,7 @@ Check the resulting content. If there are items in the *Others* section which
should be included in the changelog, add a label to the PR and regenerate
the changelog.
-Copy the resulting content into **CHANGELOG.md** and adjust the format to match
+Copy the resulting contents into **CHANGELOG.md** and adjust the format to match
the existing content.
## Process
@@ -95,23 +98,27 @@ the existing content.
> been included with their PR, so this process assumes you will not be
> generating much new content.
-* [ ] Merge any Security Advisory PRs in private forks
-* [ ] Replace **CHANGELOG.md** with the new version generated above
+* [ ] Merge any security advisory PRs in private forks.
+* [ ] Add the current version to **CHANGELOG.md** with the contents generated above.
* [ ] Update **user_guide_src/source/changelogs/v4.x.x.rst**
* Remove the section titles that have no items
* [ ] Update **user_guide_src/source/installation/upgrade_4xx.rst**
- * [ ] fill in the "All Changes" section, and add it to **upgrade_4xx.rst**
- * git diff --name-status origin/master -- . ':!system' ':!tests' ':!user_guide_src'
- * Note: `tests/` is not used for distribution repos. See `admin/starter/tests/`
+ * [ ] fill in the "All Changes" section using the following command, and add it to **upgrade_4xx.rst**:
+ ```
+ git diff --name-status origin/master -- . ':!.github/' ':!admin/' ':!system/' ':!tests/' \
+ ':!user_guide_src/' ':!utils/' ':!*.json' ':!*.xml' ':!*.dist' ':!rector.php' \
+ ':!phpstan*' ':!psalm*' ':!.php-cs-fixer.*' ':!LICENSE' ':!CHANGELOG.md'
+ ```
+ * Note: `tests/` is not used for distribution repos. See `admin/starter/tests/`.
* [ ] Remove the section titles that have no items
- * [ ] [Minor version only] Update the "from" version in the title. E.g., `from 4.3.x` → `from 4.3.8`
-* [ ] Run `php admin/prepare-release.php 4.x.x` and push to origin
+ * [ ] [Minor version only] Update the "from" version in the title, (e.g., `from 4.3.x` → `from 4.3.8`).
+* [ ] Run `php admin/prepare-release.php 4.x.x` and push to origin.
* The above command does the following:
* Create a new branch `release-4.x.x`
* Update **system/CodeIgniter.php** with the new version number:
`const CI_VERSION = '4.x.x';`
- * Update **user_guide_src/source/conf.py** with the new `version = '4.x'` (if applicable)
- and `release = '4.x.x'`
+ * Update **user_guide_src/source/conf.py** with the new `version = '4.x'` (if releasing
+ the minor version) and `release = '4.x.x'`.
* Update **user_guide_src/source/changelogs/{version}.rst**
* Set the date to format `Release Date: January 31, 2021`
* Update **phpdoc.dist.xml** with the new `
CodeIgniter v4.x API`
@@ -126,15 +133,17 @@ the existing content.
Previous version: #xxxx
Release Code: TODO
New Changelog: TODO
- ```
+
(plus checklist)
-* [ ] Let all tests run, then review and merge the PR
+ ```
+
+* [ ] Let all tests run, then review and merge the PR.
* [ ] Create a new PR from `develop` to `master`:
* Title: `4.x.x Ready code`
* Description: blank
* [ ] Merge the PR and wait for all tests.
* [ ] Create a new Release:
- * Tag: `v4.x.x` (Create new tag)
+ * Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish)
* Target: `master`
* Title: `CodeIgniter 4.x.x`
* Description:
@@ -167,31 +176,31 @@ the existing content.
created when v4.3.8 was released.
* [ ] Fast-forward `develop` branch to catch the merge commit from `master`
```console
- git fetch origin
+ git fetch upstream
git checkout develop
- git merge origin/develop
- git merge origin/master
- git push origin HEAD
+ git merge upstream/develop
+ git merge upstream/master
+ git push upstream HEAD
```
* [ ] Update the next minor version branch `4.y`:
```console
- git fetch origin
- git checkout 4.y
- git merge origin/4.y
- git merge origin/develop
- git push origin HEAD
+ git fetch upstream
+ git switch 4.y
+ git merge upstream/4.y
+ git merge upstream/develop
+ git push upstream HEAD
```
* [ ] [Minor version only] Create the new next minor version branch `4.z`:
```console
- git fetch origin
+ git fetch upstream
git switch develop
git switch -c 4.z
- git push origin HEAD
+ git push upstream HEAD
```
-* [ ] Request CVEs and Publish any Security Advisories that were resolved from private forks
- (note: publishing is restricted to administrators):
+* [ ] Request CVEs and publish any security advisories that were resolved from private forks
+ (note: publishing is restricted to administrators).
* [ ] Announce the release on the forums and Slack channel
- (note: this forum is restricted to administrators):
+ (note: this forum is restricted to administrators).
* Make a new topic in the "News & Discussion" forums:
https://forum.codeigniter.com/forum-2.html
* The content is somewhat organic, but should include any major features and
diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss
index eec3d25546e3..65f4b802e22c 100644
--- a/admin/css/debug-toolbar/toolbar.scss
+++ b/admin/css/debug-toolbar/toolbar.scss
@@ -457,6 +457,31 @@
}
}
+@media screen and (max-width: 768px) {
+ #debug-bar {
+ table {
+ display: block;
+ overflow-x: auto;
+ font-size: 12px;
+ margin: 5px 5px 10px 5px;
+
+ td,
+ th {
+ padding: 4px 6px;
+ }
+ }
+
+ .timeline {
+ display: block;
+ white-space: nowrap;
+ font-size: 12px;
+ }
+
+ .toolbar {
+ overflow-x: auto;
+ }
+ }
+ }
// THEMES
// ========================================================================== */
diff --git a/admin/framework/.gitignore b/admin/framework/.gitignore
index 8071bd3d07f8..e24e7ce497d1 100644
--- a/admin/framework/.gitignore
+++ b/admin/framework/.gitignore
@@ -100,15 +100,15 @@ _modules/*
.idea/
*.iml
-# Netbeans
-nbproject/
-build/
-nbbuild/
-dist/
-nbdist/
-nbactions.xml
-nb-configuration.xml
-.nb-gradle/
+# NetBeans
+/nbproject/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/nbactions.xml
+/nb-configuration.xml
+/.nb-gradle/
# Sublime Text
*.tmlanguage.cache
diff --git a/admin/starter/.gitignore b/admin/starter/.gitignore
index 8071bd3d07f8..e24e7ce497d1 100644
--- a/admin/starter/.gitignore
+++ b/admin/starter/.gitignore
@@ -100,15 +100,15 @@ _modules/*
.idea/
*.iml
-# Netbeans
-nbproject/
-build/
-nbbuild/
-dist/
-nbdist/
-nbactions.xml
-nb-configuration.xml
-.nb-gradle/
+# NetBeans
+/nbproject/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/nbactions.xml
+/nb-configuration.xml
+/.nb-gradle/
# Sublime Text
*.tmlanguage.cache
diff --git a/admin/starter/tests/_support/Libraries/ConfigReader.php b/admin/starter/tests/_support/Libraries/ConfigReader.php
index 40d057acbe22..0bb4a8fcf598 100644
--- a/admin/starter/tests/_support/Libraries/ConfigReader.php
+++ b/admin/starter/tests/_support/Libraries/ConfigReader.php
@@ -2,6 +2,8 @@
namespace Tests\Support\Libraries;
+use Config\App;
+
/**
* Class ConfigReader
*
@@ -9,7 +11,7 @@
* loading external values. Used to read actual local values from
* a config file.
*/
-class ConfigReader extends \Config\App
+class ConfigReader extends App
{
public function __construct()
{
diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php
index 76cd9263556e..9a928241a0eb 100644
--- a/app/Config/Autoload.php
+++ b/app/Config/Autoload.php
@@ -17,8 +17,6 @@
*
* NOTE: This class is required prior to Autoloader instantiation,
* and does not extend BaseConfig.
- *
- * @immutable
*/
class Autoload extends AutoloadConfig
{
diff --git a/app/Config/Cache.php b/app/Config/Cache.php
index 9ae2e843ac91..e6efa3acf6f5 100644
--- a/app/Config/Cache.php
+++ b/app/Config/Cache.php
@@ -108,6 +108,7 @@ class Cache extends BaseConfig
* -------------------------------------------------------------------------
* Redis settings
* -------------------------------------------------------------------------
+ *
* Your Redis server can be specified below, if you are using
* the Redis or Predis drivers.
*
diff --git a/app/Config/DocTypes.php b/app/Config/DocTypes.php
index 7e8aaacf09dd..788d68fdc117 100644
--- a/app/Config/DocTypes.php
+++ b/app/Config/DocTypes.php
@@ -2,9 +2,6 @@
namespace Config;
-/**
- * @immutable
- */
class DocTypes
{
/**
diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php
index 7722444abe7b..c2db7340cd7e 100644
--- a/app/Config/Mimes.php
+++ b/app/Config/Mimes.php
@@ -3,8 +3,6 @@
namespace Config;
/**
- * Mimes
- *
* This file contains an array of mime types. It is used by the
* Upload class to help identify allowed file types.
*
@@ -15,8 +13,6 @@
*
* When working with mime types, please make sure you have the ´fileinfo´
* extension enabled to reliably detect the media types.
- *
- * @immutable
*/
class Mimes
{
@@ -482,6 +478,8 @@ class Mimes
'application/sla',
'application/vnd.ms-pki.stl',
'application/x-navistyle',
+ 'model/stl',
+ 'application/octet-stream',
],
];
diff --git a/app/Config/Modules.php b/app/Config/Modules.php
index 8d4bf56544b0..9e03fa491260 100644
--- a/app/Config/Modules.php
+++ b/app/Config/Modules.php
@@ -9,8 +9,6 @@
*
* NOTE: This class is required prior to Autoloader instantiation,
* and does not extend BaseConfig.
- *
- * @immutable
*/
class Modules extends BaseModules
{
diff --git a/app/Config/Optimize.php b/app/Config/Optimize.php
index 6fb441fd2288..481e645f57b2 100644
--- a/app/Config/Optimize.php
+++ b/app/Config/Optimize.php
@@ -7,8 +7,6 @@
*
* NOTE: This class does not extend BaseConfig for performance reasons.
* So you cannot replace the property values with Environment Variables.
- *
- * @immutable
*/
class Optimize
{
diff --git a/app/Config/Paths.php b/app/Config/Paths.php
index 262c745ffa95..3dc9c5d93951 100644
--- a/app/Config/Paths.php
+++ b/app/Config/Paths.php
@@ -15,8 +15,6 @@
*
* NOTE: This class is required prior to Autoloader instantiation,
* and does not extend BaseConfig.
- *
- * @immutable
*/
class Paths
{
diff --git a/app/Views/errors/html/debug.css b/app/Views/errors/html/debug.css
index b20f36a53ce2..b8539a420221 100644
--- a/app/Views/errors/html/debug.css
+++ b/app/Views/errors/html/debug.css
@@ -3,7 +3,7 @@
--main-text-color: #555;
--dark-text-color: #222;
--light-text-color: #c7c7c7;
- --brand-primary-color: #E06E3F;
+ --brand-primary-color: #DC4814;
--light-bg-color: #ededee;
--dark-bg-color: #404040;
}
@@ -71,7 +71,7 @@ p.lead {
text-align: center;
padding: calc(4px + 0.2083vw);
width: 100%;
- margin-top: -2.14rem;
+ top: 0;
position: fixed;
}
diff --git a/composer.json b/composer.json
index c762845f9a7e..1f07772400f4 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
"psr/log": "^3.0"
},
"require-dev": {
- "codeigniter/phpstan-codeigniter": "^1.5.1",
+ "codeigniter/phpstan-codeigniter": "1.x-dev",
"fakerphp/faker": "^1.24",
"kint-php/kint": "^6.0",
"mikey179/vfsstream": "^1.6.12",
@@ -28,7 +28,7 @@
"phpunit/phpcov": "^9.0.2 || ^10.0",
"phpunit/phpunit": "^10.5.16 || ^11.2",
"predis/predis": "^1.1 || ^2.3",
- "rector/rector": "2.0.6",
+ "rector/rector": "2.0.14",
"shipmonk/phpstan-baseline-per-identifier": "^2.0"
},
"replace": {
@@ -81,8 +81,7 @@
},
"extra": {
"branch-alias": {
- "dev-develop": "4.x-dev",
- "dev-master": "4.x-dev"
+ "dev-*": "4.6.x-dev"
}
},
"scripts": {
diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml
index 533ad3e033f0..07612e40acf8 100644
--- a/phpdoc.dist.xml
+++ b/phpdoc.dist.xml
@@ -10,7 +10,7 @@
api/cache/
-
+ system
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index 999972f556b8..e6cc288cc678 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -1,45 +1,50 @@
includes:
- - utils/phpstan-baseline/loader.neon
+ - utils/phpstan-baseline/loader.neon
parameters:
- phpVersion: 80100
- tmpDir: build/phpstan
- level: 6
- bootstrapFiles:
- - phpstan-bootstrap.php
- paths:
- - admin/starter/tests
- - app
- - system
- - tests
- excludePaths:
- - app/Views/errors/cli/*
- - app/Views/errors/html/*
- - system/Commands/Generators/Views/*
- - system/Debug/Toolbar/Views/toolbar.tpl.php
- - system/Images/Handlers/GDHandler.php
- - system/Test/Filters/CITestStreamFilter.php
- - system/ThirdParty/*
- - system/Validation/Views/single.php
- - tests/system/View/Views/*
- scanDirectories:
- - system/Helpers
- ignoreErrors:
- -
- identifier: missingType.generics
- checkMissingCallableSignature: true
- treatPhpDocTypesAsCertain: false
- strictRules:
- allRules: false
- disallowedLooseComparison: true
- booleansInConditions: true
- disallowedBacktick: true
- disallowedEmpty: true
- disallowedImplicitArrayCreation: true
- disallowedShortTernary: true
- matchingInheritedMethodNames: true
- codeigniter:
- additionalServices:
- - AfterAutoloadModule\Config\Services
- shipmonkBaselinePerIdentifier:
- directory: %currentWorkingDirectory%
+ phpVersion: 80100
+ tmpDir: build/phpstan
+ level: 6
+ bootstrapFiles:
+ - phpstan-bootstrap.php
+ paths:
+ - admin/starter/tests
+ - app
+ - system
+ - tests
+ excludePaths:
+ analyseAndScan:
+ - app/Views/errors/cli/*
+ - app/Views/errors/html/*
+ - system/Commands/Generators/Views/*
+ - system/Debug/Toolbar/Views/toolbar.tpl.php
+ - system/Images/Handlers/GDHandler.php
+ - system/ThirdParty/*
+ - system/Validation/Views/single.php
+ - tests/system/View/Views/*
+ analyse:
+ - tests/_support/*
+ scanDirectories:
+ - system/Helpers
+ ignoreErrors:
+ -
+ identifier: missingType.generics
+ checkMissingCallableSignature: true
+ treatPhpDocTypesAsCertain: false
+ strictRules:
+ allRules: false
+ disallowedLooseComparison: true
+ booleansInConditions: true
+ disallowedBacktick: true
+ disallowedEmpty: true
+ disallowedImplicitArrayCreation: true
+ disallowedShortTernary: true
+ matchingInheritedMethodNames: true
+ codeigniter:
+ additionalServices:
+ - AfterAutoloadModule\Config\Services
+ additionalModelNamespaces:
+ - Tests\Support\Models
+ checkArgumentTypeOfModel: false
+ shipmonkBaselinePerIdentifier:
+ directory: %currentWorkingDirectory%
diff --git a/preload.php b/preload.php
index 0b453122345e..86322d5e7137 100644
--- a/preload.php
+++ b/preload.php
@@ -9,6 +9,9 @@
* the LICENSE file that was distributed with this source code.
*/
+use CodeIgniter\Boot;
+use Config\Paths;
+
/*
*---------------------------------------------------------------
* Sample file for Preloading
@@ -69,10 +72,10 @@ public function __construct()
private function loadAutoloader(): void
{
- $paths = new Config\Paths();
+ $paths = new Paths();
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php';
- CodeIgniter\Boot::preload($paths);
+ Boot::preload($paths);
}
/**
diff --git a/public/index.php b/public/index.php
index eb7f5c988838..a0a20db43dbf 100644
--- a/public/index.php
+++ b/public/index.php
@@ -1,5 +1,8 @@
systemDirectory . '/Boot.php';
-exit(CodeIgniter\Boot::bootWeb($paths));
+exit(Boot::bootWeb($paths));
diff --git a/rector.php b/rector.php
index ffa21b4e663e..b8b5e1ccc73f 100644
--- a/rector.php
+++ b/rector.php
@@ -18,7 +18,6 @@
use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector;
use Rector\CodeQuality\Rector\FuncCall\CompactToVariablesRector;
use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector;
-use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector;
use Rector\CodeQuality\Rector\Ternary\TernaryEmptyArrayArrayDimFetchToCoalesceRector;
use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector;
use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector;
@@ -36,6 +35,7 @@
use Rector\Php70\Rector\FuncCall\RandomFunctionRector;
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector;
+use Rector\PHPUnit\CodeQuality\Rector\Class_\RemoveDataProviderParamKeysRector;
use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector;
use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector;
use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
@@ -45,7 +45,6 @@
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;
use Rector\TypeDeclaration\Rector\Closure\AddClosureVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\Closure\ClosureReturnTypeRector;
-use Rector\TypeDeclaration\Rector\Empty_\EmptyOnNullableObjectToInstanceOfRector;
use Rector\TypeDeclaration\Rector\Function_\AddFunctionVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector;
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;
@@ -168,6 +167,8 @@
NullToStrictStringFuncCallArgRector::class,
CompactToVariablesRector::class,
+
+ RemoveDataProviderParamKeysRector::class,
])
// auto import fully qualified class names
->withImportNames(removeUnusedImports: true)
@@ -189,7 +190,6 @@
MakeInheritedMethodVisibilitySameAsParentRector::class,
SimplifyEmptyCheckOnEmptyArrayRector::class,
TernaryEmptyArrayArrayDimFetchToCoalesceRector::class,
- EmptyOnNullableObjectToInstanceOfRector::class,
DisallowedEmptyRuleFixerRector::class,
PrivatizeFinalClassPropertyRector::class,
BooleanInIfConditionRuleFixerRector::class,
@@ -199,7 +199,6 @@
AddMethodCallBasedStrictParamTypeRector::class,
TypedPropertyFromAssignsRector::class,
ClosureReturnTypeRector::class,
- FlipTypeControlToUseExclusiveTypeRector::class,
AddArrowFunctionReturnTypeRector::class,
])
->withConfiguredRule(StringClassNameToClassConstantRector::class, [
diff --git a/spark b/spark
index 856dc3f8a227..e7871ea8e682 100755
--- a/spark
+++ b/spark
@@ -10,6 +10,9 @@
* the LICENSE file that was distributed with this source code.
*/
+use CodeIgniter\Boot;
+use Config\Paths;
+
/*
* --------------------------------------------------------------------
* CODEIGNITER COMMAND-LINE TOOLS
@@ -76,9 +79,9 @@ chdir(FCPATH);
require FCPATH . '../app/Config/Paths.php';
// ^^^ Change this line if you move your application folder
-$paths = new Config\Paths();
+$paths = new Paths();
// LOAD THE FRAMEWORK BOOTSTRAP FILE
require $paths->systemDirectory . '/Boot.php';
-exit(CodeIgniter\Boot::bootSpark($paths));
+exit(Boot::bootSpark($paths));
diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php
index a88c673d5fc0..2e628f1590d6 100644
--- a/system/Autoloader/Autoloader.php
+++ b/system/Autoloader/Autoloader.php
@@ -123,7 +123,7 @@ public function initialize(Autoload $config, Modules $modules)
$this->files = $config->files;
}
- if (isset($config->helpers)) {
+ if ($config->helpers !== []) {
$this->helpers = [...$this->helpers, ...$config->helpers];
}
diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php
index 844ac7fc4cc9..13ecb817a56c 100644
--- a/system/Autoloader/FileLocator.php
+++ b/system/Autoloader/FileLocator.php
@@ -266,12 +266,6 @@ protected function getNamespaces()
return array_merge($namespaces, $system);
}
- /**
- * Find the qualified name of a file according to
- * the namespace of the first matched namespace path.
- *
- * @return false|string The qualified name or false if the path is not found
- */
public function findQualifiedNameFromPath(string $path)
{
$resolvedPath = realpath($path);
@@ -299,7 +293,9 @@ public function findQualifiedNameFromPath(string $path)
),
'\\',
);
+
// Remove the file extension (.php)
+ /** @var class-string */
$className = mb_substr($className, 0, -4);
if (in_array($className, $this->invalidClassnames, true)) {
diff --git a/system/Autoloader/FileLocatorInterface.php b/system/Autoloader/FileLocatorInterface.php
index 3a1112dd480e..8f6129abee17 100644
--- a/system/Autoloader/FileLocatorInterface.php
+++ b/system/Autoloader/FileLocatorInterface.php
@@ -62,7 +62,7 @@ public function search(string $path, string $ext = 'php', bool $prioritizeApp =
* Find the qualified name of a file according to
* the namespace of the first matched namespace path.
*
- * @return false|string The qualified name or false if the path is not found
+ * @return class-string|false The qualified name or false if the path is not found
*/
public function findQualifiedNameFromPath(string $path);
diff --git a/system/BaseModel.php b/system/BaseModel.php
index b0be872050c6..cf8df09998f3 100644
--- a/system/BaseModel.php
+++ b/system/BaseModel.php
@@ -121,9 +121,13 @@ abstract class BaseModel
protected ?DataConverter $converter = null;
/**
- * If this model should use "softDeletes" and
- * simply set a date when rows are deleted, or
- * do hard deletes.
+ * Determines whether the model should protect field names during
+ * mass assignment operations such as insert() and update().
+ *
+ * When set to true, only the fields explicitly defined in the $allowedFields
+ * property will be allowed for mass assignment. This helps prevent
+ * unintended modification of database fields and improves security
+ * by avoiding mass assignment vulnerabilities.
*
* @var bool
*/
diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php
index a21996507d55..b8ea4714f39b 100644
--- a/system/CLI/CLI.php
+++ b/system/CLI/CLI.php
@@ -107,12 +107,12 @@ class CLI
/**
* List of array segments.
*
- * @var array
+ * @var list
*/
protected static $segments = [];
/**
- * @var array
+ * @var array
*/
protected static $options = [];
@@ -944,6 +944,8 @@ public static function getSegment(int $index)
/**
* Returns the raw array of segments found.
+ *
+ * @return list
*/
public static function getSegments(): array
{
@@ -971,6 +973,8 @@ public static function getOption(string $name)
/**
* Returns the raw array of options found.
+ *
+ * @return array
*/
public static function getOptions(): array
{
diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php
index 732cb370382d..aecd22c3f348 100644
--- a/system/CLI/Commands.php
+++ b/system/CLI/Commands.php
@@ -21,13 +21,15 @@
/**
* Core functionality for running, listing, etc commands.
+ *
+ * @phpstan-type commands_list array, 'file': string, 'group': string,'description': string}>
*/
class Commands
{
/**
* The found commands.
*
- * @var array
+ * @var commands_list
*/
protected $commands = [];
@@ -52,6 +54,8 @@ public function __construct($logger = null)
/**
* Runs a command given
*
+ * @param array $params
+ *
* @return int Exit code
*/
public function run(string $command, array $params)
@@ -77,7 +81,7 @@ public function run(string $command, array $params)
/**
* Provide access to the list of commands.
*
- * @return array
+ * @return commands_list
*/
public function getCommands()
{
@@ -96,7 +100,7 @@ public function discoverCommands()
return;
}
- /** @var FileLocatorInterface $locator */
+ /** @var FileLocatorInterface */
$locator = service('locator');
$files = $locator->listFiles('Commands/');
@@ -109,6 +113,7 @@ public function discoverCommands()
// Loop over each file checking to see if a command with that
// alias exists in the class.
foreach ($files as $file) {
+ /** @var class-string|false */
$className = $locator->findQualifiedNameFromPath($file);
if ($className === false || ! class_exists($className)) {
@@ -122,7 +127,6 @@ public function discoverCommands()
continue;
}
- /** @var BaseCommand $class */
$class = new $className($this->logger, $this);
if (isset($class->group) && ! isset($this->commands[$class->name])) {
@@ -146,6 +150,8 @@ public function discoverCommands()
/**
* Verifies if the command being sought is found
* in the commands list.
+ *
+ * @param commands_list $commands
*/
public function verifyCommand(string $command, array $commands): bool
{
@@ -153,9 +159,9 @@ public function verifyCommand(string $command, array $commands): bool
return true;
}
- $message = lang('CLI.commandNotFound', [$command]);
-
+ $message = lang('CLI.commandNotFound', [$command]);
$alternatives = $this->getCommandAlternatives($command, $commands);
+
if ($alternatives !== []) {
if (count($alternatives) === 1) {
$message .= "\n\n" . lang('CLI.altCommandSingular') . "\n ";
@@ -175,11 +181,17 @@ public function verifyCommand(string $command, array $commands): bool
/**
* Finds alternative of `$name` among collection
* of commands.
+ *
+ * @param commands_list $collection
+ *
+ * @return list
*/
protected function getCommandAlternatives(string $name, array $collection): array
{
+ /** @var array */
$alternatives = [];
+ /** @var string $commandName */
foreach (array_keys($collection) as $commandName) {
$lev = levenshtein($name, $commandName);
diff --git a/system/CLI/Console.php b/system/CLI/Console.php
index 5cb8b57a0ad3..325eaa7b455c 100644
--- a/system/CLI/Console.php
+++ b/system/CLI/Console.php
@@ -38,14 +38,13 @@ public function run()
$appConfig = config(App::class);
Services::createRequest($appConfig, true);
// Load Routes
- Services::routes()->loadRoutes();
+ service('routes')->loadRoutes();
- $runner = Services::commands();
$params = array_merge(CLI::getSegments(), CLI::getOptions());
$params = $this->parseParamsForHelpOption($params);
$command = array_shift($params) ?? 'list';
- return $runner->run($command, $params);
+ return service('commands')->run($command, $params);
}
/**
@@ -75,6 +74,8 @@ public function showHeader(bool $suppress = false)
* If present, it will be found as `['help' => null]`.
* We'll remove that as an option from `$params` and
* unshift it as argument instead.
+ *
+ * @param array $params
*/
private function parseParamsForHelpOption(array $params): array
{
diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php
index 0a97a89f4862..4fd03e7921b0 100644
--- a/system/Cache/Handlers/FileHandler.php
+++ b/system/Cache/Handlers/FileHandler.php
@@ -63,6 +63,8 @@ public function __construct(Cache $config)
$this->mode = $config->file['mode'] ?? 0640;
$this->prefix = $config->prefix;
+
+ helper('filesystem');
}
/**
@@ -96,7 +98,7 @@ public function save(string $key, $value, int $ttl = 60)
'data' => $value,
];
- if ($this->writeFile($this->path . $key, serialize($contents))) {
+ if (write_file($this->path . $key, serialize($contents))) {
try {
chmod($this->path . $key, $this->mode);
@@ -176,7 +178,7 @@ public function decrement(string $key, int $offset = 1)
*/
public function clean()
{
- return $this->deleteFiles($this->path, false, true);
+ return delete_files($this->path, false, true);
}
/**
@@ -184,7 +186,7 @@ public function clean()
*/
public function getCacheInfo()
{
- return $this->getDirFileInfo($this->path);
+ return get_dir_file_info($this->path);
}
/**
@@ -251,6 +253,8 @@ protected function getItem(string $filename)
/**
* Writes a file to disk, or returns false if not successful.
*
+ * @deprecated 4.6.1 Use `write_file()` instead.
+ *
* @param string $path
* @param string $data
* @param string $mode
@@ -265,7 +269,9 @@ protected function writeFile($path, $data, $mode = 'wb')
flock($fp, LOCK_EX);
- for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) {
+ $result = 0;
+
+ for ($written = 0, $length = strlen($data); $written < $length; $written += $result) {
if (($result = fwrite($fp, substr($data, $written))) === false) {
break;
}
@@ -283,6 +289,8 @@ protected function writeFile($path, $data, $mode = 'wb')
* If the second parameter is set to TRUE, any directories contained
* within the supplied base directory will be nuked as well.
*
+ * @deprecated 4.6.1 Use `delete_files()` instead.
+ *
* @param string $path File path
* @param bool $delDir Whether to delete any directories found in the path
* @param bool $htdocs Whether to skip deleting .htaccess and index page files
@@ -318,6 +326,8 @@ protected function deleteFiles(string $path, bool $delDir = false, bool $htdocs
*
* Any sub-folders contained within the specified path are read as well.
*
+ * @deprecated 4.6.1 Use `get_dir_file_info()` instead.
+ *
* @param string $sourceDir Path to source
* @param bool $topLevelOnly Look only at the top level directory specified?
* @param bool $_recursion Internal variable to determine recursion status - do not use in calls
@@ -360,6 +370,8 @@ protected function getDirFileInfo(string $sourceDir, bool $topLevelOnly = true,
* Options are: name, server_path, size, date, readable, writable, executable, fileperms
* Returns FALSE if the file cannot be found.
*
+ * @deprecated 4.6.1 Use `get_file_info()` instead.
+ *
* @param string $file Path to file
* @param array|string $returnedValues Array or comma separated string of information returned
*
diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php
index 6cd43506bdb5..80c21e8559e8 100644
--- a/system/Cache/Handlers/RedisHandler.php
+++ b/system/Cache/Handlers/RedisHandler.php
@@ -181,7 +181,7 @@ public function deleteMatching(string $pattern)
$iterator = null;
do {
- /** @var false|list|Redis $keys */
+ /** @var false|list $keys */
$keys = $this->redis->scan($iterator, $pattern);
if (is_array($keys)) {
diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php
index 35f97f748fce..2c89a5e2e4f1 100644
--- a/system/CodeIgniter.php
+++ b/system/CodeIgniter.php
@@ -55,7 +55,7 @@ class CodeIgniter
/**
* The current version of CodeIgniter Framework
*/
- public const CI_VERSION = '4.6.0';
+ public const CI_VERSION = '4.6.1';
/**
* App startup time.
@@ -948,7 +948,9 @@ protected function display404errors(PageNotFoundException $e)
$this->response->setStatusCode($e->getCode());
// Is there a 404 Override available?
- if ($override = $this->router->get404Override()) {
+ $override = $this->router->get404Override();
+
+ if ($override !== null) {
$returned = null;
if ($override instanceof Closure) {
diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php
index b7d7d585e945..b5e64ec1bce1 100644
--- a/system/Commands/Generators/MigrationGenerator.php
+++ b/system/Commands/Generators/MigrationGenerator.php
@@ -112,10 +112,7 @@ protected function prepare(string $class): string
$data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default';
$data['DBDriver'] = config(Database::class)->{$data['DBGroup']}['DBDriver'];
- /** @var SessionConfig|null $session */
- $session = config(SessionConfig::class);
-
- $data['matchIP'] = $session->matchIP;
+ $data['matchIP'] = config(SessionConfig::class)->matchIP;
}
return $this->parseTemplate($class, [], [], $data);
diff --git a/system/Commands/Utilities/ConfigCheck.php b/system/Commands/Utilities/ConfigCheck.php
index fa84cb287caa..4583c67dae87 100644
--- a/system/Commands/Utilities/ConfigCheck.php
+++ b/system/Commands/Utilities/ConfigCheck.php
@@ -73,7 +73,7 @@ final class ConfigCheck extends BaseCommand
protected $options = [];
/**
- * {@inheritDoc}
+ * @return int
*/
public function run(array $params)
{
diff --git a/system/Commands/Utilities/Environment.php b/system/Commands/Utilities/Environment.php
index 103591209d1e..22794fe9d51d 100644
--- a/system/Commands/Utilities/Environment.php
+++ b/system/Commands/Utilities/Environment.php
@@ -80,7 +80,7 @@ final class Environment extends BaseCommand
];
/**
- * {@inheritDoc}
+ * @return int
*/
public function run(array $params)
{
@@ -88,7 +88,7 @@ public function run(array $params)
CLI::write(sprintf('Your environment is currently set as %s.', CLI::color($_SERVER['CI_ENVIRONMENT'] ?? ENVIRONMENT, 'green')));
CLI::newLine();
- return;
+ return EXIT_ERROR;
}
$env = strtolower(array_shift($params));
@@ -98,21 +98,21 @@ public function run(array $params)
CLI::error('You will not be able to run spark under a "testing" environment.', 'light_gray', 'red');
CLI::newLine();
- return;
+ return EXIT_ERROR;
}
if (! in_array($env, self::$knownTypes, true)) {
CLI::error(sprintf('Invalid environment type "%s". Expected one of "%s".', $env, implode('" and "', self::$knownTypes)), 'light_gray', 'red');
CLI::newLine();
- return;
+ return EXIT_ERROR;
}
if (! $this->writeNewEnvironmentToEnvFile($env)) {
CLI::error('Error in writing new environment to .env file.', 'light_gray', 'red');
CLI::newLine();
- return;
+ return EXIT_ERROR;
}
// force DotEnv to reload the new environment
@@ -124,6 +124,8 @@ public function run(array $params)
CLI::write(sprintf('Environment is successfully changed to "%s".', $env), 'green');
CLI::write('The ENVIRONMENT constant will be changed in the next script execution.');
CLI::newLine();
+
+ return EXIT_SUCCESS;
}
/**
diff --git a/system/Commands/Utilities/Optimize.php b/system/Commands/Utilities/Optimize.php
index 11872bebafa5..1a103a1b9c52 100644
--- a/system/Commands/Utilities/Optimize.php
+++ b/system/Commands/Utilities/Optimize.php
@@ -55,7 +55,7 @@ final class Optimize extends BaseCommand
protected $usage = 'optimize';
/**
- * {@inheritDoc}
+ * @return int
*/
public function run(array $params)
{
@@ -63,13 +63,13 @@ public function run(array $params)
$this->enableCaching();
$this->clearCache();
$this->removeDevPackages();
+
+ return EXIT_SUCCESS;
} catch (RuntimeException) {
CLI::error('The "spark optimize" failed.');
return EXIT_ERROR;
}
-
- return EXIT_SUCCESS;
}
private function clearCache(): void
diff --git a/system/Commands/Utilities/PhpIniCheck.php b/system/Commands/Utilities/PhpIniCheck.php
index eb2192434133..f25518fb283d 100644
--- a/system/Commands/Utilities/PhpIniCheck.php
+++ b/system/Commands/Utilities/PhpIniCheck.php
@@ -68,7 +68,7 @@ final class PhpIniCheck extends BaseCommand
protected $options = [];
/**
- * {@inheritDoc}
+ * @return int
*/
public function run(array $params)
{
diff --git a/system/Common.php b/system/Common.php
index 7fb4c5964254..910ec9b1cc28 100644
--- a/system/Common.php
+++ b/system/Common.php
@@ -124,7 +124,6 @@ function clean_path(string $path): string
*/
function command(string $command)
{
- $runner = service('commands');
$regexString = '([^\s]+?)(?:\s|(? */
$params = [];
+ $command = array_shift($args);
$optionValue = false;
foreach ($args as $i => $arg) {
@@ -187,7 +187,7 @@ function command(string $command)
}
ob_start();
- $runner->run($command, $params);
+ service('commands')->run($command, $params);
return ob_get_clean();
}
@@ -371,9 +371,9 @@ function db_connect($db = null, bool $getShared = true)
* retrieving values set from the .env file for
* use in config files.
*
- * @param string|null $default
+ * @param array|bool|float|int|object|string|null $default
*
- * @return bool|string|null
+ * @return array|bool|float|int|object|string|null
*/
function env(string $key, $default = null)
{
diff --git a/system/ComposerScripts.php b/system/ComposerScripts.php
index 993483c5775a..1794e7ffe9eb 100644
--- a/system/ComposerScripts.php
+++ b/system/ComposerScripts.php
@@ -67,7 +67,7 @@ final class ComposerScripts
* This static method is called by Composer after every update event,
* i.e., `composer install`, `composer update`, `composer remove`.
*/
- public static function postUpdate()
+ public static function postUpdate(): void
{
self::recursiveDelete(self::$path);
diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php
index e056664e24be..ce6594d45d36 100644
--- a/system/Config/BaseConfig.php
+++ b/system/Config/BaseConfig.php
@@ -11,6 +11,7 @@
namespace CodeIgniter\Config;
+use CodeIgniter\Autoloader\FileLocatorInterface;
use CodeIgniter\Exceptions\ConfigException;
use CodeIgniter\Exceptions\RuntimeException;
use Config\Encryption;
@@ -252,6 +253,7 @@ protected function registerProperties()
static::$discovering = true;
+ /** @var FileLocatorInterface */
$locator = service('locator');
$registrarsFiles = $locator->search('Config/Registrar.php');
diff --git a/system/Config/Factories.php b/system/Config/Factories.php
index 797f9fd9c7de..ab5343d15fb8 100644
--- a/system/Config/Factories.php
+++ b/system/Config/Factories.php
@@ -13,6 +13,7 @@
namespace CodeIgniter\Config;
+use CodeIgniter\Autoloader\FileLocatorInterface;
use CodeIgniter\Database\ConnectionInterface;
use CodeIgniter\Exceptions\InvalidArgumentException;
use CodeIgniter\Model;
@@ -299,6 +300,7 @@ class_exists($alias, false)
}
// Have to do this the hard way...
+ /** @var FileLocatorInterface */
$locator = service('locator');
// Check if the class alias was namespaced
@@ -511,6 +513,12 @@ public static function getBasename(string $alias): string
/**
* Gets component data for caching.
*
+ * @return array{
+ * options: array,
+ * aliases: array,
+ * instances: array,
+ * }
+ *
* @internal For caching only
*/
public static function getComponentInstances(string $component): array
diff --git a/system/Config/Filters.php b/system/Config/Filters.php
index 562eae8a26ef..7eddc721bff6 100644
--- a/system/Config/Filters.php
+++ b/system/Config/Filters.php
@@ -113,6 +113,8 @@ class Filters extends BaseConfig
*
* Example:
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
+ *
+ * @var array>>
*/
public array $filters = [];
}
diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
index e10dd557fda0..cba7f5cbb8b4 100644
--- a/system/Database/BaseBuilder.php
+++ b/system/Database/BaseBuilder.php
@@ -3380,6 +3380,8 @@ public function resetQuery()
* Resets the query builder values. Called by the get() function
*
* @param array $qbResetItems An array of fields to reset
+ *
+ * @return void
*/
protected function resetRun(array $qbResetItems)
{
@@ -3390,6 +3392,8 @@ protected function resetRun(array $qbResetItems)
/**
* Resets the query builder values. Called by the get() function
+ *
+ * @return void
*/
protected function resetSelect()
{
@@ -3407,7 +3411,7 @@ protected function resetSelect()
'QBUnion' => [],
]);
- if (! empty($this->db)) {
+ if ($this->db instanceof BaseConnection) {
$this->db->setAliasedTables([]);
}
@@ -3421,6 +3425,8 @@ protected function resetSelect()
* Resets the query builder "write" values.
*
* Called by the insert() update() insertBatch() updateBatch() and delete() functions
+ *
+ * @return void
*/
protected function resetWrite()
{
diff --git a/system/Database/Config.php b/system/Database/Config.php
index 00d1b192cae3..6f25ad3c0059 100644
--- a/system/Database/Config.php
+++ b/system/Database/Config.php
@@ -18,8 +18,6 @@
use Config\Database as DbConfig;
/**
- * Class Config
- *
* @see \CodeIgniter\Database\ConfigTest
*/
class Config extends BaseConfig
@@ -141,6 +139,8 @@ public static function seeder(?string $group = null)
/**
* Ensures the database Connection Manager/Factory is loaded and ready to use.
+ *
+ * @return void
*/
protected static function ensureFactory()
{
diff --git a/system/Database/Exceptions/DataException.php b/system/Database/Exceptions/DataException.php
index a7ccd8c6f5c3..7cd9f526e6c2 100644
--- a/system/Database/Exceptions/DataException.php
+++ b/system/Database/Exceptions/DataException.php
@@ -65,21 +65,33 @@ public static function forInvalidArgument(string $argument)
return new static(lang('Database.invalidArgument', [$argument]));
}
+ /**
+ * @return DataException
+ */
public static function forInvalidAllowedFields(string $model)
{
return new static(lang('Database.invalidAllowedFields', [$model]));
}
+ /**
+ * @return DataException
+ */
public static function forTableNotFound(string $table)
{
return new static(lang('Database.tableNotFound', [$table]));
}
+ /**
+ * @return DataException
+ */
public static function forEmptyInputGiven(string $argument)
{
return new static(lang('Database.forEmptyInputGiven', [$argument]));
}
+ /**
+ * @return DataException
+ */
public static function forFindColumnHaveMultipleColumns()
{
return new static(lang('Database.forFindColumnHaveMultipleColumns'));
diff --git a/system/Database/Forge.php b/system/Database/Forge.php
index 53c819fb24c5..8405d9f7143f 100644
--- a/system/Database/Forge.php
+++ b/system/Database/Forge.php
@@ -984,6 +984,8 @@ protected function _processColumn(array $processedField): string
/**
* Performs a data type mapping between different databases.
+ *
+ * @return void
*/
protected function _attributeType(array &$attributes)
{
@@ -999,6 +1001,8 @@ protected function _attributeType(array &$attributes)
* if $attributes['TYPE'] is found in the array
* - array(TYPE => UTYPE) will change $field['type'],
* from TYPE to UTYPE in case of a match
+ *
+ * @return void
*/
protected function _attributeUnsigned(array &$attributes, array &$field)
{
@@ -1030,6 +1034,9 @@ protected function _attributeUnsigned(array &$attributes, array &$field)
$field['unsigned'] = ($this->unsigned === true) ? ' UNSIGNED' : '';
}
+ /**
+ * @return void
+ */
protected function _attributeDefault(array &$attributes, array &$field)
{
if ($this->default === false) {
@@ -1051,6 +1058,9 @@ protected function _attributeDefault(array &$attributes, array &$field)
}
}
+ /**
+ * @return void
+ */
protected function _attributeUnique(array &$attributes, array &$field)
{
if (! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === true) {
@@ -1058,6 +1068,9 @@ protected function _attributeUnique(array &$attributes, array &$field)
}
}
+ /**
+ * @return void
+ */
protected function _attributeAutoIncrement(array &$attributes, array &$field)
{
if (! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === true
@@ -1254,6 +1267,8 @@ protected function _processForeignKeys(string $table, bool $asQuery = false): ar
/**
* Resets table creation vars
+ *
+ * @return void
*/
public function reset()
{
diff --git a/system/Database/Migration.php b/system/Database/Migration.php
index ca9e5e0cf266..f3a1dc457629 100644
--- a/system/Database/Migration.php
+++ b/system/Database/Migration.php
@@ -64,11 +64,15 @@ public function getDBGroup(): ?string
/**
* Perform a migration step.
+ *
+ * @return void
*/
abstract public function up();
/**
* Revert a migration step.
+ *
+ * @return void
*/
abstract public function down();
}
diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php
index 32842916769d..fdff86589132 100644
--- a/system/Database/MigrationRunner.php
+++ b/system/Database/MigrationRunner.php
@@ -317,6 +317,8 @@ public function regress(int $targetBatch = 0, ?string $group = null)
*
* @param string $path Full path to a valid migration file
* @param string $path Namespace of the target migration
+ *
+ * @return bool
*/
public function force(string $path, string $namespace, ?string $group = null)
{
@@ -575,6 +577,8 @@ public function clearCliMessages()
/**
* Truncates the history table.
+ *
+ * @return void
*/
public function clearHistory()
{
@@ -587,6 +591,8 @@ public function clearHistory()
* Add a history to the table.
*
* @param object $migration
+ *
+ * @return void
*/
protected function addHistory($migration, int $batch)
{
@@ -614,6 +620,8 @@ protected function addHistory($migration, int $batch)
* Removes a single history
*
* @param object $history
+ *
+ * @return void
*/
protected function removeHistory($history)
{
@@ -752,6 +760,8 @@ public function getBatchEnd(int $batch): string
/**
* Ensures that we have created our migrations table
* in the database.
+ *
+ * @return void
*/
public function ensureTable()
{
diff --git a/system/Database/OCI8/Builder.php b/system/Database/OCI8/Builder.php
index 5b586761e2c0..2e62b3121cbd 100644
--- a/system/Database/OCI8/Builder.php
+++ b/system/Database/OCI8/Builder.php
@@ -48,16 +48,6 @@ class Builder extends BaseBuilder
*/
protected $countString = 'SELECT COUNT(1) ';
- /**
- * Limit used flag
- *
- * If we use LIMIT, we'll add a field that will
- * throw off num_fields later.
- *
- * @var bool
- */
- protected $limitUsed = false;
-
/**
* A reference to the database connection.
*
@@ -214,28 +204,13 @@ protected function _update(string $table, array $values): string
protected function _limit(string $sql, bool $offsetIgnore = false): string
{
$offset = (int) ($offsetIgnore === false ? $this->QBOffset : 0);
- if (version_compare($this->db->getVersion(), '12.1', '>=')) {
- // OFFSET-FETCH can be used only with the ORDER BY clause
- if (empty($this->QBOrderBy)) {
- $sql .= ' ORDER BY 1';
- }
- return $sql . ' OFFSET ' . $offset . ' ROWS FETCH NEXT ' . $this->QBLimit . ' ROWS ONLY';
+ // OFFSET-FETCH can be used only with the ORDER BY clause
+ if (empty($this->QBOrderBy)) {
+ $sql .= ' ORDER BY 1';
}
- $this->limitUsed = true;
- $limitTemplateQuery = 'SELECT * FROM (SELECT INNER_QUERY.*, ROWNUM RNUM FROM (%s) INNER_QUERY WHERE ROWNUM < %d)' . ($offset !== 0 ? ' WHERE RNUM >= %d' : '');
-
- return sprintf($limitTemplateQuery, $sql, $offset + $this->QBLimit + 1, $offset);
- }
-
- /**
- * Resets the query builder values. Called by the get() function
- */
- protected function resetSelect()
- {
- $this->limitUsed = false;
- parent::resetSelect();
+ return $sql . ' OFFSET ' . $offset . ' ROWS FETCH NEXT ' . $this->QBLimit . ' ROWS ONLY';
}
/**
diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php
index b6078febd030..67921d2c13f8 100644
--- a/system/Database/OCI8/Connection.php
+++ b/system/Database/OCI8/Connection.php
@@ -193,9 +193,14 @@ public function getVersion(): string
return $this->dataCache['version'];
}
- if (! $this->connID || ($versionString = oci_server_version($this->connID)) === false) {
+ if ($this->connID === false) {
+ $this->initialize();
+ }
+
+ if (($versionString = oci_server_version($this->connID)) === false) {
return '';
}
+
if (preg_match('#Release\s(\d+(?:\.\d+)+)#', $versionString, $match)) {
return $this->dataCache['version'] = $match[1];
}
diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php
index 27a72b58c333..8d0d569d5e28 100644
--- a/system/Database/Postgre/Builder.php
+++ b/system/Database/Postgre/Builder.php
@@ -469,9 +469,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
return ($index->type === 'UNIQUE' || $index->type === 'PRIMARY') && $hasAllFields;
});
- foreach (array_map(static fn ($index) => $index->fields, $allIndexes) as $index) {
- $constraints[] = current($index);
- // only one index can be used?
+ foreach ($allIndexes as $index) {
+ $constraints = $index->fields;
break;
}
diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php
index 06ef62a9f842..584c452b233d 100644
--- a/system/Database/Postgre/Connection.php
+++ b/system/Database/Postgre/Connection.php
@@ -517,6 +517,8 @@ public function insertID()
/**
* Build a DSN from the provided parameters
+ *
+ * @return void
*/
protected function buildDSN()
{
diff --git a/system/Database/Query.php b/system/Database/Query.php
index f0b75513c6b5..c74ba6a687ab 100644
--- a/system/Database/Query.php
+++ b/system/Database/Query.php
@@ -287,6 +287,8 @@ public function getOriginalQuery(): string
* Escapes and inserts any binds into the finalQueryString property.
*
* @see https://regex101.com/r/EUEhay/5
+ *
+ * @return void
*/
protected function compileBinds()
{
diff --git a/system/Database/QueryInterface.php b/system/Database/QueryInterface.php
index 19cbdd0edc4a..86eb01f4e169 100644
--- a/system/Database/QueryInterface.php
+++ b/system/Database/QueryInterface.php
@@ -26,7 +26,7 @@ interface QueryInterface
*
* @param mixed $binds
*
- * @return mixed
+ * @return $this
*/
public function setQuery(string $sql, $binds = null, bool $setEscape = true);
@@ -34,7 +34,7 @@ public function setQuery(string $sql, $binds = null, bool $setEscape = true);
* Returns the final, processed query string after binding, etal
* has been performed.
*
- * @return mixed
+ * @return string
*/
public function getQuery();
@@ -43,7 +43,7 @@ public function getQuery();
* for it's start and end values. If no end value is present, will
* use the current time to determine total duration.
*
- * @return mixed
+ * @return $this
*/
public function setDuration(float $start, ?float $end = null);
@@ -57,6 +57,8 @@ public function getDuration(int $decimals = 6): string;
/**
* Stores the error description that happened for this query.
+ *
+ * @return $this
*/
public function setError(int $code, string $error);
@@ -83,7 +85,7 @@ public function isWriteType(): bool;
/**
* Swaps out one table prefix for a new one.
*
- * @return mixed
+ * @return $this
*/
public function swapPrefix(string $orig, string $swap);
}
diff --git a/system/Database/ResultInterface.php b/system/Database/ResultInterface.php
index ba26629cd518..e6383cab6585 100644
--- a/system/Database/ResultInterface.php
+++ b/system/Database/ResultInterface.php
@@ -170,6 +170,8 @@ public function getFieldData(): array;
/**
* Frees the current result.
+ *
+ * @return void
*/
public function freeResult();
diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php
index c8e1e3fbee12..7ef4f31901d1 100644
--- a/system/Database/SQLSRV/Connection.php
+++ b/system/Database/SQLSRV/Connection.php
@@ -561,11 +561,15 @@ public function getVersion(): string
return $this->dataCache['version'];
}
- if (! $this->connID || ($info = sqlsrv_server_info($this->connID)) === []) {
+ if (! $this->connID) {
$this->initialize();
}
- return isset($info['SQLServerVersion']) ? $this->dataCache['version'] = $info['SQLServerVersion'] : false;
+ if (($info = sqlsrv_server_info($this->connID)) === []) {
+ return '';
+ }
+
+ return isset($info['SQLServerVersion']) ? $this->dataCache['version'] = $info['SQLServerVersion'] : '';
}
/**
diff --git a/system/Database/SQLite3/Builder.php b/system/Database/SQLite3/Builder.php
index 6e62907ac1aa..3aa13edeb96a 100644
--- a/system/Database/SQLite3/Builder.php
+++ b/system/Database/SQLite3/Builder.php
@@ -151,8 +151,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
return ($index->type === 'PRIMARY' || $index->type === 'UNIQUE') && $hasAllFields;
});
- foreach (array_map(static fn ($index) => $index->fields, $allIndexes) as $index) {
- $constraints[] = current($index);
+ foreach ($allIndexes as $index) {
+ $constraints = $index->fields;
break;
}
diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php
index 095d96a2d333..674d26b7d6f2 100644
--- a/system/Database/SQLite3/Table.php
+++ b/system/Database/SQLite3/Table.php
@@ -17,8 +17,6 @@
use stdClass;
/**
- * Class Table
- *
* Provides missing features for altering tables that are common
* in other supported databases, but are missing from SQLite.
* These are needed in order to support migrations during testing
@@ -345,6 +343,8 @@ protected function createTable()
* Copies data from our old table to the new one,
* taking care map data correctly based on any columns
* that have been renamed.
+ *
+ * @return void
*/
protected function copyData()
{
@@ -472,6 +472,8 @@ protected function formatKeys($keys)
/**
* Attempts to drop all indexes and constraints
* from the database for this table.
+ *
+ * @return void
*/
protected function dropIndexes()
{
diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php
index 3530592fe671..aacc8e9905ce 100644
--- a/system/Database/Seeder.php
+++ b/system/Database/Seeder.php
@@ -115,6 +115,8 @@ public static function faker(): ?Generator
/**
* Loads the specified seeder and runs it.
*
+ * @return void
+ *
* @throws InvalidArgumentException
*/
public function call(string $class)
diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php
index 9a884b60f5b3..7900c7c780c5 100644
--- a/system/Debug/Toolbar.php
+++ b/system/Debug/Toolbar.php
@@ -512,7 +512,7 @@ protected function format(string $data, string $format = 'html'): string
{
$data = json_decode($data, true);
- if ($this->config->maxHistory !== 0 && preg_match('/\d+\.\d{6}/s', (string) service('request')->getGet('debugbar_time'), $debugbarTime)) {
+ if (preg_match('/\d+\.\d{6}/s', (string) service('request')->getGet('debugbar_time'), $debugbarTime)) {
$history = new History();
$history->setFiles(
$debugbarTime[0],
diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css
index b9f13c51ff2e..abf61e9cca93 100644
--- a/system/Debug/Toolbar/Views/toolbar.css
+++ b/system/Debug/Toolbar/Views/toolbar.css
@@ -332,6 +332,26 @@
display: none !important;
}
}
+@media screen and (max-width: 768px) {
+ #debug-bar table {
+ display: block;
+ overflow-x: auto;
+ font-size: 12px;
+ margin: 5px 5px 10px 5px;
+ }
+ #debug-bar table td,
+ #debug-bar table th {
+ padding: 4px 6px;
+ }
+ #debug-bar .timeline {
+ display: block;
+ white-space: nowrap;
+ font-size: 12px;
+ }
+ #debug-bar .toolbar {
+ overflow-x: auto;
+ }
+}
#debug-icon {
background-color: #FFFFFF;
box-shadow: 0 0 4px #DFDFDF;
diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js
index 54fe3d69f106..ddaa2386f260 100644
--- a/system/Debug/Toolbar/Views/toolbar.js
+++ b/system/Debug/Toolbar/Views/toolbar.js
@@ -27,22 +27,25 @@ var ciDebugBar = {
.getElementById("debug-icon-link")
.addEventListener("click", ciDebugBar.toggleToolbar, true);
- // Allows to highlight the row of the current history request
- var btn = this.toolbar.querySelector(
- 'button[data-time="' + localStorage.getItem("debugbar-time") + '"]'
- );
- ciDebugBar.addClass(btn.parentNode.parentNode, "current");
-
historyLoad = this.toolbar.getElementsByClassName("ci-history-load");
- for (var i = 0; i < historyLoad.length; i++) {
- historyLoad[i].addEventListener(
- "click",
- function () {
- loadDoc(this.getAttribute("data-time"));
- },
- true
+ if (historyLoad.length) {
+ // Allows highlighting the row of the current history request
+ var btn = this.toolbar.querySelector(
+ 'button[data-time="' + localStorage.getItem("debugbar-time-new") + '"]'
);
+ ciDebugBar.addClass(btn.parentNode.parentNode, "current");
+
+
+ for (var i = 0; i < historyLoad.length; i++) {
+ historyLoad[i].addEventListener(
+ "click",
+ function () {
+ loadDoc(this.getAttribute("data-time"));
+ },
+ true
+ );
+ }
}
// Display the active Tab on page load
@@ -77,14 +80,14 @@ var ciDebugBar = {
links[i].addEventListener("click", function() {
ciDebugBar.toggleDataTable(datatable)
}, true);
-
+
} else if (toggleData === "childrows") {
let child = links[i].getAttribute("data-child");
links[i].addEventListener("click", function() {
ciDebugBar.toggleChildRows(child)
}, true);
-
+
} else {
links[i].addEventListener("click", ciDebugBar.toggleRows, true);
}
@@ -174,10 +177,10 @@ var ciDebugBar = {
);
if (target.classList.contains("debug-bar-ndisplay")) {
- ciDebugBar.switchClass(target, "debug-bar-ndisplay", "debug-bar-dtableRow");
+ ciDebugBar.switchClass(target, "debug-bar-ndisplay", "debug-bar-dtableRow");
} else {
ciDebugBar.switchClass(target, "debug-bar-dtableRow", "debug-bar-ndisplay");
- }
+ }
}
},
@@ -261,7 +264,7 @@ var ciDebugBar = {
} else {
ciDebugBar.switchClass(ciDebugBar.icon, "debug-bar-dinlineBlock", "debug-bar-ndisplay");
ciDebugBar.switchClass(ciDebugBar.toolbar, "debug-bar-ndisplay", "debug-bar-dinlineBlock");
- }
+ }
},
toggleViewsHints: function () {
diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php
index 8179c1a8e631..0768f62915bb 100644
--- a/system/Debug/Toolbar/Views/toolbar.tpl.php
+++ b/system/Debug/Toolbar/Views/toolbar.tpl.php
@@ -1,21 +1,24 @@