diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 37093e287e13..0b83b6051d99 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -14,7 +14,6 @@ use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; @@ -39,7 +38,44 @@ __DIR__ . '/spark', ]); -$overrides = []; +$overrides = [ + // <<<<<<<<<<<<<<<<<<<<<<<< @TODO TO BE REMOVED ONCE LIVE IN CODING-STANDARD + 'blank_line_between_import_groups' => true, + 'class_definition' => [ + 'multi_line_extends_each_single_line' => true, + 'single_item_single_line' => true, + 'single_line' => true, + 'space_before_parenthesis' => true, + 'inline_constructor_arguments' => true, + ], + 'control_structure_braces' => true, + 'no_multiple_statements_per_line' => true, + 'no_trailing_comma_in_singleline' => [ + 'elements' => [ + 'arguments', + 'array_destructuring', + 'array', + 'group_import', + ], + ], + 'no_useless_nullsafe_operator' => true, + 'phpdoc_separation' => [ + 'groups' => [ + ['immutable', 'psalm-immutable'], + ['param', 'phpstan-param', 'psalm-param'], + ['phpstan-pure', 'psalm-pure'], + ['readonly', 'psalm-readonly'], + ['return', 'phpstan-return', 'psalm-return'], + ['template', 'phpstan-template', 'psalm-template'], + ['template-covariant', 'phpstan-template-covariant', 'psalm-template-covariant'], + ['phpstan-type', 'psalm-type'], + ['var', 'phpstan-var', 'psalm-var'], + ], + ], + 'single_line_comment_spacing' => true, + 'statement_indentation' => true, + // >>>>>>>>>>>>>>>>>>>>>>>>> +]; $options = [ 'cacheFile' => 'build/.php-cs-fixer.cache', @@ -47,7 +83,6 @@ 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ NoCodeSeparatorCommentFixer::name() => true, - SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/.php-cs-fixer.no-header.php b/.php-cs-fixer.no-header.php index e795b5a75577..8e9f3351953b 100644 --- a/.php-cs-fixer.no-header.php +++ b/.php-cs-fixer.no-header.php @@ -14,7 +14,6 @@ use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; @@ -31,7 +30,44 @@ __DIR__ . '/admin/starter/builds', ]); -$overrides = []; +$overrides = [ + // <<<<<<<<<<<<<<<<<<<<<<<< @TODO TO BE REMOVED ONCE LIVE IN CODING-STANDARD + 'blank_line_between_import_groups' => true, + 'class_definition' => [ + 'multi_line_extends_each_single_line' => true, + 'single_item_single_line' => true, + 'single_line' => true, + 'space_before_parenthesis' => true, + 'inline_constructor_arguments' => true, + ], + 'control_structure_braces' => true, + 'no_multiple_statements_per_line' => true, + 'no_trailing_comma_in_singleline' => [ + 'elements' => [ + 'arguments', + 'array_destructuring', + 'array', + 'group_import', + ], + ], + 'no_useless_nullsafe_operator' => true, + 'phpdoc_separation' => [ + 'groups' => [ + ['immutable', 'psalm-immutable'], + ['param', 'phpstan-param', 'psalm-param'], + ['phpstan-pure', 'psalm-pure'], + ['readonly', 'psalm-readonly'], + ['return', 'phpstan-return', 'psalm-return'], + ['template', 'phpstan-template', 'psalm-template'], + ['template-covariant', 'phpstan-template-covariant', 'psalm-template-covariant'], + ['phpstan-type', 'psalm-type'], + ['var', 'phpstan-var', 'psalm-var'], + ], + ], + 'single_line_comment_spacing' => true, + 'statement_indentation' => true, + // >>>>>>>>>>>>>>>>>>>>>>>>> +]; $options = [ 'cacheFile' => 'build/.php-cs-fixer.no-header.cache', @@ -39,7 +75,6 @@ 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ NoCodeSeparatorCommentFixer::name() => true, - SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/.php-cs-fixer.user-guide.php b/.php-cs-fixer.user-guide.php index 8081d73698ca..be38def156f6 100644 --- a/.php-cs-fixer.user-guide.php +++ b/.php-cs-fixer.user-guide.php @@ -14,7 +14,6 @@ use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; -use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; @@ -34,6 +33,42 @@ 'php_unit_internal_class' => false, 'no_unused_imports' => false, 'class_attributes_separation' => false, + // <<<<<<<<<<<<<<<<<<<<<<<< @TODO TO BE REMOVED ONCE LIVE IN CODING-STANDARD + 'blank_line_between_import_groups' => true, + 'class_definition' => [ + 'multi_line_extends_each_single_line' => true, + 'single_item_single_line' => true, + 'single_line' => true, + 'space_before_parenthesis' => true, + 'inline_constructor_arguments' => true, + ], + 'control_structure_braces' => true, + 'no_multiple_statements_per_line' => true, + 'no_trailing_comma_in_singleline' => [ + 'elements' => [ + 'arguments', + 'array_destructuring', + 'array', + 'group_import', + ], + ], + 'no_useless_nullsafe_operator' => true, + 'phpdoc_separation' => [ + 'groups' => [ + ['immutable', 'psalm-immutable'], + ['param', 'phpstan-param', 'psalm-param'], + ['phpstan-pure', 'psalm-pure'], + ['readonly', 'psalm-readonly'], + ['return', 'phpstan-return', 'psalm-return'], + ['template', 'phpstan-template', 'psalm-template'], + ['template-covariant', 'phpstan-template-covariant', 'psalm-template-covariant'], + ['phpstan-type', 'psalm-type'], + ['var', 'phpstan-var', 'psalm-var'], + ], + ], + 'single_line_comment_spacing' => true, + 'statement_indentation' => true, + // >>>>>>>>>>>>>>>>>>>>>>>>> ]; $options = [ @@ -42,7 +77,6 @@ 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ NoCodeSeparatorCommentFixer::name() => true, - SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/CHANGELOG.md b/CHANGELOG.md index 42709f5ec371..569960c8842d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [v4.2.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.2.6) (2022-09-04) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.2.5...v4.2.6) + +### Fixed Bugs +* fix: AssertionError occurs when using Validation in CLI by @daycry in https://github.com/codeigniter4/CodeIgniter4/pull/6452 +* fix: [Validation] JSON data may cause "Array to string conversion" error by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6467 +* Fix fatal error gets turned to `0` severity on shutdown handler by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6472 +* Fix redis cache increment/decrement methods by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6473 +* Fix broken caching system when array of allowed parameters used by @JavaDeveloperKiev in https://github.com/codeigniter4/CodeIgniter4/pull/6475 +* fix: Strict Validation Rules greater_than/less_than by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6492 + +### Refactoring +* refactor: fix PHPStan errors by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6470 +* Bump `friendsofphp/php-cs-fixer` to `~3.11.0` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6471 +* Fix overlooked coding style violations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6491 + ## [v4.2.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.2.5) (2022-08-28) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.2.4...v4.2.5) diff --git a/admin/framework/composer.json b/admin/framework/composer.json index b2a1d6d0e69b..5fcc156529fe 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -17,7 +17,7 @@ "require-dev": { "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "3.6.*", + "friendsofphp/php-cs-fixer": "~3.11.0", "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "phpunit/phpunit": "^9.1", diff --git a/app/Config/App.php b/app/Config/App.php index 1a5e562ddd30..79e5741b4c9c 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -437,6 +437,7 @@ class App extends BaseConfig * Defaults to `Lax` as recommended in this link: * * @see https://portswigger.net/web-security/csrf/samesite-cookies + * * @deprecated `Config\Cookie` $samesite property is used. * * @var string diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php index aa18ba9f1060..0be616301fb9 100644 --- a/app/Config/ContentSecurityPolicy.php +++ b/app/Config/ContentSecurityPolicy.php @@ -15,9 +15,9 @@ */ class ContentSecurityPolicy extends BaseConfig { - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // Broadbrush CSP management - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Default CSP report context @@ -43,10 +43,10 @@ class ContentSecurityPolicy extends BaseConfig */ public $upgradeInsecureRequests = false; - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // Sources allowed // Note: once you set a policy to 'none', it cannot be further restricted - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** * Will default to self if not overridden diff --git a/app/Config/Routes.php b/app/Config/Routes.php index ff2ac645cb9a..0bfdce972157 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -25,7 +25,7 @@ // where controller filters or CSRF protection are bypassed. // If you don't want to define all routes, please use the Auto Routing (Improved). // Set `$autoRoutesImproved` to true in `app/Config/Feature.php` and set the following to true. -//$routes->setAutoRoute(false); +// $routes->setAutoRoute(false); /* * -------------------------------------------------------------------- diff --git a/app/Config/Validation.php b/app/Config/Validation.php index a254c1850015..e0a03bdf4f08 100644 --- a/app/Config/Validation.php +++ b/app/Config/Validation.php @@ -10,9 +10,9 @@ class Validation extends BaseConfig { - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Setup - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Stores the classes that contain the @@ -38,7 +38,7 @@ class Validation extends BaseConfig 'single' => 'CodeIgniter\Validation\Views\single', ]; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Rules - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- } diff --git a/composer.json b/composer.json index 3080b701539b..83316e627ea6 100644 --- a/composer.json +++ b/composer.json @@ -17,14 +17,14 @@ "require-dev": { "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "3.6.*", + "friendsofphp/php-cs-fixer": "~3.11.0", "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", "phpstan/phpstan": "^1.7.1", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.14.0" + "rector/rector": "0.14.1" }, "suggest": { "ext-imagick": "If you use Image class ImageMagickHandler", @@ -70,7 +70,11 @@ "CodeIgniter\\ComposerScripts::postUpdate", "bash -c \"if [ -f admin/setup.sh ]; then bash admin/setup.sh; fi\"" ], - "analyze": "phpstan analyse", + "analyze": [ + "phpstan analyze", + "rector process --dry-run" + ], + "sa": "@analyze", "test": "phpunit", "cs": [ "php-cs-fixer fix --ansi --verbose --dry-run --diff --config=.php-cs-fixer.user-guide.php", @@ -81,7 +85,8 @@ "php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.user-guide.php", "php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.no-header.php", "php-cs-fixer fix --ansi --verbose --diff" - ] + ], + "style": "@cs-fix" }, "scripts-descriptions": { "analyze": "Run static analysis", diff --git a/contributing/pull_request.md b/contributing/pull_request.md index ed6d0dfde9e6..f1e29304e305 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -252,7 +252,6 @@ The best way to contribute is to fork the CodeIgniter4 repository, and "clone" t - Commit messages are expected to be descriptive of why and what you changed specifically. Commit messages like "Fixes #1234" would be asked by the reviewer to be revised. [Atomic commit](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) is recommended. See [Contribution Workflow](./workflow.md#commit-messages) for details. 9. If you have touched PHP code, run static analysis. - `> composer analyze` - - `> vendor/bin/rector process` 10. Run unit tests on the specific file you modified. If there are no existing tests yet, please create one. - `> vendor/bin/phpunit tests/system/path/to/file/you/modified` - Make sure the tests pass to have a higher chance of merging. diff --git a/contributing/workflow.md b/contributing/workflow.md index 50673ce10166..cde1f2eb5de6 100644 --- a/contributing/workflow.md +++ b/contributing/workflow.md @@ -66,7 +66,7 @@ Clone your repository, leaving a local folder for you to work with: > git clone ORIGIN_URL ``` -## Syncing your repository +## Syncing Your Repository Within your local repository, Git will have created an alias, **origin**, for the GitHub repository it is bound to. You want to create @@ -179,7 +179,11 @@ For instance, to commit your work from a debugging session: Just make sure that your commits in a feature branch are all related. -### When you work on two features +### Changing a Commit Message + +See . + +### When You Work on Two Features If you are working on two features at a time, then you will want to switch between them to keep the contributions separate. For instance: @@ -314,7 +318,7 @@ And finally push your local branch to your GitHub repository: > git push --force-with-lease origin fix/problem123 ``` -## If you sent to the wrong branch +## If You Sent to the Wrong Branch If you have sent a PR to the wrong branch, you need to create a new PR branch. diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index feeeaf9b7980..035c15273959 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -55,16 +55,6 @@ parameters: count: 1 path: system/Cache/Handlers/FileHandler.php - - - message: "#^Method MemcachePool\\:\\:decrement\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" - count: 1 - path: system/Cache/Handlers/MemcachedHandler.php - - - - message: "#^Method MemcachePool\\:\\:increment\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" - count: 1 - path: system/Cache/Handlers/MemcachedHandler.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1 @@ -545,11 +535,6 @@ parameters: count: 1 path: system/HTTP/Request.php - - - message: "#^Cannot unset offset 'path' on array{host: non-empty-string}\\.$#" - count: 1 - path: system/HTTP/URI.php - - message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$fragment \\(string\\) on left side of \\?\\? is not nullable\\.$#" count: 1 @@ -580,11 +565,6 @@ parameters: count: 1 path: system/Helpers/number_helper.php - - - message: "#^Variable \\$pool might not be defined\\.$#" - count: 2 - path: system/Helpers/text_helper.php - - message: "#^Variable \\$count might not be defined\\.$#" count: 1 diff --git a/system/API/ResponseTrait.php b/system/API/ResponseTrait.php index 5f6a52c497e5..6ae0e3a361bd 100644 --- a/system/API/ResponseTrait.php +++ b/system/API/ResponseTrait.php @@ -136,9 +136,9 @@ protected function fail($messages, int $status = 400, ?string $code = null, stri return $this->respond($response, $status, $customMessage); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Response Helpers - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Used after successfully creating a new resource. @@ -290,9 +290,9 @@ protected function failServerError(string $description = 'Internal Server Error' return $this->fail($description, $this->codes['server_error'], $code, $message); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utility Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Handles formatting a response. Currently makes some heavy assumptions diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 7a5030314948..f20a08a103ff 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -756,9 +756,9 @@ public static function wrap(?string $string = null, int $max = 0, int $padLeft = return $lines; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Command-Line 'URI' support - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Parses the command line it was called from and collects all diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index df179e7455e6..b84c0115b1f8 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -200,7 +200,7 @@ public function increment(string $key, int $offset = 1) { $key = static::validateKey($key, $this->prefix); - return $this->redis->hIncrBy($key, 'data', $offset); + return $this->redis->hIncrBy($key, '__ci_value', $offset); } /** @@ -208,9 +208,7 @@ public function increment(string $key, int $offset = 1) */ public function decrement(string $key, int $offset = 1) { - $key = static::validateKey($key, $this->prefix); - - return $this->redis->hIncrBy($key, 'data', -$offset); + return $this->increment($key, -$offset); } /** diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index d4cc2944d7f7..c81337fda21e 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -47,7 +47,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.2.5'; + public const CI_VERSION = '4.2.6'; /** * App startup time. @@ -730,9 +730,12 @@ protected function generateCacheName(Cache $config): string } $uri = $this->request->getUri(); - if ($config->cacheQueryString) { - $name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery()); + if (is_array($config->cacheQueryString)) { + $name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(['only' => $config->cacheQueryString])); + } else { + $name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery()); + } } else { $name = URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath()); } @@ -945,11 +948,9 @@ protected function display404errors(PageNotFoundException $e) $this->response->setStatusCode($e->getCode()); if (ENVIRONMENT !== 'testing') { - // @codeCoverageIgnoreStart if (ob_get_level() > 0) { - ob_end_flush(); + ob_end_flush(); // @codeCoverageIgnore } - // @codeCoverageIgnoreEnd } // When testing, one is for phpunit, another is for test case. elseif (ob_get_level() > 2) { diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 5213f426bca7..07738a74e38a 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -92,43 +92,43 @@ * @see http://blog.ircmaxell.com/2015/11/simple-easy-risk-and-change.html * @see http://www.infoq.com/presentations/Simple-Made-Easy * - * @method static CacheInterface cache(Cache $config = null, $getShared = true) - * @method static CLIRequest clirequest(App $config = null, $getShared = true) - * @method static CodeIgniter codeigniter(App $config = null, $getShared = true) - * @method static Commands commands($getShared = true) - * @method static void createRequest(App $config, bool $isCli = false) - * @method static ContentSecurityPolicy csp(CSPConfig $config = null, $getShared = true) - * @method static CURLRequest curlrequest($options = [], ResponseInterface $response = null, App $config = null, $getShared = true) - * @method static Email email($config = null, $getShared = true) - * @method static EncrypterInterface encrypter(Encryption $config = null, $getShared = false) - * @method static Exceptions exceptions(ConfigExceptions $config = null, IncomingRequest $request = null, Response $response = null, $getShared = true) - * @method static Filters filters(ConfigFilters $config = null, $getShared = true) - * @method static Format format(ConfigFormat $config = null, $getShared = true) - * @method static Honeypot honeypot(ConfigHoneyPot $config = null, $getShared = true) - * @method static BaseHandler image($handler = null, Images $config = null, $getShared = true) - * @method static IncomingRequest incomingrequest(?App $config = null, bool $getShared = true) - * @method static Iterator iterator($getShared = true) - * @method static Language language($locale = null, $getShared = true) - * @method static Logger logger($getShared = true) - * @method static MigrationRunner migrations(Migrations $config = null, ConnectionInterface $db = null, $getShared = true) - * @method static Negotiate negotiator(RequestInterface $request = null, $getShared = true) - * @method static Pager pager(ConfigPager $config = null, RendererInterface $view = null, $getShared = true) - * @method static Parser parser($viewPath = null, ConfigView $config = null, $getShared = true) - * @method static RedirectResponse redirectresponse(App $config = null, $getShared = true) - * @method static View renderer($viewPath = null, ConfigView $config = null, $getShared = true) + * @method static CacheInterface cache(Cache $config = null, $getShared = true) + * @method static CLIRequest clirequest(App $config = null, $getShared = true) + * @method static CodeIgniter codeigniter(App $config = null, $getShared = true) + * @method static Commands commands($getShared = true) + * @method static void createRequest(App $config, bool $isCli = false) + * @method static ContentSecurityPolicy csp(CSPConfig $config = null, $getShared = true) + * @method static CURLRequest curlrequest($options = [], ResponseInterface $response = null, App $config = null, $getShared = true) + * @method static Email email($config = null, $getShared = true) + * @method static EncrypterInterface encrypter(Encryption $config = null, $getShared = false) + * @method static Exceptions exceptions(ConfigExceptions $config = null, IncomingRequest $request = null, Response $response = null, $getShared = true) + * @method static Filters filters(ConfigFilters $config = null, $getShared = true) + * @method static Format format(ConfigFormat $config = null, $getShared = true) + * @method static Honeypot honeypot(ConfigHoneyPot $config = null, $getShared = true) + * @method static BaseHandler image($handler = null, Images $config = null, $getShared = true) + * @method static IncomingRequest incomingrequest(?App $config = null, bool $getShared = true) + * @method static Iterator iterator($getShared = true) + * @method static Language language($locale = null, $getShared = true) + * @method static Logger logger($getShared = true) + * @method static MigrationRunner migrations(Migrations $config = null, ConnectionInterface $db = null, $getShared = true) + * @method static Negotiate negotiator(RequestInterface $request = null, $getShared = true) + * @method static Pager pager(ConfigPager $config = null, RendererInterface $view = null, $getShared = true) + * @method static Parser parser($viewPath = null, ConfigView $config = null, $getShared = true) + * @method static RedirectResponse redirectresponse(App $config = null, $getShared = true) + * @method static View renderer($viewPath = null, ConfigView $config = null, $getShared = true) * @method static IncomingRequest|CLIRequest request(App $config = null, $getShared = true) - * @method static Response response(App $config = null, $getShared = true) - * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) - * @method static RouteCollection routes($getShared = true) - * @method static Security security(App $config = null, $getShared = true) - * @method static Session session(App $config = null, $getShared = true) - * @method static Throttler throttler($getShared = true) - * @method static Timer timer($getShared = true) - * @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true) - * @method static Typography typography($getShared = true) - * @method static URI uri($uri = null, $getShared = true) - * @method static Validation validation(ConfigValidation $config = null, $getShared = true) - * @method static Cell viewcell($getShared = true) + * @method static Response response(App $config = null, $getShared = true) + * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) + * @method static RouteCollection routes($getShared = true) + * @method static Security security(App $config = null, $getShared = true) + * @method static Session session(App $config = null, $getShared = true) + * @method static Throttler throttler($getShared = true) + * @method static Timer timer($getShared = true) + * @method static Toolbar toolbar(ConfigToolbar $config = null, $getShared = true) + * @method static Typography typography($getShared = true) + * @method static URI uri($uri = null, $getShared = true) + * @method static Validation validation(ConfigValidation $config = null, $getShared = true) + * @method static Cell viewcell($getShared = true) */ class BaseService { diff --git a/system/Cookie/CloneableCookieInterface.php b/system/Cookie/CloneableCookieInterface.php index 508c1359970e..93f6031e2010 100644 --- a/system/Cookie/CloneableCookieInterface.php +++ b/system/Cookie/CloneableCookieInterface.php @@ -60,6 +60,8 @@ public function withExpired(); * Creates a new Cookie that will virtually never expire from the browser. * * @return static + * + * @deprecated See https://github.com/codeigniter4/CodeIgniter4/pull/6413 */ public function withNeverExpiring(); diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index 22c01a7daa3c..72188451d3e2 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -152,9 +152,9 @@ public static function setDefaults($config = []) return $oldDefaults; } - //========================================================================= + // ========================================================================= // CONSTRUCTORS - //========================================================================= + // ========================================================================= /** * Create a new Cookie instance from a `Set-Cookie` header. @@ -238,9 +238,9 @@ final public function __construct(string $name, string $value = '', array $optio $this->raw = $raw; } - //========================================================================= + // ========================================================================= // GETTERS - //========================================================================= + // ========================================================================= /** * {@inheritDoc} @@ -391,9 +391,9 @@ public function getOptions(): array ]; } - //========================================================================= + // ========================================================================= // CLONING - //========================================================================= + // ========================================================================= /** * {@inheritDoc} @@ -460,7 +460,7 @@ public function withExpired() } /** - * {@inheritDoc} + * @deprecated See https://github.com/codeigniter4/CodeIgniter4/pull/6413 */ public function withNeverExpiring() { @@ -556,9 +556,9 @@ public function withRaw(bool $raw = true) return $cookie; } - //========================================================================= + // ========================================================================= // ARRAY ACCESS FOR BC - //========================================================================= + // ========================================================================= /** * Whether an offset exists. @@ -614,9 +614,9 @@ public function offsetUnset($offset): void throw new LogicException(sprintf('Cannot unset values of properties of %s as it is immutable.', static::class)); } - //========================================================================= + // ========================================================================= // CONVERTERS - //========================================================================= + // ========================================================================= /** * {@inheritDoc} @@ -716,9 +716,9 @@ protected static function convertExpiresTimestamp($expires = 0): int return $expires > 0 ? (int) $expires : 0; } - //========================================================================= + // ========================================================================= // VALIDATION - //========================================================================= + // ========================================================================= /** * Validates the cookie name per RFC 2616. diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 39e832d13d76..8d9bd87076a3 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1928,6 +1928,7 @@ public function insert($set = null, ?bool $escape = null) * @internal This is a temporary solution. * * @see https://github.com/codeigniter4/CodeIgniter4/pull/5376 + * * @TODO Fix a root cause, and this method should be removed. */ protected function removeAlias(string $from): string diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 865a1893b902..11e54ea72aaa 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1352,9 +1352,9 @@ protected function getDriverFunctionPrefix(): string return strtolower($this->DBDriver) . '_'; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // META Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns an array of table names diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index bb802149edaf..99df429089ef 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -125,7 +125,6 @@ protected function _createTableAttributes(array $attributes): string */ protected function _alterTable(string $alterType, string $table, $field) { - // Handle DROP here if ($alterType === 'DROP') { // check if fields are part of any indexes diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 9994aa7a045a..437a47268706 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -177,7 +177,7 @@ public function shutdownHandler() ['type' => $type, 'message' => $message, 'file' => $file, 'line' => $line] = $error; if (in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE], true)) { - $this->exceptionHandler(new ErrorException($message, $type, 0, $file, $line)); + $this->exceptionHandler(new ErrorException($message, 0, $type, $file, $line)); } } @@ -329,9 +329,9 @@ protected function determineCodes(Throwable $exception): array return [$statusCode, $exitStatus]; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Display Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * This makes nicer looking paths for the error output. diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 39adf0661215..e5820d075cff 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -25,6 +25,7 @@ use CodeIgniter\Entity\Cast\URICast; use CodeIgniter\Entity\Exceptions\CastException; use CodeIgniter\I18n\Time; +use DateTime; use Exception; use JsonSerializable; use ReturnTypeWillChange; @@ -147,7 +148,7 @@ public function fill(?array $data = null) * * @param bool $onlyChanged If true, only return values that have changed since object creation * @param bool $cast If true, properties will be cast. - * @param bool $recursive If true, inner entities will be casted as array as well. + * @param bool $recursive If true, inner entities will be cast as array as well. */ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recursive = false): array { @@ -189,7 +190,7 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu * Returns the raw values of the current attributes. * * @param bool $onlyChanged If true, only return values that have changed since object creation - * @param bool $recursive If true, inner entities will be casted as array as well. + * @param bool $recursive If true, inner entities will be cast as array as well. */ public function toRawArray(bool $onlyChanged = false, bool $recursive = false): array { @@ -247,7 +248,7 @@ public function syncOriginal() * was created. Or, without a parameter, checks if any * properties have changed. * - * @param string $key + * @param string|null $key class property */ public function hasChanged(?string $key = null): bool { @@ -308,11 +309,11 @@ protected function mapProperty(string $key) * Converts the given string|timestamp|DateTime|Time instance * into the "CodeIgniter\I18n\Time" object. * - * @param mixed $value + * @param DateTime|float|int|string|Time $value * * @throws Exception * - * @return mixed|Time + * @return Time */ protected function mutateDate($value) { @@ -324,13 +325,13 @@ protected function mutateDate($value) * Add ? at the beginning of $type (i.e. ?string) to get NULL * instead of casting $value if $value === null * - * @param mixed $value Attribute value - * @param string $attribute Attribute name - * @param string $method Allowed to "get" and "set" + * @param bool|float|int|string|null $value Attribute value + * @param string $attribute Attribute name + * @param string $method Allowed to "get" and "set" * * @throws CastException * - * @return mixed + * @return array|bool|float|int|object|string|null */ protected function castAs($value, string $attribute, string $method = 'get') { @@ -424,7 +425,7 @@ public function cast(?bool $cast = null) * $this->my_property = $p; * $this->setMyProperty() = $p; * - * @param mixed|null $value + * @param array|bool|float|int|object|string|null $value * * @throws Exception * @@ -471,7 +472,9 @@ public function __set(string $key, $value = null) * * @throws Exception * - * @return mixed + * @params string $key class property + * + * @return array|bool|float|int|object|string|null */ public function __get(string $key) { diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index 20b208fded43..ee1d0477d34c 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -33,9 +33,9 @@ class FileCollection implements Countable, IteratorAggregate */ protected $files = []; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Support Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Resolves a full path and verifies it is an actual directory. @@ -106,9 +106,9 @@ final protected static function matchFiles(array $files, string $pattern): array return array_filter($files, static fn ($value) => (bool) preg_match($pattern, basename($value))); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Class Core - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Loads the Filesystem helper and adds any initial files. @@ -189,9 +189,9 @@ public function add($paths, bool $recursive = true) return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // File Handling - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Verifies and adds files to the list. @@ -245,9 +245,9 @@ public function removeFile(string $file) return $this->removeFiles([$file]); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Directory Handling - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Verifies and adds files from each @@ -287,9 +287,9 @@ public function addDirectory(string $directory, bool $recursive = false) return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Filtering - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Removes any files from the list that match the supplied pattern @@ -335,9 +335,9 @@ public function retainPattern(string $pattern, ?string $scope = null) return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Interface Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the current number of files in the collection. diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index d5d5e3aae42e..ca2b8a4b5ba8 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -134,7 +134,7 @@ private function discoverFilters() $className = $locator->getClassname($file); // Don't include our main Filter config again... - if ($className === 'Config\\Filters') { + if ($className === FiltersConfig::class) { continue; } @@ -382,9 +382,9 @@ public function getArguments(?string $key = null) return $key === null ? $this->arguments : $this->arguments[$key]; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Processors - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Add any applicable (not excluded) global filter settings to the mix. diff --git a/system/HTTP/MessageTrait.php b/system/HTTP/MessageTrait.php index 90e36ad5dccc..daa70875f548 100644 --- a/system/HTTP/MessageTrait.php +++ b/system/HTTP/MessageTrait.php @@ -38,9 +38,9 @@ trait MessageTrait */ protected $headerMap = []; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Body - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the body of the current message. @@ -70,9 +70,9 @@ public function appendBody($data): self return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Headers - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Populates the $headers array with any headers the server knows about. diff --git a/system/HTTP/Negotiate.php b/system/HTTP/Negotiate.php index d0e822574b85..7b0fdc2d54b4 100644 --- a/system/HTTP/Negotiate.php +++ b/system/HTTP/Negotiate.php @@ -122,9 +122,9 @@ public function language(array $supported): string return $this->getBestMatch($supported, $this->request->getHeaderLine('accept-language'), false, false, true); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utility Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Does the grunt work of comparing any of the app-supported values diff --git a/system/HTTP/Response.php b/system/HTTP/Response.php index bcaffa49fbe8..c0f3a2e8120a 100644 --- a/system/HTTP/Response.php +++ b/system/HTTP/Response.php @@ -222,6 +222,7 @@ public function getStatusCode(): int * * @see http://tools.ietf.org/html/rfc7231#section-6 * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * * @deprecated Use getReasonPhrase() * * @codeCoverageIgnore diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index 9cf729bb841e..e8bfde68dde2 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -141,13 +141,14 @@ public function setStatusCode(int $code, string $reason = ''); * * @see http://tools.ietf.org/html/rfc7231#section-6 * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * * @deprecated Use getReasonPhrase() */ public function getReason(): string; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Convenience Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the date header @@ -185,9 +186,9 @@ public function setLink(PagerInterface $pager); */ public function setContentType(string $mime, string $charset = 'UTF-8'); - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Formatter Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Converts the $body into JSON and sets the Content Type header. @@ -225,11 +226,11 @@ public function setXML($body); */ public function getXML(); - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Cache Control Methods // // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the appropriate headers to ensure this response @@ -265,9 +266,9 @@ public function noCache(); */ public function setCache(array $options = []); - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Output Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sends the output to the browser. @@ -290,9 +291,9 @@ public function sendHeaders(); */ public function sendBody(); - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Cookie Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Set a cookie @@ -350,9 +351,9 @@ public function deleteCookie(string $name = '', string $domain = '', string $pat */ public function getCookies(); - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Response Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Perform a redirect to a new URL, in two flavors: header or location. diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 66c7ce263fed..2b96d6a083aa 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -165,9 +165,9 @@ public function setStatusCode(int $code, string $reason = '') return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Convenience Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the date header @@ -323,11 +323,11 @@ protected function formatBody($body, string $format) return $body; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Cache Control Methods // // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the appropriate headers to ensure this response @@ -422,9 +422,9 @@ public function setLastModified($date) return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Output Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sends the output to the browser. diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 5537de9c3899..bb355f70224a 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -13,9 +13,9 @@ use Config\Cookie; use Config\Services; -//============================================================================= +// ============================================================================= // CodeIgniter Cookie Helpers -//============================================================================= +// ============================================================================= if (! function_exists('set_cookie')) { /** diff --git a/system/I18n/Time.php b/system/I18n/Time.php index dd26979af13d..9b8633fe006b 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -62,9 +62,9 @@ class Time extends DateTime */ protected static $testNow; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Constructors - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Time constructor. @@ -285,6 +285,7 @@ public static function createFromInstance(DateTimeInterface $dateTime, ?string $ * @return Time * * @deprecated Use createFromInstance() instead + * * @codeCoverageIgnore */ public static function instance(DateTime $dateTime, ?string $locale = null) @@ -307,9 +308,9 @@ public function toDateTime() return $dateTime; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // For Testing - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Creates an instance of Time that will be returned during testing @@ -347,9 +348,9 @@ public static function hasTestNow(): bool return static::$testNow !== null; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Getters - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the localized Year @@ -509,9 +510,9 @@ public function getTimezoneName(): string return $this->timezone->getName(); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Setters - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the current year for this instance. @@ -688,9 +689,9 @@ public function setTimestamp($timestamp) return self::parse($time, $this->timezone, $this->locale); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Add/Subtract - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns a new Time instance with $seconds added to the time. @@ -836,9 +837,9 @@ public function subYears(int $years) return $time->sub(DateInterval::createFromDateString("{$years} years")); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Formatters - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the localized value of the date in the format 'Y-m-d H:i:s' @@ -904,9 +905,9 @@ public function toLocalizedString(?string $format = null) return IntlDateFormatter::formatObject($this->toDateTime(), $format, $this->locale); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Comparison - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Determines if the datetime passed in is equal to the current instance. @@ -984,9 +985,9 @@ public function isAfter($testTime, ?string $timezone = null): bool return $ourTime > $testTime; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Differences - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns a text string that is easily readable that describes @@ -1060,9 +1061,9 @@ public function difference($testTime, ?string $timezone = null) return new TimeDifference($ourTime, $testTime); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utilities - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns a Time instance with the timezone converted to UTC. diff --git a/system/Model.php b/system/Model.php index 5353d9a58558..434fc70dfdad 100644 --- a/system/Model.php +++ b/system/Model.php @@ -654,7 +654,7 @@ public function insert($data = null, bool $returnID = true) { if (! empty($this->tempData['data'])) { if (empty($data)) { - $data = $this->tempData['data'] ?? null; + $data = $this->tempData['data']; } else { $data = $this->transformDataToArray($data, 'insert'); $data = array_merge($this->tempData['data'], $data); @@ -680,7 +680,7 @@ public function update($id = null, $data = null): bool { if (! empty($this->tempData['data'])) { if (empty($data)) { - $data = $this->tempData['data'] ?? null; + $data = $this->tempData['data']; } else { $data = $this->transformDataToArray($data, 'update'); $data = array_merge($this->tempData['data'], $data); diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 01a3c62db657..41ecfb0d6fd1 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -85,9 +85,9 @@ class Publisher extends FileCollection */ protected $destination = FCPATH; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Support Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Discovers and returns all Publishers in the specified namespace directory. @@ -143,9 +143,9 @@ private static function wipeDirectory(string $directory): void } } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Class Core - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Loads the helper and verifies the source and destination directories. @@ -199,9 +199,9 @@ public function publish(): bool return $this->addPath('/')->merge(true); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Property Accessors - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the source directory. @@ -254,9 +254,9 @@ final public function getPublished(): array return $this->published; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Additional Handlers - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Verifies and adds paths to the list. @@ -320,9 +320,9 @@ final public function addUri(string $uri) return $this->addFile($file); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Write Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Removes the destination and all its files and folders. diff --git a/system/Router/Router.php b/system/Router/Router.php index 43b899fb56be..60aa403fa0e9 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -459,7 +459,7 @@ protected function checkRoutes(string $uri): bool return true; } - [$controller, ] = explode('::', $handler); + [$controller] = explode('::', $handler); // Checks `/` in controller name if (strpos($controller, '/') !== false) { diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index b5a105c6886b..213bcf5886c6 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -71,9 +71,9 @@ abstract class CIUnitTestCase extends TestCase */ private ?array $traits = null; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Database Properties - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Should run db migration? @@ -166,9 +166,9 @@ abstract class CIUnitTestCase extends TestCase */ protected $insertCache = []; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Feature Properties - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * If present, will override application @@ -216,9 +216,9 @@ abstract class CIUnitTestCase extends TestCase */ protected $requestBody = ''; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Staging - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Load the helpers. @@ -289,9 +289,9 @@ private function callTraitMethods(string $stage): void } } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Mocking - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Resets shared instanced for all Factories components @@ -338,9 +338,9 @@ protected function mockSession() Services::injectMock('session', $session); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Assertions - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Custom function to hook into CodeIgniter's Logging mechanism @@ -496,9 +496,9 @@ public function assertCloseEnoughString($expected, $actual, string $message = '' } } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utility - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Loads up an instance of CodeIgniter diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index 539627e29189..f7a6d532a1a6 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -42,9 +42,9 @@ trait DatabaseTestTrait */ private static $doneSeed = false; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Staging - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Runs the trait set up methods. @@ -89,9 +89,9 @@ public function loadDependencies() } } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Migrations - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Migrate on setUp @@ -163,9 +163,9 @@ protected function migrateDatabase() } } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Seeds - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Seed on setUp @@ -205,9 +205,9 @@ public function seed(string $name) $this->seeder->call($name); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utility - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Reset $doneMigration and $doneSeed @@ -264,9 +264,9 @@ public function grabFromDatabase(string $table, string $column, array $where) return $query->{$column} ?? false; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Assertions - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that records that match the conditions in $where DO diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 1407a67b0a64..822a6b2e614c 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -78,9 +78,9 @@ trait FilterTestTrait */ protected $collection; - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Staging - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Initializes dependencies once. @@ -113,9 +113,9 @@ protected function setUpFilterTestTrait(): void $this->doneFilterSetUp = true; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Utility - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns a callable method for a filter position @@ -187,9 +187,9 @@ protected function getFiltersForRoute(string $route, string $position): array return $aliases[$position]; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Assertions - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that the given route at position uses diff --git a/system/Test/Mock/MockCache.php b/system/Test/Mock/MockCache.php index ebdacccbbef5..69afc0e47039 100644 --- a/system/Test/Mock/MockCache.php +++ b/system/Test/Mock/MockCache.php @@ -236,9 +236,9 @@ public function isSupported(): bool return true; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Test Helpers - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Instructs the class to ignore all @@ -255,9 +255,9 @@ public function bypass(bool $bypass = true) return $this; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Additional Assertions - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that the cache has an item named $key. diff --git a/system/Test/TestResponse.php b/system/Test/TestResponse.php index d91f00080b14..16a50f74d1e5 100644 --- a/system/Test/TestResponse.php +++ b/system/Test/TestResponse.php @@ -60,9 +60,9 @@ public function __construct(ResponseInterface $response) $this->setResponse($response); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Getters / Setters - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Sets the request. @@ -114,9 +114,9 @@ public function response() return $this->response; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Status Checks - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Boils down the possible responses into a boolean valid/not-valid @@ -165,9 +165,9 @@ public function assertNotOK() $this->assertFalse($this->isOK(), "{$this->response->getStatusCode()} is an unexpected successful status code, or the Response has body content."); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Redirection - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns whether or not the Response was a redirect or RedirectResponse @@ -239,9 +239,9 @@ public function getRedirectUrl(): ?string return null; } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Session - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that an SESSION key has been set and, optionally, test it's value. @@ -275,9 +275,9 @@ public function assertSessionMissing(string $key) $this->assertArrayNotHasKey($key, $_SESSION, "'{$key}' should not be present in \$_SESSION."); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Headers - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that the Response contains a specific header. @@ -305,9 +305,9 @@ public function assertHeaderMissing(string $key) $this->assertFalse($this->response->hasHeader($key), "'{$key}' should not be in the Response headers."); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // Cookies - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Asserts that the response has the specified cookie. @@ -340,9 +340,9 @@ public function assertCookieExpired(string $key, string $prefix = '') $this->assertGreaterThan(time(), $this->response->getCookie($key, $prefix)->getExpiresTimestamp()); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // JSON - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the response's body as JSON @@ -401,9 +401,9 @@ public function assertJSONExact($test) $this->assertJsonStringEqualsJsonString($test, $json, 'Response does not contain matching JSON.'); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // XML Methods - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Returns the response' body as XML @@ -415,9 +415,9 @@ public function getXML() return $this->response->getXML(); } - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- // DomParser - //-------------------------------------------------------------------- + // -------------------------------------------------------------------- /** * Assert that the desired text can be found in the result body. diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 6b0068f04670..fa375808feb8 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -29,9 +29,7 @@ defined('HOMEPATH') || define('HOMEPATH', realpath(rtrim(getcwd(), '\\/ ')) . DIRECTORY_SEPARATOR); $source = is_dir(HOMEPATH . 'app') ? HOMEPATH - : (is_dir('vendor/codeigniter4/framework/') - ? 'vendor/codeigniter4/framework/' - : 'vendor/codeigniter4/codeigniter4/'); + : (is_dir('vendor/codeigniter4/framework/') ? 'vendor/codeigniter4/framework/' : 'vendor/codeigniter4/codeigniter4/'); defined('CONFIGPATH') || define('CONFIGPATH', realpath($source . 'app/Config') . DIRECTORY_SEPARATOR); defined('PUBLICPATH') || define('PUBLICPATH', realpath($source . 'public') . DIRECTORY_SEPARATOR); unset($source); diff --git a/system/Validation/FileRules.php b/system/Validation/FileRules.php index aec9d9efa2a4..ba054d134b6b 100644 --- a/system/Validation/FileRules.php +++ b/system/Validation/FileRules.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Validation; +use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\RequestInterface; @@ -39,7 +40,7 @@ public function __construct(?RequestInterface $request = null) $request = Services::request(); } - assert($request instanceof IncomingRequest); + assert($request instanceof IncomingRequest || $request instanceof CLIRequest); $this->request = $request; } diff --git a/system/Validation/StrictRules/Rules.php b/system/Validation/StrictRules/Rules.php index 8861ab727852..af8970122f5c 100644 --- a/system/Validation/StrictRules/Rules.php +++ b/system/Validation/StrictRules/Rules.php @@ -71,20 +71,36 @@ public function exact_length($str, string $val): bool /** * Greater than * - * @param mixed $str + * @param mixed $str expects int|string */ public function greater_than($str, string $min): bool { + if (is_int($str)) { + $str = (string) $str; + } + + if (! is_string($str)) { + return false; + } + return $this->nonStrictRules->greater_than($str, $min); } /** * Equal to or Greater than * - * @param mixed $str + * @param mixed $str expects int|string */ public function greater_than_equal_to($str, string $min): bool { + if (is_int($str)) { + $str = (string) $str; + } + + if (! is_string($str)) { + return false; + } + return $this->nonStrictRules->greater_than_equal_to($str, $min); } @@ -141,20 +157,36 @@ public function is_unique($str, string $field, array $data): bool /** * Less than * - * @param mixed $str + * @param mixed $str expects int|string */ public function less_than($str, string $max): bool { + if (is_int($str)) { + $str = (string) $str; + } + + if (! is_string($str)) { + return false; + } + return $this->nonStrictRules->less_than($str, $max); } /** * Equal to or Less than * - * @param mixed $str + * @param mixed $str expects int|string */ public function less_than_equal_to($str, string $max): bool { + if (is_int($str)) { + $str = (string) $str; + } + + if (! is_string($str)) { + return false; + } + return $this->nonStrictRules->less_than_equal_to($str, $max); } diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index ed370a2f5c08..68557eed4083 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -328,7 +328,9 @@ protected function processRules( if ($passed === false) { // if the $value is an array, convert it to as string representation if (is_array($value)) { - $value = '[' . implode(', ', $value) . ']'; + $value = $this->isStringList($value) + ? '[' . implode(', ', $value) . ']' + : json_encode($value); } elseif (is_object($value)) { $value = json_encode($value); } @@ -351,6 +353,32 @@ protected function processRules( return true; } + /** + * Is the array a string list `list`? + */ + private function isStringList(array $array): bool + { + $expectedKey = 0; + + foreach ($array as $key => $val) { + // Note: also covers PHP array key conversion, e.g. '5' and 5.1 both become 5 + if (! is_int($key)) { + return false; + } + + if ($key !== $expectedKey) { + return false; + } + $expectedKey++; + + if (! is_string($val)) { + return false; + } + } + + return true; + } + /** * Takes a Request object and grabs the input data to use from its * array values. diff --git a/tests/AutoReview/ComposerJsonTest.php b/tests/AutoReview/ComposerJsonTest.php index 27044861b72f..39763b079eca 100644 --- a/tests/AutoReview/ComposerJsonTest.php +++ b/tests/AutoReview/ComposerJsonTest.php @@ -20,6 +20,7 @@ * @internal * * @coversNothing + * * @group auto-review */ final class ComposerJsonTest extends TestCase diff --git a/tests/_support/Validation/TestRules.php b/tests/_support/Validation/TestRules.php index 507d17ef89bf..e44b9d459fc7 100644 --- a/tests/_support/Validation/TestRules.php +++ b/tests/_support/Validation/TestRules.php @@ -32,4 +32,9 @@ public function check_object_rule(object $value, ?string $fields, array $data = return $find; } + + public function array_count($value, $count): bool + { + return is_array($value) && count($value) === (int) $count; + } } diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index d463f0bd4d03..0222fd0c0058 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -43,19 +43,19 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// $config = new App(); foreach ([ - 'baseURL' => 'http://example.com/', - 'uriProtocol' => 'REQUEST_URI', - 'defaultLocale' => 'en', - 'negotiateLocale' => false, + 'baseURL' => 'http://example.com/', + 'uriProtocol' => 'REQUEST_URI', + 'defaultLocale' => 'en', + 'negotiateLocale' => false, 'supportedLocales' => ['en'], - 'CSPEnabled' => false, - 'cookiePrefix' => '', - 'cookieDomain' => '', - 'cookiePath' => '/', - 'cookieSecure' => false, - 'cookieHTTPOnly' => false, - 'proxyIPs' => [], - 'cookieSameSite' => 'Lax', + 'CSPEnabled' => false, + 'cookiePrefix' => '', + 'cookieDomain' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieHTTPOnly' => false, + 'proxyIPs' => [], + 'cookieSameSite' => 'Lax', ] as $key => $value) { $config->{$key} = $value; } @@ -79,7 +79,7 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// } // Create the controller class finally. - $controller = new class ($this->request, $this->response, $this->formatter) { + return new class ($this->request, $this->response, $this->formatter) { use ResponseTrait; protected $request; @@ -98,8 +98,6 @@ public function resetFormatter() $this->formatter = null; } }; - - return $controller; } public function testNoFormatterJSON() @@ -518,19 +516,19 @@ public function testFormatByRequestNegotiateIfFormatIsNotJsonOrXML() $config = new App(); foreach ([ - 'baseURL' => 'http://example.com/', - 'uriProtocol' => 'REQUEST_URI', - 'defaultLocale' => 'en', - 'negotiateLocale' => false, + 'baseURL' => 'http://example.com/', + 'uriProtocol' => 'REQUEST_URI', + 'defaultLocale' => 'en', + 'negotiateLocale' => false, 'supportedLocales' => ['en'], - 'CSPEnabled' => false, - 'cookiePrefix' => '', - 'cookieDomain' => '', - 'cookiePath' => '/', - 'cookieSecure' => false, - 'cookieHTTPOnly' => false, - 'proxyIPs' => [], - 'cookieSameSite' => 'Lax', + 'CSPEnabled' => false, + 'cookiePrefix' => '', + 'cookieDomain' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieHTTPOnly' => false, + 'proxyIPs' => [], + 'cookieSameSite' => 'Lax', ] as $key => $value) { $config->{$key} = $value; } diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index a10d92171ec8..2c79be076eca 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -166,14 +166,22 @@ public function testDeleteMatchingSuffix() $this->assertSame('keys=90', $dbInfo[0]); } - // FIXME: I don't like all Hash logic very much. It's wasting memory. - // public function testIncrement() - // { - // } - - // public function testDecrement() - // { - // } + public function testIncrementAndDecrement() + { + $this->handler->save('counter', 100); + + foreach (range(1, 10) as $step) { + $this->handler->increment('counter', $step); + } + + $this->assertSame(155, $this->handler->get('counter')); + + $this->handler->decrement('counter', 20); + $this->assertSame(135, $this->handler->get('counter')); + + $this->handler->increment('counter', 5); + $this->assertSame(140, $this->handler->get('counter')); + } public function testClean() { diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index d1b6793e4e89..4535096ccc61 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -18,6 +18,7 @@ use CodeIgniter\Test\Filters\CITestStreamFilter; use CodeIgniter\Test\Mock\MockCodeIgniter; use Config\App; +use Config\Cache; use Config\Filters; use Config\Modules; use Tests\Support\Filters\Customfilter; @@ -177,7 +178,7 @@ public function testControllersCanReturnResponseObject() $routes = Services::routes(); $routes->add('pages/(:segment)', static function ($segment) { $response = Services::response(); - $string = "You want to see 'about' page."; + $string = "You want to see 'about' page."; return $response->setBody($string); }); @@ -583,7 +584,7 @@ public function testPageCacheSendSecureHeaders() CodeIgniter::cache(3600); $response = Services::response(); - $string = 'This is a test page. Elapsed time: {elapsed_time}'; + $string = 'This is a test page. Elapsed time: {elapsed_time}'; return $response->setBody($string); }); @@ -622,4 +623,82 @@ public function testPageCacheSendSecureHeaders() stream_filter_remove($outputStreamFilter); stream_filter_remove($errorStreamFilter); } + + /** + * @param array|bool $cacheQueryStringValue + * + * @dataProvider cacheQueryStringProvider + * + * @see https://github.com/codeigniter4/CodeIgniter4/pull/6410 + */ + public function testPageCacheWithCacheQueryString($cacheQueryStringValue, int $expectedPagesInCache, array $testingUrls) + { + // Suppress command() output + CITestStreamFilter::$buffer = ''; + $outputStreamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $errorStreamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + + // Create cache config with cacheQueryString value from the dataProvider + $cacheConfig = new Cache(); + $cacheConfig->cacheQueryString = $cacheQueryStringValue; + + // Clear cache before starting the test + command('cache:clear'); + + // Calculate amount of items in the cache before the test + $cache = \Config\Services::cache(); + $cacheStartCounter = count($cache->getCacheInfo()); + + // Generate request to each URL from the testing array + foreach ($testingUrls as $testingUrl) { + $_SERVER['REQUEST_URI'] = '/' . $testingUrl; + $routes = Services::routes(true); + $routes->add($testingUrl, static function () { + CodeIgniter::cache(0); // Dont cache the page in the run() function because CodeIgniter class will create default $cacheConfig and overwrite settings from the dataProvider + $response = Services::response(); + $string = 'This is a test page, to check cache configuration'; + + return $response->setBody($string); + }); + + // Inject router + $router = Services::router($routes, Services::request(null, false)); + Services::injectMock('router', $router); + + // Cache the page output using default caching function and $cacheConfig with value from the data provider + $this->codeigniter->useSafeOutput(true)->run(); + $this->codeigniter->cachePage($cacheConfig); // Cache the page using our own $cacheConfig confugration + } + + // Calculate how much cached items exist in the cache after the test requests + $cacheEndCounter = count($cache->getCacheInfo()); + $newPagesCached = $cacheEndCounter - $cacheStartCounter; + + // Clear cache after the test + command('cache:clear'); + + // Check that amount of new items created in the cache matching expected value from the data provider + $this->assertSame($expectedPagesInCache, $newPagesCached); + + // Remove stream filters + stream_filter_remove($outputStreamFilter); + stream_filter_remove($errorStreamFilter); + } + + public function cacheQueryStringProvider(): array + { + $testingUrls = [ + 'test', // URL #1 + 'test?important_parameter=1', // URL #2 + 'test?important_parameter=2', // URL #3 + 'test?important_parameter=1¬_important_parameter=2', // URL #4 + 'test?important_parameter=1¬_important_parameter=2&another_not_important_parameter=3', // URL #5 + ]; + + return [ + '$cacheQueryString=false' => [false, 1, $testingUrls], // We expect only 1 page in the cache, because when cacheQueryString is set to false, all GET parameter should be ignored, and page URI will be absolutely same "/test" string for all 5 requests + '$cacheQueryString=true' => [true, 5, $testingUrls], // We expect all 5 pages in the cache, because when cacheQueryString is set to true, all GET parameter should be processed as unique requests + '$cacheQueryString=array' => [['important_parameter'], 3, $testingUrls], // We expect only 3 pages in the cache, because when cacheQueryString is set to array with important parameters, we should ignore all parameters thats not in the array. Only URL #1, URL #2 and URL #3 should be cached. URL #4 and URL #5 is duplication of URL #2 (with value ?important_parameter=1), so they should not be processed as new unique requests and application should return already cached page for URL #2 + ]; + } } diff --git a/tests/system/Commands/GenerateKeyTest.php b/tests/system/Commands/GenerateKeyTest.php index e4f05fddad95..4ba9e8e0ffba 100644 --- a/tests/system/Commands/GenerateKeyTest.php +++ b/tests/system/Commands/GenerateKeyTest.php @@ -86,6 +86,7 @@ public function testGenerateKeyShowsEncodedKey() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testGenerateKeyCreatesNewKey() diff --git a/tests/system/CommonFunctionsSendTest.php b/tests/system/CommonFunctionsSendTest.php index 594a0faab4db..03e675cfbfa5 100644 --- a/tests/system/CommonFunctionsSendTest.php +++ b/tests/system/CommonFunctionsSendTest.php @@ -32,6 +32,7 @@ protected function setUp(): void * See https://github.com/codeigniter4/CodeIgniter4/issues/1393 * * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testRedirectResponseCookiesSent() diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 5c2b6efa7f83..a50069d3745b 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -179,6 +179,7 @@ public function testEscapeBadContext() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSessionInstance() @@ -190,6 +191,7 @@ public function testSessionInstance() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSessionVariable() @@ -203,6 +205,7 @@ public function testSessionVariable() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSessionVariableNotThere() @@ -286,6 +289,7 @@ public function testModelExistsAbsoluteClassname() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testOldInput() @@ -321,6 +325,7 @@ public function testOldInput() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testOldInputSerializeData() @@ -354,7 +359,9 @@ public function testOldInputSerializeData() /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 + * * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testOldInputArray() @@ -468,6 +475,7 @@ public function testRedirectResponseCookies1() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testTrace() @@ -491,6 +499,7 @@ public function testViewNotSaveData() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testForceHttpsNullRequestAndResponse() @@ -571,6 +580,7 @@ public function testDWithCSP() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testTraceWithCSP() diff --git a/tests/system/Config/BaseConfigTest.php b/tests/system/Config/BaseConfigTest.php index d1de7532cb39..9434e0a2c557 100644 --- a/tests/system/Config/BaseConfigTest.php +++ b/tests/system/Config/BaseConfigTest.php @@ -80,6 +80,7 @@ public function testUseDefaultValueTypeStringValue() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testServerValues() @@ -176,6 +177,7 @@ public function testSetsDefaultValues() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSetsDefaultValuesEncryptionUsingHex2Bin() @@ -191,6 +193,7 @@ public function testSetsDefaultValuesEncryptionUsingHex2Bin() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSetDefaultValuesEncryptionUsingBase64() diff --git a/tests/system/Config/ConfigTest.php b/tests/system/Config/ConfigTest.php index e5d382527edb..af996652a92c 100644 --- a/tests/system/Config/ConfigTest.php +++ b/tests/system/Config/ConfigTest.php @@ -55,6 +55,7 @@ public function testCreateNonConfig() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testInjection() diff --git a/tests/system/Config/DotEnvTest.php b/tests/system/Config/DotEnvTest.php index aa718bd6dea6..0b9dcc984e5a 100644 --- a/tests/system/Config/DotEnvTest.php +++ b/tests/system/Config/DotEnvTest.php @@ -67,6 +67,7 @@ public function testLoadsVars() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testLoadsHex2Bin() @@ -81,6 +82,7 @@ public function testLoadsHex2Bin() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testLoadsBase64() diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index 96ce95089389..8f375d398484 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -238,6 +238,7 @@ public function testNewViewcell() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testNewSession() @@ -248,6 +249,7 @@ public function testNewSession() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testNewSessionWithNullConfig() @@ -258,6 +260,7 @@ public function testNewSessionWithNullConfig() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testCallStatic() @@ -272,6 +275,7 @@ public function testCallStatic() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testCallStaticDirectly() @@ -283,6 +287,7 @@ public function testCallStaticDirectly() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testMockInjection() @@ -305,6 +310,7 @@ public function testMockInjection() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testReset() @@ -324,6 +330,7 @@ public function testReset() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testResetSingle() diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index cc77c7507b15..b78f2c69cd2e 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -75,7 +75,7 @@ public function testConstructorHTTPS() $original = $_SERVER; $_SERVER = ['HTTPS' => 'on']; // make sure we can instantiate one - $this->controller = new class () extends Controller { + $this->controller = new class () extends Controller { protected $forceHTTPS = 1; }; $this->controller->initController($this->request, $this->response, $this->logger); @@ -182,7 +182,7 @@ public function testValidateData() public function testHelpers() { - $this->controller = new class () extends Controller { + $this->controller = new class () extends Controller { protected $helpers = [ 'cookie', 'text', diff --git a/tests/system/Database/BaseConnectionTest.php b/tests/system/Database/BaseConnectionTest.php index 3c1be631d73e..33f70bbe7521 100644 --- a/tests/system/Database/BaseConnectionTest.php +++ b/tests/system/Database/BaseConnectionTest.php @@ -106,7 +106,7 @@ public function testCanConnectToFailoverWhenNoConnectionAvailable() $options = $this->options; $options['failover'] = [$this->failoverOptions]; - $db = new class ($options) extends MockConnection { + $db = new class ($options) extends MockConnection { protected $returnValues = [ 'connect' => [false, 345], ]; diff --git a/tests/system/Database/Migrations/MigrationTest.php b/tests/system/Database/Migrations/MigrationTest.php index 1c1561044be0..54d7bb9e3b4c 100644 --- a/tests/system/Database/Migrations/MigrationTest.php +++ b/tests/system/Database/Migrations/MigrationTest.php @@ -29,7 +29,7 @@ protected function setUp(): void public function testDBGroup() { - $migration = new class () extends Migration { + $migration = new class () extends Migration { protected $DBGroup = 'tests'; public function up() diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 2838aa02269e..dabd24af73d5 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -596,7 +596,7 @@ public function testCastAsJSONSyntaxError() $this->expectExceptionMessage('Syntax error, malformed JSON'); (Closure::bind(static function (string $value) { - $entity = new Entity(); + $entity = new Entity(); $entity->casts['dummy'] = 'json[array]'; return $entity->castAs($value, 'dummy'); @@ -610,7 +610,7 @@ public function testCastAsJSONAnotherErrorDepth() $string = '{' . str_repeat('"test":{', 513) . '"test":"value"' . str_repeat('}', 513) . '}'; (Closure::bind(static function (string $value) { - $entity = new Entity(); + $entity = new Entity(); $entity->casts['dummy'] = 'json[array]'; return $entity->castAs($value, 'dummy'); @@ -624,7 +624,7 @@ public function testCastAsJSONControlCharCheck() $string = "{\n\t\"property1\": \"The quick brown fox\njumps over the lazy dog\",\n\t\"property2\":\"value2\"\n}"; (Closure::bind(static function (string $value) { - $entity = new Entity(); + $entity = new Entity(); $entity->casts['dummy'] = 'json[array]'; return $entity->castAs($value, 'dummy'); @@ -638,7 +638,7 @@ public function testCastAsJSONStateMismatch() $string = '[{"name":"jack","product_id":"1234"]'; (Closure::bind(static function (string $value) { - $entity = new Entity(); + $entity = new Entity(); $entity->casts['dummy'] = 'json[array]'; return $entity->castAs($value, 'dummy'); @@ -805,7 +805,7 @@ public function testDataMappingIssetUnsetSwapped() public function testToArraySkipAttributesWithUnderscoreInFirstCharacter() { - $entity = new class () extends Entity { + $entity = new class () extends Entity { protected $attributes = [ '_foo' => null, 'bar' => null, diff --git a/tests/system/Events/EventsTest.php b/tests/system/Events/EventsTest.php index 9b69a219b929..58a8159f3e1c 100644 --- a/tests/system/Events/EventsTest.php +++ b/tests/system/Events/EventsTest.php @@ -43,6 +43,7 @@ protected function tearDown(): void /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testInitialize() diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php index 7936cc2e62da..4b4fd9d3f63a 100644 --- a/tests/system/Files/FileCollectionTest.php +++ b/tests/system/Files/FileCollectionTest.php @@ -108,7 +108,7 @@ public function testConstructorAddsFiles() $this->file, ]; - $collection = new class ([$this->file]) extends FileCollection { + $collection = new class ([$this->file]) extends FileCollection { protected $files = [ SUPPORTPATH . 'Files/able/apple.php', ]; diff --git a/tests/system/Filters/HoneypotTest.php b/tests/system/Filters/HoneypotTest.php index 94ec0b61d1ff..c9cff3fa4125 100644 --- a/tests/system/Filters/HoneypotTest.php +++ b/tests/system/Filters/HoneypotTest.php @@ -80,6 +80,7 @@ public function testBeforeClean() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testAfter() @@ -102,6 +103,7 @@ public function testAfter() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testAfterNotApplicable() diff --git a/tests/system/HTTP/ContentSecurityPolicyTest.php b/tests/system/HTTP/ContentSecurityPolicyTest.php index 7e41c9a0d4a5..7542ed5a1934 100644 --- a/tests/system/HTTP/ContentSecurityPolicyTest.php +++ b/tests/system/HTTP/ContentSecurityPolicyTest.php @@ -60,6 +60,7 @@ protected function work(string $parm = 'Hello') /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testExistence() @@ -72,6 +73,7 @@ public function testExistence() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testReportOnly() @@ -85,6 +87,7 @@ public function testReportOnly() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testDefaults() @@ -104,6 +107,7 @@ public function testDefaults() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testChildSrc() @@ -121,6 +125,7 @@ public function testChildSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testConnectSrc() @@ -137,6 +142,7 @@ public function testConnectSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testFontSrc() @@ -155,6 +161,7 @@ public function testFontSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testFormAction() @@ -173,6 +180,7 @@ public function testFormAction() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testFrameAncestor() @@ -190,6 +198,7 @@ public function testFrameAncestor() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testFrameSrc() @@ -207,6 +216,7 @@ public function testFrameSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testImageSrc() @@ -224,6 +234,7 @@ public function testImageSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testMediaSrc() @@ -241,6 +252,7 @@ public function testMediaSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testManifestSrc() @@ -258,6 +270,7 @@ public function testManifestSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testPluginType() @@ -275,6 +288,7 @@ public function testPluginType() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testPluginArray() @@ -290,6 +304,7 @@ public function testPluginArray() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testObjectSrc() @@ -307,6 +322,7 @@ public function testObjectSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testScriptSrc() @@ -324,6 +340,7 @@ public function testScriptSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testStyleSrc() @@ -341,6 +358,7 @@ public function testStyleSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBaseURIDefault() @@ -354,6 +372,7 @@ public function testBaseURIDefault() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBaseURI() @@ -368,6 +387,7 @@ public function testBaseURI() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBaseURIRich() @@ -382,6 +402,7 @@ public function testBaseURIRich() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testDefaultSrc() @@ -398,6 +419,7 @@ public function testDefaultSrc() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testReportURI() @@ -413,6 +435,7 @@ public function testReportURI() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSandboxFlags() @@ -429,6 +452,7 @@ public function testSandboxFlags() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testUpgradeInsecureRequests() @@ -443,6 +467,7 @@ public function testUpgradeInsecureRequests() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBodyEmpty() @@ -456,6 +481,7 @@ public function testBodyEmpty() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBodyScriptNonce() @@ -527,6 +553,7 @@ public function testBodyStyleNonceDisableAutoNonce() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testBodyStyleNonce() @@ -566,6 +593,7 @@ public function testBodyStyleNonceCustomStyleTag() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeaderWrongCaseNotFound() @@ -579,6 +607,7 @@ public function testHeaderWrongCaseNotFound() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeaderIgnoreCase() @@ -592,6 +621,7 @@ public function testHeaderIgnoreCase() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testCSPDisabled() @@ -623,6 +653,7 @@ public function testGetStyleNonce() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeaderScriptNonceEmittedOnceGetScriptNonceCalled() diff --git a/tests/system/HTTP/DownloadResponseTest.php b/tests/system/HTTP/DownloadResponseTest.php index eb6df43eecac..f0c9b3024f6d 100644 --- a/tests/system/HTTP/DownloadResponseTest.php +++ b/tests/system/HTTP/DownloadResponseTest.php @@ -299,6 +299,7 @@ public function testPretendOutput() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testRealOutput() diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index f19f9cf53ee4..f7d50dccff24 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -124,6 +124,7 @@ public function testCanGetOldInputArrayWithSESSION() * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 * * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testCanGetOldInputArrayWithSessionService() diff --git a/tests/system/HTTP/RedirectResponseTest.php b/tests/system/HTTP/RedirectResponseTest.php index 95cd6003f275..1b8fe62f49d9 100644 --- a/tests/system/HTTP/RedirectResponseTest.php +++ b/tests/system/HTTP/RedirectResponseTest.php @@ -117,6 +117,7 @@ public function testRedirectRelativeConvertsToFullURI() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testWithInput() @@ -137,6 +138,7 @@ public function testWithInput() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testWithValidationErrors() @@ -157,6 +159,7 @@ public function testWithValidationErrors() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testWith() @@ -173,6 +176,7 @@ public function testWith() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testRedirectBack() @@ -189,6 +193,7 @@ public function testRedirectBack() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testRedirectBackMissing() @@ -204,6 +209,7 @@ public function testRedirectBackMissing() /** * @runInSeparateProcess + * * @preserveGlobalState disabled * * @see https://github.com/codeigniter4/CodeIgniter4/issues/2119 @@ -245,6 +251,7 @@ public function testWithCookies() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testWithCookiesWithEmptyCookies() diff --git a/tests/system/HTTP/ResponseSendTest.php b/tests/system/HTTP/ResponseSendTest.php index b67820785eb5..b30587d0493e 100644 --- a/tests/system/HTTP/ResponseSendTest.php +++ b/tests/system/HTTP/ResponseSendTest.php @@ -44,6 +44,7 @@ final class ResponseSendTest extends CIUnitTestCase /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeadersMissingDate() @@ -77,6 +78,7 @@ public function testHeadersMissingDate() * it makes sure that sending gives CSP a chance to do its thing. * * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeadersWithCSP() @@ -111,7 +113,9 @@ public function testHeadersWithCSP() * Make sure cookies are set by RedirectResponse this way * * @see https://github.com/codeigniter4/CodeIgniter4/issues/1393 + * * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testRedirectResponseCookies() diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index 1a51741b8c36..8e6bcb95ede9 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -660,6 +660,7 @@ public function testResolveRelativeURI($rel, $expected) /** * @dataProvider defaultResolutions + * * @group single * * @param mixed $rel @@ -789,6 +790,7 @@ public function testGetQueryWithStrings() /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/331 + * * @group single */ public function testNoExtraSlashes() diff --git a/tests/system/Helpers/FormHelperTest.php b/tests/system/Helpers/FormHelperTest.php index 3fdcc582d0fc..a464fbb488d5 100644 --- a/tests/system/Helpers/FormHelperTest.php +++ b/tests/system/Helpers/FormHelperTest.php @@ -836,6 +836,7 @@ public function testSetCheckboxWithValueZero() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSetRadioFromSessionOldInput() @@ -856,6 +857,7 @@ public function testSetRadioFromSessionOldInput() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSetRadioFromPost() @@ -869,6 +871,7 @@ public function testSetRadioFromPost() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testSetRadioFromPostWithValueZero() diff --git a/tests/system/Helpers/TextHelperTest.php b/tests/system/Helpers/TextHelperTest.php index 7c736614a36d..bdc236909f8c 100755 --- a/tests/system/Helpers/TextHelperTest.php +++ b/tests/system/Helpers/TextHelperTest.php @@ -196,7 +196,6 @@ public function testEntitiesToAsciiSmallOrdinals() public function testConvertAccentedCharacters() { - //$this->ci_vfs_clone('application/Config/ForeignChars.php'); $this->assertSame('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ')); $this->assertSame('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü')); } diff --git a/tests/system/I18n/TimeDifferenceTest.php b/tests/system/I18n/TimeDifferenceTest.php index 7141f71769d3..4f8a02f038af 100644 --- a/tests/system/I18n/TimeDifferenceTest.php +++ b/tests/system/I18n/TimeDifferenceTest.php @@ -19,12 +19,23 @@ */ final class TimeDifferenceTest extends CIUnitTestCase { + private string $currentLocale; + protected function setUp(): void { parent::setUp(); helper('date'); - Locale::setDefault('America/Chicago'); + + $this->currentLocale = Locale::getDefault(); + Locale::setDefault('en-US'); + } + + protected function tearDown(): void + { + parent::tearDown(); + + Locale::setDefault($this->currentLocale); } public function testDifferenceBasics() diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 2db4fcc48c2b..ff2c04640682 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -25,14 +25,25 @@ */ final class TimeTest extends CIUnitTestCase { + private string $currentLocale; + protected function setUp(): void { parent::setUp(); helper('date'); + + $this->currentLocale = Locale::getDefault(); Locale::setDefault('en_US'); } + protected function tearDown(): void + { + parent::tearDown(); + + Locale::setDefault($this->currentLocale); + } + public function testNewTimeNow() { $formatter = new IntlDateFormatter( @@ -55,7 +66,7 @@ public function testTimeWithTimezone() IntlDateFormatter::SHORT, IntlDateFormatter::SHORT, 'Europe/London', // Default for CodeIgniter - IntlDateFormatter::GREGORIAN, + IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd HH:mm:ss' ); @@ -71,7 +82,7 @@ public function testTimeWithTimezoneAndLocale() IntlDateFormatter::SHORT, IntlDateFormatter::SHORT, 'Europe/London', // Default for CodeIgniter - IntlDateFormatter::GREGORIAN, + IntlDateFormatter::GREGORIAN, 'yyyy-MM-dd HH:mm:ss' ); diff --git a/tests/system/Models/GeneralModelTest.php b/tests/system/Models/GeneralModelTest.php index cf5b890c2718..450d3cc87d60 100644 --- a/tests/system/Models/GeneralModelTest.php +++ b/tests/system/Models/GeneralModelTest.php @@ -102,7 +102,7 @@ public function testSetAllowedFields(): void 'updated_at', ]; - $model = new class () extends Model { + $model = new class () extends Model { protected $allowedFields = [ 'id', 'created_at', diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index 0ff142375fde..48387dc72968 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -263,7 +263,7 @@ public function testSaveNewEntityWithDate(): void ]; }; - $testModel = new class () extends Model { + $testModel = new class () extends Model { protected $table = 'empty'; protected $allowedFields = [ 'name', diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index d3dc0ea56a94..b65a7ddf38c4 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -36,6 +36,7 @@ * return correct responses. * * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php index c44bbba564d1..c36f6340c861 100644 --- a/tests/system/RESTful/ResourcePresenterTest.php +++ b/tests/system/RESTful/ResourcePresenterTest.php @@ -30,6 +30,7 @@ * return correct responses. * * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php index ddf4f6b42ce4..228c386793c5 100644 --- a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php @@ -31,6 +31,7 @@ /** * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php index af7f8c21905a..a87db60a19b0 100644 --- a/tests/system/Security/SecurityCSRFSessionTest.php +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -30,6 +30,7 @@ /** * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index c6cf278a6073..37faed7f2c50 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -23,6 +23,7 @@ /** * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index c03e5132ce2b..84892479fee9 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -23,6 +23,7 @@ * Exercise our Controller class. * * @runTestsInSeparateProcesses + * * @preserveGlobalState disabled * * @internal diff --git a/tests/system/Test/TestCaseEmissionsTest.php b/tests/system/Test/TestCaseEmissionsTest.php index 64f21b121734..edc3d6b34ef4 100644 --- a/tests/system/Test/TestCaseEmissionsTest.php +++ b/tests/system/Test/TestCaseEmissionsTest.php @@ -42,6 +42,7 @@ final class TestCaseEmissionsTest extends CIUnitTestCase /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeadersEmitted() @@ -70,6 +71,7 @@ public function testHeadersEmitted() /** * @runInSeparateProcess + * * @preserveGlobalState disabled */ public function testHeadersNotEmitted() diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 9430cc83fda2..419070714599 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -19,11 +19,13 @@ /** * @internal + * + * @no-final */ -final class RulesTest extends CIUnitTestCase +class RulesTest extends CIUnitTestCase { - private Validation $validation; - private array $config = [ + protected Validation $validation; + protected array $config = [ 'ruleSets' => [ Rules::class, FormatRules::class, diff --git a/tests/system/Validation/StrictRules/RulesTest.php b/tests/system/Validation/StrictRules/RulesTest.php index f3f8ce946020..e6d2e034d12c 100644 --- a/tests/system/Validation/StrictRules/RulesTest.php +++ b/tests/system/Validation/StrictRules/RulesTest.php @@ -11,20 +11,18 @@ namespace CodeIgniter\Validation\StrictRules; -use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Validation\RulesTest as TraditionalRulesTest; use CodeIgniter\Validation\Validation; -use Config\Services; use Generator; -use stdClass; use Tests\Support\Validation\TestRules; /** * @internal */ -final class RulesTest extends CIUnitTestCase +final class RulesTest extends TraditionalRulesTest { - private Validation $validation; - private array $config = [ + protected Validation $validation; + protected array $config = [ 'ruleSets' => [ Rules::class, FormatRules::class, @@ -42,91 +40,16 @@ final class RulesTest extends CIUnitTestCase ], ]; - protected function setUp(): void - { - parent::setUp(); - $this->validation = new Validation((object) $this->config, Services::renderer()); - $this->validation->reset(); - } - - /** - * @dataProvider provideRequiredCases - */ - public function testRequired(array $data, bool $expected): void - { - $this->validation->setRules(['foo' => 'required']); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function provideRequiredCases(): Generator - { - yield from [ - [['foo' => null], false], - [['foo' => 123], true], - [['foo' => null, 'bar' => 123], false], - [['foo' => [123]], true], - [['foo' => []], false], - [['foo' => new stdClass()], true], - ]; - } - - /** - * @dataProvider ifExistProvider - */ - public function testIfExist(array $rules, array $data, bool $expected): void - { - $this->validation->setRules($rules); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function ifExistProvider(): Generator - { - yield from [ - [ - ['foo' => 'required'], - ['foo' => ''], - false, - ], - [ - ['foo' => 'required'], - ['foo' => null], - false, - ], - [ - ['foo' => 'if_exist|required'], - ['foo' => ''], - false, - ], - // Input data does not exist then the other rules will be ignored - [ - ['foo' => 'if_exist|required'], - [], - true, - ], - // Testing for multi-dimensional data - [ - ['foo.bar' => 'if_exist|required'], - ['foo' => ['bar' => '']], - false, - ], - [ - ['foo.bar' => 'if_exist|required'], - ['foo' => []], - true, - ], - ]; - } - /** - * @dataProvider providePermitEmptyCases + * @dataProvider providePermitEmptyCasesStrict */ - public function testPermitEmpty(array $rules, array $data, bool $expected): void + public function testPermitEmptyStrict(array $rules, array $data, bool $expected): void { $this->validation->setRules($rules); $this->assertSame($expected, $this->validation->run($data)); } - public function providePermitEmptyCases(): Generator + public function providePermitEmptyCasesStrict(): Generator { yield from [ [ @@ -159,462 +82,101 @@ public function providePermitEmptyCases(): Generator ['foo' => false], true, ], - [ - ['foo' => 'permit_empty|valid_email'], - ['foo' => ''], - true, - ], - [ - ['foo' => 'permit_empty|valid_email'], - ['foo' => 'user@domain.tld'], - true, - ], - [ - ['foo' => 'permit_empty|valid_email'], - ['foo' => 'invalid'], - false, - ], - // Required has more priority - [ - ['foo' => 'permit_empty|required|valid_email'], - ['foo' => ''], - false, - ], - [ - ['foo' => 'permit_empty|required'], - ['foo' => ''], - false, - ], - [ - ['foo' => 'permit_empty|required'], - ['foo' => null], - false, - ], - [ - ['foo' => 'permit_empty|required'], - ['foo' => false], - false, - ], - // This tests will return true because the input data is trimmed - [ - ['foo' => 'permit_empty|required'], - ['foo' => '0'], - true, - ], - [ - ['foo' => 'permit_empty|required'], - ['foo' => 0], - true, - ], - [ - ['foo' => 'permit_empty|required'], - ['foo' => 0.0], - true, - ], - [ - ['foo' => 'permit_empty|required_with[bar]'], - ['foo' => ''], - true, - ], - [ - ['foo' => 'permit_empty|required_with[bar]'], - ['foo' => 0], - true, - ], - [ - ['foo' => 'permit_empty|required_with[bar]'], - ['foo' => 0.0, 'bar' => 1], - true, - ], - [ - ['foo' => 'permit_empty|required_with[bar]'], - ['foo' => '', 'bar' => 1], - false, - ], - [ - ['foo' => 'permit_empty|required_without[bar]'], - ['foo' => ''], - false, - ], - [ - ['foo' => 'permit_empty|required_without[bar]'], - ['foo' => 0], - true, - ], - [ - ['foo' => 'permit_empty|required_without[bar]'], - ['foo' => 0.0, 'bar' => 1], - true, - ], - [ - ['foo' => 'permit_empty|required_without[bar]'], - ['foo' => '', 'bar' => 1], - true, - ], - ]; - } - - /** - * @dataProvider provideMatchesCases - */ - public function testMatches(array $data, bool $expected): void - { - $this->validation->setRules(['foo' => 'matches[bar]']); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function provideMatchesCases(): Generator - { - yield from [ - [['foo' => null, 'bar' => null], true], - [['foo' => 'match', 'bar' => 'match'], true], - [['foo' => 'match', 'bar' => 'nope'], false], - ]; - } - - /** - * @dataProvider provideMatchesNestedCases - */ - public function testMatchesNested(array $data, bool $expected): void - { - $this->validation->setRules(['nested.foo' => 'matches[nested.bar]']); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function provideMatchesNestedCases(): Generator - { - yield from [ - [['nested' => ['foo' => 'match', 'bar' => 'match']], true], - [['nested' => ['foo' => 'match', 'bar' => 'nope']], false], ]; } /** - * @dataProvider provideMatchesCases + * @dataProvider provideGreaterThanEqualStrict + * + * @param int $value */ - public function testDiffers(array $data, bool $expected): void + public function testGreaterThanEqualStrict($value, string $param, bool $expected): void { - $this->validation->setRules(['foo' => 'differs[bar]']); - $this->assertSame(! $expected, $this->validation->run($data)); - } + $this->validation->setRules(['foo' => "greater_than_equal_to[{$param}]"]); - /** - * @dataProvider provideMatchesNestedCases - */ - public function testDiffersNested(array $data, bool $expected): void - { - $this->validation->setRules(['nested.foo' => 'differs[nested.bar]']); - $this->assertSame(! $expected, $this->validation->run($data)); - } - - /** - * @dataProvider provideEqualsCases - */ - public function testEquals(array $data, string $param, bool $expected): void - { - $this->validation->setRules(['foo' => "equals[{$param}]"]); + $data = ['foo' => $value]; $this->assertSame($expected, $this->validation->run($data)); } - public function provideEqualsCases(): Generator - { - yield from [ - 'null' => [['foo' => null], '', false], - 'empty' => [['foo' => ''], '', true], - 'fail' => [['foo' => 'bar'], 'notbar', false], - 'pass' => [['foo' => 'bar'], 'bar', true], - 'casing' => [['foo' => 'bar'], 'Bar', false], - ]; - } - - /** - * @dataProvider provideMinLengthCases - */ - public function testMinLength(?string $data, string $length, bool $expected): void - { - $this->validation->setRules(['foo' => "min_length[{$length}]"]); - $this->assertSame($expected, $this->validation->run(['foo' => $data])); - } - - public function provideMinLengthCases(): Generator + public function provideGreaterThanEqualStrict(): Generator { yield from [ - 'null' => [null, '2', false], - 'less' => ['bar', '2', true], - 'equal' => ['bar', '3', true], - 'greater' => ['bar', '4', false], + [0, '0', true], + [1, '0', true], + [-1, '0', false], + [true, '0', false], ]; } /** - * @dataProvider provideMinLengthCases - */ - public function testMaxLength(?string $data, string $length, bool $expected): void - { - $this->validation->setRules(['foo' => "max_length[{$length}]"]); - $this->assertSame(! $expected || $length === '3', $this->validation->run(['foo' => $data])); - } - - public function testMaxLengthReturnsFalseWithNonNumericVal(): void - { - $this->validation->setRules(['foo' => 'max_length[bar]']); - $this->assertFalse($this->validation->run(['foo' => 'bar'])); - } - - /** - * @dataProvider provideExactLengthCases + * @dataProvider provideGreaterThanStrict + * + * @param int $value */ - public function testExactLength(?string $data, bool $expected): void - { - $this->validation->setRules(['foo' => 'exact_length[3]']); - $this->assertSame($expected, $this->validation->run(['foo' => $data])); - } - - public function provideExactLengthCases(): Generator + public function testGreaterThanStrict($value, string $param, bool $expected): void { - yield from [ - 'null' => [null, false], - 'exact' => ['bar', true], - 'less' => ['ba', false], - 'greater' => ['bars', false], - ]; - } + $this->validation->setRules(['foo' => "greater_than[{$param}]"]); - public function testExactLengthDetectsBadLength(): void - { - $data = ['foo' => 'bar']; - $this->validation->setRules(['foo' => 'exact_length[abc]']); - $this->assertFalse($this->validation->run($data)); - } - - /** - * @dataProvider greaterThanProvider - */ - public function testGreaterThan(?string $first, ?string $second, bool $expected): void - { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "greater_than[{$second}]"]); + $data = ['foo' => $value]; $this->assertSame($expected, $this->validation->run($data)); } - public function greaterThanProvider(): Generator + public function provideGreaterThanStrict(): Generator { yield from [ - ['-10', '-11', true], - ['10', '9', true], - ['10', '10', false], - ['10', 'a', false], - ['10a', '10', false], - [null, null, false], + [-10, '-11', true], + [10, '9', true], + [10, '10', false], + [10, 'a', false], + [true, '0', false], ]; } /** - * @dataProvider greaterThanEqualProvider + * @dataProvider provideLessThanStrict + * + * @param int $value */ - public function testGreaterThanEqual(?string $first, ?string $second, bool $expected): void - { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "greater_than_equal_to[{$second}]"]); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function greaterThanEqualProvider(): Generator + public function testLessThanStrict($value, string $param, bool $expected): void { - yield from [ - ['0', '0', true], - ['1', '0', true], - ['-1', '0', false], - ['10a', '0', false], - [null, null, false], - ['1', null, true], - [null, '1', false], - ]; - } + $this->validation->setRules(['foo' => "less_than[{$param}]"]); - /** - * @dataProvider lessThanProvider - */ - public function testLessThan(?string $first, ?string $second, bool $expected): void - { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "less_than[{$second}]"]); + $data = ['foo' => $value]; $this->assertSame($expected, $this->validation->run($data)); } - public function lessThanProvider(): Generator + public function provideLessThanStrict(): Generator { yield from [ - ['-10', '-11', false], - ['9', '10', true], - ['10', '9', false], - ['10', '10', false], - ['10', 'a', true], - ['10a', '10', false], - [null, null, false], + [-10, '-11', false], + [9, '10', true], + [10, '9', false], + [10, '10', false], + [10, 'a', true], + [true, '0', false], ]; } /** - * @dataProvider lessThanEqualProvider + * @dataProvider provideLessThanEqualStrict + * + * @param int $value */ - public function testLessEqualThan(?string $first, ?string $second, bool $expected): void + public function testLessEqualThanStrict($value, ?string $param, bool $expected): void { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "less_than_equal_to[{$second}]"]); - $this->assertSame($expected, $this->validation->run($data)); - } + $this->validation->setRules(['foo' => "less_than_equal_to[{$param}]"]); - public function lessThanEqualProvider(): Generator - { - yield from [ - ['0', '0', true], - ['1', '0', false], - ['-1', '0', true], - ['10a', '0', false], - [null, null, false], - ['1', null, false], - [null, '1', false], - ]; - } - - /** - * @dataProvider inListProvider - */ - public function testInList(?string $first, ?string $second, bool $expected): void - { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "in_list[{$second}]"]); - $this->assertSame($expected, $this->validation->run($data)); - } - - /** - * @dataProvider inListProvider - */ - public function testNotInList(?string $first, ?string $second, bool $expected): void - { - $data = ['foo' => $first]; - $this->validation->setRules(['foo' => "not_in_list[{$second}]"]); - $this->assertSame(! $expected, $this->validation->run($data)); - } - - public function inListProvider(): Generator - { - yield from [ - ['red', 'red,Blue,123', true], - ['Blue', 'red, Blue,123', true], - ['Blue', 'red,Blue,123', true], - ['123', 'red,Blue,123', true], - ['Red', 'red,Blue,123', false], - [' red', 'red,Blue,123', false], - ['1234', 'red,Blue,123', false], - [null, 'red,Blue,123', false], - ['red', null, false], - ]; - } - - /** - * @dataProvider requiredWithProvider - */ - public function testRequiredWith(?string $field, ?string $check, bool $expected): void - { - $data = [ - 'foo' => 'bar', - 'bar' => 'something', - 'baz' => null, - 'array' => [ - 'nonEmptyField1' => 'value1', - 'nonEmptyField2' => 'value2', - 'emptyField1' => null, - 'emptyField2' => null, - ], - ]; - - $this->validation->setRules([$field => "required_with[{$check}]"]); + $data = ['foo' => $value]; $this->assertSame($expected, $this->validation->run($data)); } - public function requiredWithProvider(): Generator + public function provideLessThanEqualStrict(): Generator { yield from [ - ['nope', 'bar', false], - ['foo', 'bar', true], - ['nope', 'baz', true], - [null, null, true], - [null, 'foo', false], - ['foo', null, true], - [ - 'array.emptyField1', - 'array.emptyField2', - true, - ], - [ - 'array.nonEmptyField1', - 'array.emptyField2', - true, - ], - [ - 'array.emptyField1', - 'array.nonEmptyField2', - false, - ], - [ - 'array.nonEmptyField1', - 'array.nonEmptyField2', - true, - ], - ]; - } - - /** - * @dataProvider requiredWithoutProvider - */ - public function testRequiredWithout(?string $field, ?string $check, bool $expected): void - { - $data = [ - 'foo' => 'bar', - 'bar' => 'something', - 'baz' => null, - 'array' => [ - 'nonEmptyField1' => 'value1', - 'nonEmptyField2' => 'value2', - 'emptyField1' => null, - 'emptyField2' => null, - ], - ]; - - $this->validation->setRules([$field => "required_without[{$check}]"]); - $this->assertSame($expected, $this->validation->run($data)); - } - - public function requiredWithoutProvider(): Generator - { - yield from [ - ['nope', 'bars', false], - ['foo', 'nope', true], - [null, null, false], - [null, 'foo', true], - ['foo', null, true], - [ - 'array.emptyField1', - 'array.emptyField2', - false, - ], - [ - 'array.nonEmptyField1', - 'array.emptyField2', - true, - ], - [ - 'array.emptyField1', - 'array.nonEmptyField2', - true, - ], - [ - 'array.nonEmptyField1', - 'array.nonEmptyField2', - true, - ], + [0, '0', true], + [1, '0', false], + [-1, '0', true], + [true, '0', false], ]; } } diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 5a48615b6c05..09faa1bb2282 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -25,6 +25,7 @@ /** * @internal + * * @no-final */ class ValidationTest extends CIUnitTestCase @@ -641,6 +642,42 @@ public function testJsonInput(): void unset($_SERVER['CONTENT_TYPE']); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/6466 + */ + public function testJsonInputObjectArray(): void + { + $json = <<<'EOL' + { + "p": [ + { + "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + } + ] + } + EOL; + + $_SERVER['CONTENT_TYPE'] = 'application/json'; + + $config = new App(); + $config->baseURL = 'http://example.com/'; + + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + + $rules = [ + 'p' => 'required|array_count[2]', + ]; + $validated = $this->validation + ->withRequest($request->withMethod('patch')) + ->setRules($rules) + ->run(); + + $this->assertFalse($validated); + $this->assertSame(['p' => 'Validation.array_count'], $this->validation->getErrors()); + + unset($_SERVER['CONTENT_TYPE']); + } + public function testHasRule(): void { $this->validation->setRuleGroup('groupA'); diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index ab9c0860b851..3fa36585e7ea 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -267,7 +267,7 @@ public function testParseLoopObjectProperties() public function testParseLoopEntityProperties() { - $power = new class () extends Entity { + $power = new class () extends Entity { public $foo = 'bar'; protected $bar = 'baz'; @@ -297,7 +297,7 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu public function testParseLoopEntityObjectProperties() { - $power = new class () extends Entity { + $power = new class () extends Entity { protected $attributes = [ 'foo' => 'bar', 'bar' => 'baz', @@ -738,7 +738,7 @@ public function testParserPluginClosure() public function testParserPluginParams() { $this->parser->addPlugin('growth', static function ($str, array $params) { - $step = $params['step'] ?? 1; + $step = $params['step'] ?? 1; $count = $params['count'] ?? 2; $out = ''; diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index 0c1bf02a8bf0..3f9becffa838 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.2.7 v4.2.6 v4.2.5 v4.2.4 diff --git a/user_guide_src/source/changelogs/v4.2.6.rst b/user_guide_src/source/changelogs/v4.2.6.rst index d1a467297660..2da5842ea88f 100644 --- a/user_guide_src/source/changelogs/v4.2.6.rst +++ b/user_guide_src/source/changelogs/v4.2.6.rst @@ -1,7 +1,7 @@ Version 4.2.6 ############# -Release Date: Unreleased +Release Date: September 4, 2022 **4.2.6 release of CodeIgniter4** @@ -27,11 +27,12 @@ none. Deprecations ************ -none. +- :php:meth:`CodeIgniter\\Cookie\\Cookie::withNeverExpiring()` is deprecated. Bugs Fixed ********** -none. +Many bugs fixed, but notably: +- AssertionError occurs when using Validation in CLI `https://github.com/codeigniter4/CodeIgniter4/pull/6452` See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. diff --git a/user_guide_src/source/changelogs/v4.2.7.rst b/user_guide_src/source/changelogs/v4.2.7.rst new file mode 100644 index 000000000000..916a67676280 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.2.7.rst @@ -0,0 +1,37 @@ +Version 4.2.7 +############# + +Release Date: Unreleased + +**4.2.7 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 2 + +BREAKING +******** + +none. + +Enhancements +************ + +none. + +Changes +******* + +none. + +Deprecations +************ + +none. + +Bugs Fixed +********** + +none. + +See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index 6d2d282ddb7e..076101e2d2a8 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -24,7 +24,7 @@ version = '4.2' # The full version, including alpha/beta/rc tags. -release = '4.2.5' +release = '4.2.6' # -- General configuration --------------------------------------------------- diff --git a/user_guide_src/source/database/call_function/002.php b/user_guide_src/source/database/call_function/002.php index 64d5e0fbc85f..fa26ae0edc68 100644 --- a/user_guide_src/source/database/call_function/002.php +++ b/user_guide_src/source/database/call_function/002.php @@ -1,3 +1,3 @@ callFunction('some_function', $param1, $param2, /* ... */); +$db->callFunction('some_function', $param1, $param2 /* , ... */); diff --git a/user_guide_src/source/database/metadata.rst b/user_guide_src/source/database/metadata.rst index 75459e7e053c..7276f4730b40 100644 --- a/user_guide_src/source/database/metadata.rst +++ b/user_guide_src/source/database/metadata.rst @@ -103,8 +103,8 @@ database: - name - column name - type - the type of the column - max_length - maximum length of the column -- primary_key - integer ``1`` if the column is a primary key (all integer ``1``, even if there are multiple primary keys), otherwise integer ``0`` -- nullable - boolean ``true`` if the column is nullable, otherwise boolean ``false`` +- primary_key - integer ``1`` if the column is a primary key (all integer ``1``, even if there are multiple primary keys), otherwise integer ``0`` (This field is currently only available for MySQL and SQLite3) +- nullable - boolean ``true`` if the column is nullable, otherwise boolean ``false`` (This field is currently not available in SQL Server) - default - the default value List the Indexes in a Table diff --git a/user_guide_src/source/database/query_builder/042.php b/user_guide_src/source/database/query_builder/042.php index 7c9935e4f356..26a4c0316e1f 100644 --- a/user_guide_src/source/database/query_builder/042.php +++ b/user_guide_src/source/database/query_builder/042.php @@ -1,4 +1,5 @@ like('title', 'match'); $builder->orLike('body', $match); +$builder->like('title', 'match'); +$builder->orLike('body', $match); // WHERE `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/063.php b/user_guide_src/source/database/query_builder/063.php index 0b7543273430..ada34b2e65d4 100644 --- a/user_guide_src/source/database/query_builder/063.php +++ b/user_guide_src/source/database/query_builder/063.php @@ -1,4 +1,5 @@ havingLike('title', 'match'); $builder->orHavingLike('body', $match); +$builder->havingLike('title', 'match'); +$builder->orHavingLike('body', $match); // HAVING `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/incoming/controllers/004.php b/user_guide_src/source/incoming/controllers/004.php index 65b1c77f8014..9216bab50032 100644 --- a/user_guide_src/source/incoming/controllers/004.php +++ b/user_guide_src/source/incoming/controllers/004.php @@ -8,7 +8,7 @@ public function updateUser(int $userID) { if (! $this->validate([ 'email' => "required|is_unique[users.email,id,{$userID}]", - 'name' => 'required|alpha_numeric_spaces', + 'name' => 'required|alpha_numeric_spaces', ])) { return view('users/update', [ 'errors' => $this->validator->getErrors(), diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 86f53d3be3df..98c9191dab15 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -47,6 +47,23 @@ You can supply multiple verbs that a route should match by passing them in as an .. literalinclude:: routing/004.php +Controller's Namespace +====================== + +If a controller name is stated without beginning with ``\``, the :ref:`routing-default-namespace` will be prepended: + +.. literalinclude:: routing/063.php + +If you put ``\`` at the beginning, it is treated as a fully qualified class name: + +.. literalinclude:: routing/064.php + +You can also specify the namespace with the ``namespace`` option: + +.. literalinclude:: routing/038.php + +See :ref:`assigning-namespace` for details. + Placeholders ============ @@ -394,7 +411,7 @@ You specify an array for the filter value: Assigning Namespace ------------------- -While a default namespace will be prepended to the generated controllers (see below), you can also specify +While a :ref:`routing-default-namespace` will be prepended to the generated controllers, you can also specify a different namespace to be used in any options array, with the ``namespace`` option. The value should be the namespace you want modified: @@ -480,6 +497,8 @@ Routes Configuration Options The RoutesCollection class provides several options that affect all routes, and can be modified to meet your application's needs. These options are available at the top of **app/Config/Routes.php**. +.. _routing-default-namespace: + Default Namespace ================= diff --git a/user_guide_src/source/incoming/routing/063.php b/user_guide_src/source/incoming/routing/063.php new file mode 100644 index 000000000000..4996345ed7ae --- /dev/null +++ b/user_guide_src/source/incoming/routing/063.php @@ -0,0 +1,4 @@ +post('api/users', 'Api\Users::update'); diff --git a/user_guide_src/source/incoming/routing/064.php b/user_guide_src/source/incoming/routing/064.php new file mode 100644 index 000000000000..8d6df0548e30 --- /dev/null +++ b/user_guide_src/source/incoming/routing/064.php @@ -0,0 +1,4 @@ +get('blog', '\Acme\Blog\Controllers\Home::list'); diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst index 4adac8a7613a..e932b8cdf1ff 100644 --- a/user_guide_src/source/installation/upgrade_420.rst +++ b/user_guide_src/source/installation/upgrade_420.rst @@ -38,6 +38,26 @@ Config/Constants.php The constants ``EVENT_PRIORITY_LOW``, ``EVENT_PRIORITY_NORMAL`` and ``EVENT_PRIORITY_HIGH`` are deprecated, and the definitions are moved to ``app/Config/Constants.php``. If you use these constants, define them in ``app/Config/Constants.php``. Or use new class constants ``CodeIgniter\Events\Events::PRIORITY_LOW``, ``CodeIgniter\Events\Events::PRIORITY_NORMAL`` and ``CodeIgniter\Events\Events::PRIORITY_HIGH``. +composer.json +============= + +If you use Composer, when you installed CodeIgniter v4.1.9 or before, and +if there are ``App\\`` and ``Config\\`` namespaces in your ``/composer.json``'s ``autoload.psr-4`` +like the following, you need to remove these lines, and run ``composer dump-autoload``. + +.. code-block:: text + + { + ... + "autoload": { + "psr-4": { + "App\\": "app", <-- Remove this line + "Config\\": "app/Config" <-- Remove this line + } + }, + ... + } + Breaking Changes **************** diff --git a/user_guide_src/source/installation/upgrade_426.rst b/user_guide_src/source/installation/upgrade_426.rst new file mode 100644 index 000000000000..a6d91b1d297b --- /dev/null +++ b/user_guide_src/source/installation/upgrade_426.rst @@ -0,0 +1,32 @@ +############################# +Upgrading from 4.2.5 to 4.2.6 +############################# + +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 + + +Project Files +************* + +A few files in the **project space** (root, app, public, writable) received cosmetic updates. +You need not touch these files at all. There are some third-party CodeIgniter modules available +to assist with merging changes to the project space: `Explore on Packagist `_. + +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: + +* app/Config/App.php +* app/Config/ContentSecurityPolicy.php +* app/Config/Routes.php +* app/Config/Validation.php diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index a31a3164d9c2..e89ad02ad94f 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_426 upgrade_425 upgrade_423 upgrade_422 diff --git a/user_guide_src/source/libraries/cookies.rst b/user_guide_src/source/libraries/cookies.rst index 1964eb4cf144..6cfc37327106 100644 --- a/user_guide_src/source/libraries/cookies.rst +++ b/user_guide_src/source/libraries/cookies.rst @@ -223,7 +223,7 @@ In runtime, you can manually supply a new default using the ``Cookie::setDefault Class Reference *************** -.. php:namespace:: CodeIgniter\HTTP\Cookie +.. php:namespace:: CodeIgniter\Cookie .. php:class:: Cookie @@ -326,6 +326,8 @@ Class Reference .. php:method:: withNeverExpiring() + .. important:: This method is deprecated. + :param string $name: :rtype: ``Cookie`` :returns: new ``Cookie`` instance diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index b88f1761d841..86b3de4549df 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -380,13 +380,20 @@ Cleans out the database table by permanently removing all rows that have 'delete .. literalinclude:: model/026.php +In-Model Validation +=================== + Validating Data -=============== +--------------- For many people, validating data in the model is the preferred way to ensure the data is kept to a single standard, without duplicating code. The Model class provides a way to automatically have all data validated prior to saving to the database with the ``insert()``, ``update()``, or ``save()`` methods. +.. important:: When you update data, the validation in the model class only validate provided fields. + So when you set the rule ``required``, if you don't pass the required field data, + the validation won't fail. This is to avoid validation errors when updating only some fields. + 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: @@ -394,7 +401,11 @@ be applied. If you have custom error message that you want to use, place them in The other way to set the validation rules to fields by functions, -.. php:function:: setValidationRule($field, $fieldRules) +.. php:namespace:: CodeIgniter + +.. php:class:: Model + +.. php:method:: setValidationRule($field, $fieldRules) :param string $field: :param array $fieldRules: @@ -405,7 +416,7 @@ The other way to set the validation rules to fields by functions, .. literalinclude:: model/028.php -.. php:function:: setValidationRules($validationRules) +.. php:method:: setValidationRules($validationRules) :param array $validationRules: @@ -417,7 +428,7 @@ The other way to set the validation rules to fields by functions, The other way to set the validation message to fields by functions, -.. php:function:: setValidationMessage($field, $fieldMessages) +.. php:method:: setValidationMessage($field, $fieldMessages) :param string $field: :param array $fieldMessages: @@ -428,7 +439,7 @@ The other way to set the validation message to fields by functions, .. literalinclude:: model/030.php -.. php:function:: setValidationMessages($fieldMessages) +.. php:method:: setValidationMessages($fieldMessages) :param array $fieldMessages: @@ -454,7 +465,7 @@ and simply set ``$validationRules`` to the name of the validation rule group you .. literalinclude:: model/034.php Retrieving Validation Rules -=========================== +--------------------------- You can retrieve a model's validation rules by accessing its ``validationRules`` property: @@ -473,7 +484,7 @@ value an array of fieldnames of interest: .. literalinclude:: model/037.php Validation Placeholders -======================= +----------------------- The model provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply diff --git a/user_guide_src/source/tutorial/create_news_items/002.php b/user_guide_src/source/tutorial/create_news_items/002.php index 66ff5e26776b..d98f9f8b4a44 100644 --- a/user_guide_src/source/tutorial/create_news_items/002.php +++ b/user_guide_src/source/tutorial/create_news_items/002.php @@ -10,7 +10,7 @@ public function create() if ($this->request->getMethod() === 'post' && $this->validate([ 'title' => 'required|min_length[3]|max_length[255]', - 'body' => 'required', + 'body' => 'required', ])) { $model->save([ 'title' => $this->request->getPost('title'), diff --git a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php index 530fe18b029e..054eb75a2800 100644 --- a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php +++ b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php @@ -55,7 +55,7 @@ public function run($a_b) } } CODE_SAMPLE -, + , <<<'CODE_SAMPLE' final class SomeClass {