From 0f6a341d855500ac3f0d4e88b9368cdbf5650e72 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 May 2023 10:15:25 +0900 Subject: [PATCH 001/135] docs: add changelog and upgrade for v4.3.6 --- user_guide_src/source/changelogs/index.rst | 1 + user_guide_src/source/changelogs/v4.3.6.rst | 29 +++++++++++ .../source/installation/upgrade_436.rst | 50 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 4 files changed, 81 insertions(+) create mode 100644 user_guide_src/source/changelogs/v4.3.6.rst create mode 100644 user_guide_src/source/installation/upgrade_436.rst diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index c93591cdfd07..f1d8427dc42b 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.3.6 v4.3.5 v4.3.4 v4.3.3 diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst new file mode 100644 index 000000000000..ed38514b5ecf --- /dev/null +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -0,0 +1,29 @@ +Version 4.3.6 +############# + +Release Date: Unreleased + +**{version} release of CodeIgniter4** + +.. contents:: + :local: + :depth: 3 + +BREAKING +******** + +Message Changes +*************** + +Changes +******* + +Deprecations +************ + +Bugs Fixed +********** + +See the repo's +`CHANGELOG.md `_ +for a complete list of bugs fixed. diff --git a/user_guide_src/source/installation/upgrade_436.rst b/user_guide_src/source/installation/upgrade_436.rst new file mode 100644 index 000000000000..85536f9dbcc7 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_436.rst @@ -0,0 +1,50 @@ +############################# +Upgrading from 4.3.5 to 4.3.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 + +Mandatory File Changes +********************** + +Breaking Changes +**************** + +Breaking Enhancements +********************* + +Project Files +************* + +Some files in the **project space** (root, app, public, writable) received updates. Due to +these files being outside of the **system** scope they will not be changed without your intervention. + +There are some third-party CodeIgniter modules available to assist with merging changes to +the project space: `Explore on Packagist `_. + +Content Changes +=============== + +The following files received significant changes (including deprecations or visual adjustments) +and it is recommended that you merge the updated versions with your application: + +Config +------ + +- @TODO + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +- @TODO diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 4d9c1339142d..6b411b767044 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_436 upgrade_435 upgrade_434 upgrade_433 From 12dce39d06a3c1bb29ec2fb5c40cb5c57164be3b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 May 2023 20:45:47 +0900 Subject: [PATCH 002/135] docs: change parameter descriptions to numbered list --- user_guide_src/source/libraries/validation.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 5b2b58d06d2a..e8e8a96b7af4 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -690,8 +690,13 @@ Your new custom rule could now be used just like any other rule: Allowing Parameters ------------------- -If your method needs to work with parameters, the function will need a minimum of three parameters: the value to validate, -the parameter string, and an array with all of the data that was submitted the form. The ``$data`` array is especially handy +If your method needs to work with parameters, the function will need a minimum of three parameters: + +1. the value to validate (``$value``) +2. the parameter string (``$params``) +3. an array with all of the data that was submitted the form (``$data``) + +The ``$data`` array is especially handy for rules like ``required_with`` that needs to check the value of another submitted field to base its result on: .. literalinclude:: validation/037.php From 403b4735813e3db5a326392aba1b9fef7c5149fe Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 May 2023 20:58:50 +0900 Subject: [PATCH 003/135] docs: add warning --- user_guide_src/source/libraries/validation.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index e8e8a96b7af4..c835ab168a8a 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -696,6 +696,11 @@ If your method needs to work with parameters, the function will need a minimum o 2. the parameter string (``$params``) 3. an array with all of the data that was submitted the form (``$data``) +.. warning:: The other field values in ``$data`` is unvalidated (or maybe invalid) + data. Using unvalidated input data is a source of vulnerability. You must + perform the necessary validation within your custom rules before using the + data in ``$data``. + The ``$data`` array is especially handy for rules like ``required_with`` that needs to check the value of another submitted field to base its result on: From 3f8f4a9edef714fd8a2bc23628b2b5f1c026bc88 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 May 2023 21:02:08 +0900 Subject: [PATCH 004/135] docs: move &$error description to numbered list --- user_guide_src/source/libraries/validation.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index c835ab168a8a..a5956dcb9c5d 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -695,6 +695,7 @@ If your method needs to work with parameters, the function will need a minimum o 1. the value to validate (``$value``) 2. the parameter string (``$params``) 3. an array with all of the data that was submitted the form (``$data``) +4. (optional) a custom error string (``&$error``), just as described above. .. warning:: The other field values in ``$data`` is unvalidated (or maybe invalid) data. Using unvalidated input data is a source of vulnerability. You must @@ -706,8 +707,6 @@ for rules like ``required_with`` that needs to check the value of another submit .. literalinclude:: validation/037.php -Custom errors can be returned as the fourth parameter ``&$error``, just as described above. - .. _validation-using-closure-rule: Using Closure Rule From d80fa7ce665c07dffa74170626b334a20933e685 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:12:22 +0900 Subject: [PATCH 005/135] chore: update psalm-baseline.xml --- psalm-baseline.xml | 151 ++++++++++----------------------------------- 1 file changed, 34 insertions(+), 117 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9816237b9c82..5a27ec1a17c3 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,44 +1,34 @@ - - - - require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php' - - + - + Memcache Memcache Memcache - - $this->memcached - $this->memcached - $this->memcached - $this->memcached - $this->memcached - $this->memcached + + memcached]]> + memcached]]> + memcached]]> + memcached]]> + memcached]]> + memcached]]> Memcache|Memcached - - - $routeWithoutController - - - + $routeWithoutController $routeWithoutController - - $this->db->transStatus + + db->transStatus]]> - + OCI_COMMIT_ON_SUCCESS OCI_COMMIT_ON_SUCCESS OCI_COMMIT_ON_SUCCESS @@ -46,167 +36,94 @@ SQLT_CHR - - - SQLSRV_ENC_CHAR - SQLSRV_ERR_ERRORS - SQLSRV_ERR_ERRORS - - - - - SQLSRV_FETCH_ASSOC - SQLSRV_SQLTYPE_BIGINT - SQLSRV_SQLTYPE_BIT - SQLSRV_SQLTYPE_CHAR - SQLSRV_SQLTYPE_DATE - SQLSRV_SQLTYPE_DATETIME - SQLSRV_SQLTYPE_DATETIME2 - SQLSRV_SQLTYPE_DATETIMEOFFSET - SQLSRV_SQLTYPE_DECIMAL - SQLSRV_SQLTYPE_FLOAT - SQLSRV_SQLTYPE_IMAGE - SQLSRV_SQLTYPE_INT - SQLSRV_SQLTYPE_MONEY - SQLSRV_SQLTYPE_NCHAR - SQLSRV_SQLTYPE_NTEXT - SQLSRV_SQLTYPE_NUMERIC - SQLSRV_SQLTYPE_NVARCHAR - SQLSRV_SQLTYPE_REAL - SQLSRV_SQLTYPE_SMALLDATETIME - SQLSRV_SQLTYPE_SMALLINT - SQLSRV_SQLTYPE_SMALLMONEY - SQLSRV_SQLTYPE_TEXT - SQLSRV_SQLTYPE_TIME - SQLSRV_SQLTYPE_TIMESTAMP - SQLSRV_SQLTYPE_TINYINT - SQLSRV_SQLTYPE_UDT - SQLSRV_SQLTYPE_UNIQUEIDENTIFIER - SQLSRV_SQLTYPE_VARBINARY - SQLSRV_SQLTYPE_VARCHAR - SQLSRV_SQLTYPE_XML - - - + renderTimeline - + $config - + $timestamp - + $output[$name] - + $count $count $count - + #[ReturnTypeWillChange] #[ReturnTypeWillChange] #[ReturnTypeWillChange] - + $filters - + $routes $routes - - - $value - - - + $this - - - $greeting - $name - - - - - $items - - - - - $value - - - - - $message - - - + $command - - 'JobModel' + UnexsistenceClass - - - SimpleConfig - - - - 'SomeWidget' + + - - $db->username - $db->username + + username]]> + username]]> - + OCI_ASSOC OCI_B_CURSOR OCI_RETURN_NULLS - + $current[$key] - - $_SESSION['_ci_old_input'] + + - + NeverHeardOfIt From 4c76bbf8509a16683452a4a14efabc0cdfc48bab Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:12:35 +0900 Subject: [PATCH 006/135] chore: add for system/Test/ControllerResponse.php --- psalm-baseline.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 5a27ec1a17c3..0c8230dcebdd 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -68,6 +68,11 @@ #[ReturnTypeWillChange] + + + dom = &$this->domParser]]> + + $filters From 77b0b1d52af0d74be09805a43f862f157cfd6b02 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:25:12 +0900 Subject: [PATCH 007/135] chore: add new parameters To suppress the following warnings: Warning: "findUnusedBaselineEntry" will be defaulted to "true" in Psalm 6. You should explicitly enable or disable this setting. Warning: "findUnusedCode" will be defaulted to "true" in Psalm 6. You should explicitly enable or disable this setting. findUnusedBaselineEntry="false" Because enabled PHP extensions vary depending on the developer's environment, setting this to true will likely result in errors. --- psalm.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/psalm.xml b/psalm.xml index edd43a2844ff..45242620028f 100644 --- a/psalm.xml +++ b/psalm.xml @@ -8,6 +8,8 @@ autoloader="psalm_autoload.php" cacheDirectory="build/psalm/" errorBaseline="psalm-baseline.xml" + findUnusedBaselineEntry="false" + findUnusedCode="false" > From 1c7212c874283f7ea999cf879da567b34eb80654 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:48:31 +0900 Subject: [PATCH 008/135] chore: exclude files that causes errors Files that were not fixed due to errors reported during fixing: 1) .../CodeIgniter4/tests/_support/View/Cells/multiplier.php 2) .../CodeIgniter4/tests/_support/View/Cells/colors.php 3) .../CodeIgniter4/tests/_support/View/Cells/addition.php --- .php-cs-fixer.dist.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 6a857588f64f..b2f86c686252 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -29,6 +29,11 @@ 'ThirdParty', 'Validation/Views', ]) + ->notPath([ + '_support/View/Cells/multiplier.php', + '_support/View/Cells/colors.php', + '_support/View/Cells/addition.php', + ]) ->notName('#Foobar.php$#') ->append([ __FILE__, From fd7ecde7e3017b5b7e15bb242b5dce98897185e1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:51:35 +0900 Subject: [PATCH 009/135] chore: fix coding style --- system/Exceptions/FrameworkException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Exceptions/FrameworkException.php b/system/Exceptions/FrameworkException.php index 744f4f906d89..333f999df84a 100644 --- a/system/Exceptions/FrameworkException.php +++ b/system/Exceptions/FrameworkException.php @@ -46,7 +46,7 @@ public static function forMissingExtension(string $extension) 'The framework needs the following extension(s) installed and loaded: %s.', $extension ); - // @codeCoverageIgnoreEnd + // @codeCoverageIgnoreEnd } else { $message = lang('Core.missingExtension', [$extension]); } From 86cadcfac766fb2aa5b64bc6e127221875d3d3d0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 May 2023 08:56:37 +0900 Subject: [PATCH 010/135] docs: remove sending PR to https://github.com/FriendsOfPHP/security-advisories `composer audit` uses GitHub Security Advisory Database. https://github.com/advisories?query=codeigniter4 --- admin/RELEASE.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/admin/RELEASE.md b/admin/RELEASE.md index be503db641ff..d052ee1dcb0e 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -149,14 +149,6 @@ the existing content. * Create **user_guide_src/source/installation/upgrade_{next_version}.rst** and add it to **upgrading.rst** (See **next-upgrading-guide.rst**) -## After Publishing Security Advisory - -* Send a PR to [PHP Security Advisories Database](https://github.com/FriendsOfPHP/security-advisories). - * E.g. https://github.com/FriendsOfPHP/security-advisories/pull/606 - * See https://github.com/FriendsOfPHP/security-advisories#contributing - * Don't forget to run `php -d memory_limit=-1 validator.php`, before - submitting the PR - ## Appendix ### Sphinx Installation From 6704da9669d8f6af369172a05105699b0d18ac28 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 12:44:59 +0900 Subject: [PATCH 011/135] docs: move note up --- user_guide_src/source/cli/cli_controllers.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/cli/cli_controllers.rst b/user_guide_src/source/cli/cli_controllers.rst index a46343c31aab..261a454f3d92 100644 --- a/user_guide_src/source/cli/cli_controllers.rst +++ b/user_guide_src/source/cli/cli_controllers.rst @@ -6,6 +6,10 @@ As well as calling an application's :doc:`Controllers ` via the URL in a browser they can also be loaded via the command-line interface (CLI). +.. note:: It is recommended to use Spark Commands for CLI scripts instead of + calling controllers via CLI. + See the :doc:`spark_commands` page for detailed information. + .. contents:: :local: :depth: 2 @@ -85,6 +89,3 @@ If you want to make sure running via CLI, check the return value of :php:func:`i However, CodeIgniter provides additional tools to make creating CLI-accessible scripts even more pleasant, include CLI-only routing, and a library that helps you with CLI-only tools. - -.. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. - See the :doc:`spark_commands` page for detailed information. \ No newline at end of file From 9d265bdbeef6fd97daefddbe47b38939ff66dd54 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 12:46:15 +0900 Subject: [PATCH 012/135] docs: add link to page --- user_guide_src/source/cli/cli_controllers.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli_controllers.rst b/user_guide_src/source/cli/cli_controllers.rst index 261a454f3d92..c8096e785c24 100644 --- a/user_guide_src/source/cli/cli_controllers.rst +++ b/user_guide_src/source/cli/cli_controllers.rst @@ -8,7 +8,8 @@ interface (CLI). .. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. - See the :doc:`spark_commands` page for detailed information. + See the :doc:`spark_commands` and :doc:`cli_commands` page for detailed + information. .. contents:: :local: From 2e1509838e7a1c6af90e9249020918ccd4fb962c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 12:54:21 +0900 Subject: [PATCH 013/135] docs: improve description --- user_guide_src/source/cli/cli_commands.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 3b500cd1531a..efc8cc73193d 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -33,7 +33,7 @@ The following properties should be used in order to get listed in CLI commands a File Location ============= -Commands must be stored within a directory named **Commands**. However, that directory can be located anywhere +Commands must be stored within a directory named **Commands**. However, that directory can be located in the PSR-4 namespaces that the :doc:`Autoloader ` can locate it. This could be in **app/Commands**, or a directory that you keep commands in to use in all of your project development, like **Acme/Commands**. From de41e834ea398a89ae3fe5cfbc3fc8613dface8c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 13:06:33 +0900 Subject: [PATCH 014/135] docs: fix group name Built-in spark commands use group names with the first letter upper case. --- user_guide_src/source/cli/cli_commands.rst | 2 +- user_guide_src/source/cli/cli_commands/002.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index efc8cc73193d..43a41e51881e 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -49,7 +49,7 @@ should contain the following code: .. literalinclude:: cli_commands/002.php -If you run the **list** command, you will see the new command listed under its own ``demo`` group. If you take +If you run the **list** command, you will see the new command listed under its own ``Demo`` group. If you take a close look, you should see how this works fairly easily. The ``$group`` property simply tells it how to organize this command with all of the other commands that exist, telling it what heading to list it under. diff --git a/user_guide_src/source/cli/cli_commands/002.php b/user_guide_src/source/cli/cli_commands/002.php index aa5d12a4438e..e2259707ae8a 100644 --- a/user_guide_src/source/cli/cli_commands/002.php +++ b/user_guide_src/source/cli/cli_commands/002.php @@ -7,7 +7,7 @@ class AppInfo extends BaseCommand { - protected $group = 'demo'; + protected $group = 'Demo'; protected $name = 'app:info'; protected $description = 'Displays basic application information.'; From d316a45b3752b6ef22d37160f6956b8b2481d23b Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 13:10:04 +0900 Subject: [PATCH 015/135] docs: fix file name decration --- user_guide_src/source/cli/cli_commands.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 43a41e51881e..de28a9135ac9 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -92,7 +92,7 @@ For example, ``return EXIT_ERROR;`` This approach can help with debugging at the system level, if the command, for example, is run via crontab. -You can use the ``EXIT_*`` exit code constants defined in the ``app/Config/Constants.php`` file. +You can use the ``EXIT_*`` exit code constants defined in the **app/Config/Constants.php** file. *********** BaseCommand From 8d96f2d6ca9dec096e3dce41f235aa232c6f5e89 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 13:32:24 +0900 Subject: [PATCH 016/135] docs: add deprecated --- user_guide_src/source/cli/cli_commands.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index de28a9135ac9..28373667910a 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -129,6 +129,9 @@ be familiar with when creating your own commands. It also has a :doc:`Logger $value array. :param integer $pad: The pad spaces. From 1584825a2a0d3c292d6fda035d69bf7b6e20cf38 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 May 2023 13:38:22 +0900 Subject: [PATCH 017/135] docs: add setPad() method --- user_guide_src/source/cli/cli_commands.rst | 19 +++++++++++++++---- .../source/cli/cli_commands/007.php | 11 +++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 28373667910a..0ff390865134 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -127,14 +127,25 @@ be familiar with when creating your own commands. It also has a :doc:`Logger $value array. :param integer $pad: The pad spaces. - A method to calculate padding for ``$key => $value`` array output. The padding can be used to output a will formatted table in CLI: - - .. literalinclude:: cli_commands/007.php + A method to calculate padding for ``$key => $value`` array output. The padding can be used to output a will formatted table in CLI. diff --git a/user_guide_src/source/cli/cli_commands/007.php b/user_guide_src/source/cli/cli_commands/007.php index 76150e4d4e5c..ebc4e98a6168 100644 --- a/user_guide_src/source/cli/cli_commands/007.php +++ b/user_guide_src/source/cli/cli_commands/007.php @@ -1,12 +1,15 @@ getPad($this->options, 6); +use CodeIgniter\CLI\CLI; + +$length = max(array_map('strlen', array_keys($this->options))); foreach ($this->options as $option => $description) { - CLI::write($tab . CLI::color(str_pad($option, $pad), 'green') . $description, 'yellow'); + CLI::write(CLI::color($this->setPad($option, $length, 2, 2), 'green') . $description); } /* * Output will be: - * -n Set migration namespace - * -r override file + * -n Set migration namespace + * -g Set database group + * --all Set for all namespaces, will ignore (-n) option */ From a4de3e7dab513684750d0025e7cca7f65898c75b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 May 2023 09:17:49 +0900 Subject: [PATCH 018/135] refactor: remove unneeded code $this->locale is set in the detectLocale() method called in the constructor. --- phpstan-baseline.neon.dist | 5 ----- system/HTTP/IncomingRequest.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index a3bc07fd877b..a32d4fc11a79 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -120,11 +120,6 @@ parameters: count: 1 path: system/HTTP/Files/UploadedFile.php - - - message: "#^Property CodeIgniter\\\\HTTP\\\\IncomingRequest\\:\\:\\$locale \\(string\\) on left side of \\?\\? is not nullable\\.$#" - count: 1 - path: system/HTTP/IncomingRequest.php - - message: "#^Property CodeIgniter\\\\HTTP\\\\Message\\:\\:\\$protocolVersion \\(string\\) on left side of \\?\\? is not nullable\\.$#" count: 1 diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 29529fd5bef0..8eeaefdb0ed8 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -554,7 +554,7 @@ public function setLocale(string $locale) */ public function getLocale(): string { - return $this->locale ?? $this->defaultLocale; + return $this->locale; } /** From da67d3de6153a0d8740175b7cc943d9b1bf08184 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sun, 28 May 2023 01:40:31 +0800 Subject: [PATCH 019/135] fix: class without import. scrolling in examples. --- user_guide_src/source/database/query_builder/028.php | 6 +++++- user_guide_src/source/database/query_builder/031.php | 6 +++++- user_guide_src/source/database/query_builder/033.php | 6 +++++- user_guide_src/source/database/query_builder/035.php | 6 +++++- user_guide_src/source/database/query_builder/037.php | 6 +++++- user_guide_src/source/database/query_builder/041.php | 6 +++++- user_guide_src/source/database/query_builder/052.php | 6 +++++- user_guide_src/source/database/query_builder/054.php | 6 +++++- user_guide_src/source/database/query_builder/056.php | 6 +++++- user_guide_src/source/database/query_builder/058.php | 6 +++++- user_guide_src/source/database/query_builder/062.php | 6 +++++- user_guide_src/source/database/query_builder/081.php | 7 ++++++- 12 files changed, 61 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/database/query_builder/028.php b/user_guide_src/source/database/query_builder/028.php index 019386718cd1..141751c40f3f 100644 --- a/user_guide_src/source/database/query_builder/028.php +++ b/user_guide_src/source/database/query_builder/028.php @@ -1,7 +1,11 @@ where('advance_amount <', static fn (BaseBuilder $builder) => $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2)); +use CodeIgniter\Database\BaseBuilder; + +$builder->where('advance_amount <', static function (BaseBuilder $builder) { + $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); +}); // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) // With builder directly diff --git a/user_guide_src/source/database/query_builder/031.php b/user_guide_src/source/database/query_builder/031.php index 5aa7619c0dc8..dbbff119aa55 100644 --- a/user_guide_src/source/database/query_builder/031.php +++ b/user_guide_src/source/database/query_builder/031.php @@ -1,7 +1,11 @@ whereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->whereIn('id', static function (BaseBuilder $builder) { + $builder->select('job_id')->from('users_jobs')->where('user_id', 3); +}); // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/033.php b/user_guide_src/source/database/query_builder/033.php index ae8ddb7ce7a4..20ebd3e682cf 100644 --- a/user_guide_src/source/database/query_builder/033.php +++ b/user_guide_src/source/database/query_builder/033.php @@ -1,7 +1,11 @@ orWhereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->orWhereIn('id', static function (BaseBuilder $builder) { + $builder->select('job_id')->from('users_jobs')->where('user_id', 3); +}); // Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/035.php b/user_guide_src/source/database/query_builder/035.php index 02904a3962f3..2c7a2e51bec6 100644 --- a/user_guide_src/source/database/query_builder/035.php +++ b/user_guide_src/source/database/query_builder/035.php @@ -1,7 +1,11 @@ whereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->whereNotIn('id', static function (BaseBuilder $builder) { + $builder->select('job_id')->from('users_jobs')->where('user_id', 3); +}); // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/037.php b/user_guide_src/source/database/query_builder/037.php index f5668aa1a30d..0eacfbe3a8b3 100644 --- a/user_guide_src/source/database/query_builder/037.php +++ b/user_guide_src/source/database/query_builder/037.php @@ -1,7 +1,11 @@ orWhereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->orWhereNotIn('id', static function (BaseBuilder $builder) { + $builder->select('job_id')->from('users_jobs')->where('user_id', 3); +}); // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/041.php b/user_guide_src/source/database/query_builder/041.php index 0583a2a79187..f6b13abbb4a0 100644 --- a/user_guide_src/source/database/query_builder/041.php +++ b/user_guide_src/source/database/query_builder/041.php @@ -2,4 +2,8 @@ $array = ['title' => $match, 'page1' => $match, 'page2' => $match]; $builder->like($array); -// WHERE `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' +/* + * WHERE `title` LIKE '%match%' ESCAPE '!' + * AND `page1` LIKE '%match%' ESCAPE '!' + * AND `page2` LIKE '%match%' ESCAPE '!' + */ diff --git a/user_guide_src/source/database/query_builder/052.php b/user_guide_src/source/database/query_builder/052.php index 1f5736243866..08ae4dca5354 100644 --- a/user_guide_src/source/database/query_builder/052.php +++ b/user_guide_src/source/database/query_builder/052.php @@ -1,7 +1,11 @@ havingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->havingIn('id', static function (BaseBuilder $builder) { + $builder->select('user_id')->from('users_jobs')->where('group_id', 3); +}); // Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/054.php b/user_guide_src/source/database/query_builder/054.php index 8a19ff4ac7d8..2594b111d667 100644 --- a/user_guide_src/source/database/query_builder/054.php +++ b/user_guide_src/source/database/query_builder/054.php @@ -1,7 +1,11 @@ orHavingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->orHavingIn('id', static function (BaseBuilder $builder) { + $builder->select('user_id')->from('users_jobs')->where('group_id', 3); +}); // Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/056.php b/user_guide_src/source/database/query_builder/056.php index 67a54f87f7bc..7b68c688d0df 100644 --- a/user_guide_src/source/database/query_builder/056.php +++ b/user_guide_src/source/database/query_builder/056.php @@ -1,7 +1,11 @@ havingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->havingNotIn('id', static function (BaseBuilder $builder) { + $builder->select('user_id')->from('users_jobs')->where('group_id', 3); +}); // Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/058.php b/user_guide_src/source/database/query_builder/058.php index 8a92da5725b2..b93ab3ae9a9c 100644 --- a/user_guide_src/source/database/query_builder/058.php +++ b/user_guide_src/source/database/query_builder/058.php @@ -1,7 +1,11 @@ orHavingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +use CodeIgniter\Database\BaseBuilder; + +$builder->orHavingNotIn('id', static function (BaseBuilder $builder) { + $builder->select('user_id')->from('users_jobs')->where('group_id', 3); +}); // Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/062.php b/user_guide_src/source/database/query_builder/062.php index ba1767f6706e..e383c0be1520 100644 --- a/user_guide_src/source/database/query_builder/062.php +++ b/user_guide_src/source/database/query_builder/062.php @@ -2,4 +2,8 @@ $array = ['title' => $match, 'page1' => $match, 'page2' => $match]; $builder->havingLike($array); -// HAVING `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' +/* + * HAVING `title` LIKE '%match%' ESCAPE '!' + * AND `page1` LIKE '%match%' ESCAPE '!' + * AND `page2` LIKE '%match%' ESCAPE '!' + */ diff --git a/user_guide_src/source/database/query_builder/081.php b/user_guide_src/source/database/query_builder/081.php index 0f263005c18e..812c32194521 100644 --- a/user_guide_src/source/database/query_builder/081.php +++ b/user_guide_src/source/database/query_builder/081.php @@ -14,4 +14,9 @@ ]; $builder->insertBatch($data); -// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date') +/* + * Produces: + * INSERT INTO mytable (title, name, date) + * VALUES ('My title', 'My name', 'My date'), + * ('Another title', 'Another name', 'Another date') + */ From fa26b4806585ebc166229e48eaee41aaf1bb47da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:57:05 +0000 Subject: [PATCH 020/135] build(deps-dev): update rector/rector requirement from 0.16.0 to 0.17.0 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.16.0...0.17.0) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 08af7d632a0f..49e50bfc7413 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.16.0", + "rector/rector": "0.17.0", "vimeo/psalm": "^5.0" }, "suggest": { From c988fd712e62bfe529be49d21f7a9b97357f6a84 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 2 Jun 2023 06:55:10 +0700 Subject: [PATCH 021/135] Remove ForToForeachRector and AddPregQuoteDelimiterRector and re-run rector --- rector.php | 4 ---- system/Common.php | 6 +----- system/Model.php | 6 +----- tests/system/Database/Live/ForgeTest.php | 3 +-- tests/system/HTTP/RedirectResponseTest.php | 2 +- tests/system/Language/LanguageTest.php | 2 +- 6 files changed, 5 insertions(+), 18 deletions(-) diff --git a/rector.php b/rector.php index d79d47cb3fee..6cb5a5c7e451 100644 --- a/rector.php +++ b/rector.php @@ -12,9 +12,7 @@ use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector; use Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector; -use Rector\CodeQuality\Rector\For_\ForToForeachRector; use Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector; -use Rector\CodeQuality\Rector\FuncCall\AddPregQuoteDelimiterRector; use Rector\CodeQuality\Rector\FuncCall\ChangeArrayPushToArrayAssignRector; use Rector\CodeQuality\Rector\FuncCall\SimplifyRegexPatternRector; use Rector\CodeQuality\Rector\FuncCall\SimplifyStrposLowerRector; @@ -125,7 +123,6 @@ $rectorConfig->rule(RemoveAlwaysElseRector::class); $rectorConfig->rule(PassStrictParameterToFunctionParameterRector::class); $rectorConfig->rule(CountArrayToEmptyArrayComparisonRector::class); - $rectorConfig->rule(ForToForeachRector::class); $rectorConfig->rule(ChangeNestedForeachIfsToEarlyContinueRector::class); $rectorConfig->rule(ChangeIfElseValueAssignToEarlyReturnRector::class); $rectorConfig->rule(SimplifyStrposLowerRector::class); @@ -140,7 +137,6 @@ $rectorConfig->rule(UnnecessaryTernaryExpressionRector::class); $rectorConfig->rule(RemoveErrorSuppressInTryCatchStmtsRector::class); $rectorConfig->rule(RemoveVarTagFromClassConstantRector::class); - $rectorConfig->rule(AddPregQuoteDelimiterRector::class); $rectorConfig->rule(SimplifyRegexPatternRector::class); $rectorConfig->rule(FuncGetArgsToVariadicParamRector::class); $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class); diff --git a/system/Common.php b/system/Common.php index 2a98253cb6b4..8d366973f14d 100644 --- a/system/Common.php +++ b/system/Common.php @@ -744,11 +744,7 @@ function is_windows(?bool $mock = null): bool $mocked = $mock; } - if (isset($mocked)) { - return $mocked; - } - - return DIRECTORY_SEPARATOR === '\\'; + return $mocked ?? DIRECTORY_SEPARATOR === '\\'; } } diff --git a/system/Model.php b/system/Model.php index 2df1bb2f5132..80e4bb48a34c 100644 --- a/system/Model.php +++ b/system/Model.php @@ -800,11 +800,7 @@ public function __get(string $name) return parent::__get($name); } - if (isset($this->builder()->{$name})) { - return $this->builder()->{$name}; - } - - return null; + return $this->builder()->{$name} ?? null; } /** diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 54704a79e4c1..d6ee4ee31f88 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1519,8 +1519,7 @@ public function testAddTextColumnWithConstraint() $this->assertTrue($this->db->fieldExists('text_with_constraint', 'user')); - // SQLSRV requires dropping default constraint before dropping column - $result = $this->forge->dropColumn('user', 'text_with_constraint'); + $this->forge->dropColumn('user', 'text_with_constraint'); $this->db->resetDataCache(); diff --git a/tests/system/HTTP/RedirectResponseTest.php b/tests/system/HTTP/RedirectResponseTest.php index 65fc0e62d03c..5f95b307d8cf 100644 --- a/tests/system/HTTP/RedirectResponseTest.php +++ b/tests/system/HTTP/RedirectResponseTest.php @@ -293,7 +293,7 @@ public function testWithHeadersWithEmptyHeaders() } $response = new RedirectResponse(new App()); - $response = $response->withHeaders(); + $response->withHeaders(); $this->assertEmpty($baseResponse->headers()); } diff --git a/tests/system/Language/LanguageTest.php b/tests/system/Language/LanguageTest.php index 4148a0f4a500..8006ad6cf133 100644 --- a/tests/system/Language/LanguageTest.php +++ b/tests/system/Language/LanguageTest.php @@ -179,7 +179,7 @@ public function testLanguageFileLoadingReturns() $this->assertNotContains('More', $this->lang->loaded()); $this->assertCount(3, $result); - $result = $this->lang->loadem('More', 'en'); + $this->lang->loadem('More', 'en'); $this->assertContains('More', $this->lang->loaded()); $this->assertCount(1, $this->lang->loaded()); } From 4900d7a92127a322594c9514092e82a99d3e7fe1 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 2 Jun 2023 06:58:13 +0700 Subject: [PATCH 022/135] rollback comment on removed on run rector --- tests/system/Database/Live/ForgeTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index d6ee4ee31f88..6dc792760ac4 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1519,6 +1519,7 @@ public function testAddTextColumnWithConstraint() $this->assertTrue($this->db->fieldExists('text_with_constraint', 'user')); + // SQLSRV requires dropping default constraint before dropping column $this->forge->dropColumn('user', 'text_with_constraint'); $this->db->resetDataCache(); From a5958bd738289597d330996785609fe487bb03c2 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 2 Jun 2023 07:10:42 +0700 Subject: [PATCH 023/135] remove unused variable on ForgeTest --- tests/system/Database/Live/ForgeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 6dc792760ac4..90b42aec7de8 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1513,7 +1513,7 @@ public function testDropKey() public function testAddTextColumnWithConstraint() { // some DBMS do not allow a constraint for type TEXT - $result = $this->forge->addColumn('user', [ + $this->forge->addColumn('user', [ 'text_with_constraint' => ['type' => 'text', 'constraint' => 255, 'default' => ''], ]); From 8e9e3a44b430e2d3a83934826ac68b39a569cc58 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 11:48:42 +0900 Subject: [PATCH 024/135] docs: set TOC depth to 3 --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index c2d72bdab746..2201ea4beafd 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -4,7 +4,7 @@ URI Routing .. contents:: :local: - :depth: 2 + :depth: 3 What is URI Routing? ******************** From 84a6c515e14f788e4f8b59ae8234d09bf42ed326 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 11:49:12 +0900 Subject: [PATCH 025/135] docs: text decoration Also remove add() in examples becase it is not recommended. --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 2201ea4beafd..98e7205ce08e 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -390,7 +390,7 @@ available from the command line: Global Options ============== -All of the methods for creating a route (add, get, post, :doc:`resource ` etc) can take an array of options that +All of the methods for creating a route (``get()``, ``post()``, :doc:`resource() ` etc) can take an array of options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter: .. literalinclude:: routing/033.php From 291a4bf18441f5a489038f95fbd06c74aebdf75d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 11:51:50 +0900 Subject: [PATCH 026/135] docs: add sub section titles --- user_guide_src/source/incoming/routing.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 98e7205ce08e..9ba95eb9bd82 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -269,12 +269,18 @@ extensive set of routes that all share the opening string, like when building an This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. +Setting Namespace +----------------- + If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback: .. literalinclude:: routing/024.php This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. +Setting Filters +--------------- + You can also use a specific :doc:`filter ` for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging: @@ -282,6 +288,9 @@ run the filter before or after the controller. This is especially handy during a The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. +Nesting Groups +-------------- + It is possible to nest groups within groups for finer organization if you need it: .. literalinclude:: routing/026.php @@ -290,6 +299,9 @@ This would handle the URL at **admin/users/list**. .. note:: Options passed to the outer ``group()`` (for example ``namespace`` and ``filter``) are not merged with the inner ``group()`` options. +Setting Other Options +--------------------- + At some point, you may want to group routes for the purpose of applying filters or other route config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the From 8fa52edf748a3e9778b14b221995bd8bd3b0e614 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 12:25:25 +0900 Subject: [PATCH 027/135] docs: move "Nesting Groups" down --- user_guide_src/source/incoming/routing.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 9ba95eb9bd82..88f54a4fcf81 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -288,6 +288,16 @@ run the filter before or after the controller. This is especially handy during a The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. +Setting Other Options +--------------------- + +At some point, you may want to group routes for the purpose of applying filters or other route +config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass +an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the +given route config options: + +.. literalinclude:: routing/027.php + Nesting Groups -------------- @@ -299,16 +309,6 @@ This would handle the URL at **admin/users/list**. .. note:: Options passed to the outer ``group()`` (for example ``namespace`` and ``filter``) are not merged with the inner ``group()`` options. -Setting Other Options ---------------------- - -At some point, you may want to group routes for the purpose of applying filters or other route -config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass -an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the -given route config options: - -.. literalinclude:: routing/027.php - Environment Restrictions ======================== From 3eaecb64699c716c63c0b54826a400ef003bc85a Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 12:33:59 +0900 Subject: [PATCH 028/135] docs: level up "Grouping Routes" --- user_guide_src/source/incoming/routing.rst | 102 ++++++++++----------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 88f54a4fcf81..3b507d01302b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -258,57 +258,6 @@ redirect and is recommended in most cases: If a redirect route is matched during a page load, the user will be immediately redirected to the new page before a controller can be loaded. -Grouping Routes -=============== - -You can group your routes under a common name with the ``group()`` method. The group name becomes a segment that -appears prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an -extensive set of routes that all share the opening string, like when building an admin area: - -.. literalinclude:: routing/023.php - -This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. - -Setting Namespace ------------------ - -If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback: - -.. literalinclude:: routing/024.php - -This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. - -Setting Filters ---------------- - -You can also use a specific :doc:`filter ` for a group of routes. This will always -run the filter before or after the controller. This is especially handy during authentication or api logging: - -.. literalinclude:: routing/025.php - -The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. - -Setting Other Options ---------------------- - -At some point, you may want to group routes for the purpose of applying filters or other route -config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass -an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the -given route config options: - -.. literalinclude:: routing/027.php - -Nesting Groups --------------- - -It is possible to nest groups within groups for finer organization if you need it: - -.. literalinclude:: routing/026.php - -This would handle the URL at **admin/users/list**. - -.. note:: Options passed to the outer ``group()`` (for example ``namespace`` and ``filter``) are not merged with the inner ``group()`` options. - Environment Restrictions ======================== @@ -512,6 +461,57 @@ be used when the first parameter is a language string: .. literalinclude:: routing/042.php +Grouping Routes +*************** + +You can group your routes under a common name with the ``group()`` method. The group name becomes a segment that +appears prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an +extensive set of routes that all share the opening string, like when building an admin area: + +.. literalinclude:: routing/023.php + +This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. + +Setting Namespace +================= + +If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback: + +.. literalinclude:: routing/024.php + +This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. + +Setting Filters +=============== + +You can also use a specific :doc:`filter ` for a group of routes. This will always +run the filter before or after the controller. This is especially handy during authentication or api logging: + +.. literalinclude:: routing/025.php + +The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. + +Setting Other Options +===================== + +At some point, you may want to group routes for the purpose of applying filters or other route +config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass +an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the +given route config options: + +.. literalinclude:: routing/027.php + +Nesting Groups +============== + +It is possible to nest groups within groups for finer organization if you need it: + +.. literalinclude:: routing/026.php + +This would handle the URL at **admin/users/list**. + +.. note:: Options passed to the outer ``group()`` (for example ``namespace`` and ``filter``) are not merged with the inner ``group()`` options. + .. _routing-priority: Route Priority From eb776e878ea4a1637c871667fafbf84e0ad195da Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 12:48:17 +0900 Subject: [PATCH 029/135] docs: level up "Reverse Routing" and "Named Routes" --- user_guide_src/source/incoming/routing.rst | 60 +++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 3b507d01302b..0bfbc8317990 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -268,36 +268,6 @@ routes defined within this closure are only accessible from the given environmen .. literalinclude:: routing/028.php -.. _reverse-routing: - -Reverse Routing -=============== - -Reverse routing allows you to define the controller and method, as well as any parameters, that a link should go -to, and have the router lookup the current route to it. This allows route definitions to change without you having -to update your application code. This is typically used within views to create links. - -For example, if you have a route to a photo gallery that you want to link to, you can use the :php:func:`url_to()` helper -function to get the route that should be used. The first parameter is the fully qualified Controller and method, -separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that -should be passed to the route are passed in next: - -.. literalinclude:: routing/029.php - -.. _using-named-routes: - -Using Named Routes -================== - -You can name routes to make your application less fragile. This applies a name to a route that can be called -later, and even if the route definition changes, all of the links in your application built with :php:func:`url_to()` -will still work without you having to make any changes. A route is named by passing in the ``as`` option -with the name of the route: - -.. literalinclude:: routing/030.php - -This has the added benefit of making the views more readable, too. - Routes with any HTTP verbs ========================== @@ -461,6 +431,36 @@ be used when the first parameter is a language string: .. literalinclude:: routing/042.php +.. _reverse-routing: + +Reverse Routing +*************** + +Reverse routing allows you to define the controller and method, as well as any parameters, that a link should go +to, and have the router lookup the current route to it. This allows route definitions to change without you having +to update your application code. This is typically used within views to create links. + +For example, if you have a route to a photo gallery that you want to link to, you can use the :php:func:`url_to()` helper +function to get the route that should be used. The first parameter is the fully qualified Controller and method, +separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that +should be passed to the route are passed in next: + +.. literalinclude:: routing/029.php + +.. _using-named-routes: + +Named Routes +************ + +You can name routes to make your application less fragile. This applies a name to a route that can be called +later, and even if the route definition changes, all of the links in your application built with :php:func:`url_to()` +will still work without you having to make any changes. A route is named by passing in the ``as`` option +with the name of the route: + +.. literalinclude:: routing/030.php + +This has the added benefit of making the views more readable, too. + Grouping Routes *************** From 6d8edbadf52019c0550d939c35d0d681eb6bada7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 12:52:09 +0900 Subject: [PATCH 030/135] docs: level up "Global Options" --- user_guide_src/source/incoming/routing.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 0bfbc8317990..0c66bdb5d51b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -319,7 +319,7 @@ available from the command line: See the :doc:`../cli/spark_commands` page for detailed information. Global Options -============== +************** All of the methods for creating a route (``get()``, ``post()``, :doc:`resource() ` etc) can take an array of options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter: @@ -329,7 +329,7 @@ can modify the generated routes, or further restrict them. The ``$options`` arra .. _applying-filters: Applying Filters ----------------- +================ You can alter the behavior of specific routes by supplying filters to run before or after the controller. This is especially handy during authentication or api logging. The value for the filter can be a string or an array of strings: @@ -347,7 +347,7 @@ See :doc:`Controller filters ` for more information on setting up filte See :ref:`use-defined-routes-only` to disable auto-routing. Alias Filter -^^^^^^^^^^^^ +------------ You specify an alias defined in **app/Config/Filters.php** for the filter value: @@ -358,7 +358,7 @@ You may also supply arguments to be passed to the alias filter's ``before()`` an .. literalinclude:: routing/035.php Classname Filter -^^^^^^^^^^^^^^^^ +---------------- .. versionadded:: 4.1.5 @@ -367,7 +367,7 @@ You specify a filter classname for the filter value: .. literalinclude:: routing/036.php Multiple Filters -^^^^^^^^^^^^^^^^ +---------------- .. versionadded:: 4.1.5 @@ -380,7 +380,7 @@ You specify an array for the filter value: .. _assigning-namespace: Assigning Namespace -------------------- +=================== 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 @@ -393,7 +393,7 @@ For any methods that create multiple routes, the new namespace is attached to al or, in the case of ``group()``, all routes generated while in the closure. Limit to Hostname ------------------ +================= You can restrict groups of routes to function only in certain domain or sub-domains of your application by passing the "hostname" option along with the desired domain to allow it on as part of the options array: @@ -404,7 +404,7 @@ This example would only allow the specified hosts to work if the domain exactly It would not work under the main site at **example.com**. Limit to Subdomains -------------------- +=================== When the ``subdomain`` option is present, the system will restrict the routes to only be available on that sub-domain. The route will only be matched if the subdomain is the one the application is being viewed through: @@ -421,7 +421,7 @@ that does not have any subdomain present, this will not be matched: to separate suffixes or www) can potentially lead to false positives. Offsetting the Matched Parameters ---------------------------------- +================================= You can offset the matched parameters in your route by any numeric value with the ``offset`` option, with the value being the number of segments to offset. From 0ec5e7158adeb6472aee83402f993b1b4d6216b1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 13:09:56 +0900 Subject: [PATCH 031/135] docs: improve section titles --- user_guide_src/source/incoming/routing.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 0c66bdb5d51b..e80b20de82b2 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -68,8 +68,8 @@ and the ``productLookupByID()`` method passing in the match as a variable to the .. literalinclude:: routing/009.php -HTTP verbs -========== +HTTP verb Routes +================ You can use any standard HTTP verb (GET, POST, PUT, DELETE, OPTIONS, etc): @@ -213,8 +213,8 @@ For those of you who don't know regular expressions and want to learn more about .. note:: You can also mix and match placeholders with regular expressions. -Closures -======== +Using Closures +============== You can use an anonymous function, or Closure, as the destination that a route maps to. This function will be executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing @@ -224,8 +224,8 @@ a simple view: .. _view-routes: -Views -===== +View Routes +=========== .. versionadded:: 4.3.0 From c399d66e511574e19afef25fdbe3df48fa4ad184 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 13:11:50 +0900 Subject: [PATCH 032/135] docs: move "Array Callable Syntax" up --- user_guide_src/source/incoming/routing.rst | 53 +++++++++++----------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index e80b20de82b2..a459c140aaf0 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -96,6 +96,32 @@ You can also specify the namespace with the ``namespace`` option: See :ref:`assigning-namespace` for details. +Array Callable Syntax +===================== + +.. versionadded:: 4.2.0 + +Since v4.2.0, you can use array callable syntax to specify the controller: + +.. literalinclude:: routing/013.php + :lines: 2- + +Or using ``use`` keyword: + +.. literalinclude:: routing/014.php + :lines: 2- + +If there are placeholders, it will automatically set the parameters in the specified order: + +.. literalinclude:: routing/015.php + :lines: 2- + +But the auto-configured parameters may not be correct if you use regular expressions in routes. +In such a case, you can specify the parameters manually: + +.. literalinclude:: routing/016.php + :lines: 2- + Placeholders ============ @@ -147,33 +173,6 @@ routes. With the examples URLs from above: will only match **product/123** and generate 404 errors for other example. - -Array Callable Syntax -===================== - -.. versionadded:: 4.2.0 - -Since v4.2.0, you can use array callable syntax to specify the controller: - -.. literalinclude:: routing/013.php - :lines: 2- - -Or using ``use`` keyword: - -.. literalinclude:: routing/014.php - :lines: 2- - -If there are placeholders, it will automatically set the parameters in the specified order: - -.. literalinclude:: routing/015.php - :lines: 2- - -But the auto-configured parameters may not be correct if you use regular expressions in routes. -In such a case, you can specify the parameters manually: - -.. literalinclude:: routing/016.php - :lines: 2- - Custom Placeholders =================== From 64370c40650f90f27aee8581f8d240e20993600e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 2 Jun 2023 13:18:53 +0900 Subject: [PATCH 033/135] docs: add sections --- user_guide_src/source/incoming/routing.rst | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a459c140aaf0..3455189f9ec6 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -79,8 +79,11 @@ You can supply multiple verbs that a route should match by passing them in as an .. literalinclude:: routing/004.php +Specifying Route Handlers +========================= + Controller's Namespace -====================== +---------------------- If a controller name is stated without beginning with ``\``, the :ref:`routing-default-namespace` will be prepended: @@ -97,7 +100,7 @@ You can also specify the namespace with the ``namespace`` option: See :ref:`assigning-namespace` for details. Array Callable Syntax -===================== +--------------------- .. versionadded:: 4.2.0 @@ -122,8 +125,20 @@ In such a case, you can specify the parameters manually: .. literalinclude:: routing/016.php :lines: 2- +Using Closures +-------------- + +You can use an anonymous function, or Closure, as the destination that a route maps to. This function will be +executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing +a simple view: + +.. literalinclude:: routing/020.php + +Specifying Route Paths +====================== + Placeholders -============ +------------ A typical route might look something like this: @@ -174,7 +189,7 @@ routes. With the examples URLs from above: will only match **product/123** and generate 404 errors for other example. Custom Placeholders -=================== +------------------- You can create your own placeholders that can be used in your routes file to fully customize the experience and readability. @@ -186,7 +201,7 @@ This must be called before you add the route: .. literalinclude:: routing/017.php Regular Expressions -=================== +------------------- If you prefer you can use regular expressions to define your routing rules. Any valid regular expression is allowed, as are back-references. @@ -212,15 +227,6 @@ For those of you who don't know regular expressions and want to learn more about .. note:: You can also mix and match placeholders with regular expressions. -Using Closures -============== - -You can use an anonymous function, or Closure, as the destination that a route maps to. This function will be -executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing -a simple view: - -.. literalinclude:: routing/020.php - .. _view-routes: View Routes From f2d87d27ab6b6fcd9ae3ebb072eee5bd601f0884 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 08:57:36 +0900 Subject: [PATCH 034/135] style: break long lines --- system/View/View.php | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index 9a39104728df..a924563a60a4 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -178,13 +178,18 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n // Was it cached? if (isset($this->renderVars['options']['cache'])) { - $cacheName = $this->renderVars['options']['cache_name'] ?? str_replace('.php', '', $this->renderVars['view']); + $cacheName = $this->renderVars['options']['cache_name'] + ?? str_replace('.php', '', $this->renderVars['view']); $cacheName = str_replace(['\\', '/'], '', $cacheName); $this->renderVars['cacheName'] = $cacheName; if ($output = cache($this->renderVars['cacheName'])) { - $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); + $this->logPerformance( + $this->renderVars['start'], + microtime(true), + $this->renderVars['view'] + ); return $output; } @@ -193,7 +198,11 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $this->renderVars['file'] = $this->viewPath . $this->renderVars['view']; if (! is_file($this->renderVars['file'])) { - $this->renderVars['file'] = $this->loader->locateFile($this->renderVars['view'], 'Views', empty($fileExt) ? 'php' : $fileExt); + $this->renderVars['file'] = $this->loader->locateFile( + $this->renderVars['view'], + 'Views', + empty($fileExt) ? 'php' : $fileExt + ); } // locateFile will return an empty string if the file cannot be found. @@ -233,7 +242,11 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $output = $this->decorateOutput($output); - $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); + $this->logPerformance( + $this->renderVars['start'], + microtime(true), + $this->renderVars['view'] + ); if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) && in_array(DebugToolbar::class, service('filters')->getFiltersClass()['after'], true) @@ -253,7 +266,11 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n // Should we cache? if (isset($this->renderVars['options']['cache'])) { - cache()->save($this->renderVars['cacheName'], $output, (int) $this->renderVars['options']['cache']); + cache()->save( + $this->renderVars['cacheName'], + $output, + (int) $this->renderVars['options']['cache'] + ); } $this->tempData = null; From 56f855cf052bc777ad71aa06ed996a3195bbb69e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 08:59:29 +0900 Subject: [PATCH 035/135] style: add empty lines --- system/View/View.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index a924563a60a4..47226d9f2e22 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -171,8 +171,11 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n // multiple views are called in a view, it won't // clean it unless we mean it to. $saveData ??= $this->saveData; - $fileExt = pathinfo($view, PATHINFO_EXTENSION); - $realPath = empty($fileExt) ? $view . '.php' : $view; // allow Views as .html, .tpl, etc (from CI3) + + $fileExt = pathinfo($view, PATHINFO_EXTENSION); + // allow Views as .html, .tpl, etc (from CI3) + $realPath = empty($fileExt) ? $view . '.php' : $view; + $this->renderVars['view'] = $realPath; $this->renderVars['options'] = $options ?? []; From 3a70fb421c590daab14a81d575af426ad87e590e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 09:00:34 +0900 Subject: [PATCH 036/135] refactor: add variable for if condition --- system/View/View.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index 47226d9f2e22..a6e32b808546 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -251,8 +251,10 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $this->renderVars['view'] ); - if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) - && in_array(DebugToolbar::class, service('filters')->getFiltersClass()['after'], true) + $afterFilters = service('filters')->getFiltersClass()['after']; + if ( + ($this->debug && (! isset($options['debug']) || $options['debug'] === true)) + && in_array(DebugToolbar::class, $afterFilters, true) ) { $toolbarCollectors = config(Toolbar::class)->collectors; From ec607be10a47817cca097b14bef3648357db9e99 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 09:15:29 +0900 Subject: [PATCH 037/135] refactor: remove variable --- system/View/View.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index a6e32b808546..164d67642305 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -174,9 +174,8 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $fileExt = pathinfo($view, PATHINFO_EXTENSION); // allow Views as .html, .tpl, etc (from CI3) - $realPath = empty($fileExt) ? $view . '.php' : $view; + $this->renderVars['view'] = empty($fileExt) ? $view . '.php' : $view; - $this->renderVars['view'] = $realPath; $this->renderVars['options'] = $options ?? []; // Was it cached? From 9050b8ab223dc880e66855521d9a4847ed94aca5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 09:46:00 +0900 Subject: [PATCH 038/135] test: replace ApplicationDirectory with AppDirectory --- tests/system/Autoloader/FileLocatorTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index cf966cb0f5da..72479b0c751e 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -67,7 +67,7 @@ public function testLocateFileWithLegacyStructureNotFound() $this->assertFalse($this->locator->locateFile($file)); } - public function testLocateFileWorksInApplicationDirectory() + public function testLocateFileWorksInAppDirectory() { $file = 'welcome_message'; @@ -76,7 +76,7 @@ public function testLocateFileWorksInApplicationDirectory() $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); } - public function testLocateFileWorksInApplicationDirectoryWithoutFolder() + public function testLocateFileWorksInAppDirectoryWithoutFolder() { $file = 'Common'; @@ -85,7 +85,7 @@ public function testLocateFileWorksInApplicationDirectoryWithoutFolder() $this->assertSame($expected, $this->locator->locateFile($file)); } - public function testLocateFileWorksInNestedApplicationDirectory() + public function testLocateFileWorksInNestedAppDirectory() { $file = 'Controllers/Home'; From 3672ce9b2bb314a3940483b5acdf0524128dde79 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:11:21 +0900 Subject: [PATCH 039/135] docs: add comments --- tests/system/Autoloader/FileLocatorTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 72479b0c751e..e5f59f9b2eff 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -53,7 +53,7 @@ protected function setUp(): void public function testLocateFileWorksWithLegacyStructure() { - $file = 'Controllers/Home'; + $file = 'Controllers/Home'; // not namespaced $expected = APPPATH . 'Controllers/Home.php'; @@ -62,14 +62,14 @@ public function testLocateFileWorksWithLegacyStructure() public function testLocateFileWithLegacyStructureNotFound() { - $file = 'Unknown'; + $file = 'Unknown'; // not namespaced $this->assertFalse($this->locator->locateFile($file)); } public function testLocateFileWorksInAppDirectory() { - $file = 'welcome_message'; + $file = 'welcome_message'; // not namespaced $expected = APPPATH . 'Views/welcome_message.php'; @@ -78,7 +78,7 @@ public function testLocateFileWorksInAppDirectory() public function testLocateFileWorksInAppDirectoryWithoutFolder() { - $file = 'Common'; + $file = 'Common'; // not namespaced $expected = APPPATH . 'Common.php'; @@ -87,7 +87,7 @@ public function testLocateFileWorksInAppDirectoryWithoutFolder() public function testLocateFileWorksInNestedAppDirectory() { - $file = 'Controllers/Home'; + $file = 'Controllers/Home'; // not namespaced $expected = APPPATH . 'Controllers/Home.php'; @@ -105,7 +105,7 @@ public function testLocateFileReplacesFolderName() public function testLocateFileReplacesFolderNameLegacy() { - $file = 'Views/welcome_message.php'; + $file = 'Views/welcome_message.php'; // not namespaced $expected = APPPATH . 'Views/welcome_message.php'; From e05c0b740eb86f2950fc39d953c96d7996fb9e3c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:14:22 +0900 Subject: [PATCH 040/135] test: rename test method names --- tests/system/Autoloader/FileLocatorTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index e5f59f9b2eff..41b6845dfb31 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -51,7 +51,7 @@ protected function setUp(): void $this->locator = new FileLocator($autoloader); } - public function testLocateFileWorksWithLegacyStructure() + public function testLocateFileNotNamespacedWorks() { $file = 'Controllers/Home'; // not namespaced @@ -60,14 +60,14 @@ public function testLocateFileWorksWithLegacyStructure() $this->assertSame($expected, $this->locator->locateFile($file)); } - public function testLocateFileWithLegacyStructureNotFound() + public function testLocateFileNotNamespacedNotFound() { $file = 'Unknown'; // not namespaced $this->assertFalse($this->locator->locateFile($file)); } - public function testLocateFileWorksInAppDirectory() + public function testLocateFileNotNamespacedWorksInAppDirectory() { $file = 'welcome_message'; // not namespaced @@ -76,7 +76,7 @@ public function testLocateFileWorksInAppDirectory() $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); } - public function testLocateFileWorksInAppDirectoryWithoutFolder() + public function testLocateFileNotNamespacedWorksInAppDirectoryWithoutFolder() { $file = 'Common'; // not namespaced @@ -85,7 +85,7 @@ public function testLocateFileWorksInAppDirectoryWithoutFolder() $this->assertSame($expected, $this->locator->locateFile($file)); } - public function testLocateFileWorksInNestedAppDirectory() + public function testLocateFileNotNamespacedWorksInNestedAppDirectory() { $file = 'Controllers/Home'; // not namespaced From 7f9ffacf43f30446ece16bfcf2bdcc6c56cc7a1a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:16:18 +0900 Subject: [PATCH 041/135] test: rename test methods and add comments --- tests/system/Autoloader/FileLocatorTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 41b6845dfb31..837c9390ce2f 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -94,21 +94,23 @@ public function testLocateFileNotNamespacedWorksInNestedAppDirectory() $this->assertSame($expected, $this->locator->locateFile($file, 'Controllers')); } - public function testLocateFileReplacesFolderName() + public function testLocateFileWithFolderNameInFile() { $file = '\App\Views/errors/html/error_404.php'; $expected = APPPATH . 'Views/errors/html/error_404.php'; + // This works because $file contains `Views`. $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); } - public function testLocateFileReplacesFolderNameLegacy() + public function testLocateFileNotNamespacedWithFolderNameInFile() { $file = 'Views/welcome_message.php'; // not namespaced $expected = APPPATH . 'Views/welcome_message.php'; + // This works because $file contains `Views`. $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); } From 60188ac2dfc02c6af26b4d7011a45e65717208d1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:42:16 +0900 Subject: [PATCH 042/135] test: rename test method names --- tests/system/Autoloader/FileLocatorTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 837c9390ce2f..cb75fb0348df 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -51,7 +51,7 @@ protected function setUp(): void $this->locator = new FileLocator($autoloader); } - public function testLocateFileNotNamespacedWorks() + public function testLocateFileNotNamespacedFindsInAppDirectory() { $file = 'Controllers/Home'; // not namespaced @@ -67,7 +67,7 @@ public function testLocateFileNotNamespacedNotFound() $this->assertFalse($this->locator->locateFile($file)); } - public function testLocateFileNotNamespacedWorksInAppDirectory() + public function testLocateFileNotNamespacedFindsWithFolderInAppDirectory() { $file = 'welcome_message'; // not namespaced @@ -76,7 +76,7 @@ public function testLocateFileNotNamespacedWorksInAppDirectory() $this->assertSame($expected, $this->locator->locateFile($file, 'Views')); } - public function testLocateFileNotNamespacedWorksInAppDirectoryWithoutFolder() + public function testLocateFileNotNamespacedFindesWithoutFolderInAppDirectory() { $file = 'Common'; // not namespaced From 9dab01a7591385b57c48fe75338b0690355f76de Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:42:49 +0900 Subject: [PATCH 043/135] docs: add comments --- tests/system/Autoloader/FileLocatorTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index cb75fb0348df..fc5f56a66d3b 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -91,6 +91,7 @@ public function testLocateFileNotNamespacedWorksInNestedAppDirectory() $expected = APPPATH . 'Controllers/Home.php'; + // This works because $file contains `Controllers`. $this->assertSame($expected, $this->locator->locateFile($file, 'Controllers')); } @@ -120,6 +121,7 @@ public function testLocateFileCanFindNamespacedView() $expected = APPPATH . 'Views/errors/html/error_404.php'; + // The namespace `Errors` (APPPATH . 'Views/errors') + the folder (`html`) + `error_404` $this->assertSame($expected, $this->locator->locateFile($file, 'html')); } From d8a1565c517d9b459b71b52314195d2429e8ed9c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 10:43:06 +0900 Subject: [PATCH 044/135] docs: make doc comments more specific --- system/Autoloader/FileLocator.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index f58d5c791d97..a4f7c67677d0 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -33,8 +33,13 @@ public function __construct(Autoloader $autoloader) * Attempts to locate a file by examining the name for a namespace * and looking through the PSR-4 namespaced files that we know about. * - * @param string $file The namespaced file to locate - * @param string|null $folder The folder within the namespace that we should look for the file. + * @param string $file The relative file path or namespaced file to + * locate. If not namespaced, search in the app + * folder. + * @param string|null $folder The folder within the namespace that we should + * look for the file. If $file does not contain + * this value, it will be appended to the namespace + * folder. * @param string $ext The file extension the file should have. * * @return false|string The path to the file, or false if not found. From 7af4ff8d2313fca1d3e0e67f093c9d6870702e91 Mon Sep 17 00:00:00 2001 From: Maksim Date: Sat, 3 Jun 2023 11:46:31 +1000 Subject: [PATCH 045/135] fix typos --- user_guide_src/source/libraries/time.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 6c6ec9c5c8ce..c9baf8a8f597 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -11,7 +11,7 @@ is the ``Time`` class and lives in the ``CodeIgniter\I18n`` namespace. .. note:: Prior to v4.3.0, the Time class extended ``DateTime`` and some inherited methods changed the current object state. The bug was fixed in v4.3.0. If you need the old Time class for backward - compatibility, you can use deprecated ``TimeLegay`` class for the time being. + compatibility, you can use deprecated ``TimeLegacy`` class for the time being. .. contents:: :local: From 8fc46bbec10a7be563b009b823c318ac02c1edb4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 3 Jun 2023 17:49:39 +0900 Subject: [PATCH 046/135] docs: fix by proofreading Co-authored-by: Michal Sniatala --- user_guide_src/source/cli/cli_commands.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 0ff390865134..dff328c78d6a 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -33,8 +33,8 @@ The following properties should be used in order to get listed in CLI commands a File Location ============= -Commands must be stored within a directory named **Commands**. However, that directory can be located in the PSR-4 namespaces -that the :doc:`Autoloader ` can locate it. This could be in **app/Commands**, or +Commands must be stored within a directory named **Commands**. However, that directory has to be located in the PSR-4 namespaces +so that the :doc:`Autoloader ` can locate it. This could be in **app/Commands**, or a directory that you keep commands in to use in all of your project development, like **Acme/Commands**. .. note:: When the commands are executed, the full CodeIgniter CLI environment has been loaded, making it From 0de4ce27b66f62d8cd146aa4488027a4a1f7e069 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 3 Jun 2023 17:09:27 +0800 Subject: [PATCH 047/135] Update user_guide_src/source/database/query_builder/062.php Co-authored-by: kenjis --- user_guide_src/source/database/query_builder/062.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/query_builder/062.php b/user_guide_src/source/database/query_builder/062.php index e383c0be1520..08753407c447 100644 --- a/user_guide_src/source/database/query_builder/062.php +++ b/user_guide_src/source/database/query_builder/062.php @@ -4,6 +4,6 @@ $builder->havingLike($array); /* * HAVING `title` LIKE '%match%' ESCAPE '!' - * AND `page1` LIKE '%match%' ESCAPE '!' + * AND `page1` LIKE '%match%' ESCAPE '!' * AND `page2` LIKE '%match%' ESCAPE '!' */ From 923e2b33c22040d650b6d047b933492f00f0e479 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 12:16:16 +0900 Subject: [PATCH 048/135] refactor: fix incorrect return value See https://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members --- system/Entity/Entity.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 4247c82b66fe..07e1e26393c8 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -429,7 +429,7 @@ public function cast(?bool $cast = null) * * @param array|bool|float|int|object|string|null $value * - * @return $this + * @return void * * @throws Exception */ @@ -452,7 +452,7 @@ public function __set(string $key, $value = null) if (method_exists($this, $method)) { $this->{$method}($value); - return $this; + return; } // Otherwise, just the value. This allows for creation of new @@ -460,8 +460,6 @@ public function __set(string $key, $value = null) // saved. Useful for grabbing values through joins, assigning // relationships, etc. $this->attributes[$dbColumn] = $value; - - return $this; } /** From 05fbcd4a2ad8bf3034de10aa3ed643426c21f89b Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 07:55:07 +0900 Subject: [PATCH 049/135] test: add test for feature test with validation twice --- tests/system/Test/FeatureTestTraitTest.php | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/system/Test/FeatureTestTraitTest.php b/tests/system/Test/FeatureTestTraitTest.php index 4636d58d3927..d622a00aaedf 100644 --- a/tests/system/Test/FeatureTestTraitTest.php +++ b/tests/system/Test/FeatureTestTraitTest.php @@ -102,6 +102,36 @@ public function testCallPostWithBody() $response->assertSee('Hello Mars!'); } + public function testCallValidationTwice() + { + $this->withRoutes([ + [ + 'post', + 'section/create', + static function () { + $validation = Services::validation(); + $validation->setRule('title', 'title', 'required|min_length[3]'); + + $post = Services::request()->getPost(); + + if ($validation->run($post)) { + return 'Okay'; + } + + return 'Invalid'; + }, + ], + ]); + + $response = $this->post('section/create', ['foo' => 'Mars']); + + $response->assertSee('Invalid'); + + $response = $this->post('section/create', ['title' => 'Section Title']); + + $response->assertSee('Okay'); + } + public function testCallPut() { $this->withRoutes([ From dbf469fe92facf846264b63394ca80a810c70a79 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 07:57:03 +0900 Subject: [PATCH 050/135] fix: feature testing does not reset validation result --- system/Test/FeatureTestTrait.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index e6e8492ea466..3d5668b07067 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -175,6 +175,9 @@ public function call(string $method, string $path, ?array $params = null) // Make sure filters are reset between tests Services::injectMock('filters', Services::filters(null, false)); + // Make sure validation is reset between tests + Services::injectMock('validation', Services::validation(null, false)); + $response = $this->app ->setContext('web') ->setRequest($request) From 0410b825a65188a7e0a7050ea1f0443baa82dd86 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 08:02:58 +0900 Subject: [PATCH 051/135] docs: fix by proofreading Co-authored-by: Michal Sniatala --- user_guide_src/source/libraries/validation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index a5956dcb9c5d..9a69dc7ae58f 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -697,8 +697,8 @@ If your method needs to work with parameters, the function will need a minimum o 3. an array with all of the data that was submitted the form (``$data``) 4. (optional) a custom error string (``&$error``), just as described above. -.. warning:: The other field values in ``$data`` is unvalidated (or maybe invalid) - data. Using unvalidated input data is a source of vulnerability. You must +.. warning:: The field values in ``$data`` are unvalidated (or may be invalid). + Using unvalidated input data is a source of vulnerability. You must perform the necessary validation within your custom rules before using the data in ``$data``. From 8c0b58e6447ed760164ece61c9469d76fd99fc9f Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 09:11:04 +0900 Subject: [PATCH 052/135] test: improve test method names --- .../Validation/StrictRules/DatabaseRelatedRulesTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php b/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php index e1336ac70f8b..32ef569911f9 100644 --- a/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php +++ b/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php @@ -82,7 +82,7 @@ public function testIsUniqueTrue(): void $this->assertTrue($this->validation->run($data)); } - public function testIsUniqueIgnoresParams(): void + public function testIsUniqueWithIgnoreValue(): void { $db = Database::connect(); $db @@ -102,7 +102,7 @@ public function testIsUniqueIgnoresParams(): void $this->assertTrue($this->validation->run($data)); } - public function testIsUniqueIgnoresParamsPlaceholders(): void + public function testIsUniqueWithIgnoreValuePlaceholder(): void { $this->hasInDatabase('user', [ 'name' => 'Derek', From ce2df7af935bd1c2937a2397db31a13b290747b0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 10:23:35 +0900 Subject: [PATCH 053/135] test: add test for invalid DBGroup --- .../StrictRules/DatabaseRelatedRulesTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php b/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php index 32ef569911f9..5083bec69fe8 100644 --- a/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php +++ b/tests/system/Validation/StrictRules/DatabaseRelatedRulesTest.php @@ -16,6 +16,7 @@ use CodeIgniter\Validation\Validation; use Config\Database; use Config\Services; +use InvalidArgumentException; use Tests\Support\Validation\TestRules; /** @@ -82,6 +83,16 @@ public function testIsUniqueTrue(): void $this->assertTrue($this->validation->run($data)); } + public function testIsUniqueWithInvalidDBGroup(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('invalidGroup is not a valid database connection group'); + + $this->validation->setRules(['email' => 'is_unique[user.email]']); + $data = ['email' => 'derek@world.co.uk']; + $this->assertTrue($this->validation->run($data, null, 'invalidGroup')); + } + public function testIsUniqueWithIgnoreValue(): void { $db = Database::connect(); From b5bea514c59e0ac60bcdf0701acd93949ed903e0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 10:25:03 +0900 Subject: [PATCH 054/135] docs: add @TODO --- system/Validation/Validation.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 9b77b3c8b075..4d5384a3807a 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -116,6 +116,9 @@ public function __construct($config, RendererInterface $view) * @param array|null $data The array of data to validate. * @param string|null $group The predefined group of rules to apply. * @param string|null $dbGroup The database group to use. + * + * @TODO Type ?string for $dbGroup should be removed. + * See https://github.com/codeigniter4/CodeIgniter4/issues/6723 */ public function run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool { From 66e38044857e3e8fd265dca1a89bb98ed298891b Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 4 Jun 2023 20:26:37 +0900 Subject: [PATCH 055/135] docs: remove unneeded @throws --- system/CodeIgniter.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 943fa360d1ce..c7a93a802fb4 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -310,8 +310,6 @@ private function configureKint(): void * makes all of the pieces work together. * * @return ResponseInterface|void - * - * @throws RedirectException */ public function run(?RouteCollectionInterface $routes = null, bool $returnResponse = false) { From 0012fe3802f57e58356e83328b85571fb860a386 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 10:39:37 +0900 Subject: [PATCH 056/135] docs: remove uneeded @throws --- system/Test/FeatureTestCase.php | 3 --- system/Test/FeatureTestTrait.php | 3 --- 2 files changed, 6 deletions(-) diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index 2c2233df81b0..bf157aea52af 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -148,9 +148,6 @@ public function skipEvents() * instance that can be used to run many assertions against. * * @return FeatureResponse - * - * @throws Exception - * @throws RedirectException */ public function call(string $method, string $path, ?array $params = null) { diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index e6e8492ea466..2417dd61a95f 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -138,9 +138,6 @@ public function skipEvents() * instance that can be used to run many assertions against. * * @return TestResponse - * - * @throws RedirectException - * @throws Exception */ public function call(string $method, string $path, ?array $params = null) { From 96e690cebfd9fd874daabadd9361469f14a80d29 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 10:25:29 +0900 Subject: [PATCH 057/135] fix: DBGroup is ignored in validation process while using placeholders --- system/Validation/Validation.php | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 4d5384a3807a..ddbbc2b44adc 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -190,6 +190,9 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup * Runs the validation process, returning true or false * determining whether validation was successful or not. * + * @TODO the method signature is not good. Should make the checkValue() + * method this method. + * * @param array|bool|float|int|object|string|null $value * @param string[] $errors */ @@ -200,6 +203,31 @@ public function check($value, string $rule, array $errors = []): bool return $this->setRule('check', null, $rule, $errors)->run(['check' => $value]); } + /** + * Runs the validation process, returning true or false determining whether + * validation was successful or not. + * + * @param array|bool|float|int|object|string|null $value + * @param array|string $rules + * @param string[] $errors + * @param string|null $dbGroup The database group to use. + */ + private function checkValue($value, $rules, array $errors = [], $dbGroup = null): bool + { + $this->reset(); + + return $this->setRule( + 'check', + null, + $rules, + $errors + )->run( + ['check' => $value], + null, + $dbGroup + ); + } + /** * Runs all of $rules against $field, until one fails, or * all of them have been processed. If one fails, it adds @@ -682,6 +710,7 @@ protected function fillPlaceholders(array $rules, array $data): array foreach ($placeholderFields as $field) { $validator ??= Services::validation(null, false); + assert($validator instanceof Validation); $placeholderRules = $rules[$field]['rules'] ?? null; @@ -702,7 +731,8 @@ protected function fillPlaceholders(array $rules, array $data): array } // Validate the placeholder field - if (! $validator->check($data[$field], implode('|', $placeholderRules))) { + $dbGroup = $data['DBGroup'] ?? null; + if (! $validator->checkValue($data[$field], $placeholderRules, [], $dbGroup)) { // if fails, do nothing continue; } From 0e739318a3e958504b51027e74a7f627f61db60c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 10:52:05 +0900 Subject: [PATCH 058/135] docs: improve comment --- system/Validation/Validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index ddbbc2b44adc..706abfc7d3a6 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -124,7 +124,7 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup { $data ??= $this->data; - // i.e. is_unique + // `DBGroup` is a reserved name. For is_unique and is_not_unique $data['DBGroup'] = $dbGroup; $this->loadRuleSets(); From 0318d87794350465d0b1fdf5f46f53ba076e1b24 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 17:57:23 +0900 Subject: [PATCH 059/135] fix: [BC] Validation::check() cannot specify non-default database group. --- system/Validation/Validation.php | 21 ++------------------- system/Validation/ValidationInterface.php | 6 ++++-- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 706abfc7d3a6..fe24743f1d3d 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -186,23 +186,6 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup return $this->getErrors() === []; } - /** - * Runs the validation process, returning true or false - * determining whether validation was successful or not. - * - * @TODO the method signature is not good. Should make the checkValue() - * method this method. - * - * @param array|bool|float|int|object|string|null $value - * @param string[] $errors - */ - public function check($value, string $rule, array $errors = []): bool - { - $this->reset(); - - return $this->setRule('check', null, $rule, $errors)->run(['check' => $value]); - } - /** * Runs the validation process, returning true or false determining whether * validation was successful or not. @@ -212,7 +195,7 @@ public function check($value, string $rule, array $errors = []): bool * @param string[] $errors * @param string|null $dbGroup The database group to use. */ - private function checkValue($value, $rules, array $errors = [], $dbGroup = null): bool + public function check($value, $rules, array $errors = [], $dbGroup = null): bool { $this->reset(); @@ -732,7 +715,7 @@ protected function fillPlaceholders(array $rules, array $data): array // Validate the placeholder field $dbGroup = $data['DBGroup'] ?? null; - if (! $validator->checkValue($data[$field], $placeholderRules, [], $dbGroup)) { + if (! $validator->check($data[$field], $placeholderRules, [], $dbGroup)) { // if fails, do nothing continue; } diff --git a/system/Validation/ValidationInterface.php b/system/Validation/ValidationInterface.php index 8c018b9a0dc2..9336c26e7f62 100644 --- a/system/Validation/ValidationInterface.php +++ b/system/Validation/ValidationInterface.php @@ -32,12 +32,14 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup * Check; runs the validation process, returning true or false * determining whether or not validation was successful. * - * @param array|bool|float|int|object|string|null $value Value to validate. + * @param array|bool|float|int|object|string|null $value Value to validate. + * @param array|string $rules * @param string[] $errors + * @param string|null $dbGroup The database group to use. * * @return bool True if valid, else false. */ - public function check($value, string $rule, array $errors = []): bool; + public function check($value, $rules, array $errors = [], $dbGroup = null): bool; /** * Takes a Request object and grabs the input data to use from its From a4113697afa37277254cad36f844a8ba4b8df2f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 17:58:43 +0900 Subject: [PATCH 060/135] docs: add changelog and upgrade guide --- user_guide_src/source/changelogs/v4.3.6.rst | 27 +++++++++++++++++++ .../source/installation/upgrade_436.rst | 3 +++ 2 files changed, 30 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst index ed38514b5ecf..ee9290096696 100644 --- a/user_guide_src/source/changelogs/v4.3.6.rst +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -12,6 +12,28 @@ Release Date: Unreleased BREAKING ******** +Interface Changes +================= + +.. note:: As long as you have not extended the relevant CodeIgniter core classes + or implemented these interfaces, all these changes are backward compatible + and require no intervention. + +ValidationInterface::check() +---------------------------- + +- The second parameter has changed from ``string $rule`` to ``$rules``. +- The optional fourth parameter ``$dbGroup = null`` has been added. + +Method Signature Changes +======================== + +Validation::check() +------------------- + +- The second parameter has changed from ``string $rule`` to ``$rules``. +- The optional fourth parameter ``$dbGroup = null`` has been added. + Message Changes *************** @@ -24,6 +46,11 @@ Deprecations Bugs Fixed ********** +- **Validation:** Fixed a bug that ``$DBGroup`` is ignored when checking + the value of a placeholder. +- **Validation:** Fixed a bug that ``check()`` cannot specify non-default + database group. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed. diff --git a/user_guide_src/source/installation/upgrade_436.rst b/user_guide_src/source/installation/upgrade_436.rst index 85536f9dbcc7..71efd80d9f85 100644 --- a/user_guide_src/source/installation/upgrade_436.rst +++ b/user_guide_src/source/installation/upgrade_436.rst @@ -21,6 +21,9 @@ Breaking Changes Breaking Enhancements ********************* +- The method signatures of ``ValidationInterface::check()`` and ``Validation::check()`` + have been changed. If you implement or extend them, update the signatures. + Project Files ************* From c68e6d021aa3e51b2ffbd254a92e5bdde3eb0f01 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 21:38:55 +0900 Subject: [PATCH 061/135] docs: fix RST format or so --- user_guide_src/source/changelogs/v4.3.5.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.3.5.rst b/user_guide_src/source/changelogs/v4.3.5.rst index 152f27f33a9c..0e5ab12a2fb1 100644 --- a/user_guide_src/source/changelogs/v4.3.5.rst +++ b/user_guide_src/source/changelogs/v4.3.5.rst @@ -21,11 +21,11 @@ SECURITY Changes ******* -- **make:cell** When creating a new cell, the controller would always have the ``Cell`` suffixed to the class name. - For the view file, the final ``_cell`` is always removed. -- **Cells** For compatibility with previous versions, view filenames ending with ``_cell`` can still be - located by the ``Cell`` as long as auto-detection of view file is enabled (via setting the ``$view`` property - to an empty string). +- **make:cell command:** When creating a new cell, the controller would always have the ``Cell`` suffixed to the class name. + For the view file, the final ``_cell`` is always removed. +- **View Cells:** For compatibility with previous versions, view filenames ending with ``_cell`` can still be + located by the ``Cell`` as long as auto-detection of view file is enabled (via setting the ``$view`` property + to an empty string). Deprecations ************ @@ -37,8 +37,8 @@ Bugs Fixed ********** - **Validation:** Fixed a bug where a closure used in combination with ``permit_empty`` or ``if_exist`` rules was causing an error. -- **make:cell** Fixed generating view files as classes. -- **make:cell** Fixed treatment of single word class input for case-insensitive OS. +- **make:cell command:** Fixed generating view files as classes. +- **make:cell command:** Fixed treatment of single word class input for case-insensitive OS. See the repo's `CHANGELOG.md `_ From f36ef7044ac58462b70e619d4e790bd9342af1a8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 9 Jun 2023 10:02:56 +0900 Subject: [PATCH 062/135] docs: improve doc comments --- system/Database/Config.php | 2 +- system/Database/Database.php | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/system/Database/Config.php b/system/Database/Config.php index eedbbd441465..802a4da25ac6 100644 --- a/system/Database/Config.php +++ b/system/Database/Config.php @@ -37,7 +37,7 @@ class Config extends BaseConfig protected static $factory; /** - * Creates the default + * Returns the database connection * * @param array|BaseConnection|string|null $group The name of the connection group to use, * or an array of configuration settings. diff --git a/system/Database/Database.php b/system/Database/Database.php index df3ad9ae1550..6527c21a6c1c 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -16,7 +16,7 @@ /** * Database Connection Factory * - * Creates and returns an instance of the appropriate DatabaseConnection + * Creates and returns an instance of the appropriate Database Connection. */ class Database { @@ -32,8 +32,7 @@ class Database protected $connections = []; /** - * Parses the connection binds and returns an instance of the driver - * ready to go. + * Parses the connection binds and creates a Database Connection instance. * * @return BaseConnection * @@ -83,7 +82,7 @@ public function loadUtils(ConnectionInterface $db): BaseUtils } /** - * Parse universal DSN string + * Parses universal DSN string * * @throws InvalidArgumentException */ From ebccb293145db4f5e97b6c38075373188b299a32 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 9 Jun 2023 10:05:49 +0900 Subject: [PATCH 063/135] refactor: do not reassign --- system/Database/Database.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/system/Database/Database.php b/system/Database/Database.php index 6527c21a6c1c..90e7e3d61899 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -120,21 +120,22 @@ protected function parseDSN(array $params): array } /** - * Initialize database driver. + * Creates a database object. * * @param string $driver Driver name. FQCN can be used. - * @param array|object $argument + * @param string $class 'Connection'|'Forge'|'Utils' + * @param array|object $argument The constructor parameter. * * @return BaseConnection|BaseUtils|Forge */ protected function initDriver(string $driver, string $class, $argument): object { - $class = $driver . '\\' . $class; - if (strpos($driver, '\\') === false) { - $class = "CodeIgniter\\Database\\{$class}"; + $classname = "CodeIgniter\\Database\\{$driver}\\{$class}"; + } else { + $classname = $driver . '\\' . $class; } - return new $class($argument); + return new $classname($argument); } } From 07f3274d8854779b655127b5ea15b62d6a5a7700 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 9 Jun 2023 12:01:35 +0900 Subject: [PATCH 064/135] refactor: use ternary operator --- system/Database/Database.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/system/Database/Database.php b/system/Database/Database.php index 90e7e3d61899..2818fe220928 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -130,11 +130,9 @@ protected function parseDSN(array $params): array */ protected function initDriver(string $driver, string $class, $argument): object { - if (strpos($driver, '\\') === false) { - $classname = "CodeIgniter\\Database\\{$driver}\\{$class}"; - } else { - $classname = $driver . '\\' . $class; - } + $classname = (strpos($driver, '\\') === false) + ? "CodeIgniter\\Database\\{$driver}\\{$class}" + : $driver . '\\' . $class; return new $classname($argument); } From d7826f54bcd112aecda84535a2438ecdd06a5eb6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:42:05 +0900 Subject: [PATCH 065/135] docs: add section titles --- user_guide_src/source/database/connecting.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index aa6089e52339..6015d0571199 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -6,6 +6,12 @@ Connecting to your Database :local: :depth: 2 +Connecting to a Database +======================== + +Connecting to the Default Group +------------------------------- + You can connect to your database by adding this line of code in any function where it is needed, or in your class constructor to make the database available globally in that class. From de3635b8c29e0d466a782d5acbbb40f44cd72082 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:42:38 +0900 Subject: [PATCH 066/135] docs: fix section title --- user_guide_src/source/database/connecting.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index 6015d0571199..8fad58c5950c 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -36,8 +36,8 @@ Available Parameters #. ``$getShared``: true/false (boolean). Whether to return the shared connection (see Connecting to Multiple Databases below). -Manually Connecting to a Database ---------------------------------- +Connecting to Specific Group +---------------------------- The first parameter of this function can **optionally** be used to specify a particular database group from your config file. Examples: From 7789dcf117aa817085896dd647176569be4e634e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:42:56 +0900 Subject: [PATCH 067/135] docs: capitalize first letter of title --- user_guide_src/source/database/connecting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index 8fad58c5950c..ddb101a9b766 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -97,7 +97,7 @@ or re-establish it. .. literalinclude:: connecting/007.php -Manually closing the Connection +Manually Closing the Connection =============================== While CodeIgniter intelligently takes care of closing your database From c3720700631059c1cbd92d8d2461b34035d52e07 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:44:08 +0900 Subject: [PATCH 068/135] docs: fix variable notation --- user_guide_src/source/database/connecting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index ddb101a9b766..9a9833d5b94b 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -32,7 +32,7 @@ Available Parameters **\\Config\\Database::connect($group = null, bool $getShared = true): BaseConnection** -#. ``$group``: The database group name, a string that must match the config class' property name. Default value is ``$config->defaultGroup``. +#. ``$group``: The database group name, a string that must match the config class' property name. Default value is ``Config\Database::$defaultGroup``. #. ``$getShared``: true/false (boolean). Whether to return the shared connection (see Connecting to Multiple Databases below). From df4e640850125d2d45b0e59254156f3600810deb Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:44:27 +0900 Subject: [PATCH 069/135] docs: decorate string in sample code --- user_guide_src/source/database/connecting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index 9a9833d5b94b..a94968df75c5 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -46,7 +46,7 @@ To choose a specific group from your config file you can do this: .. literalinclude:: connecting/003.php -Where group_name is the name of the connection group from your config +Where ``group_name`` is the name of the connection group from your config file. Multiple Connections to Same Database From b93a90143e632e2ade88a89727d81b0a793eb09a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 10:45:28 +0900 Subject: [PATCH 070/135] docs: do not show unneeded ` Date: Sat, 10 Jun 2023 11:44:40 +0900 Subject: [PATCH 071/135] docs: fix incorrect property name --- user_guide_src/source/database/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index f9e5749ed548..b4e475b0bd80 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -125,7 +125,7 @@ Explanation of Values: =============== =========================================================================================================== Name Config Description =============== =========================================================================================================== -**dsn** The DSN connect string (an all-in-one configuration sequence). +**DSN** The DSN connect string (an all-in-one configuration sequence). **hostname** The hostname of your database server. Often this is 'localhost'. **username** The username used to connect to the database. (``SQLite3`` does not use this.) **password** The password used to connect to the database. (``SQLite3`` does not use this.) From 9426a5a21c98da10f5a39febe87622a27b98c0ae Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 11:45:13 +0900 Subject: [PATCH 072/135] docs: make TOC depth 3 --- user_guide_src/source/database/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index b4e475b0bd80..e227d038ae9d 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -4,7 +4,7 @@ Database Configuration .. contents:: :local: - :depth: 2 + :depth: 3 .. note:: See :ref:`requirements-supported-databases` for currently supported database drivers. From 2ebf49703816893cc276f566d6f11fea81400154 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 11:46:59 +0900 Subject: [PATCH 073/135] docs: fix section title --- user_guide_src/source/database/configuration.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index e227d038ae9d..e1ad75d1069d 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -82,8 +82,8 @@ variable located in the config file: default we've used the word "default" for the primary connection, but it too can be renamed to something more relevant to your project. -defaultGroup -============ +Changing Databases Automatically +================================ You could modify the config file to detect the environment and automatically update the `defaultGroup` value to the correct one by adding the required logic From e2774067932fbc83fb89d5c8561e270766693182 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 11:47:37 +0900 Subject: [PATCH 074/135] docs: fix text decoration --- user_guide_src/source/database/configuration.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index e1ad75d1069d..950a71e6880b 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -26,7 +26,7 @@ prototype: The name of the class property is the connection name, and can be used while connecting to specify a group name. -.. note:: The default location of the SQLite3 database is in the ``writable`` folder. +.. note:: The default location of the SQLite3 database is in the **writable** folder. If you want to change the location, you must set the full path to the new folder. DSN @@ -78,15 +78,15 @@ variable located in the config file: .. literalinclude:: configuration/007.php -.. note:: The name 'test' is arbitrary. It can be anything you want. By - default we've used the word "default" for the primary connection, +.. note:: The name ``test`` is arbitrary. It can be anything you want. By + default we've used the word ``default`` for the primary connection, but it too can be renamed to something more relevant to your project. Changing Databases Automatically ================================ You could modify the config file to detect the environment and automatically -update the `defaultGroup` value to the correct one by adding the required logic +update the ``defaultGroup`` value to the correct one by adding the required logic within the class' constructor: .. literalinclude:: configuration/008.php From bceb19e7fc847a7f2c10e86610a470ac16d17a07 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 11:48:26 +0900 Subject: [PATCH 075/135] docs: add section titles --- user_guide_src/source/database/configuration.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 950a71e6880b..66a4fb57ebbb 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -18,6 +18,9 @@ connection values (username, password, database name, etc.). The config file is located at **app/Config/Database.php**. You can also set database connection values in the **.env** file. See below for more details. +Setting Default Database +======================== + The config settings are stored in a class property that is an array with this prototype: @@ -30,7 +33,7 @@ while connecting to specify a group name. If you want to change the location, you must set the full path to the new folder. DSN -=== +--- Some database drivers (such as PDO, PostgreSQL, Oracle, ODBC) might require a full DSN string to be provided. If that is the case, you @@ -42,6 +45,9 @@ driver's underlying native PHP extension, like this: .. note:: If you do not specify a DSN string for a driver that requires it, CodeIgniter will try to build it with the rest of the provided settings. +DSN in Universal Manner +^^^^^^^^^^^^^^^^^^^^^^^ + You can also set a Data Source Name in universal manner (URL like). In that case DSNs must have this prototype: .. literalinclude:: configuration/003.php @@ -56,7 +62,7 @@ add the config variables as a query string: fields, CodeIgniter will append them. Failovers -========= +--------- You can also specify failovers for the situation when the main connection cannot connect for some reason. These failovers can be specified by setting the failover for a connection like this: @@ -65,6 +71,9 @@ These failovers can be specified by setting the failover for a connection like t You can specify as many failovers as you like. +Setting Multiple Databases +========================== + You may optionally store multiple sets of connection values. If, for example, you run multiple environments (development, production, test, etc.) under a single installation, you can set up a From 5eeb98809e928c83744dcbb0341f5981bddbc06e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 11:57:20 +0900 Subject: [PATCH 076/135] docs: fix incorrect description We don't have PDO and ODBC drivers. Some driver uses DSN to connect, but it is not a must because CI builds it from other settings. --- .../source/database/configuration.rst | 14 ++++++------- .../source/database/configuration/002.php | 21 ++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 66a4fb57ebbb..0b8b7ae9df57 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -35,15 +35,15 @@ while connecting to specify a group name. DSN --- -Some database drivers (such as PDO, PostgreSQL, Oracle, ODBC) might -require a full DSN string to be provided. If that is the case, you -should use the 'DSN' configuration setting, as if you're using the -driver's underlying native PHP extension, like this: +Some database drivers (such as Postgre, OCI8) requires a full DSN string to connect. +But if you do not specify a DSN string for a driver that requires it, CodeIgniter +will try to build it with the rest of the provided settings. -.. literalinclude:: configuration/002.php +If you specify a DSN, you should use the ``'DSN'`` configuration setting, as if +you're using the driver's underlying native PHP extension, like this: -.. note:: If you do not specify a DSN string for a driver that requires it, CodeIgniter - will try to build it with the rest of the provided settings. +.. literalinclude:: configuration/002.php + :lines: 11-15 DSN in Universal Manner ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/user_guide_src/source/database/configuration/002.php b/user_guide_src/source/database/configuration/002.php index 7f9f9dabc62b..10551acdc509 100644 --- a/user_guide_src/source/database/configuration/002.php +++ b/user_guide_src/source/database/configuration/002.php @@ -1,13 +1,18 @@ 'pgsql:host=localhost;port=5432;dbname=database_name', +namespace Config; + +use CodeIgniter\Database\Config; + +class Database extends Config +{ // ... -]; -// Oracle -$default = [ - 'DSN' => '//localhost/XE', + // OCI8 + public array $default = [ + 'DSN' => '//localhost/XE', + // ... + ]; + // ... -]; +} From faaadd6bdc0d6d0023f6a4c2f1bfb3056a5fca5d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 12:03:33 +0900 Subject: [PATCH 077/135] docs: update sample files --- .../source/database/configuration.rst | 5 ++ .../source/database/configuration/001.php | 6 +- .../source/database/configuration/003.php | 17 +++- .../source/database/configuration/004.php | 21 +++-- .../source/database/configuration/005.php | 83 +++++++++++-------- .../source/database/configuration/006.php | 4 +- .../source/database/configuration/007.php | 13 ++- .../source/database/configuration/010.php | 18 ++++ 8 files changed, 118 insertions(+), 49 deletions(-) create mode 100644 user_guide_src/source/database/configuration/010.php diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 0b8b7ae9df57..ae0605d0a81d 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -51,11 +51,16 @@ DSN in Universal Manner You can also set a Data Source Name in universal manner (URL like). In that case DSNs must have this prototype: .. literalinclude:: configuration/003.php + :lines: 11-14 To override default config values when connecting with a universal version of the DSN string, add the config variables as a query string: .. literalinclude:: configuration/004.php + :lines: 11-15 + +.. literalinclude:: configuration/010.php + :lines: 11-15 .. note:: If you provide a DSN string and it is missing some valid settings (e.g., the database character set), which are present in the rest of the configuration diff --git a/user_guide_src/source/database/configuration/001.php b/user_guide_src/source/database/configuration/001.php index 6531870602d2..b4336abbf1c0 100644 --- a/user_guide_src/source/database/configuration/001.php +++ b/user_guide_src/source/database/configuration/001.php @@ -6,7 +6,9 @@ class Database extends Config { - public $default = [ + // ... + + public array $default = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => 'root', @@ -14,7 +16,7 @@ class Database extends Config 'database' => 'database_name', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', - 'pConnect' => true, + 'pConnect' => false, 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', diff --git a/user_guide_src/source/database/configuration/003.php b/user_guide_src/source/database/configuration/003.php index 1c8ea93e8288..b0fc11d308f9 100644 --- a/user_guide_src/source/database/configuration/003.php +++ b/user_guide_src/source/database/configuration/003.php @@ -1,6 +1,17 @@ 'DBDriver://username:password@hostname:port/database', +namespace Config; + +use CodeIgniter\Database\Config; + +class Database extends Config +{ + // ... + + public array $default = [ + 'DSN' => 'DBDriver://username:password@hostname:port/database', + // ... + ]; + // ... -]; +} diff --git a/user_guide_src/source/database/configuration/004.php b/user_guide_src/source/database/configuration/004.php index 05681bf62a45..4b77961706da 100644 --- a/user_guide_src/source/database/configuration/004.php +++ b/user_guide_src/source/database/configuration/004.php @@ -1,13 +1,18 @@ 'MySQLi://username:password@hostname:3306/database?charset=utf8&DBCollat=utf8_general_ci', +namespace Config; + +use CodeIgniter\Database\Config; + +class Database extends Config +{ // ... -]; -// Postgre -$default = [ - 'DSN' => 'Postgre://username:password@hostname:5432/database?charset=utf8&connect_timeout=5&sslmode=1', + // MySQLi + public array $default = [ + 'DSN' => 'MySQLi://username:password@hostname:3306/database?charset=utf8&DBCollat=utf8_general_ci', + // ... + ]; + // ... -]; +} diff --git a/user_guide_src/source/database/configuration/005.php b/user_guide_src/source/database/configuration/005.php index 7e2da93f95d3..ca23aea169d9 100644 --- a/user_guide_src/source/database/configuration/005.php +++ b/user_guide_src/source/database/configuration/005.php @@ -1,36 +1,51 @@ 'localhost1', - 'username' => '', - 'password' => '', - 'database' => '', - 'DBDriver' => 'MySQLi', - 'DBPrefix' => '', - 'pConnect' => true, - 'DBDebug' => true, - 'charset' => 'utf8', - 'DBCollat' => 'utf8_general_ci', - 'swapPre' => '', - 'encrypt' => false, - 'compress' => false, - 'strictOn' => false, - ], - [ - 'hostname' => 'localhost2', - 'username' => '', - 'password' => '', - 'database' => '', - 'DBDriver' => 'MySQLi', - 'DBPrefix' => '', - 'pConnect' => true, - 'DBDebug' => true, - 'charset' => 'utf8', - 'DBCollat' => 'utf8_general_ci', - 'swapPre' => '', - 'encrypt' => false, - 'compress' => false, - 'strictOn' => false, - ], -]; +namespace Config; + +use CodeIgniter\Database\Config; + +class Database extends Config +{ + // ... + + public array $default = [ + // ... + 'failover' => [ + [ + 'hostname' => 'localhost1', + 'username' => '', + 'password' => '', + 'database' => '', + 'DBDriver' => 'MySQLi', + 'DBPrefix' => '', + 'pConnect' => true, + 'DBDebug' => true, + 'charset' => 'utf8', + 'DBCollat' => 'utf8_general_ci', + 'swapPre' => '', + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, + ], + [ + 'hostname' => 'localhost2', + 'username' => '', + 'password' => '', + 'database' => '', + 'DBDriver' => 'MySQLi', + 'DBPrefix' => '', + 'pConnect' => true, + 'DBDebug' => true, + 'charset' => 'utf8', + 'DBCollat' => 'utf8_general_ci', + 'swapPre' => '', + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, + ], + ], + // ... + ]; + + // ... +} diff --git a/user_guide_src/source/database/configuration/006.php b/user_guide_src/source/database/configuration/006.php index 4381a0a71fff..1cd5fafe421b 100644 --- a/user_guide_src/source/database/configuration/006.php +++ b/user_guide_src/source/database/configuration/006.php @@ -6,7 +6,9 @@ class Database extends Config { - public $test = [ + // ... + + public array $test = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => 'root', diff --git a/user_guide_src/source/database/configuration/007.php b/user_guide_src/source/database/configuration/007.php index 97e8523fc621..7b9d57d58aca 100644 --- a/user_guide_src/source/database/configuration/007.php +++ b/user_guide_src/source/database/configuration/007.php @@ -1,3 +1,14 @@ 'Postgre://username:password@hostname:5432/database?charset=utf8&connect_timeout=5&sslmode=1', + // ... + ]; + + // ... +} From b9d4bf9a3fac481a99e6f813362b2c5b2e29b031 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 13:16:34 +0900 Subject: [PATCH 078/135] docs: update DBDebug for testing --- tests/_support/Config/Registrar.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/_support/Config/Registrar.php b/tests/_support/Config/Registrar.php index ffdd9cba9bf7..a47b9c4ff010 100644 --- a/tests/_support/Config/Registrar.php +++ b/tests/_support/Config/Registrar.php @@ -33,7 +33,7 @@ class Registrar 'DBDriver' => 'MySQLi', 'DBPrefix' => 'db_', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', @@ -52,7 +52,7 @@ class Registrar 'DBDriver' => 'Postgre', 'DBPrefix' => 'db_', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', @@ -71,7 +71,7 @@ class Registrar 'DBDriver' => 'SQLite3', 'DBPrefix' => 'db_', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', @@ -91,7 +91,7 @@ class Registrar 'DBDriver' => 'SQLSRV', 'DBPrefix' => 'db_', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', @@ -110,7 +110,7 @@ class Registrar 'DBDriver' => 'OCI8', 'DBPrefix' => 'db_', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', From a6b876bd81fc042e7e8907659c372a5039aacd99 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 13:43:17 +0900 Subject: [PATCH 079/135] test: fix charset for OCI8 --- tests/_support/Config/Registrar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/_support/Config/Registrar.php b/tests/_support/Config/Registrar.php index a47b9c4ff010..a9c7c3097630 100644 --- a/tests/_support/Config/Registrar.php +++ b/tests/_support/Config/Registrar.php @@ -111,7 +111,7 @@ class Registrar 'DBPrefix' => 'db_', 'pConnect' => false, 'DBDebug' => true, - 'charset' => 'utf8', + 'charset' => 'AL32UTF8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', 'encrypt' => false, From 99b93bf671ef6543b2c54462d9ea425742b7e477 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Sat, 10 Jun 2023 12:04:57 +0200 Subject: [PATCH 080/135] fix: [Postgre] Semicolon in the connection parameters break the DSN string (#7552) move all related code to the convertDSN() method --- system/Database/Postgre/Connection.php | 45 ++++++++++++++++++--- tests/system/Database/ConfigTest.php | 44 ++++++++++++++++++++ user_guide_src/source/changelogs/v4.3.6.rst | 1 + 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 8e96128264e2..56905ec922d2 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -64,14 +64,11 @@ public function connect(bool $persistent = false) $this->buildDSN(); } - // Strip pgsql if exists + // Convert DSN string if (mb_strpos($this->DSN, 'pgsql:') === 0) { - $this->DSN = mb_substr($this->DSN, 6); + $this->convertDSN(); } - // Convert semicolons to spaces. - $this->DSN = str_replace(';', ' ', $this->DSN); - $this->connID = $persistent === true ? pg_pconnect($this->DSN) : pg_connect($this->DSN); if ($this->connID !== false) { @@ -92,6 +89,44 @@ public function connect(bool $persistent = false) return $this->connID; } + /** + * Converts the DSN with semicolon syntax. + */ + private function convertDSN() + { + // Strip pgsql + $this->DSN = mb_substr($this->DSN, 6); + + // Convert semicolons to spaces in DSN format like: + // pgsql:host=localhost;port=5432;dbname=database_name + // https://www.php.net/manual/en/function.pg-connect.php + $allowedParams = ['host', 'port', 'dbname', 'user', 'password', 'connect_timeout', 'options', 'sslmode', 'service']; + + $parameters = explode(';', $this->DSN); + + $output = ''; + $previousParameter = ''; + + foreach ($parameters as $parameter) { + [$key, $value] = explode('=', $parameter, 2); + if (in_array($key, $allowedParams, true)) { + if ($previousParameter !== '') { + if (array_search($key, $allowedParams, true) < array_search($previousParameter, $allowedParams, true)) { + $output .= ';'; + } else { + $output .= ' '; + } + } + $output .= $parameter; + $previousParameter = $key; + } else { + $output .= ';' . $parameter; + } + } + + $this->DSN = $output; + } + /** * Keep or establish the connection if no queries have been sent for * a length of time exceeding the server's idle timeout. diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index 4c0cc78ce9a4..3e963749dd57 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\ReflectionHelper; +use Generator; /** * @internal @@ -190,4 +191,47 @@ public function testConnectionGroupWithDSNPostgreNative() $this->assertTrue($this->getPrivateProperty($conn, 'strictOn')); $this->assertSame([], $this->getPrivateProperty($conn, 'failover')); } + + /** + * @dataProvider convertDSNProvider + * + * @see https://github.com/codeigniter4/CodeIgniter4/issues/7550 + */ + public function testConvertDSN(string $input, string $expected) + { + $this->dsnGroupPostgreNative['DSN'] = $input; + $conn = Config::connect($this->dsnGroupPostgreNative, false); + $this->assertInstanceOf(BaseConnection::class, $conn); + + $method = $this->getPrivateMethodInvoker($conn, 'convertDSN'); + $method(); + + $this->assertSame($expected, $this->getPrivateProperty($conn, 'DSN')); + } + + public function convertDSNProvider(): Generator + { + yield from [ + [ + 'pgsql:host=localhost;port=5432;dbname=database_name;user=username;password=password', + 'host=localhost port=5432 dbname=database_name user=username password=password', + ], + [ + 'pgsql:host=localhost;port=5432;dbname=database_name;user=username;password=we;port=we', + 'host=localhost port=5432 dbname=database_name user=username password=we;port=we', + ], + [ + 'pgsql:host=localhost;port=5432;dbname=database_name', + 'host=localhost port=5432 dbname=database_name', + ], + [ + "pgsql:host=localhost;port=5432;dbname=database_name;options='--client_encoding=UTF8'", + "host=localhost port=5432 dbname=database_name options='--client_encoding=UTF8'", + ], + [ + 'pgsql:host=localhost;port=5432;dbname=database_name;something=stupid', + 'host=localhost port=5432 dbname=database_name;something=stupid', + ], + ]; + } } diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst index ee9290096696..01fc0893d41d 100644 --- a/user_guide_src/source/changelogs/v4.3.6.rst +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -50,6 +50,7 @@ Bugs Fixed the value of a placeholder. - **Validation:** Fixed a bug that ``check()`` cannot specify non-default database group. +- **Database:** Fixed a bug where semicolon character (``;``) in one of the Postgre connection parameters would break the DSN string. See the repo's `CHANGELOG.md `_ From 7c5a540d64a5d686efaf92d09ddb6d47f1ae4e50 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 17:14:08 +0900 Subject: [PATCH 081/135] docs: decorate example code --- .../source/libraries/validation.rst | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 9a69dc7ae58f..ebb6a82b2276 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -768,20 +768,20 @@ alpha_numeric_punct No Fails if field contains anything other than decimal No Fails if field contains anything other than a decimal number. Also accepts a + or - sign for the number. -differs Yes Fails if field does not differ from the one differs[field_name] +differs Yes Fails if field does not differ from the one ``differs[field_name]`` in the parameter. -exact_length Yes Fails if field is not exactly the parameter exact_length[5] or exact_length[5,8,12] +exact_length Yes Fails if field is not exactly the parameter ``exact_length[5]`` or ``exact_length[5,8,12]`` value. One or more comma-separated values. -greater_than Yes Fails if field is less than or equal to greater_than[8] +greater_than Yes Fails if field is less than or equal to ``greater_than[8]`` the parameter value or not numeric. -greater_than_equal_to Yes Fails if field is less than the parameter greater_than_equal_to[5] +greater_than_equal_to Yes Fails if field is less than the parameter ``greater_than_equal_to[5]`` value, or not numeric. hex No Fails if field contains anything other than hexadecimal characters. if_exist No If this rule is present, validation will only return possible errors if the field key exists, regardless of its value. -in_list Yes Fails if field is not within a predetermined in_list[red,blue,green] +in_list Yes Fails if field is not within a predetermined ``in_list[red,blue,green]`` list. integer No Fails if field contains anything other than an integer. @@ -789,36 +789,36 @@ is_natural No Fails if field contains anything other than a natural number: 0, 1, 2, 3, etc. is_natural_no_zero No Fails if field contains anything other than a natural number, except zero: 1, 2, 3, etc. -is_not_unique Yes Checks the database to see if the given value is_not_unique[table.field,where_field,where_value] +is_not_unique Yes Checks the database to see if the given value ``is_not_unique[table.field,where_field,where_value]`` exist. Can ignore records by field/value to filter (currently accept only one filter). -is_unique Yes Checks if this field value exists in the is_unique[table.field,ignore_field,ignore_value] +is_unique Yes Checks if this field value exists in the ``is_unique[table.field,ignore_field,ignore_value]`` database. Optionally set a column and value to ignore, useful when updating records to ignore itself. -less_than Yes Fails if field is greater than or equal to less_than[8] +less_than Yes Fails if field is greater than or equal to ``less_than[8]`` the parameter value or not numeric. -less_than_equal_to Yes Fails if field is greater than the parameter less_than_equal_to[8] +less_than_equal_to Yes Fails if field is greater than the parameter ``less_than_equal_to[8]`` value or not numeric. matches Yes The value must match the value of the field - in the parameter. matches[field] -max_length Yes Fails if field is longer than the parameter max_length[8] + in the parameter. ``matches[field]`` +max_length Yes Fails if field is longer than the parameter ``max_length[8]`` value. -min_length Yes Fails if field is shorter than the parameter min_length[3] +min_length Yes Fails if field is shorter than the parameter ``min_length[3]`` value. -not_in_list Yes Fails if field is within a predetermined not_in_list[red,blue,green] +not_in_list Yes Fails if field is within a predetermined ``not_in_list[red,blue,green]`` list. numeric No Fails if field contains anything other than numeric characters. -regex_match Yes Fails if field does not match the regular regex_match[/regex/] +regex_match Yes Fails if field does not match the regular ``regex_match[/regex/]`` expression. permit_empty No Allows the field to receive an empty array, empty string, null or false. required No Fails if the field is an empty array, empty string, null or false. -required_with Yes The field is required when any of the other required_with[field1,field2] +required_with Yes The field is required when any of the other ``required_with[field1,field2]`` required fields are present in the data. -required_without Yes The field is required when any of other required_without[field1,field2] +required_without Yes The field is required when any of other ``required_without[field1,field2]`` fields do not pass ``required`` checks. string No A generic alternative to the alpha* rules that confirms the element is a string @@ -832,21 +832,21 @@ valid_email No Fails if field does not contain a valid email address. valid_emails No Fails if any value provided in a comma separated list is not a valid email. -valid_ip No Fails if the supplied IP is not valid. valid_ip[ipv6] +valid_ip No Fails if the supplied IP is not valid. ``valid_ip[ipv6]`` Accepts an optional parameter of 'ipv4' or 'ipv6' to specify an IP format. valid_url No Fails if field does not contain (loosely) a URL. Includes simple strings that could be hostnames, like "codeigniter". -valid_url_strict Yes Fails if field does not contain a valid URL. valid_url_strict[https] +valid_url_strict Yes Fails if field does not contain a valid URL. ``valid_url_strict[https]`` You can optionally specify a list of valid schemas. If not specified, ``http,https`` are valid. This rule uses PHP's ``FILTER_VALIDATE_URL``. -valid_date No Fails if field does not contain a valid date. valid_date[d/m/Y] +valid_date No Fails if field does not contain a valid date. ``valid_date[d/m/Y]`` Accepts an optional parameter to matches a date format. -valid_cc_number Yes Verifies that the credit card number matches valid_cc_number[amex] +valid_cc_number Yes Verifies that the credit card number matches ``valid_cc_number[amex]`` the format used by the specified provider. Current supported providers are: American Express (amex), @@ -892,25 +892,25 @@ file upload related rules:: ======================= ========== ============================================= =================================================== Rule Parameter Description Example ======================= ========== ============================================= =================================================== -uploaded Yes Fails if the name of the parameter does not uploaded[field_name] +uploaded Yes Fails if the name of the parameter does not ``uploaded[field_name]`` match the name of any uploaded files. -max_size Yes Fails if the uploaded file named in the max_size[field_name,2048] +max_size Yes Fails if the uploaded file named in the ``max_size[field_name,2048]`` parameter is larger than the second parameter in kilobytes (kb). Or if the file is larger than allowed maximum size declared in php.ini config file - ``upload_max_filesize`` directive. -max_dims Yes Fails if the maximum width and height of an max_dims[field_name,300,150] +max_dims Yes Fails if the maximum width and height of an ``max_dims[field_name,300,150]`` uploaded image exceed values. The first parameter is the field name. The second is the width, and the third is the height. Will also fail if the file cannot be determined to be an image. -mime_in Yes Fails if the file's mime type is not one mime_in[field_name,image/png,image/jpeg] +mime_in Yes Fails if the file's mime type is not one ``mime_in[field_name,image/png,image/jpeg]`` listed in the parameters. -ext_in Yes Fails if the file's extension is not one ext_in[field_name,png,jpg,gif] +ext_in Yes Fails if the file's extension is not one ``ext_in[field_name,png,jpg,gif]`` listed in the parameters. -is_image Yes Fails if the file cannot be determined to be is_image[field_name] +is_image Yes Fails if the file cannot be determined to be ``is_image[field_name]`` an image based on the mime type. ======================= ========== ============================================= =================================================== From b79feaa2b5e456eb04790cd17507315bd7ef292b Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 17:27:03 +0900 Subject: [PATCH 082/135] docs: decorate text --- .../source/libraries/validation.rst | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index ebb6a82b2276..c19527874116 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -759,15 +759,16 @@ alpha_numeric_space No Fails if field contains anything other than alphanumeric or space characters. alpha_numeric_punct No Fails if field contains anything other than alphanumeric, space, or this limited set of - punctuation characters: ~ (tilde), - ! (exclamation), # (number), $ (dollar), - % (percent), & (ampersand), * (asterisk), - - (dash), _ (underscore), + (plus), - = (equals), | (vertical bar), : (colon), - . (period). + punctuation characters: ``~`` (tilde), + ``!`` (exclamation), ``#`` (number), + ``$`` (dollar), ``% (percent), & (ampersand), + ``*`` (asterisk), ``-`` (dash), + ``_`` (underscore), ``+`` (plus), + ``=`` (equals), ``|`` (vertical bar), + ``:`` (colon), ``.`` (period). decimal No Fails if field contains anything other than - a decimal number. - Also accepts a + or - sign for the number. + a decimal number. Also accepts a ``+`` or + ``-`` sign for the number. differs Yes Fails if field does not differ from the one ``differs[field_name]`` in the parameter. exact_length Yes Fails if field is not exactly the parameter ``exact_length[5]`` or ``exact_length[5,8,12]`` @@ -833,8 +834,8 @@ valid_email No Fails if field does not contain a valid valid_emails No Fails if any value provided in a comma separated list is not a valid email. valid_ip No Fails if the supplied IP is not valid. ``valid_ip[ipv6]`` - Accepts an optional parameter of 'ipv4' or - 'ipv6' to specify an IP format. + Accepts an optional parameter of ``ipv4`` or + ``ipv6`` to specify an IP format. valid_url No Fails if field does not contain (loosely) a URL. Includes simple strings that could be hostnames, like "codeigniter". @@ -849,22 +850,23 @@ valid_date No Fails if field does not contain a valid date. valid_cc_number Yes Verifies that the credit card number matches ``valid_cc_number[amex]`` the format used by the specified provider. Current supported providers are: - American Express (amex), - China Unionpay (unionpay), - Diners Club CarteBlance (carteblanche), - Diners Club (dinersclub), - Discover Card (discover), - Interpayment (interpayment), JCB (jcb), - Maestro (maestro), Dankort (dankort), - NSPK MIR (mir), - Troy (troy), MasterCard (mastercard), - Visa (visa), UATP (uatp), Verve (verve), - CIBC Convenience Card (cibc), - Royal Bank of Canada Client Card (rbc), - TD Canada Trust Access Card (tdtrust), - Scotiabank Scotia Card (scotia), - BMO ABM Card (bmoabm), - HSBC Canada Card (hsbc) + American Express (``amex``), + China Unionpay (``unionpay``), + Diners Club CarteBlance (``carteblanche``), + Diners Club (``dinersclub``), + Discover Card (``discover``), + Interpayment (``interpayment``), + JCB (``jcb``), Maestro (``maestro``), + Dankort (``dankort``), NSPK MIR (``mir``), + Troy (``troy``), MasterCard (``mastercard``), + Visa (``visa``), UATP (``uatp``), + Verve (``verve``), + CIBC Convenience Card (``cibc``), + Royal Bank of Canada Client Card (``rbc``), + TD Canada Trust Access Card (``tdtrust``), + Scotiabank Scotia Card (``scotia``), + BMO ABM Card (``bmoabm``), + HSBC Canada Card (``hsbc``) ======================= ========== ============================================= =================================================== .. note:: You can also use any native PHP functions that return boolean and From ea5669eed7fe02ecad851f5b80789c9baab61af2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 17:27:57 +0900 Subject: [PATCH 083/135] docs: add link to PHP manual --- user_guide_src/source/libraries/validation.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index c19527874116..825f7d6e4686 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -824,7 +824,7 @@ required_without Yes The field is required when any of other string No A generic alternative to the alpha* rules that confirms the element is a string timezone No Fails if field does match a timezone per - ``timezone_identifiers_list`` + `timezone_identifiers_list()`_ valid_base64 No Fails if field contains anything other than valid Base64 characters. valid_json No Fails if field does not contain a valid JSON @@ -873,6 +873,8 @@ valid_cc_number Yes Verifies that the credit card number matches permit at least one parameter, the field data to validate. The Validation library **never alters the data** to validate. +.. _timezone_identifiers_list(): https://www.php.net/manual/en/function.timezone-identifiers-list.php + .. _rules-for-file-uploads: Rules for File Uploads From f51fb5d3eb5b0bab7c949a495e314fc2d3787a87 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 17:39:03 +0900 Subject: [PATCH 084/135] docs: improve description --- user_guide_src/source/libraries/validation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 825f7d6e4686..ec9c7073d036 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -780,8 +780,8 @@ greater_than_equal_to Yes Fails if field is less than the parameter hex No Fails if field contains anything other than hexadecimal characters. if_exist No If this rule is present, validation will - only return possible errors if the field key - exists, regardless of its value. + check the field only when the field key + exists in the data to validate. in_list Yes Fails if field is not within a predetermined ``in_list[red,blue,green]`` list. integer No Fails if field contains anything other than From 13fbaa5667a95962fb0b9e69ad09e2e656dab1cd Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 17:47:28 +0900 Subject: [PATCH 085/135] docs: align comments --- user_guide_src/source/libraries/validation/038.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation/038.php b/user_guide_src/source/libraries/validation/038.php index f37307b0ae07..5916b0bc9cf5 100644 --- a/user_guide_src/source/libraries/validation/038.php +++ b/user_guide_src/source/libraries/validation/038.php @@ -6,5 +6,5 @@ 'name' => "is_unique[supplier.name,uuid, {$uuid}]", // is not ok 'name' => "is_unique[supplier.name,uuid,{$uuid} ]", // is not ok 'name' => "is_unique[supplier.name,uuid,{$uuid}]", // is ok - 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" + 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" ]); From af55149c91227996d3ace9480e5eb2517a60309d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 11 Jun 2023 18:13:20 +0900 Subject: [PATCH 086/135] docs: add warning to sample code --- user_guide_src/source/libraries/validation/038.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/libraries/validation/038.php b/user_guide_src/source/libraries/validation/038.php index 5916b0bc9cf5..f4ec3371527f 100644 --- a/user_guide_src/source/libraries/validation/038.php +++ b/user_guide_src/source/libraries/validation/038.php @@ -8,3 +8,5 @@ 'name' => "is_unique[supplier.name,uuid,{$uuid}]", // is ok 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" ]); +// Warning: If `$uuid` is a user input, be sure to validate the format of the value before using it. +// Otherwise, it is vulnerable. From 019ebeaed681293d9e656bff40db2ff59c3f2674 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 08:47:53 +0900 Subject: [PATCH 087/135] docs: add sub section title --- user_guide_src/source/incoming/routing.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 3455189f9ec6..e579328698df 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -114,6 +114,9 @@ Or using ``use`` keyword: .. literalinclude:: routing/014.php :lines: 2- +Array Callable Syntax and Placeholders +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + If there are placeholders, it will automatically set the parameters in the specified order: .. literalinclude:: routing/015.php From a24e4b6dec3d8702b7b759609a2013d76022d9c1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 09:02:26 +0900 Subject: [PATCH 088/135] docs: add explanation for namespacing --- user_guide_src/source/incoming/routing.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index e579328698df..e001022fcafe 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -85,7 +85,8 @@ Specifying Route Handlers Controller's Namespace ---------------------- -If a controller name is stated without beginning with ``\``, the :ref:`routing-default-namespace` will be prepended: +When you specify a controller and method name as a string, +if a controller name is stated without beginning with ``\``, the :ref:`routing-default-namespace` will be prepended: .. literalinclude:: routing/063.php @@ -114,6 +115,14 @@ Or using ``use`` keyword: .. literalinclude:: routing/014.php :lines: 2- +If you forget ``use App\Controllers\Home;``, the controller classname is interpreted +as ``Config\Home``, not ``App\Controllers\Home`` because **app/Config/Routes.php** +has ``namespace Config;`` at the top. + +.. note:: When you use Array Callable Syntax, the classname is always interpreted + as a fully qualified classname. So :ref:`routing-default-namespace` and + :ref:`namespace option ` have no effect. + Array Callable Syntax and Placeholders ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 1ae436319f96daa620796e1cba49a2834cf80d70 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 16:45:49 +0900 Subject: [PATCH 089/135] docs: add explanation and fix incorrect Parameter values --- user_guide_src/source/libraries/validation.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index ec9c7073d036..862725d60118 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -833,20 +833,25 @@ valid_email No Fails if field does not contain a valid email address. valid_emails No Fails if any value provided in a comma separated list is not a valid email. -valid_ip No Fails if the supplied IP is not valid. ``valid_ip[ipv6]`` +valid_ip Yes Fails if the supplied IP is not valid. ``valid_ip[ipv6]`` Accepts an optional parameter of ``ipv4`` or ``ipv6`` to specify an IP format. valid_url No Fails if field does not contain (loosely) a URL. Includes simple strings that could be hostnames, like "codeigniter". + **Normally,** ``valid_url_strict`` **should + be used.** valid_url_strict Yes Fails if field does not contain a valid URL. ``valid_url_strict[https]`` You can optionally specify a list of valid schemas. If not specified, ``http,https`` - are valid. This rule uses - PHP's ``FILTER_VALIDATE_URL``. -valid_date No Fails if field does not contain a valid date. ``valid_date[d/m/Y]`` - Accepts an optional parameter to matches - a date format. + are valid. This rule uses PHP's + ``FILTER_VALIDATE_URL``. +valid_date Yes Fails if field does not contain a valid date. ``valid_date[d/m/Y]`` + Any string that `strtotime()`_ accepts is + valid if you don't specify an optional + parameter to matches a date format. + **So it is usually necessary to specify + the parameter.** valid_cc_number Yes Verifies that the credit card number matches ``valid_cc_number[amex]`` the format used by the specified provider. Current supported providers are: @@ -874,6 +879,7 @@ valid_cc_number Yes Verifies that the credit card number matches The Validation library **never alters the data** to validate. .. _timezone_identifiers_list(): https://www.php.net/manual/en/function.timezone-identifiers-list.php +.. _strtotime(): https://www.php.net/manual/en/function.strtotime.php .. _rules-for-file-uploads: From ef7672944f68dd590ea3318e7d7ffb8d94fc0c7b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 08:33:46 +0900 Subject: [PATCH 090/135] fix: incorrect sql without space before "ON DUPLICATE KEY UPDATE" --- system/Database/BaseBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index fab6e30d2362..07486cffaeec 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1997,7 +1997,7 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri } if (isset($this->QBOptions['setQueryAsData'])) { - $data = $this->QBOptions['setQueryAsData']; + $data = $this->QBOptions['setQueryAsData'] . "\n"; } else { $data = 'VALUES ' . implode(', ', $this->formatValues($values)) . "\n"; } From 23f72b6ca6aaed284dd69df44a14a17ea6916612 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 13 Jun 2023 11:53:28 +0800 Subject: [PATCH 091/135] refactor: remove Factories::models() --- system/Config/Factories.php | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 7abd3f5c4449..d752f55c506e 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -24,6 +24,7 @@ * instantiation checks. * * @method static BaseConfig|null config(...$arguments) + * @method static Model|null models(string $name, array $options = [], ?ConnectionInterface &$conn = null) */ class Factories { @@ -69,23 +70,6 @@ class Factories */ protected static $instances = []; - /** - * This method is only to prevent PHPStan error. - * If we have a solution, we can remove this method. - * See https://github.com/codeigniter4/CodeIgniter4/pull/5358 - * - * @template T of Model - * - * @phpstan-param class-string $name - * - * @return Model - * @phpstan-return T - */ - public static function models(string $name, array $options = [], ?ConnectionInterface &$conn = null) - { - return self::__callStatic('models', [$name, $options, $conn]); - } - /** * Loads instances based on the method component name. Either * creates a new instance or returns an existing shared instance. From f6bcb65f8d5dc772200226e3e8367166ecc36492 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 15:11:21 +0900 Subject: [PATCH 092/135] docs: fix by proofreading --- user_guide_src/source/incoming/routing.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index e001022fcafe..0ccb9ae9ab6b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -85,8 +85,9 @@ Specifying Route Handlers Controller's Namespace ---------------------- -When you specify a controller and method name as a string, -if a controller name is stated without beginning with ``\``, the :ref:`routing-default-namespace` will be prepended: +When you specify a controller and method name as a string, if a controller is +written without a leading ``\``, the :ref:`routing-default-namespace` will be +prepended: .. literalinclude:: routing/063.php @@ -115,9 +116,9 @@ Or using ``use`` keyword: .. literalinclude:: routing/014.php :lines: 2- -If you forget ``use App\Controllers\Home;``, the controller classname is interpreted -as ``Config\Home``, not ``App\Controllers\Home`` because **app/Config/Routes.php** -has ``namespace Config;`` at the top. +If you forget to add ``use App\Controllers\Home;``, the controller classname is +interpreted as ``Config\Home``, not ``App\Controllers\Home`` because +**app/Config/Routes.php** has ``namespace Config;`` at the top. .. note:: When you use Array Callable Syntax, the classname is always interpreted as a fully qualified classname. So :ref:`routing-default-namespace` and From a842af45bf6d338ab631d163046619735f76a91f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 16:47:23 +0900 Subject: [PATCH 093/135] docs: improve description for required_with and required_without --- user_guide_src/source/libraries/validation.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 862725d60118..6142a9f9f6be 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -818,9 +818,9 @@ permit_empty No Allows the field to receive an empty array, required No Fails if the field is an empty array, empty string, null or false. required_with Yes The field is required when any of the other ``required_with[field1,field2]`` - required fields are present in the data. -required_without Yes The field is required when any of other ``required_without[field1,field2]`` - fields do not pass ``required`` checks. + fields is not `empty()`_ in the data. +required_without Yes The field is required when any of the other ``required_without[field1,field2]`` + fields is `empty()`_ in the data. string No A generic alternative to the alpha* rules that confirms the element is a string timezone No Fails if field does match a timezone per @@ -880,6 +880,7 @@ valid_cc_number Yes Verifies that the credit card number matches .. _timezone_identifiers_list(): https://www.php.net/manual/en/function.timezone-identifiers-list.php .. _strtotime(): https://www.php.net/manual/en/function.strtotime.php +.. _empty(): https://www.php.net/manual/en/function.empty.php .. _rules-for-file-uploads: From ef732e080fb89931eb7b01bef5fde1279a3533a3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 15:53:43 +0900 Subject: [PATCH 094/135] test: add tests for required_with --- tests/system/Validation/RulesTest.php | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 0ed3ac97e49c..c27dd8a2c2b7 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -614,6 +614,44 @@ public function requiredWithProvider(): Generator ]; } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/7557 + * + * @dataProvider RequiredWithAndOtherRuleProvider + */ + public function testRequiredWithAndOtherRule(bool $expected, array $data): void + { + $this->validation->setRules([ + 'mustBeADate' => 'required_with[otherField]|permit_empty|valid_date', + ]); + + $result = $this->validation->run($data); + + $this->assertSame($expected, $result); + } + + public function RequiredWithAndOtherRuleProvider(): Generator + { + yield from [ + // `otherField` and `mustBeADate` do not exist + [true, []], + // `mustBeADate` does not exist + [false, ['otherField' => 'exists']], + // ``otherField` does not exist + [true, ['mustBeADate' => '2023-06-12']], + [true, ['mustBeADate' => '']], + [true, ['mustBeADate' => null]], + [true, ['mustBeADate' => []]], + // `otherField` and `mustBeADate` exist + [true, ['mustBeADate' => '', 'otherField' => '']], + [true, ['mustBeADate' => '2023-06-12', 'otherField' => 'exists']], + [true, ['mustBeADate' => '2023-06-12', 'otherField' => '']], + [false, ['mustBeADate' => '', 'otherField' => 'exists']], + [false, ['mustBeADate' => [], 'otherField' => 'exists']], + [false, ['mustBeADate' => null, 'otherField' => 'exists']], + ]; + } + /** * @dataProvider requiredWithoutProvider */ From 281615f8ef5a3e4d0c8ea6655b9aaaf406c03553 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 16:05:31 +0900 Subject: [PATCH 095/135] test: add tests for required_with with zero value --- tests/system/Validation/RulesTest.php | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index c27dd8a2c2b7..7760401655d6 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -617,9 +617,9 @@ public function requiredWithProvider(): Generator /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/7557 * - * @dataProvider RequiredWithAndOtherRuleProvider + * @dataProvider RequiredWithAndOtherRulesProvider */ - public function testRequiredWithAndOtherRule(bool $expected, array $data): void + public function testRequiredWithAndOtherRules(bool $expected, array $data): void { $this->validation->setRules([ 'mustBeADate' => 'required_with[otherField]|permit_empty|valid_date', @@ -630,7 +630,7 @@ public function testRequiredWithAndOtherRule(bool $expected, array $data): void $this->assertSame($expected, $result); } - public function RequiredWithAndOtherRuleProvider(): Generator + public function RequiredWithAndOtherRulesProvider(): Generator { yield from [ // `otherField` and `mustBeADate` do not exist @@ -652,6 +652,30 @@ public function RequiredWithAndOtherRuleProvider(): Generator ]; } + /** + * @dataProvider RequiredWithAndOtherRuleWithValueZeroProvider + */ + public function testRequiredWithAndOtherRuleWithValueZero(bool $expected, array $data): void + { + $this->validation->setRules([ + 'married' => ['rules' => ['in_list[0,1]']], + 'partner_name' => ['rules' => ['permit_empty', 'required_with[married]', 'alpha_space']], + ]); + + $result = $this->validation->run($data); + + $this->assertSame($expected, $result); + } + + public function RequiredWithAndOtherRuleWithValueZeroProvider(): Generator + { + yield from [ + [true, ['married' => '0', 'partner_name' => '']], + [true, ['married' => '1', 'partner_name' => 'Foo']], + [false, ['married' => '1', 'partner_name' => '']], + ]; + } + /** * @dataProvider requiredWithoutProvider */ From b7e15b91979378382c8f3829ef41abf007783f50 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 10:55:48 +0900 Subject: [PATCH 096/135] refactor: extract methods --- system/Validation/Validation.php | 159 +++++++++++++++++++------------ 1 file changed, 96 insertions(+), 63 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index fe24743f1d3d..b1741d378c33 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -234,71 +234,14 @@ protected function processRules( throw new InvalidArgumentException('You must supply the parameter: data.'); } - if (in_array('if_exist', $rules, true)) { - $flattenedData = array_flatten_with_dots($data); - $ifExistField = $field; - - if (strpos($field, '.*') !== false) { - // We'll change the dot notation into a PCRE pattern that can be used later - $ifExistField = str_replace('\.\*', '\.(?:[^\.]+)', preg_quote($field, '/')); - $dataIsExisting = false; - $pattern = sprintf('/%s/u', $ifExistField); - - foreach (array_keys($flattenedData) as $item) { - if (preg_match($pattern, $item) === 1) { - $dataIsExisting = true; - break; - } - } - } else { - $dataIsExisting = array_key_exists($ifExistField, $flattenedData); - } - - unset($ifExistField, $flattenedData); - - if (! $dataIsExisting) { - // we return early if `if_exist` is not satisfied. we have nothing to do here. - return true; - } - - // Otherwise remove the if_exist rule and continue the process - $rules = array_filter($rules, static fn ($rule) => $rule instanceof Closure || $rule !== 'if_exist'); + $rules = $this->processIfExist($field, $rules, $data); + if ($rules === true) { + return true; } - if (in_array('permit_empty', $rules, true)) { - if ( - ! in_array('required', $rules, true) - && (is_array($value) ? $value === [] : trim((string) $value) === '') - ) { - $passed = true; - - foreach ($rules as $rule) { - if (! $this->isClosure($rule) && preg_match('/(.*?)\[(.*)\]/', $rule, $match)) { - $rule = $match[1]; - $param = $match[2]; - - if (! in_array($rule, ['required_with', 'required_without'], true)) { - continue; - } - - // Check in our rulesets - foreach ($this->ruleSetInstances as $set) { - if (! method_exists($set, $rule)) { - continue; - } - - $passed = $passed && $set->{$rule}($value, $param, $data); - break; - } - } - } - - if ($passed === true) { - return true; - } - } - - $rules = array_filter($rules, static fn ($rule) => $rule instanceof Closure || $rule !== 'permit_empty'); + $rules = $this->processPermitEmpty($value, $rules, $data); + if ($rules === true) { + return true; } foreach ($rules as $i => $rule) { @@ -374,6 +317,96 @@ protected function processRules( return true; } + /** + * @param array|null $rules + * @param array|null $data The array of data to validate, with `DBGroup`. + * + * @return array|true The modified rules or true if we return early + */ + private function processIfExist(string $field, $rules, ?array $data) + { + if (in_array('if_exist', $rules, true)) { + $flattenedData = array_flatten_with_dots($data); + $ifExistField = $field; + + if (strpos($field, '.*') !== false) { + // We'll change the dot notation into a PCRE pattern that can be used later + $ifExistField = str_replace('\.\*', '\.(?:[^\.]+)', preg_quote($field, '/')); + $dataIsExisting = false; + $pattern = sprintf('/%s/u', $ifExistField); + + foreach (array_keys($flattenedData) as $item) { + if (preg_match($pattern, $item) === 1) { + $dataIsExisting = true; + break; + } + } + } else { + $dataIsExisting = array_key_exists($ifExistField, $flattenedData); + } + + unset($ifExistField, $flattenedData); + + if (! $dataIsExisting) { + // we return early if `if_exist` is not satisfied. we have nothing to do here. + return true; + } + + // Otherwise remove the if_exist rule and continue the process + $rules = array_filter($rules, static fn ($rule) => $rule instanceof Closure || $rule !== 'if_exist'); + } + + return $rules; + } + + /** + * @param array|string $value + * @param array|null $rules + * @param array|null $data The array of data to validate, with `DBGroup`. + * + * @return array|true The modified rules or true if we return early + */ + private function processPermitEmpty($value, $rules = null, ?array $data = null) + { + if (in_array('permit_empty', $rules, true)) { + if ( + ! in_array('required', $rules, true) + && (is_array($value) ? $value === [] : trim((string) $value) === '') + ) { + $passed = true; + + foreach ($rules as $rule) { + if (! $this->isClosure($rule) && preg_match('/(.*?)\[(.*)\]/', $rule, $match)) { + $rule = $match[1]; + $param = $match[2]; + + if (! in_array($rule, ['required_with', 'required_without'], true)) { + continue; + } + + // Check in our rulesets + foreach ($this->ruleSetInstances as $set) { + if (! method_exists($set, $rule)) { + continue; + } + + $passed = $passed && $set->{$rule}($value, $param, $data); + break; + } + } + } + + if ($passed === true) { + return true; + } + } + + $rules = array_filter($rules, static fn ($rule) => $rule instanceof Closure || $rule !== 'permit_empty'); + } + + return $rules; + } + /** * @param Closure|string $rule */ From 0a54bca624e72f8817496222ceda2e33adf95b4c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 10:57:28 +0900 Subject: [PATCH 097/135] refactor: remove uneeded unset() --- system/Validation/Validation.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index b1741d378c33..bb13473c1d84 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -345,8 +345,6 @@ private function processIfExist(string $field, $rules, ?array $data) $dataIsExisting = array_key_exists($ifExistField, $flattenedData); } - unset($ifExistField, $flattenedData); - if (! $dataIsExisting) { // we return early if `if_exist` is not satisfied. we have nothing to do here. return true; From 675b32e2e4c88db2063c249fa79968866a6a737a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 11:10:42 +0900 Subject: [PATCH 098/135] fix: parameter types --- system/Validation/Validation.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index bb13473c1d84..60b4340aeb68 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -218,16 +218,16 @@ public function check($value, $rules, array $errors = [], $dbGroup = null): bool * so that we can collect all of the first errors. * * @param array|string $value - * @param array|null $rules - * @param array|null $data The array of data to validate, with `DBGroup`. + * @param array $rules + * @param array $data The array of data to validate, with `DBGroup`. * @param string|null $originalField The original asterisk field name like "foo.*.bar". */ protected function processRules( string $field, ?string $label, $value, - $rules = null, - ?array $data = null, + $rules = null, // @TODO remove `= null` + ?array $data = null, // @TODO remove `= null` ?string $originalField = null ): bool { if ($data === null) { @@ -318,12 +318,11 @@ protected function processRules( } /** - * @param array|null $rules - * @param array|null $data The array of data to validate, with `DBGroup`. + * @param array|null $data The array of data to validate, with `DBGroup`. * * @return array|true The modified rules or true if we return early */ - private function processIfExist(string $field, $rules, ?array $data) + private function processIfExist(string $field, array $rules, ?array $data) { if (in_array('if_exist', $rules, true)) { $flattenedData = array_flatten_with_dots($data); @@ -359,12 +358,11 @@ private function processIfExist(string $field, $rules, ?array $data) /** * @param array|string $value - * @param array|null $rules * @param array|null $data The array of data to validate, with `DBGroup`. * * @return array|true The modified rules or true if we return early */ - private function processPermitEmpty($value, $rules = null, ?array $data = null) + private function processPermitEmpty($value, array $rules, ?array $data = null) { if (in_array('permit_empty', $rules, true)) { if ( From 021a616c981e3d43fa4b922cdbfee4a755909a3c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 11:31:56 +0900 Subject: [PATCH 099/135] style: break long line --- system/Validation/Rules.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 93b86ea6b1dd..27ed515b0f81 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -276,7 +276,10 @@ public function required_with($str = null, ?string $fields = null, array $data = $requiredFields = []; foreach ($fields as $field) { - if ((array_key_exists($field, $data) && ! empty($data[$field])) || (strpos($field, '.') !== false && ! empty(dot_array_search($field, $data)))) { + if ( + (array_key_exists($field, $data) && ! empty($data[$field])) + || (strpos($field, '.') !== false && ! empty(dot_array_search($field, $data))) + ) { $requiredFields[] = $field; } } From cd0fb1a84b9ceda996e045956a941200e704e054 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 12:57:23 +0900 Subject: [PATCH 100/135] refactor: remove unneeded variables --- system/Validation/Rules.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 27ed515b0f81..efaba90ac692 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -263,7 +263,6 @@ public function required_with($str = null, ?string $fields = null, array $data = // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. - $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { @@ -272,10 +271,10 @@ public function required_with($str = null, ?string $fields = null, array $data = // Still here? Then we fail this test if // any of the fields are present in $data - // as $fields is the lis + // as $fields is the list $requiredFields = []; - foreach ($fields as $field) { + foreach (explode(',', $fields) as $field) { if ( (array_key_exists($field, $data) && ! empty($data[$field])) || (strpos($field, '.') !== false && ! empty(dot_array_search($field, $data))) @@ -308,8 +307,7 @@ public function required_without($str = null, ?string $otherFields = null, array // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. - $otherFields = explode(',', $otherFields); - $present = $this->required($str ?? ''); + $present = $this->required($str ?? ''); if ($present) { return true; @@ -317,7 +315,7 @@ public function required_without($str = null, ?string $otherFields = null, array // Still here? Then we fail this test if // any of the fields are not present in $data - foreach ($otherFields as $otherField) { + foreach (explode(',', $otherFields) as $otherField) { if ((strpos($otherField, '.') === false) && (! array_key_exists($otherField, $data) || empty($data[$otherField]))) { return false; } From d83a8ba89299c31f8aa2c157e72961646f4d05f9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 12 Jun 2023 13:00:00 +0900 Subject: [PATCH 101/135] style: break long line --- system/Validation/Rules.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index efaba90ac692..e59a86465948 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -316,9 +316,13 @@ public function required_without($str = null, ?string $otherFields = null, array // Still here? Then we fail this test if // any of the fields are not present in $data foreach (explode(',', $otherFields) as $otherField) { - if ((strpos($otherField, '.') === false) && (! array_key_exists($otherField, $data) || empty($data[$otherField]))) { + if ( + (strpos($otherField, '.') === false) + && (! array_key_exists($otherField, $data) || empty($data[$otherField])) + ) { return false; } + if (strpos($otherField, '.') !== false) { if ($field === null) { throw new InvalidArgumentException('You must supply the parameters: field.'); From c7865daa47eec01f5a3aea0e1a758891e74aa13f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 11:51:37 +0900 Subject: [PATCH 102/135] fix: param types --- system/Validation/Validation.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 60b4340aeb68..5e539561271a 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -318,11 +318,11 @@ protected function processRules( } /** - * @param array|null $data The array of data to validate, with `DBGroup`. + * @param array $data The array of data to validate, with `DBGroup`. * * @return array|true The modified rules or true if we return early */ - private function processIfExist(string $field, array $rules, ?array $data) + private function processIfExist(string $field, array $rules, array $data) { if (in_array('if_exist', $rules, true)) { $flattenedData = array_flatten_with_dots($data); @@ -358,11 +358,11 @@ private function processIfExist(string $field, array $rules, ?array $data) /** * @param array|string $value - * @param array|null $data The array of data to validate, with `DBGroup`. + * @param array $data The array of data to validate, with `DBGroup`. * * @return array|true The modified rules or true if we return early */ - private function processPermitEmpty($value, array $rules, ?array $data = null) + private function processPermitEmpty($value, array $rules, array $data) { if (in_array('permit_empty', $rules, true)) { if ( From 87b52376fe5c83b74074b22ce2f8855c17f72132 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 16:17:51 +0900 Subject: [PATCH 103/135] docs: remove `of` in comments --- system/Validation/Rules.php | 2 +- system/Validation/StrictRules/Rules.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index e59a86465948..1aaf09da0dcf 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -287,7 +287,7 @@ public function required_with($str = null, ?string $fields = null, array $data = } /** - * The field is required when all of the other fields are present + * The field is required when all the other fields are present * in the data but not required. * * Example (field is required when the id or email field is missing): diff --git a/system/Validation/StrictRules/Rules.php b/system/Validation/StrictRules/Rules.php index f95bbe7d4083..c83e3d0b709f 100644 --- a/system/Validation/StrictRules/Rules.php +++ b/system/Validation/StrictRules/Rules.php @@ -347,7 +347,7 @@ public function required_with($str = null, ?string $fields = null, array $data = } /** - * The field is required when all of the other fields are present + * The field is required when all the other fields are present * in the data but not required. * * Example (field is required when the id or email field is missing): From 39230fe684962eddc2afba459e03d5592903b63f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 16:18:27 +0900 Subject: [PATCH 104/135] style: break long line --- system/Validation/Rules.php | 9 +++++++-- system/Validation/StrictRules/Rules.php | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 1aaf09da0dcf..1bb2c243ebf5 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -298,8 +298,13 @@ public function required_with($str = null, ?string $fields = null, array $data = * @param string|null $otherFields The param fields of required_without[]. * @param string|null $field This rule param fields aren't present, this field is required. */ - public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool - { + public function required_without( + $str = null, + ?string $otherFields = null, + array $data = [], + ?string $error = null, + ?string $field = null + ): bool { if ($otherFields === null || empty($data)) { throw new InvalidArgumentException('You must supply the parameters: otherFields, data.'); } diff --git a/system/Validation/StrictRules/Rules.php b/system/Validation/StrictRules/Rules.php index c83e3d0b709f..cdc20f5e2e4e 100644 --- a/system/Validation/StrictRules/Rules.php +++ b/system/Validation/StrictRules/Rules.php @@ -358,8 +358,13 @@ public function required_with($str = null, ?string $fields = null, array $data = * @param string|null $otherFields The param fields of required_without[]. * @param string|null $field This rule param fields aren't present, this field is required. */ - public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool - { + public function required_without( + $str = null, + ?string $otherFields = null, + array $data = [], + ?string $error = null, + ?string $field = null + ): bool { return $this->nonStrictRules->required_without($str, $otherFields, $data, $error, $field); } } From 31859425a63ea52ec6b21cf19011490b0e312fa7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 20:59:39 +0900 Subject: [PATCH 105/135] fix: wrong classname in exception message --- system/View/Cell.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/View/Cell.php b/system/View/Cell.php index 2e0fc22b8bb3..b898adc0e754 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -175,9 +175,9 @@ protected function determineClass(string $library): array } // locate and return an instance of the cell - $class = Factories::cells($class); + $object = Factories::cells($class); - if (! is_object($class)) { + if (! is_object($object)) { throw ViewException::forInvalidCellClass($class); } @@ -186,7 +186,7 @@ protected function determineClass(string $library): array } return [ - $class, + $object, $method, ]; } From 5b0c405e0303bf043ac82b35d1760859dc03a9f8 Mon Sep 17 00:00:00 2001 From: ping-yee <611077101@mail.nknu.edu.tw> Date: Tue, 13 Jun 2023 22:45:22 +0800 Subject: [PATCH 106/135] fix: fix the image handler. --- system/Images/Handlers/GDHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Images/Handlers/GDHandler.php b/system/Images/Handlers/GDHandler.php index 6063ef94496b..840c1bb2e4eb 100644 --- a/system/Images/Handlers/GDHandler.php +++ b/system/Images/Handlers/GDHandler.php @@ -354,7 +354,7 @@ protected function getImageResource(string $path, int $imageType) throw ImageException::forInvalidImageCreate(lang('Images.pngNotSupported')); } - return imagecreatefrompng($path); + return @imagecreatefrompng($path); case IMAGETYPE_WEBP: if (! function_exists('imagecreatefromwebp')) { From d2ef51ff44afea5238859f4bb2a9272a28df4250 Mon Sep 17 00:00:00 2001 From: ping-yee <611077101@mail.nknu.edu.tw> Date: Tue, 13 Jun 2023 23:43:38 +0800 Subject: [PATCH 107/135] docs: replace mixed type at Encryption class. --- system/Encryption/Encryption.php | 2 +- system/Encryption/Handlers/BaseHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index 81b25eeff5f5..d0484b06070b 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -149,7 +149,7 @@ public static function createKey($length = 32) * * @param string $key Property name * - * @return mixed + * @return array|EncrypterInterface|string|null */ public function __get($key) { diff --git a/system/Encryption/Handlers/BaseHandler.php b/system/Encryption/Handlers/BaseHandler.php index 13f60e970362..c6894dc2fb8c 100644 --- a/system/Encryption/Handlers/BaseHandler.php +++ b/system/Encryption/Handlers/BaseHandler.php @@ -61,7 +61,7 @@ protected static function substr($str, $start, $length = null) * * @param string $key Property name * - * @return mixed + * @return LoggerInterface|null */ public function __get($key) { From a18c7b9d6b3ec41fd21c927a22225b2e30e480c9 Mon Sep 17 00:00:00 2001 From: ping-yee <611077101@mail.nknu.edu.tw> Date: Wed, 14 Jun 2023 00:07:25 +0800 Subject: [PATCH 108/135] docs: replace mixed type at Config class. --- system/Config/BaseConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 359fcc1488ba..8d41ffed0b10 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -86,7 +86,7 @@ public function __construct() /** * Initialization an environment-specific configuration setting * - * @param mixed $property + * @param array|bool|float|int|string $property * * @return void */ From d4bcffdd77f22a3e0a79c077abcbb409ae575df9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 12:05:08 +0900 Subject: [PATCH 109/135] test: add test for feature testing and auto routing improved --- .../FeatureTestAutoRoutingImprovedTest.php | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/system/Test/FeatureTestAutoRoutingImprovedTest.php diff --git a/tests/system/Test/FeatureTestAutoRoutingImprovedTest.php b/tests/system/Test/FeatureTestAutoRoutingImprovedTest.php new file mode 100644 index 000000000000..897697146fb5 --- /dev/null +++ b/tests/system/Test/FeatureTestAutoRoutingImprovedTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Test; + +use CodeIgniter\Events\Events; +use Config\Feature; +use Config\Services; + +/** + * @group Others + * + * @internal + */ +final class FeatureTestAutoRoutingImprovedTest extends CIUnitTestCase +{ + use FeatureTestTrait; + + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + Events::simulate(true); + + self::initializeRouter(); + } + + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + + Events::simulate(false); + + Services::reset(); + } + + private static function initializeRouter(): void + { + $routes = Services::routes(); + $routes->resetRoutes(); + $routes->loadRoutes(); + + $routes->setAutoRoute(true); + config(Feature::class)->autoRoutesImproved = true; + + $namespace = 'Tests\Support\Controllers'; + $routes->setDefaultNamespace($namespace); + + $router = Services::router($routes); + + Services::injectMock('router', $router); + } + + public function testCallGet() + { + $response = $this->get('newautorouting'); + + $response->assertSee('Hello'); + } + + public function testCallPost() + { + $response = $this->post('newautorouting/save/1/a/b'); + + $response->assertSee('Saved'); + } +} From 7dbf0d1c10d23f31f0db6498a87967ef5f376db4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 13:04:10 +0900 Subject: [PATCH 110/135] fix: [BC] feature testing may use incorrect HTTP verb for auto routing improved Fixes AutoRouterInterface::getRoute(). --- system/Router/AutoRouter.php | 2 +- system/Router/AutoRouterImproved.php | 23 ++++++++++++++--------- system/Router/AutoRouterInterface.php | 2 +- system/Router/Router.php | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/system/Router/AutoRouter.php b/system/Router/AutoRouter.php index 3c29ff8290d4..3096b3bbd6f9 100644 --- a/system/Router/AutoRouter.php +++ b/system/Router/AutoRouter.php @@ -80,7 +80,7 @@ public function __construct( * * @return array [directory_name, controller_name, controller_method, params] */ - public function getRoute(string $uri): array + public function getRoute(string $uri, string $httpVerb): array { $segments = explode('/', $uri); diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 39b264ecf780..3b8c595528cc 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -60,8 +60,10 @@ final class AutoRouterImproved implements AutoRouterInterface /** * HTTP verb for the request. + * + * @deprecated No longer used. */ - private string $httpVerb; + private string $httpVerb; // @phpstan-ignore-line /** * The namespace for controllers. @@ -74,15 +76,17 @@ final class AutoRouterImproved implements AutoRouterInterface private string $defaultController; /** - * The name of the default method + * The name of the default method without HTTP verb prefix. */ private string $defaultMethod; /** * @param class-string[] $protectedControllers * @param string $defaultController Short classname + * + * @deprecated $httpVerb is deprecated. No longer used. */ - public function __construct( + public function __construct(// @phpstan-ignore-line array $protectedControllers, string $namespace, string $defaultController, @@ -93,13 +97,11 @@ public function __construct( $this->protectedControllers = $protectedControllers; $this->namespace = rtrim($namespace, '\\') . '\\'; $this->translateURIDashes = $translateURIDashes; - $this->httpVerb = $httpVerb; $this->defaultController = $defaultController; - $this->defaultMethod = $httpVerb . ucfirst($defaultMethod); + $this->defaultMethod = $defaultMethod; // Set the default values $this->controller = $this->defaultController; - $this->method = $this->defaultMethod; } /** @@ -107,8 +109,11 @@ public function __construct( * * @return array [directory_name, controller_name, controller_method, params] */ - public function getRoute(string $uri): array + public function getRoute(string $uri, string $httpVerb): array { + $defaultMethod = $httpVerb . ucfirst($this->defaultMethod); + $this->method = $defaultMethod; + $segments = explode('/', $uri); // WARNING: Directories get shifted out of the segments array. @@ -144,10 +149,10 @@ public function getRoute(string $uri): array $methodSegment = $this->translateURIDashes(array_shift($nonDirSegments)); // Prefix HTTP verb - $this->method = $this->httpVerb . ucfirst($methodSegment); + $this->method = $httpVerb . ucfirst($methodSegment); // Prevent access to default method path - if (strtolower($this->method) === strtolower($this->defaultMethod)) { + if (strtolower($this->method) === strtolower($defaultMethod)) { throw new PageNotFoundException( 'Cannot access the default method "' . $this->method . '" with the method name URI path.' ); diff --git a/system/Router/AutoRouterInterface.php b/system/Router/AutoRouterInterface.php index 9ecdd3ec2b30..6d98aec4a5bf 100644 --- a/system/Router/AutoRouterInterface.php +++ b/system/Router/AutoRouterInterface.php @@ -21,5 +21,5 @@ interface AutoRouterInterface * * @return array [directory_name, controller_name, controller_method, params] */ - public function getRoute(string $uri): array; + public function getRoute(string $uri, string $httpVerb): array; } diff --git a/system/Router/Router.php b/system/Router/Router.php index 8dd35c656e39..1ef9675ca8a6 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -504,7 +504,7 @@ protected function checkRoutes(string $uri): bool public function autoRoute(string $uri) { [$this->directory, $this->controller, $this->method, $this->params] - = $this->autoRouter->getRoute($uri); + = $this->autoRouter->getRoute($uri, $this->collection->getHTTPVerb()); } /** From a932dc141bde871b7b6af211401644a48fa292b2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 13:33:41 +0900 Subject: [PATCH 111/135] test: update test code --- .../system/Router/AutoRouterImprovedTest.php | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/system/Router/AutoRouterImprovedTest.php b/tests/system/Router/AutoRouterImprovedTest.php index ec94676be121..5b2fdff532c1 100644 --- a/tests/system/Router/AutoRouterImprovedTest.php +++ b/tests/system/Router/AutoRouterImprovedTest.php @@ -57,7 +57,7 @@ public function testAutoRouteFindsDefaultControllerAndMethodGet() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('/'); + = $router->getRoute('/', 'get'); $this->assertNull($directory); $this->assertSame('\\' . Index::class, $controller); @@ -72,7 +72,7 @@ public function testAutoRouteFindsDefaultControllerAndMethodPost() $router = $this->createNewAutoRouter('post'); [$directory, $controller, $method, $params] - = $router->getRoute('/'); + = $router->getRoute('/', 'post'); $this->assertNull($directory); $this->assertSame('\\' . Index::class, $controller); @@ -85,7 +85,7 @@ public function testAutoRouteFindsControllerWithFileAndMethod() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('mycontroller/somemethod'); + = $router->getRoute('mycontroller/somemethod', 'get'); $this->assertNull($directory); $this->assertSame('\\' . Mycontroller::class, $controller); @@ -98,7 +98,7 @@ public function testFindsControllerAndMethodAndParam() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('mycontroller/somemethod/a'); + = $router->getRoute('mycontroller/somemethod/a', 'get'); $this->assertNull($directory); $this->assertSame('\\' . Mycontroller::class, $controller); @@ -115,7 +115,7 @@ public function testUriParamCountIsGreaterThanMethodParams() $router = $this->createNewAutoRouter(); - $router->getRoute('mycontroller/somemethod/a/b'); + $router->getRoute('mycontroller/somemethod/a/b', 'get'); } public function testAutoRouteFindsControllerWithFile() @@ -123,7 +123,7 @@ public function testAutoRouteFindsControllerWithFile() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('mycontroller'); + = $router->getRoute('mycontroller', 'get'); $this->assertNull($directory); $this->assertSame('\\' . Mycontroller::class, $controller); @@ -136,7 +136,7 @@ public function testAutoRouteFindsControllerWithSubfolder() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('subfolder/mycontroller/somemethod'); + = $router->getRoute('subfolder/mycontroller/somemethod', 'get'); $this->assertSame('Subfolder/', $directory); $this->assertSame('\\' . \CodeIgniter\Router\Controllers\Subfolder\Mycontroller::class, $controller); @@ -149,7 +149,7 @@ public function testAutoRouteFindsDashedSubfolder() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('dash-folder/mycontroller/somemethod'); + = $router->getRoute('dash-folder/mycontroller/somemethod', 'get'); $this->assertSame('Dash_folder/', $directory); $this->assertSame( @@ -165,7 +165,7 @@ public function testAutoRouteFindsDashedController() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('dash-folder/dash-controller/somemethod'); + = $router->getRoute('dash-folder/dash-controller/somemethod', 'get'); $this->assertSame('Dash_folder/', $directory); $this->assertSame('\\' . Dash_controller::class, $controller); @@ -178,7 +178,7 @@ public function testAutoRouteFindsDashedMethod() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('dash-folder/dash-controller/dash-method'); + = $router->getRoute('dash-folder/dash-controller/dash-method', 'get'); $this->assertSame('Dash_folder/', $directory); $this->assertSame('\\' . Dash_controller::class, $controller); @@ -191,7 +191,7 @@ public function testAutoRouteFindsDefaultDashFolder() $router = $this->createNewAutoRouter(); [$directory, $controller, $method, $params] - = $router->getRoute('dash-folder'); + = $router->getRoute('dash-folder', 'get'); $this->assertSame('Dash_folder/', $directory); $this->assertSame('\\' . Home::class, $controller); @@ -205,7 +205,7 @@ public function testAutoRouteRejectsSingleDot() $router = $this->createNewAutoRouter(); - $router->getRoute('.'); + $router->getRoute('.', 'get'); } public function testAutoRouteRejectsDoubleDot() @@ -214,7 +214,7 @@ public function testAutoRouteRejectsDoubleDot() $router = $this->createNewAutoRouter(); - $router->getRoute('..'); + $router->getRoute('..', 'get'); } public function testAutoRouteRejectsMidDot() @@ -223,7 +223,7 @@ public function testAutoRouteRejectsMidDot() $router = $this->createNewAutoRouter(); - $router->getRoute('foo.bar'); + $router->getRoute('foo.bar', 'get'); } public function testRejectsDefaultControllerPath() @@ -232,7 +232,7 @@ public function testRejectsDefaultControllerPath() $router = $this->createNewAutoRouter(); - $router->getRoute('home'); + $router->getRoute('home', 'get'); } public function testRejectsDefaultControllerAndDefaultMethodPath() @@ -241,7 +241,7 @@ public function testRejectsDefaultControllerAndDefaultMethodPath() $router = $this->createNewAutoRouter(); - $router->getRoute('home/index'); + $router->getRoute('home/index', 'get'); } public function testRejectsDefaultMethodPath() @@ -250,7 +250,7 @@ public function testRejectsDefaultMethodPath() $router = $this->createNewAutoRouter(); - $router->getRoute('mycontroller/index'); + $router->getRoute('mycontroller/index', 'get'); } public function testRejectsControllerWithRemapMethod() @@ -262,6 +262,6 @@ public function testRejectsControllerWithRemapMethod() $router = $this->createNewAutoRouter(); - $router->getRoute('remap/test'); + $router->getRoute('remap/test', 'get'); } } From 3410ea99644d66524ed617fb3fd88c491cea2ae2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 13:29:29 +0900 Subject: [PATCH 112/135] fix: ensure HTTP verb is lower case HTTP verb in Router must be lower case. --- system/Router/AutoRouterImproved.php | 2 +- system/Router/RouteCollection.php | 6 ++++-- system/Router/Router.php | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 3b8c595528cc..54360d65fbed 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -111,7 +111,7 @@ public function __construct(// @phpstan-ignore-line */ public function getRoute(string $uri, string $httpVerb): array { - $defaultMethod = $httpVerb . ucfirst($this->defaultMethod); + $defaultMethod = strtolower($httpVerb) . ucfirst($this->defaultMethod); $this->method = $defaultMethod; $segments = explode('/', $uri); diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 50b73616ea0e..1e015538f435 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -150,7 +150,7 @@ class RouteCollection implements RouteCollectionInterface /** * The current method that the script is being called by. * - * @var string + * @var string HTTP verb (lower case) or `*` */ protected $HTTPVerb = '*'; @@ -550,11 +550,13 @@ public function getHTTPVerb(): string * Sets the current HTTP verb. * Used primarily for testing. * + * @param string $verb HTTP verb + * * @return $this */ public function setHTTPVerb(string $verb) { - $this->HTTPVerb = $verb; + $this->HTTPVerb = strtolower($verb); return $this; } diff --git a/system/Router/Router.php b/system/Router/Router.php index 1ef9675ca8a6..f9299fa1dd0a 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -126,7 +126,7 @@ public function __construct(RouteCollectionInterface $routes, ?Request $request $this->controller = $this->collection->getDefaultController(); $this->method = $this->collection->getDefaultMethod(); - $this->collection->setHTTPVerb(strtolower($request->getMethod() ?? $_SERVER['REQUEST_METHOD'])); + $this->collection->setHTTPVerb($request->getMethod() ?? $_SERVER['REQUEST_METHOD']); $this->translateURIDashes = $this->collection->shouldTranslateURIDashes(); From c32182ecd289c5d3e44d53f9e49eb36291221614 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 13:43:39 +0900 Subject: [PATCH 113/135] refactor: remove unused private property --- system/Router/AutoRouterImproved.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 54360d65fbed..603c7f3620d7 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -58,13 +58,6 @@ final class AutoRouterImproved implements AutoRouterInterface */ private bool $translateURIDashes; - /** - * HTTP verb for the request. - * - * @deprecated No longer used. - */ - private string $httpVerb; // @phpstan-ignore-line - /** * The namespace for controllers. */ From ab0ebb98ceda797a10b77ef60c05188f5fa33eda Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 6 Jun 2023 14:07:05 +0900 Subject: [PATCH 114/135] docs: add docs --- user_guide_src/source/changelogs/v4.3.6.rst | 7 +++++++ user_guide_src/source/installation/upgrade_436.rst | 3 +++ 2 files changed, 10 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst index 01fc0893d41d..cb98d5958510 100644 --- a/user_guide_src/source/changelogs/v4.3.6.rst +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -19,6 +19,11 @@ Interface Changes or implemented these interfaces, all these changes are backward compatible and require no intervention. +AutoRouterInterface +------------------- + +Now ``AutoRouterInterface::getRoute()`` has the new second parameter ``string $httpVerb``. + ValidationInterface::check() ---------------------------- @@ -51,6 +56,8 @@ Bugs Fixed - **Validation:** Fixed a bug that ``check()`` cannot specify non-default database group. - **Database:** Fixed a bug where semicolon character (``;``) in one of the Postgre connection parameters would break the DSN string. +- **AutoRouting Improved:** Fixed a bug that feature testing may not find + controller/method. See the repo's `CHANGELOG.md `_ diff --git a/user_guide_src/source/installation/upgrade_436.rst b/user_guide_src/source/installation/upgrade_436.rst index 71efd80d9f85..7d4e99bb602a 100644 --- a/user_guide_src/source/installation/upgrade_436.rst +++ b/user_guide_src/source/installation/upgrade_436.rst @@ -18,6 +18,9 @@ Mandatory File Changes Breaking Changes **************** +- ``AutoRouterInterface::getRoute()`` has the new second parameter ``string $httpVerb``. + If you implement it, add the parameter. + Breaking Enhancements ********************* From 27729b17fdce2d58e3eca3aa1ae4d7b4990ce0af Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 8 Jun 2023 08:10:45 +0900 Subject: [PATCH 115/135] chore: add skip rule for deprecated constructor param --- rector.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rector.php b/rector.php index 6cb5a5c7e451..cf6985af1488 100644 --- a/rector.php +++ b/rector.php @@ -26,6 +26,7 @@ use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; @@ -88,6 +89,11 @@ __DIR__ . '/tests/system/Test/ReflectionHelperTest.php', ], + RemoveUnusedConstructorParamRector::class => [ + // @TODO remove if deprecated $httpVerb is removed + __DIR__ . '/system/Router/AutoRouterImproved.php', + ], + // call on purpose for nothing happen check RemoveEmptyMethodCallRector::class => [ __DIR__ . '/tests', From fbff5a2a4891391561b56aa28fc460888dab81b4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 10 Jun 2023 17:28:46 +0900 Subject: [PATCH 116/135] docs: add deprecation --- user_guide_src/source/changelogs/v4.3.6.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst index cb98d5958510..34551c1ede03 100644 --- a/user_guide_src/source/changelogs/v4.3.6.rst +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -48,6 +48,9 @@ Changes Deprecations ************ +- **AutoRouterImproved:** The constructor parameter ``$httpVerb`` is deprecated. + No longer used. + Bugs Fixed ********** From f22139b6ad1a0c02c2e4f8a1fc3233d7412f5417 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 13 Jun 2023 09:13:02 +0900 Subject: [PATCH 117/135] docs: add value examples --- system/Router/RouteCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 1e015538f435..66724935e31c 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -150,7 +150,7 @@ class RouteCollection implements RouteCollectionInterface /** * The current method that the script is being called by. * - * @var string HTTP verb (lower case) or `*` + * @var string HTTP verb (lower case) like `get`,`post` or `*` */ protected $HTTPVerb = '*'; From 78b5156d1114dfc6de65f70eb464b4cbb366b355 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 07:52:33 +0900 Subject: [PATCH 118/135] docs: remove redundant note --- user_guide_src/source/incoming/routing.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 0ccb9ae9ab6b..a7f3050d4538 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -333,9 +333,6 @@ available from the command line: .. warning:: If you enable :ref:`auto-routing-legacy` and place the command file in **app/Controllers**, anyone could access the command with the help of Auto Routing (Legacy) via HTTP. -.. note:: It is recommended to use Spark Commands instead of CLI routes. - See the :doc:`../cli/spark_commands` page for detailed information. - Global Options ************** From e431447c51e06703159125ce706475cd76330835 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 07:54:07 +0900 Subject: [PATCH 119/135] docs: move note up --- user_guide_src/source/incoming/routing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a7f3050d4538..85efe01fe3c1 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -320,6 +320,9 @@ define an array of routes and then pass it as the first parameter to the ``map() Command-Line Only Routes ======================== +.. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. + See the :doc:`../cli/cli_commands` page for detailed information. + You can create routes that work only from the command-line, and are inaccessible from the web browser, with the ``cli()`` method. Any route created by any of the HTTP-verb-based route methods will also be inaccessible from the CLI, but routes created by the ``add()`` method will still be @@ -327,9 +330,6 @@ available from the command line: .. literalinclude:: routing/032.php -.. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. - See the :doc:`../cli/cli_commands` page for detailed information. - .. warning:: If you enable :ref:`auto-routing-legacy` and place the command file in **app/Controllers**, anyone could access the command with the help of Auto Routing (Legacy) via HTTP. From 062e8d506a6d7ba334293d1b229b2eea52ebe43f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 08:00:22 +0900 Subject: [PATCH 120/135] docs: fix incorrect sample code (:any) matches multiple segments. --- user_guide_src/source/incoming/routing/008.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing/008.php b/user_guide_src/source/incoming/routing/008.php index d840165c7809..0e9c3afdafa7 100644 --- a/user_guide_src/source/incoming/routing/008.php +++ b/user_guide_src/source/incoming/routing/008.php @@ -1,3 +1,3 @@ get('product/(:any)', 'Catalog::productLookup'); +$routes->get('product/(:segment)', 'Catalog::productLookup'); From 30ffa635df374239288f6e85e7fa895d814a5091 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 08:08:40 +0900 Subject: [PATCH 121/135] docs: use term "route path" and "route handler" --- user_guide_src/source/incoming/routing.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 85efe01fe3c1..a19efa9f5648 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -31,7 +31,8 @@ If you expect a GET request, you use the ``get()`` method: .. literalinclude:: routing/001.php -A route takes the URI path (``/``) on the left, and maps it to the controller and method (``Home::index``) on the right, +A route takes the **Route Path** (URI path relative to the BaseURL. ``/``) on the left, +and maps it to the **Route Handler** (controller and method ``Home::index``) on the right, along with any parameters that should be passed to the controller. The controller and method should @@ -534,7 +535,7 @@ Route Priority Routes are registered in the routing table in the order in which they are defined. This means that when a URI is accessed, the first matching route will be executed. -.. note:: If a route (the URI path) is defined more than once with different handlers, only the first defined route is registered. +.. note:: If a route path is defined more than once with different handlers, only the first defined route is registered. You can check registered routes in the routing table by running the :ref:`spark routes ` command. @@ -851,9 +852,9 @@ The output is like the following: The *Method* column shows the HTTP method that the route is listening for. -The *Route* column shows the route (URI path) to match. The route of a defined route is expressed as a regular expression. +The *Route* column shows the route path to match. The route of a defined route is expressed as a regular expression. -Since v4.3.0, the *Name* column shows the route name. ``»`` indicates the name is the same as the route. +Since v4.3.0, the *Name* column shows the route name. ``»`` indicates the name is the same as the route path. .. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. If you want to check filters for a route, you can use :ref:`spark filter:check ` command. From 61d87fa378217836db01efd87ea8d122c43294d5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 08:11:38 +0900 Subject: [PATCH 122/135] docs: add note in section "Auto Routing (Improved)" --- user_guide_src/source/incoming/routing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a19efa9f5648..14abbf66a392 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -875,6 +875,8 @@ The *Method* will be like ``GET(auto)``. ``/..`` in the *Route* column indicates one segment. ``[/..]`` indicates it is optional. +.. note:: When auto-routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. + If you see a route starting with ``x`` like the following, it indicates an invalid route that won't be routed, but the controller has a public method for routing. From ebaa5ea4e43b961b0857a9b79c544b2974596cd6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 08:14:47 +0900 Subject: [PATCH 123/135] docs: improve section title --- user_guide_src/source/incoming/routing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 14abbf66a392..f91a282160ef 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -832,8 +832,8 @@ CodeIgniter has the following :doc:`command ` to display al .. _routing-spark-routes: -routes -====== +spark routes +============ Displays all routes and filters:: From 9527ee974bb36ce805aed73ee1eb1c7ce56e2599 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 09:02:38 +0900 Subject: [PATCH 124/135] refactor: ensure $httpVerb is lower case --- system/Router/AutoRouterImproved.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 603c7f3620d7..6f2aa1af5ece 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -104,7 +104,9 @@ public function __construct(// @phpstan-ignore-line */ public function getRoute(string $uri, string $httpVerb): array { - $defaultMethod = strtolower($httpVerb) . ucfirst($this->defaultMethod); + $httpVerb = strtolower($httpVerb); + + $defaultMethod = $httpVerb . ucfirst($this->defaultMethod); $this->method = $defaultMethod; $segments = explode('/', $uri); From 8ebbc9e37184c28a4408777d425f8a8c28f10586 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 14 Jun 2023 10:30:34 +0900 Subject: [PATCH 125/135] docs: fix incorrect comments --- user_guide_src/source/database/query_builder/098.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/database/query_builder/098.php b/user_guide_src/source/database/query_builder/098.php index 50d274d63a54..026c4b204c5d 100644 --- a/user_guide_src/source/database/query_builder/098.php +++ b/user_guide_src/source/database/query_builder/098.php @@ -1,6 +1,6 @@ select(['field1', 'field2']) ->where('field3', 5) ->getCompiledSelect(false); @@ -13,5 +13,5 @@ $data = $builder->get()->getResultArray(); /* * Would execute and return an array of results of the following query: - * SELECT field1, field1 from mytable where field3 = 5; + * SELECT field1, field2 FROM mytable WHERE field3 = 5; */ From 5c17f47536556d414091fa8b0631fb950c748b79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:56:44 +0000 Subject: [PATCH 126/135] chore(deps-dev): update rector/rector requirement from 0.17.0 to 0.17.1 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.17.0...0.17.1) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 49e50bfc7413..08c6d72d8d18 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1 || ^2.0", - "rector/rector": "0.17.0", + "rector/rector": "0.17.1", "vimeo/psalm": "^5.0" }, "suggest": { From f658272c7b06ead493a81ab39d5a49cdf21fdf76 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 14 Jun 2023 23:01:49 +0700 Subject: [PATCH 127/135] update rector config and re-run rector --- rector.php | 8 ------ system/Database/OCI8/Connection.php | 2 +- system/Helpers/text_helper.php | 2 +- system/Router/RouteCollection.php | 2 +- .../Routes/SampleURIGeneratorTest.php | 2 +- tests/system/Database/Builder/SelectTest.php | 6 ++--- tests/system/Database/RawSqlTest.php | 4 +-- tests/system/Router/RouteCollectionTest.php | 25 ++++++++++--------- tests/system/Validation/FormatRulesTest.php | 4 +-- tests/system/Validation/ValidationTest.php | 20 +++++++-------- 10 files changed, 34 insertions(+), 41 deletions(-) diff --git a/rector.php b/rector.php index cf6985af1488..2356339cb93b 100644 --- a/rector.php +++ b/rector.php @@ -29,7 +29,6 @@ use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; -use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; use Rector\EarlyReturn\Rector\If_\ChangeIfElseValueAssignToEarlyReturnRector; use Rector\EarlyReturn\Rector\If_\RemoveAlwaysElseRector; @@ -43,7 +42,6 @@ use Rector\PHPUnit\Rector\MethodCall\GetMockBuilderGetMockToCreateMockRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector; -use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; use Utils\Rector\PassStrictParameterToFunctionParameterRector; @@ -94,11 +92,6 @@ __DIR__ . '/system/Router/AutoRouterImproved.php', ], - // call on purpose for nothing happen check - RemoveEmptyMethodCallRector::class => [ - __DIR__ . '/tests', - ], - // check on constant compare UnwrapFutureCompatibleIfPhpVersionRector::class => [ __DIR__ . '/system/Autoloader/Autoloader.php', @@ -147,7 +140,6 @@ $rectorConfig->rule(FuncGetArgsToVariadicParamRector::class); $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class); $rectorConfig->rule(SimplifyEmptyArrayCheckRector::class); - $rectorConfig->rule(NormalizeNamespaceByPSR4ComposerAutoloadRector::class); $rectorConfig->rule(StringClassNameToClassConstantRector::class); $rectorConfig->rule(PrivatizeFinalClassPropertyRector::class); $rectorConfig->rule(CompleteDynamicPropertiesRector::class); diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index ce6554ddc63a..ee5b48a8b37a 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -53,7 +53,7 @@ class Connection extends BaseConnection protected $validDSNs = [ 'tns' => '/^\(DESCRIPTION=(\(.+\)){2,}\)$/', // TNS // Easy Connect string (Oracle 10g+) - 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9][0-9]{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i', + 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9]\d{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i', 'in' => '/^[a-z0-9$_]+$/i', // Instance name (defined in tnsnames.ora) ]; diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 2343a89bfafe..8f96b423b02b 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -662,7 +662,7 @@ function _from_random(int $length, string $pool): string */ function increment_string(string $str, string $separator = '_', int $first = 1): string { - preg_match('/(.+)' . preg_quote($separator, '/') . '([0-9]+)$/', $str, $match); + preg_match('/(.+)' . preg_quote($separator, '/') . '(\d+)$/', $str, $match); return isset($match[2]) ? $match[1] . $separator . ((int) $match[2] + 1) : $str . $separator . $first; } diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 66724935e31c..ab3066f9eff4 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -98,7 +98,7 @@ class RouteCollection implements RouteCollectionInterface 'any' => '.*', 'segment' => '[^/]+', 'alphanum' => '[a-zA-Z0-9]+', - 'num' => '[0-9]+', + 'num' => '\d+', 'alpha' => '[a-zA-Z]+', 'hash' => '[^/]+', ]; diff --git a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php index 4b7b8fa3e814..8c64a72ab198 100644 --- a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php +++ b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php @@ -38,7 +38,7 @@ public function routeKeyProvider(): Generator { yield from [ 'root' => ['/', '/'], - 'placeholder num' => ['shop/product/([0-9]+)', 'shop/product/123'], + 'placeholder num' => ['shop/product/(\d+)', 'shop/product/123'], 'placeholder segment' => ['shop/product/([^/]+)', 'shop/product/abc_123'], 'placeholder any' => ['shop/product/(.*)', 'shop/product/123/abc'], 'auto route' => ['home/index[/...]', 'home/index/1/2/3/4/5'], diff --git a/tests/system/Database/Builder/SelectTest.php b/tests/system/Database/Builder/SelectTest.php index af7bf96d119e..5f92d6f5f5ed 100644 --- a/tests/system/Database/Builder/SelectTest.php +++ b/tests/system/Database/Builder/SelectTest.php @@ -105,7 +105,7 @@ public function testSelectWorksWithRawSql() { $builder = new BaseBuilder('users', $this->db); - $sql = 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral'; + $sql = 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral'; $builder->select(new RawSql($sql)); $expected = 'SELECT ' . $sql . ' FROM "users"'; @@ -134,12 +134,12 @@ public function testSelectRegularExpressionWorksWithEscpaeFalse() $builder = new BaseBuilder('ob_human_resources', $this->db); $builder->select( - 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral', + 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral', false ); $expected = <<<'SQL' - SELECT REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral + SELECT REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral FROM "ob_human_resources" SQL; $this->assertSame($expected, $builder->getCompiledSelect()); diff --git a/tests/system/Database/RawSqlTest.php b/tests/system/Database/RawSqlTest.php index 695a63980e89..b28b0b6ecfea 100644 --- a/tests/system/Database/RawSqlTest.php +++ b/tests/system/Database/RawSqlTest.php @@ -22,7 +22,7 @@ final class RawSqlTest extends CIUnitTestCase { public function testCanConvertToString() { - $expected = 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral'; + $expected = 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral'; $rawSql = new RawSql($expected); $this->assertSame($expected, (string) $rawSql); @@ -47,6 +47,6 @@ public function testGetBindingKey() $key = $rawSql->getBindingKey(); - $this->assertMatchesRegularExpression('/\ARawSql[0-9]+\z/', $key); + $this->assertMatchesRegularExpression('/\ARawSql\d+\z/', $key); } } diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 6458449a02c9..a37d98f1c6e2 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Router; use CodeIgniter\Config\Services; +use CodeIgniter\controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; @@ -88,7 +89,7 @@ public function testBasicAddCallableWithParamsString() $routes = $routes->getRoutes(); $expects = [ - 'product/([0-9]+)/([0-9]+)' => '\Tests\Support\Controllers\Hello::index/$2/$1', + 'product/(\d+)/(\d+)' => '\Tests\Support\Controllers\Hello::index/$2/$1', ]; $this->assertSame($expects, $routes); } @@ -101,7 +102,7 @@ public function testBasicAddCallableWithParamsWithoutString() $routes = $routes->getRoutes(); $expects = [ - 'product/([0-9]+)/([0-9]+)' => '\Tests\Support\Controllers\Hello::index/$1/$2', + 'product/(\d+)/(\d+)' => '\Tests\Support\Controllers\Hello::index/$1/$2', ]; $this->assertSame($expects, $routes); } @@ -237,7 +238,7 @@ public function testAddRecognizesCustomNamespaces() $routes->add('home', 'controller'); $expects = [ - 'home' => '\CodeIgniter\controller', + 'home' => '\\' . controller::class, ]; $routes = $routes->getRoutes(); @@ -615,10 +616,10 @@ public function testResourcesWithCustomPlaceholder() $routes->resource('photos', ['placeholder' => ':num']); $expected = [ - 'photos' => '\Photos::index', - 'photos/new' => '\Photos::new', - 'photos/([0-9]+)/edit' => '\Photos::edit/$1', - 'photos/([0-9]+)' => '\Photos::show/$1', + 'photos' => '\Photos::index', + 'photos/new' => '\Photos::new', + 'photos/(\d+)/edit' => '\Photos::edit/$1', + 'photos/(\d+)' => '\Photos::show/$1', ]; $this->assertSame($expected, $routes->getRoutes()); @@ -633,10 +634,10 @@ public function testResourcesWithDefaultPlaceholder() $routes->resource('photos'); $expected = [ - 'photos' => '\Photos::index', - 'photos/new' => '\Photos::new', - 'photos/([0-9]+)/edit' => '\Photos::edit/$1', - 'photos/([0-9]+)' => '\Photos::show/$1', + 'photos' => '\Photos::index', + 'photos/new' => '\Photos::new', + 'photos/(\d+)/edit' => '\Photos::edit/$1', + 'photos/(\d+)' => '\Photos::show/$1', ]; $this->assertSame($expected, $routes->getRoutes()); @@ -1399,7 +1400,7 @@ public function testOffsetParameters() $routes = $this->getCollector(); $routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); - $expected = ['users/([0-9]+)' => '\users/show/$2']; + $expected = ['users/(\d+)' => '\users/show/$2']; $this->assertSame($expected, $routes->getRoutes()); } diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index 8e78750e494e..856a797f2911 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -63,7 +63,7 @@ public function testRegexMatch(): void $this->validation->setRules([ 'foo' => 'regex_match[/[a-z]/]', - 'phone' => 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', + 'phone' => 'regex_match[/^(01[2689]|09)\d{8}$/]', ]); $this->assertTrue($this->validation->run($data)); @@ -78,7 +78,7 @@ public function testRegexMatchFalse(): void $this->validation->setRules([ 'foo' => 'regex_match[\d]', - 'phone' => 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', + 'phone' => 'regex_match[/^(01[2689]|09)\d{8}$/]', ]); $this->assertFalse($this->validation->run($data)); diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index efc00290ebd4..1ca2e8970425 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -883,7 +883,7 @@ public function testHasError(): void public function testSplitRulesTrue(): void { $this->validation->setRules([ - 'phone' => 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', + 'phone' => 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', ]); $this->assertTrue($this->validation->run(['phone' => '0987654321'])); } @@ -891,7 +891,7 @@ public function testSplitRulesTrue(): void public function testSplitRulesFalse(): void { $this->validation->setRules([ - 'phone' => 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', + 'phone' => 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', ]); $this->assertFalse($this->validation->run(['phone' => '09876543214'])); } @@ -909,8 +909,8 @@ public function testSplitNotRegex(): void public function testSplitRegex(): void { $method = $this->getPrivateMethodInvoker($this->validation, 'splitRules'); - $result = $method('required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]'); - $this->assertSame('regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', $result[1]); + $result = $method('required|regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]|max_length[10]'); + $this->assertSame('regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]', $result[1]); } public function testTagReplacement(): void @@ -1365,18 +1365,18 @@ public function provideStringRulesCases(): iterable ]; yield [ - 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', - ['required', 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', 'numeric'], + 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', + ['required', 'regex_match[/^(01[2689]|09)\d{8}$/]', 'numeric'], ]; yield [ - 'required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]', - ['required', 'regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', 'max_length[10]'], + 'required|regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]|max_length[10]', + ['required', 'regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]', 'max_length[10]'], ]; yield [ - 'required|regex_match[/^(01|2689|09)[0-9]{8}$/]|numeric', - ['required', 'regex_match[/^(01|2689|09)[0-9]{8}$/]', 'numeric'], + 'required|regex_match[/^(01|2689|09)\d{8}$/]|numeric', + ['required', 'regex_match[/^(01|2689|09)\d{8}$/]', 'numeric'], ]; } From f171b089a458513354ebf05997f5a11b53308204 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 15 Jun 2023 09:50:44 +0700 Subject: [PATCH 128/135] skip SimplifyRegexPatternRector --- rector.php | 2 ++ system/Database/OCI8/Connection.php | 2 +- system/Helpers/text_helper.php | 2 +- system/Router/RouteCollection.php | 2 +- .../Routes/SampleURIGeneratorTest.php | 2 +- tests/system/Database/Builder/SelectTest.php | 6 ++--- tests/system/Database/RawSqlTest.php | 4 +-- tests/system/Router/RouteCollectionTest.php | 25 +++++++++---------- tests/system/Validation/FormatRulesTest.php | 4 +-- tests/system/Validation/ValidationTest.php | 20 +++++++-------- 10 files changed, 35 insertions(+), 34 deletions(-) diff --git a/rector.php b/rector.php index 2356339cb93b..df51a9b43b5a 100644 --- a/rector.php +++ b/rector.php @@ -112,6 +112,8 @@ GetMockBuilderGetMockToCreateMockRector::class => [ __DIR__ . '/tests/system/Email/EmailTest.php', ], + + SimplifyRegexPatternRector::class, ]); // auto import fully qualified class names diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index ee5b48a8b37a..ce6554ddc63a 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -53,7 +53,7 @@ class Connection extends BaseConnection protected $validDSNs = [ 'tns' => '/^\(DESCRIPTION=(\(.+\)){2,}\)$/', // TNS // Easy Connect string (Oracle 10g+) - 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9]\d{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i', + 'ec' => '/^(\/\/)?[a-z0-9.:_-]+(:[1-9][0-9]{0,4})?(\/[a-z0-9$_]+)?(:[^\/])?(\/[a-z0-9$_]+)?$/i', 'in' => '/^[a-z0-9$_]+$/i', // Instance name (defined in tnsnames.ora) ]; diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 8f96b423b02b..2343a89bfafe 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -662,7 +662,7 @@ function _from_random(int $length, string $pool): string */ function increment_string(string $str, string $separator = '_', int $first = 1): string { - preg_match('/(.+)' . preg_quote($separator, '/') . '(\d+)$/', $str, $match); + preg_match('/(.+)' . preg_quote($separator, '/') . '([0-9]+)$/', $str, $match); return isset($match[2]) ? $match[1] . $separator . ((int) $match[2] + 1) : $str . $separator . $first; } diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index ab3066f9eff4..66724935e31c 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -98,7 +98,7 @@ class RouteCollection implements RouteCollectionInterface 'any' => '.*', 'segment' => '[^/]+', 'alphanum' => '[a-zA-Z0-9]+', - 'num' => '\d+', + 'num' => '[0-9]+', 'alpha' => '[a-zA-Z]+', 'hash' => '[^/]+', ]; diff --git a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php index 8c64a72ab198..4b7b8fa3e814 100644 --- a/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php +++ b/tests/system/Commands/Utilities/Routes/SampleURIGeneratorTest.php @@ -38,7 +38,7 @@ public function routeKeyProvider(): Generator { yield from [ 'root' => ['/', '/'], - 'placeholder num' => ['shop/product/(\d+)', 'shop/product/123'], + 'placeholder num' => ['shop/product/([0-9]+)', 'shop/product/123'], 'placeholder segment' => ['shop/product/([^/]+)', 'shop/product/abc_123'], 'placeholder any' => ['shop/product/(.*)', 'shop/product/123/abc'], 'auto route' => ['home/index[/...]', 'home/index/1/2/3/4/5'], diff --git a/tests/system/Database/Builder/SelectTest.php b/tests/system/Database/Builder/SelectTest.php index 5f92d6f5f5ed..af7bf96d119e 100644 --- a/tests/system/Database/Builder/SelectTest.php +++ b/tests/system/Database/Builder/SelectTest.php @@ -105,7 +105,7 @@ public function testSelectWorksWithRawSql() { $builder = new BaseBuilder('users', $this->db); - $sql = 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral'; + $sql = 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral'; $builder->select(new RawSql($sql)); $expected = 'SELECT ' . $sql . ' FROM "users"'; @@ -134,12 +134,12 @@ public function testSelectRegularExpressionWorksWithEscpaeFalse() $builder = new BaseBuilder('ob_human_resources', $this->db); $builder->select( - 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral', + 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral', false ); $expected = <<<'SQL' - SELECT REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral + SELECT REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral FROM "ob_human_resources" SQL; $this->assertSame($expected, $builder->getCompiledSelect()); diff --git a/tests/system/Database/RawSqlTest.php b/tests/system/Database/RawSqlTest.php index b28b0b6ecfea..695a63980e89 100644 --- a/tests/system/Database/RawSqlTest.php +++ b/tests/system/Database/RawSqlTest.php @@ -22,7 +22,7 @@ final class RawSqlTest extends CIUnitTestCase { public function testCanConvertToString() { - $expected = 'REGEXP_SUBSTR(ral_anno,"\d{1,2}([,.]\d{1,3})([,.]\d{1,3})") AS ral'; + $expected = 'REGEXP_SUBSTR(ral_anno,"[0-9]{1,2}([,.][0-9]{1,3})([,.][0-9]{1,3})") AS ral'; $rawSql = new RawSql($expected); $this->assertSame($expected, (string) $rawSql); @@ -47,6 +47,6 @@ public function testGetBindingKey() $key = $rawSql->getBindingKey(); - $this->assertMatchesRegularExpression('/\ARawSql\d+\z/', $key); + $this->assertMatchesRegularExpression('/\ARawSql[0-9]+\z/', $key); } } diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index a37d98f1c6e2..6458449a02c9 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Router; use CodeIgniter\Config\Services; -use CodeIgniter\controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; @@ -89,7 +88,7 @@ public function testBasicAddCallableWithParamsString() $routes = $routes->getRoutes(); $expects = [ - 'product/(\d+)/(\d+)' => '\Tests\Support\Controllers\Hello::index/$2/$1', + 'product/([0-9]+)/([0-9]+)' => '\Tests\Support\Controllers\Hello::index/$2/$1', ]; $this->assertSame($expects, $routes); } @@ -102,7 +101,7 @@ public function testBasicAddCallableWithParamsWithoutString() $routes = $routes->getRoutes(); $expects = [ - 'product/(\d+)/(\d+)' => '\Tests\Support\Controllers\Hello::index/$1/$2', + 'product/([0-9]+)/([0-9]+)' => '\Tests\Support\Controllers\Hello::index/$1/$2', ]; $this->assertSame($expects, $routes); } @@ -238,7 +237,7 @@ public function testAddRecognizesCustomNamespaces() $routes->add('home', 'controller'); $expects = [ - 'home' => '\\' . controller::class, + 'home' => '\CodeIgniter\controller', ]; $routes = $routes->getRoutes(); @@ -616,10 +615,10 @@ public function testResourcesWithCustomPlaceholder() $routes->resource('photos', ['placeholder' => ':num']); $expected = [ - 'photos' => '\Photos::index', - 'photos/new' => '\Photos::new', - 'photos/(\d+)/edit' => '\Photos::edit/$1', - 'photos/(\d+)' => '\Photos::show/$1', + 'photos' => '\Photos::index', + 'photos/new' => '\Photos::new', + 'photos/([0-9]+)/edit' => '\Photos::edit/$1', + 'photos/([0-9]+)' => '\Photos::show/$1', ]; $this->assertSame($expected, $routes->getRoutes()); @@ -634,10 +633,10 @@ public function testResourcesWithDefaultPlaceholder() $routes->resource('photos'); $expected = [ - 'photos' => '\Photos::index', - 'photos/new' => '\Photos::new', - 'photos/(\d+)/edit' => '\Photos::edit/$1', - 'photos/(\d+)' => '\Photos::show/$1', + 'photos' => '\Photos::index', + 'photos/new' => '\Photos::new', + 'photos/([0-9]+)/edit' => '\Photos::edit/$1', + 'photos/([0-9]+)' => '\Photos::show/$1', ]; $this->assertSame($expected, $routes->getRoutes()); @@ -1400,7 +1399,7 @@ public function testOffsetParameters() $routes = $this->getCollector(); $routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); - $expected = ['users/(\d+)' => '\users/show/$2']; + $expected = ['users/([0-9]+)' => '\users/show/$2']; $this->assertSame($expected, $routes->getRoutes()); } diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index 856a797f2911..8e78750e494e 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -63,7 +63,7 @@ public function testRegexMatch(): void $this->validation->setRules([ 'foo' => 'regex_match[/[a-z]/]', - 'phone' => 'regex_match[/^(01[2689]|09)\d{8}$/]', + 'phone' => 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', ]); $this->assertTrue($this->validation->run($data)); @@ -78,7 +78,7 @@ public function testRegexMatchFalse(): void $this->validation->setRules([ 'foo' => 'regex_match[\d]', - 'phone' => 'regex_match[/^(01[2689]|09)\d{8}$/]', + 'phone' => 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', ]); $this->assertFalse($this->validation->run($data)); diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 1ca2e8970425..efc00290ebd4 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -883,7 +883,7 @@ public function testHasError(): void public function testSplitRulesTrue(): void { $this->validation->setRules([ - 'phone' => 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', + 'phone' => 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', ]); $this->assertTrue($this->validation->run(['phone' => '0987654321'])); } @@ -891,7 +891,7 @@ public function testSplitRulesTrue(): void public function testSplitRulesFalse(): void { $this->validation->setRules([ - 'phone' => 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', + 'phone' => 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', ]); $this->assertFalse($this->validation->run(['phone' => '09876543214'])); } @@ -909,8 +909,8 @@ public function testSplitNotRegex(): void public function testSplitRegex(): void { $method = $this->getPrivateMethodInvoker($this->validation, 'splitRules'); - $result = $method('required|regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]|max_length[10]'); - $this->assertSame('regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]', $result[1]); + $result = $method('required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]'); + $this->assertSame('regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', $result[1]); } public function testTagReplacement(): void @@ -1365,18 +1365,18 @@ public function provideStringRulesCases(): iterable ]; yield [ - 'required|regex_match[/^(01[2689]|09)\d{8}$/]|numeric', - ['required', 'regex_match[/^(01[2689]|09)\d{8}$/]', 'numeric'], + 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', + ['required', 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', 'numeric'], ]; yield [ - 'required|regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]|max_length[10]', - ['required', 'regex_match[/^\d{4}[\-\.\[\/]\d{2}[\-\.\[\/]\d{2}/]', 'max_length[10]'], + 'required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]', + ['required', 'regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', 'max_length[10]'], ]; yield [ - 'required|regex_match[/^(01|2689|09)\d{8}$/]|numeric', - ['required', 'regex_match[/^(01|2689|09)\d{8}$/]', 'numeric'], + 'required|regex_match[/^(01|2689|09)[0-9]{8}$/]|numeric', + ['required', 'regex_match[/^(01|2689|09)[0-9]{8}$/]', 'numeric'], ]; } From 8967217e6fb727a9b544138144312933626667cb Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 15 Jun 2023 09:52:49 +0700 Subject: [PATCH 129/135] Re-run Rector --- tests/system/Router/RouteCollectionTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 6458449a02c9..40c5da39b091 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Router; use CodeIgniter\Config\Services; +use CodeIgniter\controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; @@ -237,7 +238,7 @@ public function testAddRecognizesCustomNamespaces() $routes->add('home', 'controller'); $expects = [ - 'home' => '\CodeIgniter\controller', + 'home' => '\\' . controller::class, ]; $routes = $routes->getRoutes(); From 8b8da0f6a8bc53c943e7b421d17d5b7fe9f6cb7a Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 15 Jun 2023 17:01:47 +0900 Subject: [PATCH 130/135] docs: change note to warning --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index f91a282160ef..1642d8b97655 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -535,7 +535,7 @@ Route Priority Routes are registered in the routing table in the order in which they are defined. This means that when a URI is accessed, the first matching route will be executed. -.. note:: If a route path is defined more than once with different handlers, only the first defined route is registered. +.. warning:: If a route path is defined more than once with different handlers, only the first defined route is registered. You can check registered routes in the routing table by running the :ref:`spark routes ` command. From 59da1737a45fed9bb17a268c39f5e9a1169e8eed Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 15 Jun 2023 17:03:21 +0900 Subject: [PATCH 131/135] docs: fix by proofreading --- user_guide_src/source/incoming/routing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 1642d8b97655..a5d195f53e46 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -875,7 +875,7 @@ The *Method* will be like ``GET(auto)``. ``/..`` in the *Route* column indicates one segment. ``[/..]`` indicates it is optional. -.. note:: When auto-routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. +.. note:: When auto-routing is enabled and you have the route ``home``, it can be also accessed by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. but the command will show only ``home``. If you see a route starting with ``x`` like the following, it indicates an invalid route that won't be routed, but the controller has a public method for routing. @@ -913,7 +913,7 @@ The *Method* will be ``auto``. ``[/...]`` in the *Route* column indicates any number of segments. -.. note:: When auto-routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. +.. note:: When auto-routing is enabled and you have the route ``home``, it can be also accessed by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. but the command will show only ``home``. .. _routing-spark-routes-sort-by-handler: From 8e5c50e8bf4adf652015c499f9ca21b4f9ac37b3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 15 Jun 2023 18:44:37 +0900 Subject: [PATCH 132/135] chore: scan tests/_support --- psalm_autoload.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/psalm_autoload.php b/psalm_autoload.php index 374964846b1f..d0f0c9af46e6 100644 --- a/psalm_autoload.php +++ b/psalm_autoload.php @@ -23,4 +23,23 @@ } } +$dirs = [ + 'tests/_support/Controllers', +]; + +foreach ($dirs as $dir) { + $dir = __DIR__ . '/' . $dir; + if (! is_dir($dir)) { + continue; + } + + chdir($dir); + + foreach (glob('*.php') as $filename) { + $filePath = realpath($dir . '/' . $filename); + + require_once $filePath; + } +} + chdir(__DIR__); From 1d2eb6302ce0f6d2447ffb99c52e4ee3a2579328 Mon Sep 17 00:00:00 2001 From: ping-yee <611077101@mail.nknu.edu.tw> Date: Fri, 16 Jun 2023 00:06:46 +0800 Subject: [PATCH 133/135] docs: add type null. --- system/Config/BaseConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 8d41ffed0b10..300e9ffac5f9 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -86,7 +86,7 @@ public function __construct() /** * Initialization an environment-specific configuration setting * - * @param array|bool|float|int|string $property + * @param array|bool|float|int|string|null $property * * @return void */ From ed327576fc47175ae957957096ea970c3992dd87 Mon Sep 17 00:00:00 2001 From: ping-yee <611077101@mail.nknu.edu.tw> Date: Fri, 16 Jun 2023 00:10:22 +0800 Subject: [PATCH 134/135] docs: modify the type. --- system/Encryption/Encryption.php | 2 +- system/Encryption/Handlers/BaseHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index d0484b06070b..fda9906240cb 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -149,7 +149,7 @@ public static function createKey($length = 32) * * @param string $key Property name * - * @return array|EncrypterInterface|string|null + * @return array|string|null */ public function __get($key) { diff --git a/system/Encryption/Handlers/BaseHandler.php b/system/Encryption/Handlers/BaseHandler.php index c6894dc2fb8c..64195672439e 100644 --- a/system/Encryption/Handlers/BaseHandler.php +++ b/system/Encryption/Handlers/BaseHandler.php @@ -61,7 +61,7 @@ protected static function substr($str, $start, $length = null) * * @param string $key Property name * - * @return LoggerInterface|null + * @return array|bool|int|string|null */ public function __get($key) { From 1f05ec69baf8aef510caaebeaa673a94a209277e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 18 Jun 2023 05:55:00 +0900 Subject: [PATCH 135/135] Prep for 4.3.6 release --- CHANGELOG.md | 26 +++++++++++++++++++ system/CodeIgniter.php | 2 +- user_guide_src/source/changelogs/v4.3.6.rst | 10 ++----- user_guide_src/source/conf.py | 2 +- .../source/installation/upgrade_436.rst | 22 ++-------------- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76a163c0c7a7..a0233fff0e7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [v4.3.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.3.6) (2023-06-18) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.3.5...v4.3.6) + +### Breaking Changes + +* fix: [Validation] DBGroup is ignored when checking the value of a placeholder by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7549 +* fix: [Auto Routing Improved] feature testing may not find controller/method by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7543 + +### Fixed Bugs + +* fix: feature test with validation by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7548 +* fix: [Postgre] Semicolon in the connection parameters break the DSN string by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/7552 +* fix: [QueryBuilder] incorrect SQL without space before "ON DUPLICATE KEY UPDATE" by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7564 +* fix: wrong classname in exception message in Cell by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7569 +* fix: `imagecreatefrompng()` gd-png: libpng warning by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/7570 + +### Refactoring + +* refactor: remove unneeded code in IncomingRequest by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7525 +* refactor: View by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7534 +* refactor: [Entity] fix incorrect return value by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7542 +* refactor: Database::initDriver() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7553 +* refactor: remove Factories::models() by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7566 +* refactor: Validation::processRules() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7565 +* refactor: [Auto Routing Improved] ensure $httpVerb is lower case by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7575 + ## [v4.3.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.3.5) (2023-05-21) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.3.4...v4.3.5) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index c7a93a802fb4..829b65ea952b 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.3.5'; + public const CI_VERSION = '4.3.6'; /** * App startup time. diff --git a/user_guide_src/source/changelogs/v4.3.6.rst b/user_guide_src/source/changelogs/v4.3.6.rst index 34551c1ede03..fb4538a7e957 100644 --- a/user_guide_src/source/changelogs/v4.3.6.rst +++ b/user_guide_src/source/changelogs/v4.3.6.rst @@ -1,9 +1,9 @@ Version 4.3.6 ############# -Release Date: Unreleased +Release Date: June 18, 2023 -**{version} release of CodeIgniter4** +**4.3.6 release of CodeIgniter4** .. contents:: :local: @@ -39,12 +39,6 @@ Validation::check() - The second parameter has changed from ``string $rule`` to ``$rules``. - The optional fourth parameter ``$dbGroup = null`` has been added. -Message Changes -*************** - -Changes -******* - Deprecations ************ diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index 63748f794fb2..9d86d441c660 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -26,7 +26,7 @@ version = '4.3' # The full version, including alpha/beta/rc tags. -release = '4.3.5' +release = '4.3.6' # -- General configuration --------------------------------------------------- diff --git a/user_guide_src/source/installation/upgrade_436.rst b/user_guide_src/source/installation/upgrade_436.rst index 7d4e99bb602a..cd4ff8bdeeb1 100644 --- a/user_guide_src/source/installation/upgrade_436.rst +++ b/user_guide_src/source/installation/upgrade_436.rst @@ -12,9 +12,6 @@ Please refer to the upgrade instructions corresponding to your installation meth :local: :depth: 2 -Mandatory File Changes -********************** - Breaking Changes **************** @@ -30,22 +27,7 @@ Breaking Enhancements Project Files ************* -Some files in the **project space** (root, app, public, writable) received updates. Due to -these files being outside of the **system** scope they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to -the project space: `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) -and it is recommended that you merge the updated versions with your application: - -Config ------- - -- @TODO +Version 4.3.6 did not alter any executable code in project files. All Changes =========== @@ -53,4 +35,4 @@ All Changes This is a list of all files in the **project space** that received changes; many will be simple comments or formatting that have no effect on the runtime: -- @TODO +- composer.json