From 749307e1b57cfe65705d37fea0a1a957b28eb24e Mon Sep 17 00:00:00 2001 From: MGatner Date: Fri, 3 Jun 2022 15:58:09 +0000 Subject: [PATCH 01/78] Update website process --- admin/RELEASE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/RELEASE.md b/admin/RELEASE.md index b7ec0ced1905..dc51ca3c9b07 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -87,11 +87,11 @@ composer test && composer info codeigniter4/framework * Description: "CodeIgniter 4.x.x User Guide" * Watch for the "github pages" Environment to make sure the deployment succeeds -## Website +### Website -Currently the User Guide on the website has to be updated manually. Visit Jim's user home -where the served directory **codeigniter.com** exists. Copy the latest **docs** folder from -the User Guide repo to **public/userguide4** and browse to the website to make sure it works. +The User Guide website should update itself via the deploy GitHub Action. Should this fail +the server must be updated manually. See repo and hosting details in the deploy script +at the User Guide repo. ## Announcement From 5b702874625f1e5462060249dc6bccb3508a85de Mon Sep 17 00:00:00 2001 From: Eskiso Date: Fri, 3 Jun 2022 18:42:08 +0000 Subject: [PATCH 02/78] Adds information that ignore() is not unique to insert Adds information that ignore() can be used in insertBatch, update and delete (when database supports it). Not really clear on the docs at the moment. --- user_guide_src/source/database/query_builder.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index f03c499863b6..eca7b2bd2cf0 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -809,7 +809,8 @@ $builder->ignore() Generates an insert ignore string based on the data you supply, and runs the query. So if an entry with the same primary key already exists, the query won't be inserted. -You can optionally pass an **boolean** to the method. Here is an example using the array of the above example: +You can optionally pass an **boolean** to the method. Can also be used on **insertBatch**, **update** and **delete** (when supported). +Here is an example using the array of the above example: .. literalinclude:: query_builder/078.php From 148ee022cbbc60e8b5d30d2989a7e2e6e92dae3e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 5 Jun 2022 09:38:12 +0900 Subject: [PATCH 03/78] docs: update for v4.2 --- user_guide_src/source/installation/upgrade_4xx.rst | 6 ++++++ user_guide_src/source/installation/upgrade_routing.rst | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index a97a2e339a29..b0c3d3dea9be 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -55,6 +55,12 @@ Application Structure - There is no longer a nested **application/core** folder, as we have a different mechanism for extending framework components (see below). +Routing +======= + +- The Auto Routing is disabled by default. If you want to use the Auto Routing in the same way as CI3, you need to enable :ref:`auto-routing`. +- CI4 also has an optional new more secure :ref:`auto-routing-improved`. + Model, View and Controller ========================== diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 882ef380ca92..669b00dc2751 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -13,11 +13,16 @@ Documentations What has been changed ===================== + +- In CI4 the Auto Routing is disabled by default. +- In CI4 the new more secure :ref:`auto-routing-improved` is introduced. - In CI4 the routing is no longer configured by setting the routes as array. Upgrade Guide ============= -1. You have to change the syntax of each routing line and append it in **app/Config/Routes.php**. For example: + +1. If you use the Auto Routing in the same way as CI3, you need to enable :ref:`auto-routing`. +2. You have to change the syntax of each routing line and append it in **app/Config/Routes.php**. For example: - ``$route['journals'] = 'blogs';`` to ``$routes->add('journals', 'Blogs::index');``. This would map to the ``index()`` method in the ``Blogs`` controller. - ``$route['product/(:any)'] = 'catalog/product_lookup';`` to ``$routes->add('product/(:any)', 'Catalog::productLookup');`` From 3713970f9b438fbffb309a30140e8c9a4b42f16d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 5 Jun 2022 17:42:36 +0900 Subject: [PATCH 04/78] docs: update authentication.rst --- user_guide_src/source/extending/authentication.rst | 11 +++++++---- user_guide_src/source/libraries/official_packages.rst | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/extending/authentication.rst b/user_guide_src/source/extending/authentication.rst index 5ab8f1bf3552..e319472099f8 100644 --- a/user_guide_src/source/extending/authentication.rst +++ b/user_guide_src/source/extending/authentication.rst @@ -1,9 +1,12 @@ -Authentication +Authentication ##################################### -CodeIgniter intentionally does not provide an internal authentication or authorization class. There are a number -of great third-party modules that provide these services, as well as resources in the community for writing -your own. The following are recommended guidelines to encourage consistency among developers of +CodeIgniter provides an official authentication and authorization framework +:ref:`CodeIgniter Shield ` for CodeIgniter 4, +It is designed to be secure, flexible, and easily extendable to meet the needs +of many different types of websites. + +The following are recommended guidelines to encourage consistency among developers of modules, projects, and the framework itself. Recommendations diff --git a/user_guide_src/source/libraries/official_packages.rst b/user_guide_src/source/libraries/official_packages.rst index 769da6aac3ed..17acdd3d14cf 100644 --- a/user_guide_src/source/libraries/official_packages.rst +++ b/user_guide_src/source/libraries/official_packages.rst @@ -11,6 +11,8 @@ additional functionality that not every site will need or want. :local: :depth: 2 +.. _shield: + ****** Shield ****** From 57e9237406c696e23311f2bd6ab22344371cfbc7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 10:12:40 +0900 Subject: [PATCH 05/78] fix: get_cookie() does not take Config\Cookie::$prefix --- system/Helpers/cookie_helper.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 51a746c5395b..d7e8af570ca1 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -10,6 +10,7 @@ */ use Config\App; +use Config\Cookie; use Config\Services; //============================================================================= @@ -63,7 +64,13 @@ function set_cookie( */ function get_cookie($index, bool $xssClean = false) { - $prefix = isset($_COOKIE[$index]) ? '' : config(App::class)->cookiePrefix; + /** @var Cookie|null $cookie */ + $cookie = config('Cookie'); + + // @TODO Remove Config\App fallback when deprecated `App` members are removed. + $cookiePrefix = $cookie instanceof Cookie ? $cookie->prefix : config(App::class)->cookiePrefix; + + $prefix = isset($_COOKIE[$index]) ? '' : $cookiePrefix; $request = Services::request(); $filter = $xssClean ? FILTER_SANITIZE_FULL_SPECIAL_CHARS : FILTER_DEFAULT; From 784d8c902fb90469ed00bd00f36832967b0ca5b9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 10:36:51 +0900 Subject: [PATCH 06/78] fix: Session Handlers does not take Config\Cookie --- system/Session/Handlers/BaseHandler.php | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/system/Session/Handlers/BaseHandler.php b/system/Session/Handlers/BaseHandler.php index 008cae369e80..63f0c6dbdb48 100644 --- a/system/Session/Handlers/BaseHandler.php +++ b/system/Session/Handlers/BaseHandler.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Session\Handlers; use Config\App as AppConfig; +use Config\Cookie as CookieConfig; use Psr\Log\LoggerAwareTrait; use SessionHandlerInterface; @@ -102,14 +103,27 @@ abstract class BaseHandler implements SessionHandlerInterface public function __construct(AppConfig $config, string $ipAddress) { - $this->cookiePrefix = $config->cookiePrefix; - $this->cookieDomain = $config->cookieDomain; - $this->cookiePath = $config->cookiePath; - $this->cookieSecure = $config->cookieSecure; - $this->cookieName = $config->sessionCookieName; - $this->matchIP = $config->sessionMatchIP; - $this->savePath = $config->sessionSavePath; - $this->ipAddress = $ipAddress; + /** @var CookieConfig|null $cookie */ + $cookie = config('Cookie'); + + if ($cookie instanceof CookieConfig) { + $this->cookiePrefix = $cookie->prefix; + $this->cookieDomain = $cookie->domain; + $this->cookiePath = $cookie->path; + $this->cookieSecure = $cookie->secure; + } else { + // @TODO Remove this fallback when deprecated `App` members are removed. + // `Config/Cookie.php` is absence + $this->cookiePrefix = $config->cookiePrefix; + $this->cookieDomain = $config->cookieDomain; + $this->cookiePath = $config->cookiePath; + $this->cookieSecure = $config->cookieSecure; + } + + $this->cookieName = $config->sessionCookieName; + $this->matchIP = $config->sessionMatchIP; + $this->savePath = $config->sessionSavePath; + $this->ipAddress = $ipAddress; } /** From d82b7e2d0ce41d9940c93e20c494d66f3dc09bfe Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 20:49:36 +0900 Subject: [PATCH 07/78] docs: make PHPDoc more accurate --- system/HTTP/ResponseTrait.php | 5 ++++- system/Helpers/cookie_helper.php | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 0e945b6288f1..f8dd174b4332 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -543,7 +543,7 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null * @param string $expire Cookie expiration time in seconds * @param string $domain Cookie domain (e.g.: '.yourdomain.com') * @param string $path Cookie path (default: '/') - * @param string $prefix Cookie name prefix + * @param string $prefix Cookie name prefix ('': the default prefix) * @param bool $secure Whether to only transfer cookies via SSL * @param bool $httponly Whether only make the cookie accessible via HTTP (no javascript) * @param string|null $samesite @@ -618,6 +618,9 @@ public function hasCookie(string $name, ?string $value = null, string $prefix = /** * Returns the cookie * + * @param string $prefix Cookie prefix. + * '': the default prefix + * * @return Cookie|Cookie[]|null */ public function getCookie(?string $name = null, string $prefix = '') diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 51a746c5395b..c7a7028773b6 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -28,7 +28,7 @@ * @param string $expire The number of seconds until expiration * @param string $domain For site-wide cookie. Usually: .yourdomain.com * @param string $path The cookie path - * @param string $prefix The cookie prefix + * @param string $prefix The cookie prefix ('': the default prefix) * @param bool $secure True makes the cookie secure * @param bool $httpOnly True makes the cookie accessible via http(s) only (no javascript) * @param string|null $sameSite The cookie SameSite value From 17824fb2e03c7afe1410b00bf093b0979f52575d Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 20:56:43 +0900 Subject: [PATCH 08/78] docs: add details --- user_guide_src/source/helpers/cookie_helper.rst | 2 +- user_guide_src/source/outgoing/response.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 683564ad652a..5976c48ea99a 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -28,7 +28,7 @@ The following functions are available: :param int $expire: Number of seconds until expiration :param string $domain: Cookie domain (usually: .yourdomain.com) :param string $path: Cookie path - :param string $prefix: Cookie name prefix + :param string $prefix: Cookie name prefix. If ``''``, the default from **app/Config/Cookie.php** is used :param bool $secure: Whether to only send the cookie through HTTPS :param bool $httpOnly: Whether to hide the cookie from JavaScript :param string $sameSite: The value for the SameSite cookie parameter. If ``null``, the default from **app/Config/Cookie.php** is used diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 2227a166e096..e03106ab6ffe 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -367,7 +367,7 @@ The methods provided by the parent class that are available are: :param int $expire: Cookie expiration time in seconds :param string $domain: Cookie domain :param string $path: Cookie path - :param string $prefix: Cookie name prefix + :param string $prefix: Cookie name prefix. If set to ``''``, the default value from **app/Config/Cookie.php** will be used :param bool $secure: Whether to only transfer the cookie through HTTPS :param bool $httponly: Whether to only make the cookie accessible for HTTP requests (no JavaScript) :param string $samesite: The value for the SameSite cookie parameter. If set to ``''``, no SameSite attribute will be set on the cookie. If set to ``null``, the default value from **app/Config/Cookie.php** will be used From b350c5ca0c08bc494e1a90b5c3e97d7a41b2de01 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 20:57:20 +0900 Subject: [PATCH 09/78] docs: fix typo --- user_guide_src/source/libraries/cookies/002.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/cookies/002.php b/user_guide_src/source/libraries/cookies/002.php index 3feb4347d330..8c2fb03fea9d 100644 --- a/user_guide_src/source/libraries/cookies/002.php +++ b/user_guide_src/source/libraries/cookies/002.php @@ -3,7 +3,7 @@ use CodeIgniter\Cookie\Cookie; use Config\Cookie as CookieConfig; -// pass in an Config\Cookie instance before constructing a Cookie class +// pass in a Config\Cookie instance before constructing a Cookie class Cookie::setDefaults(new CookieConfig()); $cookie = new Cookie('login_token'); From 09f22a1afa9906fc287624ca385cfed89422e23a Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Mon, 6 Jun 2022 15:21:57 +0100 Subject: [PATCH 10/78] Apply translateURIDashes() --- system/Router/AutoRouterImproved.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/system/Router/AutoRouterImproved.php b/system/Router/AutoRouterImproved.php index 7b03e705a1df..39b264ecf780 100644 --- a/system/Router/AutoRouterImproved.php +++ b/system/Router/AutoRouterImproved.php @@ -251,11 +251,7 @@ private function scanControllers(array $segments): array $c = count($segments); while ($c-- > 0) { - $segmentConvert = ucfirst( - $this->translateURIDashes === true - ? str_replace('-', '_', $segments[0]) - : $segments[0] - ); + $segmentConvert = $this->translateURIDashes(ucfirst($segments[0])); // as soon as we encounter any segment that is not PSR-4 compliant, stop searching if (! $this->isValidSegment($segmentConvert)) { From bc141f9cd620e27b45207bebc5a3f3a1f703df19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 15:04:07 +0000 Subject: [PATCH 11/78] chore(deps-dev): update rector/rector requirement from 0.13.3 to 0.13.4 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.13.3...0.13.4) --- 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 2c93e30b7d72..7271a5aa6c02 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.7.1", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.13.3" + "rector/rector": "0.13.4" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 5c2211b08e8756d98ba642eda197e0df9f738a1f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Jun 2022 05:41:53 +0700 Subject: [PATCH 12/78] re-run rector 0.13.4 to remove unneeded @var --- tests/system/Cookie/CookieTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/system/Cookie/CookieTest.php b/tests/system/Cookie/CookieTest.php index 341280024ae4..0754c04a8282 100644 --- a/tests/system/Cookie/CookieTest.php +++ b/tests/system/Cookie/CookieTest.php @@ -56,9 +56,6 @@ public function testCookieInitializationWithDefaults(): void public function testConfigInjectionForDefaults(): void { - /** - * @var CookieConfig $config - */ $config = new CookieConfig(); $old = Cookie::setDefaults($config); From 8e4a6692ee776c2515cfad529c95fdf74cdac920 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Jun 2022 07:17:32 +0700 Subject: [PATCH 13/78] Move preload.php example to starter app --- preload.php => admin/starter/preload.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) rename preload.php => admin/starter/preload.php (95%) diff --git a/preload.php b/admin/starter/preload.php similarity index 95% rename from preload.php rename to admin/starter/preload.php index 7e1a04956fa9..f36bacf3b0d1 100644 --- a/preload.php +++ b/admin/starter/preload.php @@ -41,15 +41,14 @@ function str_contains(string $haystack, string $needle): bool } } -class Preload +class preload { /** * @var array Paths to preload. */ private array $paths = [ [ - 'include' => // __DIR__ . '/vendor/codeigniter4/framework/system', - __DIR__ . '/system', + 'include' => __DIR__ . '/vendor/codeigniter4/framework/system', 'exclude' => [ // Not needed if you don't use them. '/system/Database/OCI8/', @@ -110,4 +109,4 @@ public function load() } } -(new Preload())->load(); +(new preload())->load(); From 4559b319cd4b24db6a8a20b4d3647355b01d47e8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Jun 2022 11:21:35 +0900 Subject: [PATCH 14/78] fix: remove $this->cookiePrefix because Session cookie ignores it --- system/Session/Handlers/BaseHandler.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/system/Session/Handlers/BaseHandler.php b/system/Session/Handlers/BaseHandler.php index 63f0c6dbdb48..c441aa086153 100644 --- a/system/Session/Handlers/BaseHandler.php +++ b/system/Session/Handlers/BaseHandler.php @@ -40,6 +40,9 @@ abstract class BaseHandler implements SessionHandlerInterface /** * Cookie prefix * + * The Config\Cookie::$prefix setting is completely ignored. + * See https://codeigniter4.github.io/CodeIgniter4/libraries/sessions.html#session-preferences + * * @var string */ protected $cookiePrefix = ''; @@ -107,14 +110,14 @@ public function __construct(AppConfig $config, string $ipAddress) $cookie = config('Cookie'); if ($cookie instanceof CookieConfig) { - $this->cookiePrefix = $cookie->prefix; + // Session cookies have no prefix. $this->cookieDomain = $cookie->domain; $this->cookiePath = $cookie->path; $this->cookieSecure = $cookie->secure; } else { // @TODO Remove this fallback when deprecated `App` members are removed. // `Config/Cookie.php` is absence - $this->cookiePrefix = $config->cookiePrefix; + // Session cookies have no prefix. $this->cookieDomain = $config->cookieDomain; $this->cookiePath = $config->cookiePath; $this->cookieSecure = $config->cookieSecure; From b1e0dc3826e6a75993070c3337e709b6bb3a5c55 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 6 Jun 2022 23:14:03 -0500 Subject: [PATCH 15/78] Fix decorators --- system/View/ViewDecoratorTrait.php | 2 +- user_guide_src/source/outgoing/view_decorators.rst | 2 +- user_guide_src/source/outgoing/view_decorators/001.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/View/ViewDecoratorTrait.php b/system/View/ViewDecoratorTrait.php index 243c229bfbde..841cbc71593d 100644 --- a/system/View/ViewDecoratorTrait.php +++ b/system/View/ViewDecoratorTrait.php @@ -24,7 +24,7 @@ protected function decorateOutput(string $html): string $decorators = \config('View')->decorators; foreach ($decorators as $decorator) { - if (! is_subclass_of($decorator, ViewDecoratorInterface::class)) { + if (! in_array(ViewDecoratorInterface::class, class_implements($decorator))) { throw ViewException::forInvalidDecorator($decorator); } diff --git a/user_guide_src/source/outgoing/view_decorators.rst b/user_guide_src/source/outgoing/view_decorators.rst index 83f3154f54c5..f0b2239b0f65 100644 --- a/user_guide_src/source/outgoing/view_decorators.rst +++ b/user_guide_src/source/outgoing/view_decorators.rst @@ -9,7 +9,7 @@ prior to being cached, and allows you to apply custom functionality to your view Creating Decorators ******************* -Creating your own view decorators requires creating a new class that implements ``CodeIgniter\Views\ViewDecoratorInterface``. +Creating your own view decorators requires creating a new class that implements ``CodeIgniter\View\ViewDecoratorInterface``. This requires a single method that takes the generated HTML string, performs any modifications on it, and returns the resulting HTML. diff --git a/user_guide_src/source/outgoing/view_decorators/001.php b/user_guide_src/source/outgoing/view_decorators/001.php index be05e93b5818..bdde6a19060c 100644 --- a/user_guide_src/source/outgoing/view_decorators/001.php +++ b/user_guide_src/source/outgoing/view_decorators/001.php @@ -2,7 +2,7 @@ namespace App\Views\Decorators; -use CodeIgniter\Views\ViewDecoratorInterface; +use CodeIgniter\View\ViewDecoratorInterface; class MyDecorator implements ViewDecoratorInterface { From f86119af7f8b2f26163836823544a4b3c10f0786 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 6 Jun 2022 23:26:03 -0500 Subject: [PATCH 16/78] Strict is_array check --- system/View/ViewDecoratorTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/View/ViewDecoratorTrait.php b/system/View/ViewDecoratorTrait.php index 841cbc71593d..d1982fc12295 100644 --- a/system/View/ViewDecoratorTrait.php +++ b/system/View/ViewDecoratorTrait.php @@ -24,7 +24,7 @@ protected function decorateOutput(string $html): string $decorators = \config('View')->decorators; foreach ($decorators as $decorator) { - if (! in_array(ViewDecoratorInterface::class, class_implements($decorator))) { + if (! in_array(ViewDecoratorInterface::class, class_implements($decorator), true)) { throw ViewException::forInvalidDecorator($decorator); } From 558f97b2976b7909068657bf213d6333e0cfa2e1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Jun 2022 15:51:21 +0900 Subject: [PATCH 17/78] fix: Cookie class option prefix bug When option prefix is '0', it is not set correctly. --- system/Cookie/Cookie.php | 4 +++- tests/system/Cookie/CookieTest.php | 33 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index e40d0a1201d5..22c01a7daa3c 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -119,6 +119,8 @@ class Cookie implements ArrayAccess, CloneableCookieInterface * Set the default attributes to a Cookie instance by injecting * the values from the `CookieConfig` config or an array. * + * This method is called from Response::__construct(). + * * @param array|CookieConfig $config * * @return array The old defaults array. Useful for resetting. @@ -209,7 +211,7 @@ final public function __construct(string $name, string $value = '', array $optio } // to preserve backward compatibility with array-based cookies in previous CI versions - $prefix = $options['prefix'] ?: self::$defaults['prefix']; + $prefix = ($options['prefix'] === '') ? self::$defaults['prefix'] : $options['prefix']; $path = $options['path'] ?: self::$defaults['path']; $domain = $options['domain'] ?: self::$defaults['domain']; diff --git a/tests/system/Cookie/CookieTest.php b/tests/system/Cookie/CookieTest.php index 0754c04a8282..a442933dfe05 100644 --- a/tests/system/Cookie/CookieTest.php +++ b/tests/system/Cookie/CookieTest.php @@ -16,6 +16,7 @@ use Config\Cookie as CookieConfig; use DateTimeImmutable; use DateTimeZone; +use Generator; use LogicException; /** @@ -76,6 +77,38 @@ public function testConfigInjectionForDefaults(): void Cookie::setDefaults($old); } + /** + * @dataProvider prefixProvider + */ + public function testConfigPrefix(string $configPrefix, string $optionPrefix, string $expected): void + { + $config = new CookieConfig(); + $config->prefix = $configPrefix; + Cookie::setDefaults($config); + + $cookie = new Cookie( + 'test', + 'value', + [ + 'prefix' => $optionPrefix, + ] + ); + + $this->assertSame($expected, $cookie->getPrefixedName()); + } + + public function prefixProvider(): Generator + { + yield from [ + ['prefix_', '', 'prefix_test'], + ['prefix_', '0', '0test'], + ['prefix_', 'new_', 'new_test'], + ['', '', 'test'], + ['', '0', '0test'], + ['', 'new_', 'new_test'], + ]; + } + public function testValidationOfRawCookieName(): void { $this->expectException(CookieException::class); From 026ac2240fd84660531e696cc26f5ab43f458049 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Jun 2022 15:54:16 +0900 Subject: [PATCH 18/78] fix: session cookie name has cookie config prefix The config prefix should be ignored. > the Config\Cookie::$prefix setting is completely ignored. > https://codeigniter.com/user_guide/libraries/sessions.html#session-preferences --- system/Session/Session.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Session/Session.php b/system/Session/Session.php index 0b27b03fa46e..965edf88d9ed 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -187,7 +187,7 @@ public function __construct(SessionHandlerInterface $driver, App $config) /** @var CookieConfig $cookie */ $cookie = config('Cookie'); - $this->cookie = new Cookie($this->sessionCookieName, '', [ + $this->cookie = (new Cookie($this->sessionCookieName, '', [ 'expires' => $this->sessionExpiration === 0 ? 0 : time() + $this->sessionExpiration, 'path' => $cookie->path ?? $config->cookiePath, 'domain' => $cookie->domain ?? $config->cookieDomain, @@ -195,7 +195,7 @@ public function __construct(SessionHandlerInterface $driver, App $config) 'httponly' => true, // for security 'samesite' => $cookie->samesite ?? $config->cookieSameSite ?? Cookie::SAMESITE_LAX, 'raw' => $cookie->raw ?? false, - ]); + ]))->withPrefix(''); // Cookie prefix should be ignored. helper('array'); } From 2b8acc54d427baa05daa0828764633ab4870ae61 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Jun 2022 16:41:25 +0900 Subject: [PATCH 19/78] docs: fix typo --- user_guide_src/source/cli/cli_controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli_controllers.rst b/user_guide_src/source/cli/cli_controllers.rst index 9c16e1bb30ac..c4230091de7c 100644 --- a/user_guide_src/source/cli/cli_controllers.rst +++ b/user_guide_src/source/cli/cli_controllers.rst @@ -23,7 +23,7 @@ in it: .. literalinclude:: cli_controllers/001.php -.. note:: If you use :ref:`auto-routing-improved`, change the method name to ``cli_message()``. +.. note:: If you use :ref:`auto-routing-improved`, change the method name to ``cliMessage()``. Then save the file to your **app/Controllers/** directory. From f48f7491d97d0c89508b5667246408c9af2367d0 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 1 Jun 2022 12:39:32 +0800 Subject: [PATCH 20/78] Fix MIME guessing of extension from type --- app/Config/Mimes.php | 19 +++---- system/Files/File.php | 7 ++- tests/system/Files/FileTest.php | 25 +++++++++ .../system/HTTP/Files/FileCollectionTest.php | 10 ++-- user_guide_src/source/changelogs/index.rst | 1 + user_guide_src/source/changelogs/v4.2.1.rst | 18 +++++++ .../source/installation/upgrade_421.rst | 53 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 8 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 user_guide_src/source/changelogs/v4.2.1.rst create mode 100644 user_guide_src/source/installation/upgrade_421.rst diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index a1bb458a2804..884e76bc6f53 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -102,8 +102,6 @@ class Mimes ], 'pptx' => [ 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'application/x-zip', - 'application/zip', ], 'wbxml' => 'application/wbxml', 'wmlc' => 'application/wmlc', @@ -512,20 +510,19 @@ public static function guessExtensionFromType(string $type, ?string $proposedExt $proposedExtension = trim(strtolower($proposedExtension ?? '')); - if ($proposedExtension !== '') { - if (array_key_exists($proposedExtension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposedExtension]) ? [static::$mimes[$proposedExtension]] : static::$mimes[$proposedExtension], true)) { - // The detected mime type matches with the proposed extension. - return $proposedExtension; - } - - // An extension was proposed, but the media type does not match the mime type list. - return null; + if ( + $proposedExtension !== '' + && array_key_exists($proposedExtension, static::$mimes) + && in_array($type, (array) static::$mimes[$proposedExtension], true) + ) { + // The detected mime type matches with the proposed extension. + return $proposedExtension; } // Reverse check the mime type list if no extension was proposed. // This search is order sensitive! foreach (static::$mimes as $ext => $types) { - if ((is_string($types) && $types === $type) || (is_array($types) && in_array($type, $types, true))) { + if (in_array($type, (array) $types, true)) { return $ext; } } diff --git a/system/Files/File.php b/system/Files/File.php index b3bdb47b90de..4d4067d4caa5 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -89,7 +89,12 @@ public function getSizeByUnit(string $unit = 'b') */ public function guessExtension(): ?string { - return Mimes::guessExtensionFromType($this->getMimeType()); + // naively get the path extension using pathinfo + $pathinfo = pathinfo($this->getRealPath() ?: $this->__toString()) + ['extension' => '']; + + $proposedExtension = $pathinfo['extension']; + + return Mimes::guessExtensionFromType($this->getMimeType(), $proposedExtension); } /** diff --git a/tests/system/Files/FileTest.php b/tests/system/Files/FileTest.php index 573c8cdb3499..1176bd2e2622 100644 --- a/tests/system/Files/FileTest.php +++ b/tests/system/Files/FileTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Files\Exceptions\FileNotFoundException; use CodeIgniter\Test\CIUnitTestCase; +use ZipArchive; /** * @internal @@ -44,10 +45,34 @@ public function testGuessExtension() { $file = new File(SYSTEMPATH . 'Common.php'); $this->assertSame('php', $file->guessExtension()); + $file = new File(SYSTEMPATH . 'index.html'); $this->assertSame('html', $file->guessExtension()); + $file = new File(ROOTPATH . 'phpunit.xml.dist'); $this->assertSame('xml', $file->guessExtension()); + + $tmp = tempnam(SUPPORTPATH, 'foo'); + $file = new File($tmp, true); + $this->assertNull($file->guessExtension()); + unlink($tmp); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/6046 + */ + public function testGuessExtensionOnZip(): void + { + $tmp = SUPPORTPATH . 'foobar.zip'; + + $zip = new ZipArchive(); + $zip->open($tmp, ZipArchive::CREATE | ZipArchive::CHECKCONS | ZipArchive::EXCL); + $zip->addFile(SYSTEMPATH . 'Common.php'); + $zip->close(); + + $file = new File($tmp, true); + $this->assertSame('zip', $file->guessExtension()); + unlink($tmp); } public function testRandomName() diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 6b3c7533ff96..c870099108cc 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -194,7 +194,7 @@ public function testExtensionGuessing() $this->assertInstanceOf(UploadedFile::class, $file); $this->assertSame('txt', $file->getExtension()); // but not client mime type - $this->assertNull(Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); + $this->assertSame('csv', Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); // proposed extension does not match finfo_open mime type (text/plain) // but can be resolved by reverse searching @@ -208,14 +208,12 @@ public function testExtensionGuessing() $this->assertSame('zip', $file->getExtension()); // proposed extension matches client mime type, but not finfo_open mime type (application/zip) - // this is a zip file (userFile4) but hat been renamed to 'rar' + // this is a zip file (userFile4) but has been renamed to 'rar' $file = $collection->getFile('userfile5'); $this->assertInstanceOf(UploadedFile::class, $file); - // getExtension falls back to clientExtension (insecure) - $this->assertSame('rar', $file->getExtension()); + $this->assertSame('zip', $file->getExtension()); $this->assertSame('rar', Mimes::guessExtensionFromType($file->getClientMimeType(), $file->getClientExtension())); - // guessExtension is secure and does not returns empty - $this->assertSame('', $file->guessExtension()); + $this->assertSame('zip', $file->guessExtension()); } /** diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index a6aefc4cd181..edef0a8e2208 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,6 +12,7 @@ See all the changes. .. toctree:: :titlesonly: + v4.2.1 v4.2.0 v4.1.9 v4.1.8 diff --git a/user_guide_src/source/changelogs/v4.2.1.rst b/user_guide_src/source/changelogs/v4.2.1.rst new file mode 100644 index 000000000000..d591d08cf008 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.2.1.rst @@ -0,0 +1,18 @@ +Version 4.2.1 +############# + +Release Date: Unreleased + +**4.2.1 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 2 + +BREAKING +******** + +Behavior Changes +================ + +- Guessing the file extension from the MIME type has been changed if the proposed extension is not valid. Previously, the guessing will early terminate and return ``null``. Now, if a proposed extension is given and is invalid, the MIME guessing will continue checking using the mapping of extension to MIME types. diff --git a/user_guide_src/source/installation/upgrade_421.rst b/user_guide_src/source/installation/upgrade_421.rst new file mode 100644 index 000000000000..fb5825179c10 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_421.rst @@ -0,0 +1,53 @@ +############################# +Upgrading from 4.2.0 to 4.2.1 +############################# + +Please refer to the upgrade instructions corresponding to your installation method. + +- :ref:`Composer Installation App Starter Upgrading ` +- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` +- :ref:`Manual Installation Upgrading ` + +.. contents:: + :local: + :depth: 2 + +Mandatory File Changes +********************** + +app/Config/Mimes.php +=================== + +- The mapping of file extensions to MIME types in **app/Config/Mimes.php** was updated to fix a bug. Also, the logic of ``Mimes::getExtensionFromType()`` was changed. + +Breaking Changes +**************** + + +Breaking Enhancements +********************* + + +Project Files +************* + +Numerous 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 `_. + +.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space + will break your application. All changes noted here are optional until the next major version, + and any mandatory changes will be covered in the sections above. + +Content Changes +=============== + + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +* app/Config/Mimes.php diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index aa79ef0d6bc7..3570419e19c2 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -12,6 +12,7 @@ upgrading from. .. toctree:: :titlesonly: + upgrade_421 upgrade_420 upgrade_418 upgrade_417 From 6ae194b0d836b803188ae218bcc13c3389a47ffe Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 7 Jun 2022 23:18:45 +0800 Subject: [PATCH 21/78] Remove renumerate script in file list to lint --- .php-cs-fixer.dist.php | 1 - 1 file changed, 1 deletion(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 02c6549b2c03..a0502a6d9cae 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -33,7 +33,6 @@ __DIR__ . '/.php-cs-fixer.user-guide.php', __DIR__ . '/rector.php', __DIR__ . '/spark', - __DIR__ . '/user_guide_src/renumerate.php', ]); $overrides = []; From 29272afc919c2c9e5f72f5996a0b5cef7d2cae8f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 7 Jun 2022 23:28:20 +0800 Subject: [PATCH 22/78] Remove useless catch --- system/Cache/Handlers/MemcachedHandler.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index f240a5d08de2..b317652dd99e 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -115,8 +115,6 @@ public function initialize() } else { throw new CriticalError('Cache: Not support Memcache(d) extension.'); } - } catch (CriticalError $e) { - throw $e; } catch (Exception $e) { throw new CriticalError('Cache: Memcache(d) connection refused (' . $e->getMessage() . ').'); } From a04ba620e6fe1ec9b7161619f64b89302d49f20c Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Jun 2022 06:31:57 +0900 Subject: [PATCH 23/78] chore: update workflow for 4.3 branch --- .github/workflows/test-deptrac.yml | 4 ++-- .github/workflows/test-phpcpd.yml | 4 ++-- .github/workflows/test-phpstan.yml | 4 ++-- .github/workflows/test-phpunit.yml | 3 ++- .github/workflows/test-rector.yml | 4 ++-- .github/workflows/test-scss.yml | 4 ++-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml index 42b77998325c..ff8551aa9500 100644 --- a/.github/workflows/test-deptrac.yml +++ b/.github/workflows/test-deptrac.yml @@ -6,7 +6,7 @@ on: pull_request: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' @@ -16,7 +16,7 @@ on: push: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index e4d869c09d4a..967e49d9ad46 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -6,7 +6,7 @@ on: pull_request: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'public/**.php' @@ -16,7 +16,7 @@ on: push: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'public/**.php' diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index 805e34edcdde..d723983d6d46 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -6,7 +6,7 @@ on: pull_request: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' @@ -18,7 +18,7 @@ on: push: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 9b7850ea03d5..7a7b72513070 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -4,6 +4,7 @@ on: push: branches: - develop + - '4.*' paths: - 'app/**.php' - 'system/**.php' @@ -16,7 +17,7 @@ on: pull_request: branches: - develop - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml index f98d759f6edb..b9917c01e62b 100644 --- a/.github/workflows/test-rector.yml +++ b/.github/workflows/test-rector.yml @@ -6,7 +6,7 @@ on: pull_request: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' @@ -18,7 +18,7 @@ on: push: branches: - 'develop' - - 'v4.*' + - '4.*' paths: - 'app/**.php' - 'system/**.php' diff --git a/.github/workflows/test-scss.yml b/.github/workflows/test-scss.yml index 0d335a29552a..3517a4f26500 100644 --- a/.github/workflows/test-scss.yml +++ b/.github/workflows/test-scss.yml @@ -4,7 +4,7 @@ on: pull_request: branches: - 'develop' - - 'v4.x' + - '4.*' paths: - '**.scss' - '**.css' @@ -13,7 +13,7 @@ on: push: branches: - 'develop' - - 'v4.x' + - '4.*' paths: - '**.scss' - '**.css' From eadd0958e1a68210f4f96825377d26aef4ff04c1 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 7 Jun 2022 23:21:55 -0500 Subject: [PATCH 24/78] Restore old ViewDecoratorTrait --- system/View/ViewDecoratorTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/View/ViewDecoratorTrait.php b/system/View/ViewDecoratorTrait.php index d1982fc12295..243c229bfbde 100644 --- a/system/View/ViewDecoratorTrait.php +++ b/system/View/ViewDecoratorTrait.php @@ -24,7 +24,7 @@ protected function decorateOutput(string $html): string $decorators = \config('View')->decorators; foreach ($decorators as $decorator) { - if (! in_array(ViewDecoratorInterface::class, class_implements($decorator), true)) { + if (! is_subclass_of($decorator, ViewDecoratorInterface::class)) { throw ViewException::forInvalidDecorator($decorator); } From f457affe475dd424e65f30d3cad914b94fb89c1a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Jun 2022 17:12:15 +0900 Subject: [PATCH 25/78] fix: spark routes shows "ERROR: 404" By adding the method Home::getTest, the command php spark routes gives the result: ERROR: 404 Cannot access the default controller "Home" with the controller name URI path. --- .../Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index 0df2e6bff490..e7597014f899 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -65,7 +65,7 @@ public function get(): array foreach ($finder->find() as $class) { // Exclude controllers in Defined Routes. - if (in_array($class, $this->protectedControllers, true)) { + if (in_array('\\' . $class, $this->protectedControllers, true)) { continue; } From 5de6cf585ba8996da01cbbaef4f7c4e0a8740012 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Jun 2022 17:46:15 +0900 Subject: [PATCH 26/78] style: compile sass --- system/Debug/Toolbar/Views/toolbar.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 11a3301a954c..4cb379cbb4cc 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -303,7 +303,6 @@ #debug-bar .ci-label img { margin: unset; } - .hide-sm { display: none !important; } @@ -432,7 +431,6 @@ #debug-icon a:visited { color: #DD8615; } - #debug-bar { background-color: #252525; color: #DFDFDF; @@ -526,11 +524,9 @@ #debug-bar .timeline .timer { background-color: #DD8615; } - .debug-view.show-view { border-color: #DD8615; } - .debug-view-path { background-color: #FDC894; color: #434343; From 4174a868dc74d6a012657b29c54b80cadcaa064d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 15:03:20 +0000 Subject: [PATCH 27/78] chore(deps-dev): update predis/predis requirement from ^1.1 to ^2.0 Updates the requirements on predis/predis to permit the latest version. --- updated-dependencies: - dependency-name: predis/predis 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 7271a5aa6c02..676d57dd63cf 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "nexusphp/tachycardia": "^1.0", "phpstan/phpstan": "^1.7.1", "phpunit/phpunit": "^9.1", - "predis/predis": "^1.1", + "predis/predis": "^2.0", "rector/rector": "0.13.4" }, "suggest": { From 359c26c85cbd998aaa02339ad0a7d086e1d97e21 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Jun 2022 16:40:35 +0900 Subject: [PATCH 28/78] docs: add highlights for v4.2.0 --- user_guide_src/source/changelogs/v4.2.0.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 1d0cf70f6795..a75f74d99fcb 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -9,6 +9,14 @@ Release Date: June 3, 2022 :local: :depth: 2 +Highlights +********** + +- Update minimal PHP requirement to 7.4. +- **OCI8 Driver for Oracle Database** (*contributed by* `ytetsuro `_). See `Database`_. +- **Improved Auto Routing** (opt-in) (*contributed by* `kenjis `_). See `New Improved Auto Routing`_. +- Query Builder **Subqueries** and **UNION** support (*contributed by* `Andrey Pyzhikov `_). See `Database`_. + BREAKING ******** From 1cf8a1813af6b11d07ec837871f7751a5e8eafc2 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Jun 2022 18:30:18 +0800 Subject: [PATCH 29/78] Fix too short title underline --- user_guide_src/source/installation/upgrade_421.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_421.rst b/user_guide_src/source/installation/upgrade_421.rst index fb5825179c10..9359d8ecc796 100644 --- a/user_guide_src/source/installation/upgrade_421.rst +++ b/user_guide_src/source/installation/upgrade_421.rst @@ -16,7 +16,7 @@ Mandatory File Changes ********************** app/Config/Mimes.php -=================== +==================== - The mapping of file extensions to MIME types in **app/Config/Mimes.php** was updated to fix a bug. Also, the logic of ``Mimes::getExtensionFromType()`` was changed. From d7aa1b480eb3a3b360b04083f89feadb438bb61c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Jun 2022 19:49:10 +0900 Subject: [PATCH 30/78] docs: add New Contributors --- user_guide_src/source/changelogs/v4.2.0.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index a75f74d99fcb..fc4088e715a8 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -17,6 +17,20 @@ Highlights - **Improved Auto Routing** (opt-in) (*contributed by* `kenjis `_). See `New Improved Auto Routing`_. - Query Builder **Subqueries** and **UNION** support (*contributed by* `Andrey Pyzhikov `_). See `Database`_. +New Contributors +================ + +* `@fdomgjoni99 `_ made their first contribution in `#5608 `_ +* `@Nudasoft `_ made their first contribution in `#5715 `_ +* `@beganovich `_ made their first contribution in `#5823 `_ +* `@tcgumus `_ made their first contribution in `#5851 `_ +* `@michaelrk02 `_ made their first contribution in `#5878 `_ +* `@datamweb `_ made their first contribution in `#5894 `_ +* `@xlii-chl `_ made their first contribution in `#5884 `_ +* `@valmorflores `_ made their first contribution in `#6051 `_ +* `@tearoom6 `_ made their first contribution in `#6012 `_ +* `@lonnie-vault `_ made their first contribution in `#6060 `_ + BREAKING ******** From c1dceda717cdd60fdf904120ad68f51cea2d142e Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Jun 2022 20:20:38 +0800 Subject: [PATCH 31/78] Update predis to v2.0 in framework --- admin/framework/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/framework/composer.json b/admin/framework/composer.json index 03d3965770ba..015029a28b38 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -21,7 +21,7 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "phpunit/phpunit": "^9.1", - "predis/predis": "^1.1" + "predis/predis": "^2.0" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From f191dfd4cf374f20b6abc05cd53ba5906fde02ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 15:02:55 +0000 Subject: [PATCH 32/78] chore(deps-dev): update rector/rector requirement from 0.13.4 to 0.13.5 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.13.4...0.13.5) --- 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 7271a5aa6c02..fcbca36a4730 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.7.1", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.13.4" + "rector/rector": "0.13.5" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From a4fbe4b95d88e648887c0670a3be8ddea5e51b4a Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 10 Jun 2022 05:39:31 +0700 Subject: [PATCH 33/78] re-run rector on rector 0.13.5 --- system/Email/Email.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/system/Email/Email.php b/system/Email/Email.php index 966c08e6f830..753dfe7d2bf7 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -1046,10 +1046,8 @@ public function wordWrap($str, $charlim = null) $output .= $line . $this->newline; } - if ($unwrap) { - foreach ($unwrap as $key => $val) { - $output = str_replace('{{unwrapped' . $key . '}}', $val, $output); - } + foreach ($unwrap as $key => $val) { + $output = str_replace('{{unwrapped' . $key . '}}', $val, $output); } return $output; From a1859601e0b264c61f41d62fc939bf80e18187f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 10:16:59 +0900 Subject: [PATCH 34/78] fix: reverse routing does not work with full classname starting with `\` E.g., url_to('\App\Controllers\backend\Dashboard::index') --- system/Router/RouteCollection.php | 2 +- tests/system/Router/RouteCollectionTest.php | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 35fe41928751..4998a16c9ba6 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1008,7 +1008,7 @@ public function reverseRoute(string $search, ...$params) $namespace = trim($this->defaultNamespace, '\\') . '\\'; if ( substr($search, 0, 1) !== '\\' - || substr($search, 0, strlen($namespace)) !== $namespace + && substr($search, 0, strlen($namespace)) !== $namespace ) { $search = $namespace . $search; } diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 0e6ddbf8a185..22533e77e173 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -15,6 +15,7 @@ use CodeIgniter\Router\Exceptions\RouterException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; +use Generator; use Tests\Support\Controllers\Hello; /** @@ -855,14 +856,26 @@ public function testReverseRoutingWithLocale() $this->assertSame('/en/contact', $routes->reverseRoute('myController::goto')); } - public function testReverseRoutingDefaultNamespaceAppController() + public function reverseRoutingHandlerProvider(): Generator + { + return yield from [ + 'Omit namespace' => ['Galleries::showUserGallery'], + 'Specify full ns starting with /' => ['\App\Controllers\Galleries::showUserGallery'], + 'Specify full ns w/o staring /' => ['App\Controllers\Galleries::showUserGallery'], + ]; + } + + /** + * @dataProvider reverseRoutingHandlerProvider + */ + public function testReverseRoutingDefaultNamespaceAppController(string $controller) { $routes = $this->getCollector(); $routes->setDefaultNamespace('App\Controllers'); $routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2'); - $match = $routes->reverseRoute('Galleries::showUserGallery', 15, 12); + $match = $routes->reverseRoute($controller, 15, 12); $this->assertSame('/users/15/gallery12', $match); } From b2df4f7f0087f37c14c537fd2da35dc5da69fcfc Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 10:33:06 +0900 Subject: [PATCH 35/78] test: split big TestCase class --- .../RouteCollectionReverseRouteTest.php | 194 ++++++++++++++++++ tests/system/Router/RouteCollectionTest.php | 144 ------------- 2 files changed, 194 insertions(+), 144 deletions(-) create mode 100644 tests/system/Router/RouteCollectionReverseRouteTest.php diff --git a/tests/system/Router/RouteCollectionReverseRouteTest.php b/tests/system/Router/RouteCollectionReverseRouteTest.php new file mode 100644 index 000000000000..c9a32c096574 --- /dev/null +++ b/tests/system/Router/RouteCollectionReverseRouteTest.php @@ -0,0 +1,194 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Router; + +use CodeIgniter\Config\Services; +use CodeIgniter\Router\Exceptions\RouterException; +use CodeIgniter\Test\CIUnitTestCase; +use Config\Modules; +use Generator; + +/** + * @internal + */ +final class RouteCollectionReverseRouteTest extends CIUnitTestCase +{ + protected function setUp(): void + { + parent::setUp(); + + $this->resetServices(true); + $this->resetFactories(); + } + + protected function getCollector(array $config = [], array $files = [], $moduleConfig = null) + { + $defaults = [ + 'Config' => APPPATH . 'Config', + 'App' => APPPATH, + ]; + $config = array_merge($config, $defaults); + + Services::autoloader()->addNamespace($config); + + $loader = Services::locator(); + + if ($moduleConfig === null) { + $moduleConfig = new Modules(); + $moduleConfig->enabled = false; + } + + return (new RouteCollection($loader, $moduleConfig))->setHTTPVerb('get'); + } + + public function testReverseRoutingFindsSimpleMatch() + { + $routes = $this->getCollector(); + + $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); + + $match = $routes->reverseRoute('myController::goto', 'string', 13); + + $this->assertSame('/path/string/to/13', $match); + } + + public function testReverseRoutingWithLocaleAndFindsSimpleMatch() + { + $routes = $this->getCollector(); + + $routes->add('{locale}/path/(:any)/to/(:num)', 'myController::goto/$1/$2'); + + $match = $routes->reverseRoute('myController::goto', 'string', 13); + + $this->assertSame('/en/path/string/to/13', $match); + } + + public function testReverseRoutingReturnsFalseWithBadParamCount() + { + $routes = $this->getCollector(); + + $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1'); + + $this->assertFalse($routes->reverseRoute('myController::goto', 'string', 13)); + } + + public function testReverseRoutingReturnsFalseWithNoMatch() + { + $routes = $this->getCollector(); + + $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); + + $this->assertFalse($routes->reverseRoute('myBadController::goto', 'string', 13)); + } + + public function testReverseRoutingThrowsExceptionWithBadParamTypes() + { + $routes = $this->getCollector(); + + $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); + + $this->expectException(RouterException::class); + $routes->reverseRoute('myController::goto', 13, 'string'); + } + + public function testReverseRoutingWithLocale() + { + $routes = $this->getCollector(); + + $routes->add('{locale}/contact', 'myController::goto'); + + $this->assertSame('/en/contact', $routes->reverseRoute('myController::goto')); + } + + public function reverseRoutingHandlerProvider(): Generator + { + return yield from [ + 'Omit namespace' => ['Galleries::showUserGallery'], + 'Specify full ns starting with /' => ['\App\Controllers\Galleries::showUserGallery'], + 'Specify full ns w/o staring /' => ['App\Controllers\Galleries::showUserGallery'], + ]; + } + + /** + * @dataProvider reverseRoutingHandlerProvider + */ + public function testReverseRoutingDefaultNamespaceAppController(string $controller) + { + $routes = $this->getCollector(); + $routes->setDefaultNamespace('App\Controllers'); + + $routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2'); + + $match = $routes->reverseRoute($controller, 15, 12); + + $this->assertSame('/users/15/gallery12', $match); + } + + public function testReverseRoutingDefaultNamespaceAppControllerSubNamespace() + { + $routes = $this->getCollector(); + $routes->setDefaultNamespace('App\Controllers'); + + $routes->get('admin/(:num)/gallery(:any)', 'Admin\Galleries::showUserGallery/$1/$2'); + + $match = $routes->reverseRoute('Admin\Galleries::showUserGallery', 15, 12); + + $this->assertSame('/admin/15/gallery12', $match); + } + + public function testReverseRouteMatching() + { + $routes = $this->getCollector(); + + $routes->get('test/(:segment)/(:segment)', 'TestController::test/$1/$2', ['as' => 'testRouter']); + + $match = $routes->reverseRoute('testRouter', 1, 2); + + $this->assertSame('/test/1/2', $match); + } + + public function testReverseRouteMatchingWithLocale() + { + $routes = $this->getCollector(); + + $routes->get('{locale}/test/(:segment)/(:segment)', 'TestController::test/$1/$2', ['as' => 'testRouter']); + + $match = $routes->reverseRoute('testRouter', 1, 2); + + $this->assertSame('/en/test/1/2', $match); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/568 + */ + public function testReverseRoutingWithClosure() + { + $routes = $this->getCollector(); + + $routes->add('login', static function () { + }); + + $match = $routes->reverseRoute('login'); + + $this->assertSame('/login', $match); + } + + public function testReverseRoutingWithClosureNoMatch() + { + $routes = $this->getCollector(); + + $routes->add('login', static function () { + }); + + $this->assertFalse($routes->reverseRoute('foobar')); + } +} diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 22533e77e173..f367a203473e 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -12,10 +12,8 @@ namespace CodeIgniter\Router; use CodeIgniter\Config\Services; -use CodeIgniter\Router\Exceptions\RouterException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; -use Generator; use Tests\Support\Controllers\Hello; /** @@ -797,101 +795,6 @@ static function ($routes) { $this->assertSame($expected, $routes->getRoutes()); } - public function testReverseRoutingFindsSimpleMatch() - { - $routes = $this->getCollector(); - - $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); - - $match = $routes->reverseRoute('myController::goto', 'string', 13); - - $this->assertSame('/path/string/to/13', $match); - } - - public function testReverseRoutingWithLocaleAndFindsSimpleMatch() - { - $routes = $this->getCollector(); - - $routes->add('{locale}/path/(:any)/to/(:num)', 'myController::goto/$1/$2'); - - $match = $routes->reverseRoute('myController::goto', 'string', 13); - - $this->assertSame('/en/path/string/to/13', $match); - } - - public function testReverseRoutingReturnsFalseWithBadParamCount() - { - $routes = $this->getCollector(); - - $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1'); - - $this->assertFalse($routes->reverseRoute('myController::goto', 'string', 13)); - } - - public function testReverseRoutingReturnsFalseWithNoMatch() - { - $routes = $this->getCollector(); - - $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); - - $this->assertFalse($routes->reverseRoute('myBadController::goto', 'string', 13)); - } - - public function testReverseRoutingThrowsExceptionWithBadParamTypes() - { - $routes = $this->getCollector(); - - $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2'); - - $this->expectException(RouterException::class); - $routes->reverseRoute('myController::goto', 13, 'string'); - } - - public function testReverseRoutingWithLocale() - { - $routes = $this->getCollector(); - - $routes->add('{locale}/contact', 'myController::goto'); - - $this->assertSame('/en/contact', $routes->reverseRoute('myController::goto')); - } - - public function reverseRoutingHandlerProvider(): Generator - { - return yield from [ - 'Omit namespace' => ['Galleries::showUserGallery'], - 'Specify full ns starting with /' => ['\App\Controllers\Galleries::showUserGallery'], - 'Specify full ns w/o staring /' => ['App\Controllers\Galleries::showUserGallery'], - ]; - } - - /** - * @dataProvider reverseRoutingHandlerProvider - */ - public function testReverseRoutingDefaultNamespaceAppController(string $controller) - { - $routes = $this->getCollector(); - $routes->setDefaultNamespace('App\Controllers'); - - $routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2'); - - $match = $routes->reverseRoute($controller, 15, 12); - - $this->assertSame('/users/15/gallery12', $match); - } - - public function testReverseRoutingDefaultNamespaceAppControllerSubNamespace() - { - $routes = $this->getCollector(); - $routes->setDefaultNamespace('App\Controllers'); - - $routes->get('admin/(:num)/gallery(:any)', 'Admin\Galleries::showUserGallery/$1/$2'); - - $match = $routes->reverseRoute('Admin\Galleries::showUserGallery', 15, 12); - - $this->assertSame('/admin/15/gallery12', $match); - } - public function testNamedRoutes() { $routes = $this->getCollector(); @@ -1003,28 +906,6 @@ public function testNamedRoutesWithPipesInRegex() $this->assertSame('/system/that', $routes->reverseRoute('pipedRoute', 'that')); } - public function testReverseRouteMatching() - { - $routes = $this->getCollector(); - - $routes->get('test/(:segment)/(:segment)', 'TestController::test/$1/$2', ['as' => 'testRouter']); - - $match = $routes->reverseRoute('testRouter', 1, 2); - - $this->assertSame('/test/1/2', $match); - } - - public function testReverseRouteMatchingWithLocale() - { - $routes = $this->getCollector(); - - $routes->get('{locale}/test/(:segment)/(:segment)', 'TestController::test/$1/$2', ['as' => 'testRouter']); - - $match = $routes->reverseRoute('testRouter', 1, 2); - - $this->assertSame('/en/test/1/2', $match); - } - public function testAddRedirect() { $routes = $this->getCollector(); @@ -1205,31 +1086,6 @@ public function testWithSubdomainOrdered() $this->assertSame($expects, $routes->getRoutes()); } - /** - * @see https://github.com/codeigniter4/CodeIgniter4/issues/568 - */ - public function testReverseRoutingWithClosure() - { - $routes = $this->getCollector(); - - $routes->add('login', static function () { - }); - - $match = $routes->reverseRoute('login'); - - $this->assertSame('/login', $match); - } - - public function testReverseRoutingWithClosureNoMatch() - { - $routes = $this->getCollector(); - - $routes->add('login', static function () { - }); - - $this->assertFalse($routes->reverseRoute('foobar')); - } - public function testWillDiscoverLocal() { $config = ['SampleSpace' => TESTPATH . '_support']; From 0720d83b07013de8e1ae84462fd8fcf99fe3afac Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 17:08:11 +0900 Subject: [PATCH 36/78] fix: get_cookie() may not use cookie prefix --- system/Helpers/cookie_helper.php | 20 +++++++----- tests/system/Helpers/CookieHelperTest.php | 37 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 4f3eb9a9140f..96a8bb3c998a 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -56,21 +56,25 @@ function set_cookie( /** * Fetch an item from the $_COOKIE array * - * @param string $index + * @param string $index + * @param string|null $prefix Cookie prefix. + * '': the prefix in Config\Cookie + * null: no prefix * - * @return mixed + * @return array|string|null * * @see \CodeIgniter\HTTP\IncomingRequest::getCookie() */ - function get_cookie($index, bool $xssClean = false) + function get_cookie($index, bool $xssClean = false, ?string $prefix = '') { - /** @var Cookie|null $cookie */ - $cookie = config('Cookie'); + if ($prefix === '') { + /** @var Cookie|null $cookie */ + $cookie = config('Cookie'); - // @TODO Remove Config\App fallback when deprecated `App` members are removed. - $cookiePrefix = $cookie instanceof Cookie ? $cookie->prefix : config(App::class)->cookiePrefix; + // @TODO Remove Config\App fallback when deprecated `App` members are removed. + $prefix = $cookie instanceof Cookie ? $cookie->prefix : config(App::class)->cookiePrefix; + } - $prefix = isset($_COOKIE[$index]) ? '' : $cookiePrefix; $request = Services::request(); $filter = $xssClean ? FILTER_SANITIZE_FULL_SPECIAL_CHARS : FILTER_DEFAULT; diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index 2b09aa2afb3a..e9a208bd03a1 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Helpers; +use CodeIgniter\Config\Factories; use CodeIgniter\Cookie\Exceptions\CookieException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; @@ -19,6 +20,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockResponse; use Config\App; +use Config\Cookie as CookieConfig; use Config\Services; /** @@ -33,6 +35,8 @@ final class CookieHelperTest extends CIUnitTestCase protected function setUp(): void { + $_COOKIE = []; + parent::setUp(); $this->name = 'greetings'; @@ -123,6 +127,39 @@ public function testGetCookie() $this->assertSame('5', get_cookie('TEST')); } + public function testGetCookieDefaultPrefix() + { + $_COOKIE['prefix_TEST'] = '5'; + + $config = new CookieConfig(); + $config->prefix = 'prefix_'; + Factories::injectMock('config', CookieConfig::class, $config); + + $this->assertSame('5', get_cookie('TEST', false, '')); + } + + public function testGetCookiePrefix() + { + $_COOKIE['abc_TEST'] = '5'; + + $config = new CookieConfig(); + $config->prefix = 'prefix_'; + Factories::injectMock('config', CookieConfig::class, $config); + + $this->assertSame('5', get_cookie('TEST', false, 'abc_')); + } + + public function testGetCookieNoPrefix() + { + $_COOKIE['abc_TEST'] = '5'; + + $config = new CookieConfig(); + $config->prefix = 'prefix_'; + Factories::injectMock('config', CookieConfig::class, $config); + + $this->assertSame('5', get_cookie('abc_TEST', false, null)); + } + public function testDeleteCookieAfterLastSet() { delete_cookie($this->name); From e23f9402674324e637620dc33f695c727e44030a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Jun 2022 17:19:02 +0900 Subject: [PATCH 37/78] test: fix $_COOKIE value It should be a string. --- tests/system/Helpers/CookieHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index e9a208bd03a1..640a43cb3551 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -122,7 +122,7 @@ public function testDeleteCookie() public function testGetCookie() { - $_COOKIE['TEST'] = 5; + $_COOKIE['TEST'] = '5'; $this->assertSame('5', get_cookie('TEST')); } From a09683de94b8913b93ca8808a1aee91f2efdf608 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Jun 2022 15:20:36 +0900 Subject: [PATCH 38/78] docs: fix doc comment --- system/Helpers/cookie_helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 96a8bb3c998a..5537de9c3899 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -57,7 +57,7 @@ function set_cookie( * Fetch an item from the $_COOKIE array * * @param string $index - * @param string|null $prefix Cookie prefix. + * @param string|null $prefix Cookie name prefix. * '': the prefix in Config\Cookie * null: no prefix * From 4d3e4c2c22dd9ce56edfedd629039c797a059ce6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 11:28:11 +0900 Subject: [PATCH 39/78] docs: add documentation --- user_guide_src/source/changelogs/v4.2.1.rst | 1 + .../source/helpers/cookie_helper.rst | 7 ++-- .../source/installation/upgrade_421.rst | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.2.1.rst b/user_guide_src/source/changelogs/v4.2.1.rst index d591d08cf008..fddd5ca08f7d 100644 --- a/user_guide_src/source/changelogs/v4.2.1.rst +++ b/user_guide_src/source/changelogs/v4.2.1.rst @@ -16,3 +16,4 @@ Behavior Changes ================ - Guessing the file extension from the MIME type has been changed if the proposed extension is not valid. Previously, the guessing will early terminate and return ``null``. Now, if a proposed extension is given and is invalid, the MIME guessing will continue checking using the mapping of extension to MIME types. +- If there is a cookie with a prefixed name and a cookie with the same name without a prefix, the previous ``get_cookie()`` had the tricky behavior of returning the cookie without the prefix. Now the behavior has been fixed as a bug, and has been changed. See :ref:`Upgrading ` for details. diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 5976c48ea99a..b3328c3dc466 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -39,13 +39,16 @@ The following functions are available: a description of its use, as this function is an alias for :php:func:`Response::setCookie() `. -.. php:function:: get_cookie($index[, $xssClean = false]) +.. php:function:: get_cookie($index[, $xssClean = false[, $prefix = '']]) :param string $index: Cookie name :param bool $xssClean: Whether to apply XSS filtering to the returned value + :param string|null $prefix: Cookie name prefix. If set to ``''``, the default value from **app/Config/Cookie.php** will be used. If set to ``null``, no prefix :returns: The cookie value or null if not found :rtype: mixed + .. note:: Since v4.2.1, the third parameter ``$prefix`` has been introduced and the behavior has been changed a bit due to a bug fix. See :ref:`Upgrading ` for details. + This helper function gives you friendlier syntax to get browser cookies. Refer to the :doc:`IncomingRequest Library ` for detailed description of its use, as this function acts very @@ -53,7 +56,7 @@ The following functions are available: the ``Config\Cookie::$prefix`` that you might've set in your **app/Config/Cookie.php** file. -.. warning:: Using XSS filtering is a bad practice. It does not prevent XSS attacks perfectly. Using ``esc()`` with the correct ``$context`` in the views is recommended. + .. warning:: Using XSS filtering is a bad practice. It does not prevent XSS attacks perfectly. Using ``esc()`` with the correct ``$context`` in the views is recommended. .. php:function:: delete_cookie($name[, $domain = ''[, $path = '/'[, $prefix = '']]]) diff --git a/user_guide_src/source/installation/upgrade_421.rst b/user_guide_src/source/installation/upgrade_421.rst index 9359d8ecc796..6b3b0f7cb995 100644 --- a/user_guide_src/source/installation/upgrade_421.rst +++ b/user_guide_src/source/installation/upgrade_421.rst @@ -23,6 +23,41 @@ app/Config/Mimes.php Breaking Changes **************** +.. _upgrade-421-get_cookie: + +get_cookie() +============ + +If there is a cookie with a prefixed name and a cookie with the same name without a prefix, the previous ``get_cookie()`` had the tricky behavior of returning the cookie without the prefix. + +For example, when ``Config\Cookie::$prefix`` is ``prefix_``, there are two cookies, ``test`` and ``prefix_test``: + +.. code-block:: php + + $_COOKIES = [ + 'test' => 'Non CI Cookie', + 'prefix_test' => 'CI Cookie', + ]; + +Previously, ``get_cookie()`` returns the following: + +.. code-block:: php + + get_cookie('test'); // returns "Non CI Cookie" + get_cookie('prefix_test'); // returns "CI Cookie" + +Now the behavior has been fixed as a bug, and has been changed like the following. + +.. code-block:: php + + get_cookie('test'); // returns "CI Cookie" + get_cookie('prefix_test'); // returns null + get_cookie('test', false, null); // returns "Non CI Cookie" + +If you depend on the previous behavior, you need to change your code. + +.. note:: In the example above, if there is only one cookie ``prefix_test``, + the previous ``get_cookie('test')`` also returns ``"CI Cookie"``. Breaking Enhancements ********************* From 8aa14d7af98b1addc35243aae8f21adcc5cd1e9e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 17:57:52 +0900 Subject: [PATCH 40/78] docs: update branch model --- contributing/pull_request.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index 51f976232987..58a4a92659ca 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -154,8 +154,9 @@ working on your contribution. ### Branching -CodeIgniter4 uses the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model -which requires all Pull Requests to be sent to the __"develop"__ branch; this is where the next planned version will be developed. +All bug fixes should be sent to the __"develop"__ branch, this is where the next bug fix version will be developed. + +PRs with any enhancement should be sent to __"4.3"__ branch, this is where the next minor upgrade version will be developed. The __"master"__ branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g. an emergency security patch) can be applied to the "master" branch to create a new version, without worrying From f3798495c1284b1bd26ae888acfb2efe37330fe8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 17:58:19 +0900 Subject: [PATCH 41/78] docs: remove spaces at the end of line --- contributing/pull_request.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index 58a4a92659ca..48ec9a261471 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -18,8 +18,8 @@ The [Open Source Guide](https://opensource.guide/) is a good first read for thos ## CodeIgniter Internals Overview -[CodeIgniter Internals Overview](./internals.md) should help contributors -understand how the core of the framework works. Specifically, it details the +[CodeIgniter Internals Overview](./internals.md) should help contributors +understand how the core of the framework works. Specifically, it details the information needed to create new packages for the core. ## Guidelines @@ -27,7 +27,7 @@ information needed to create new packages for the core. Before we look into how to contribute to CodeIgniter4, here are some guidelines. Your Pull Requests (PRs) need to meet our guidelines. -If your Pull Requests fail to pass these guidelines, they will be declined, +If your Pull Requests fail to pass these guidelines, they will be declined, and you will need to re-submit when you’ve made the changes. This might sound a bit tough, but it is required for us to maintain the quality of the codebase. @@ -38,7 +38,7 @@ This might sound a bit tough, but it is required for us to maintain the quality All code must conform to our [Style Guide](./styleguide.md), which is based on PSR-12. -This makes certain that all submitted code is of the same format +This makes certain that all submitted code is of the same format as the existing code and ensures that the codebase will be as readable as possible. You can fix most of the coding style violations by running this command in your terminal: @@ -63,7 +63,7 @@ class would test the `Banana` class. There will be occasions when it is more convenient to have separate classes to test different functionality of a single CodeIgniter component. -See [Running System Tests](../tests/README.md) +See [Running System Tests](../tests/README.md) and the [PHPUnit website](https://phpunit.de/) for more information. ### Comments @@ -92,11 +92,11 @@ Each framework component or group of components needs a corresponding section in the User Guide. Some of the more fundamental components will show up in more than one place. -If you change anything that requires a change to documentation, -then you will need to add to the documentation. -New classes, methods, parameters, changing default values, etc. -are all changes that require a change to documentation. -Also, the [changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html) must be updated for every change, +If you change anything that requires a change to documentation, +then you will need to add to the documentation. +New classes, methods, parameters, changing default values, etc. +are all changes that require a change to documentation. +Also, the [changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html) must be updated for every change, and [PHPDoc](https://github.com/codeigniter4/CodeIgniter4/blob/develop/phpdoc.dist.xml) blocks must be maintained. See [Writing CodeIgniter Documentation](./documentation.rst). From f6cb0477f940194de426f2eb15ad3f6ab4c3214c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 18:00:27 +0900 Subject: [PATCH 42/78] docs: update command example style --- contributing/pull_request.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index 48ec9a261471..a4a3ee89e740 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -43,11 +43,15 @@ as the existing code and ensures that the codebase will be as readable as possib You can fix most of the coding style violations by running this command in your terminal: - composer cs-fix +``` +> composer cs-fix +``` You can check the coding style violations: - composer cs +``` +> composer cs +``` ### Unit Testing @@ -194,15 +198,21 @@ so that you can fix whatever errors that pop up with your submission. PHPStan is expected to scan the entire framework by running this command in your terminal: - vendor/bin/phpstan analyse +``` +> vendor/bin/phpstan analyse +``` Rector, on the other hand, can be run on the specific files you modified or added: - vendor/bin/rector process --dry-run path/to/file +``` +> vendor/bin/rector process --dry-run path/to/file +``` If you run it without `--dry-run`, Rector will fix the code: - vendor/bin/rector process path/to/file +``` +> vendor/bin/rector process path/to/file +``` [1]: https://github.com/phpstan/phpstan-src [2]: https://github.com/rector/rector From f33f68fa74382fe74f3d473e9e54e6694d369980 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Jun 2022 18:03:52 +0900 Subject: [PATCH 43/78] chore: update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5b48f145ee3a..83e79e42ab05 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,8 @@ Each pull request should address a single issue and have a meaningful title. +- All bug fixes should be sent to the __"develop"__ branch, this is where the next bug fix version will be developed. +- PRs with any enhancement should be sent to __"4.3"__ branch, this is where the next minor upgrade version will be developed. + **Description** Explain what you have changed, and why. From d2cc6a361acb6b8e843bd28e3ddf65c59baf1503 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Jun 2022 08:11:54 +0900 Subject: [PATCH 44/78] fix: insert error message --- system/Database/BaseBuilder.php | 2 +- tests/system/Database/Builder/InsertTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index ca983691ea0c..2d54b90f6961 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1923,7 +1923,7 @@ protected function validateInsert(): bool { if (empty($this->QBSet)) { if (CI_DEBUG) { - throw new DatabaseException('You must use the "set" method to update an entry.'); + throw new DatabaseException('You must use the "set" method to insert an entry.'); } return false; // @codeCoverageIgnore diff --git a/tests/system/Database/Builder/InsertTest.php b/tests/system/Database/Builder/InsertTest.php index 713e77bd15a7..2e6d3b89650e 100644 --- a/tests/system/Database/Builder/InsertTest.php +++ b/tests/system/Database/Builder/InsertTest.php @@ -64,7 +64,7 @@ public function testThrowsExceptionOnNoValuesSet() $builder = $this->db->table('jobs'); $this->expectException(DatabaseException::class); - $this->expectExceptionMessage('You must use the "set" method to update an entry.'); + $this->expectExceptionMessage('You must use the "set" method to insert an entry.'); $builder->testMode()->insert(null, true); } From 189e3780993d98c0764562de8147d2eae2e9f8c1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Jun 2022 06:41:33 +0900 Subject: [PATCH 45/78] docs: fix by proofreading Co-authored-by: MGatner --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 83e79e42ab05..fa2172c2f309 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,7 @@ Each pull request should address a single issue and have a meaningful title. - All bug fixes should be sent to the __"develop"__ branch, this is where the next bug fix version will be developed. -- PRs with any enhancement should be sent to __"4.3"__ branch, this is where the next minor upgrade version will be developed. +- PRs with any enhancement should be sent to the next minor version branch, e.g. __"4.3"__ **Description** Explain what you have changed, and why. From 850d59a631e3b3d11e0eb2bc89c608f560d93386 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Jun 2022 06:41:40 +0900 Subject: [PATCH 46/78] docs: fix by proofreading Co-authored-by: MGatner --- contributing/pull_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index a4a3ee89e740..6cf29d11e7da 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -160,7 +160,7 @@ working on your contribution. All bug fixes should be sent to the __"develop"__ branch, this is where the next bug fix version will be developed. -PRs with any enhancement should be sent to __"4.3"__ branch, this is where the next minor upgrade version will be developed. +PRs with any enhancement should be sent to next minor version branch, e.g. __"4.3"__ The __"master"__ branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g. an emergency security patch) can be applied to the "master" branch to create a new version, without worrying From 0015abd96fe6ec24daf28a5609fb0c27313878f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Jun 2022 06:47:33 +0900 Subject: [PATCH 47/78] docs: add language identifier `console` to code blocks https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks https://github.com/github/linguist/blob/d7799da826e01acdb8f84694d33116dccaabe9c2/lib/linguist/languages.yml#L6063 --- contributing/pull_request.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index 6cf29d11e7da..eaa0c0f24c5a 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -43,13 +43,13 @@ as the existing code and ensures that the codebase will be as readable as possib You can fix most of the coding style violations by running this command in your terminal: -``` +```console > composer cs-fix ``` You can check the coding style violations: -``` +```console > composer cs ``` @@ -198,19 +198,19 @@ so that you can fix whatever errors that pop up with your submission. PHPStan is expected to scan the entire framework by running this command in your terminal: -``` +```console > vendor/bin/phpstan analyse ``` Rector, on the other hand, can be run on the specific files you modified or added: -``` +```console > vendor/bin/rector process --dry-run path/to/file ``` If you run it without `--dry-run`, Rector will fix the code: -``` +```console > vendor/bin/rector process path/to/file ``` From 418831192f2693a4c18af3fb18764d27e6ab9054 Mon Sep 17 00:00:00 2001 From: ytetsuro Date: Sun, 12 Jun 2022 16:56:53 +0900 Subject: [PATCH 48/78] test: fix lost error message when after testInsertResultFail. --- tests/system/Models/InsertModelTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 2bcc912e3d80..0b5fedb57ea4 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -26,6 +26,12 @@ */ final class InsertModelTest extends LiveModelTestCase { + public function tearDown(): void + { + parent::tearDown(); + $this->setPrivateProperty($this->db, 'DBDebug', true); + } + public function testSetWorksWithInsert(): void { $this->dontSeeInDatabase('user', [ From b1da2b6890e0c5c4b4fe14318092c4f59e5f4e09 Mon Sep 17 00:00:00 2001 From: ytetsuro Date: Sun, 12 Jun 2022 17:07:11 +0900 Subject: [PATCH 49/78] style: fix style. --- tests/system/Models/InsertModelTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 0b5fedb57ea4..19a8c6d8dfb5 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -26,10 +26,10 @@ */ final class InsertModelTest extends LiveModelTestCase { - public function tearDown(): void + protected function tearDown(): void { - parent::tearDown(); - $this->setPrivateProperty($this->db, 'DBDebug', true); + parent::tearDown(); + $this->setPrivateProperty($this->db, 'DBDebug', true); } public function testSetWorksWithInsert(): void From b8486c2381f2aef18775099eb97b13794d899198 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:02:16 +0800 Subject: [PATCH 50/78] Use both predis v1.1 and v2.0 Co-authored-by: MGatner --- admin/framework/composer.json | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/framework/composer.json b/admin/framework/composer.json index 015029a28b38..95ea60802e1c 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -21,7 +21,7 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "phpunit/phpunit": "^9.1", - "predis/predis": "^2.0" + "predis/predis": "^1.1 || ^2.0" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" diff --git a/composer.json b/composer.json index 676d57dd63cf..ff28601b1e68 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "nexusphp/tachycardia": "^1.0", "phpstan/phpstan": "^1.7.1", "phpunit/phpunit": "^9.1", - "predis/predis": "^2.0", + "predis/predis": "^1.1 || ^2.0", "rector/rector": "0.13.4" }, "suggest": { From 05f4768e43c42bc56088ee852eac4dbc156e015b Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 11:19:42 +0900 Subject: [PATCH 51/78] test: add disableDBDebug() and enableDBDebug() --- system/Test/DatabaseTestTrait.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index d15a5fb44480..539627e29189 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -323,4 +323,22 @@ public function seeNumRecords(int $expected, string $table, array $where) $this->assertEquals($expected, $count, 'Wrong number of matching rows in database.'); } + + /** + * Sets $DBDebug to false. + * + * WARNING: this value will persist! take care to roll it back. + */ + protected function disableDBDebug(): void + { + $this->setPrivateProperty($this->db, 'DBDebug', false); + } + + /** + * Sets $DBDebug to true. + */ + protected function enableDBDebug(): void + { + $this->setPrivateProperty($this->db, 'DBDebug', true); + } } From a6d75726593f238c184a4fba5e940d97f22121d7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 11:26:33 +0900 Subject: [PATCH 52/78] test: refactor to use disableDBDebug() and enableDBDebug() --- tests/system/Database/Live/BadQueryTest.php | 19 +++---------------- tests/system/Database/Live/DbDebugTest.php | 7 ++++--- tests/system/Database/Live/DbUtilsTest.php | 21 ++++----------------- tests/system/Models/DeleteModelTest.php | 6 ++++-- tests/system/Models/InsertModelTest.php | 3 ++- tests/system/Models/SaveModelTest.php | 6 ++++-- tests/system/Models/UpdateModelTest.php | 3 ++- 7 files changed, 23 insertions(+), 42 deletions(-) diff --git a/tests/system/Database/Live/BadQueryTest.php b/tests/system/Database/Live/BadQueryTest.php index 7a0c81ff8b2c..195afe04751f 100644 --- a/tests/system/Database/Live/BadQueryTest.php +++ b/tests/system/Database/Live/BadQueryTest.php @@ -27,22 +27,10 @@ final class BadQueryTest extends CIUnitTestCase protected $refresh = true; protected $seed = CITestSeeder::class; - private static $origDebug; - - /** - * This test must run first to store the inital debug value before we tinker with it below - */ - public function testFirst() - { - $this::$origDebug = $this->getPrivateProperty($this->db, 'DBDebug'); - - $this->assertIsBool($this::$origDebug); - } public function testBadQueryDebugTrue() { - // WARNING this value will persist! take care to roll it back. - $this->setPrivateProperty($this->db, 'DBDebug', true); + $this->enableDBDebug(); // expect an exception, class and message varies by DBMS $this->expectException(Exception::class); $this->db->query('SELECT * FROM table_does_not_exist'); @@ -53,12 +41,11 @@ public function testBadQueryDebugTrue() public function testBadQueryDebugFalse() { // WARNING this value will persist! take care to roll it back. - $this->setPrivateProperty($this->db, 'DBDebug', false); + $this->disableDBDebug(); // this throws an exception when DBDebug is true, but it'll return FALSE when DBDebug is false $query = $this->db->query('SELECT * FROM table_does_not_exist'); $this->assertFalse($query); - // restore the DBDebug value in effect when this unit test began - $this->setPrivateProperty($this->db, 'DBDebug', self::$origDebug); + $this->enableDBDebug(); } } diff --git a/tests/system/Database/Live/DbDebugTest.php b/tests/system/Database/Live/DbDebugTest.php index 8caadf5144fe..d2a64b0ee62a 100644 --- a/tests/system/Database/Live/DbDebugTest.php +++ b/tests/system/Database/Live/DbDebugTest.php @@ -27,21 +27,22 @@ final class DbDebugTest extends CIUnitTestCase public function testDBDebugTrue() { - $this->setPrivateProperty($this->db, 'DBDebug', true); + $this->enableDBDebug(); $this->expectException('Exception'); $this->db->simpleQuery('SELECT * FROM db_error'); } public function testDBDebugFalse() { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $result = $this->db->simpleQuery('SELECT * FROM db_error'); $this->assertFalse($result); } protected function tearDown(): void { - $this->setPrivateProperty($this->db, 'DBDebug', true); + $this->enableDBDebug(); parent::tearDown(); } } diff --git a/tests/system/Database/Live/DbUtilsTest.php b/tests/system/Database/Live/DbUtilsTest.php index 964e024b24c9..e95f0118cd5e 100644 --- a/tests/system/Database/Live/DbUtilsTest.php +++ b/tests/system/Database/Live/DbUtilsTest.php @@ -28,17 +28,6 @@ final class DbUtilsTest extends CIUnitTestCase protected $refresh = true; protected $seed = CITestSeeder::class; - private static $origDebug; - - /** - * This test must run first to store the inital debug value before we tinker with it below - */ - public function testFirst() - { - $this::$origDebug = $this->getPrivateProperty($this->db, 'DBDebug'); - - $this->assertIsBool($this::$origDebug); - } public function testUtilsBackup() { @@ -125,8 +114,7 @@ public function testUtilsOptimizeTableFalseOptimizeDatabaseDebugTrue() $util = (new Database())->loadUtils($this->db); $this->setPrivateProperty($util, 'optimizeTable', false); - // set debug to true -- WARNING this change will persist! - $this->setPrivateProperty($this->db, 'DBDebug', true); + $this->enableDBDebug(); $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); @@ -140,14 +128,13 @@ public function testUtilsOptimizeTableFalseOptimizeDatabaseDebugFalse() $util = (new Database())->loadUtils($this->db); $this->setPrivateProperty($util, 'optimizeTable', false); - // set debug to false -- WARNING this change will persist! - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $result = $util->optimizeDatabase(); $this->assertFalse($result); - // restore original value grabbed from testFirst -- WARNING this change will persist! - $this->setPrivateProperty($this->db, 'DBDebug', self::$origDebug); + $this->enableDBDebug(); } public function testUtilsOptimizeTable() diff --git a/tests/system/Models/DeleteModelTest.php b/tests/system/Models/DeleteModelTest.php index 1d25181068d6..8d21fde25226 100644 --- a/tests/system/Models/DeleteModelTest.php +++ b/tests/system/Models/DeleteModelTest.php @@ -34,7 +34,8 @@ public function testDeleteBasics(): void public function testDeleteFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $this->createModel(JobModel::class); $this->seeInDatabase('job', ['name' => 'Developer']); @@ -68,7 +69,8 @@ public function testDeleteWithSoftDeletes(): void public function testDeleteWithSoftDeleteFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $this->createModel(UserModel::class); $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 19a8c6d8dfb5..85bf753d1070 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -147,7 +147,8 @@ public function testInsertResult(): void public function testInsertResultFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $data = [ 'name123' => 'Apprentice', diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index 48b63c14b211..c13212d5620e 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -55,7 +55,8 @@ public function testSaveNewRecordArray(): void public function testSaveNewRecordArrayFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $this->createModel(JobModel::class); $data = [ @@ -84,7 +85,8 @@ public function testSaveUpdateRecordArray(): void public function testSaveUpdateRecordArrayFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $this->createModel(JobModel::class); $data = [ diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 5b6c9ca75972..d8a054f247f5 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -96,7 +96,8 @@ public function testUpdateArray(): void public function testUpdateResultFail(): void { - $this->setPrivateProperty($this->db, 'DBDebug', false); + // WARNING this value will persist! take care to roll it back. + $this->disableDBDebug(); $data = [ 'name' => 'Foo', From 9e1de18f5926884648ad317fb801d54020e09bdf Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 11:27:54 +0900 Subject: [PATCH 53/78] test: add missing $this->enableDBDebug() --- tests/system/Models/DeleteModelTest.php | 4 ++++ tests/system/Models/InsertModelTest.php | 8 ++------ tests/system/Models/SaveModelTest.php | 4 ++++ tests/system/Models/UpdateModelTest.php | 2 ++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/system/Models/DeleteModelTest.php b/tests/system/Models/DeleteModelTest.php index 8d21fde25226..56c548d0ba2f 100644 --- a/tests/system/Models/DeleteModelTest.php +++ b/tests/system/Models/DeleteModelTest.php @@ -42,6 +42,8 @@ public function testDeleteFail(): void $result = $this->model->where('name123', 'Developer')->delete(); $this->assertFalse($result); $this->seeInDatabase('job', ['name' => 'Developer']); + + $this->enableDBDebug(); } public function testDeleteStringPrimaryKey(): void @@ -77,6 +79,8 @@ public function testDeleteWithSoftDeleteFail(): void $result = $this->model->where('name123', 'Derek Jones')->delete(); $this->assertFalse($result); $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); + + $this->enableDBDebug(); } public function testDeleteWithSoftDeletesPurge(): void diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 85bf753d1070..2db16beabc62 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -26,12 +26,6 @@ */ final class InsertModelTest extends LiveModelTestCase { - protected function tearDown(): void - { - parent::tearDown(); - $this->setPrivateProperty($this->db, 'DBDebug', true); - } - public function testSetWorksWithInsert(): void { $this->dontSeeInDatabase('user', [ @@ -162,6 +156,8 @@ public function testInsertResultFail(): void $lastInsertId = $this->model->getInsertID(); $this->assertSame(0, $lastInsertId); $this->dontSeeInDatabase('job', ['id' => $lastInsertId]); + + $this->enableDBDebug(); } public function testInsertBatchNewEntityWithDateTime(): void diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index c13212d5620e..984ae4df1bd7 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -67,6 +67,8 @@ public function testSaveNewRecordArrayFail(): void $result = $this->model->protect(false)->save($data); $this->assertFalse($result); $this->dontSeeInDatabase('job', ['name' => 'Apprentice']); + + $this->enableDBDebug(); } public function testSaveUpdateRecordArray(): void @@ -98,6 +100,8 @@ public function testSaveUpdateRecordArrayFail(): void $result = $this->model->protect(false)->save($data); $this->assertFalse($result); $this->dontSeeInDatabase('job', ['name' => 'Apprentice']); + + $this->enableDBDebug(); } public function testSaveUpdateRecordObject(): void diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index d8a054f247f5..29d7fb12e2ad 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -113,6 +113,8 @@ public function testUpdateResultFail(): void $result = $this->model->update(1, ['name123' => 'Foo Bar 1']); $this->assertFalse($result); $this->dontSeeInDatabase('user', ['id' => 1, 'name' => 'Foo Bar 1']); + + $this->enableDBDebug(); } public function testUpdateBatchSuccess(): void From d20d0213d241de8fb59c5c5b0a3f448b24a53a61 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 11:28:21 +0900 Subject: [PATCH 54/78] test: add empty lines or so To make more readable. --- tests/system/Database/Live/BadQueryTest.php | 4 ++++ tests/system/Database/Live/DbDebugTest.php | 5 +++++ tests/system/Database/Live/DbUtilsTest.php | 1 + tests/system/Models/DeleteModelTest.php | 6 ++++++ tests/system/Models/InsertModelTest.php | 4 +++- tests/system/Models/SaveModelTest.php | 4 ++-- tests/system/Models/UpdateModelTest.php | 5 +++-- 7 files changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/system/Database/Live/BadQueryTest.php b/tests/system/Database/Live/BadQueryTest.php index 195afe04751f..86189c8b9f87 100644 --- a/tests/system/Database/Live/BadQueryTest.php +++ b/tests/system/Database/Live/BadQueryTest.php @@ -31,8 +31,10 @@ final class BadQueryTest extends CIUnitTestCase public function testBadQueryDebugTrue() { $this->enableDBDebug(); + // expect an exception, class and message varies by DBMS $this->expectException(Exception::class); + $this->db->query('SELECT * FROM table_does_not_exist'); // this code is never executed @@ -42,8 +44,10 @@ public function testBadQueryDebugFalse() { // WARNING this value will persist! take care to roll it back. $this->disableDBDebug(); + // this throws an exception when DBDebug is true, but it'll return FALSE when DBDebug is false $query = $this->db->query('SELECT * FROM table_does_not_exist'); + $this->assertFalse($query); $this->enableDBDebug(); diff --git a/tests/system/Database/Live/DbDebugTest.php b/tests/system/Database/Live/DbDebugTest.php index d2a64b0ee62a..0322ce192961 100644 --- a/tests/system/Database/Live/DbDebugTest.php +++ b/tests/system/Database/Live/DbDebugTest.php @@ -28,7 +28,9 @@ final class DbDebugTest extends CIUnitTestCase public function testDBDebugTrue() { $this->enableDBDebug(); + $this->expectException('Exception'); + $this->db->simpleQuery('SELECT * FROM db_error'); } @@ -36,13 +38,16 @@ public function testDBDebugFalse() { // WARNING this value will persist! take care to roll it back. $this->disableDBDebug(); + $result = $this->db->simpleQuery('SELECT * FROM db_error'); + $this->assertFalse($result); } protected function tearDown(): void { $this->enableDBDebug(); + parent::tearDown(); } } diff --git a/tests/system/Database/Live/DbUtilsTest.php b/tests/system/Database/Live/DbUtilsTest.php index e95f0118cd5e..d4750044b64c 100644 --- a/tests/system/Database/Live/DbUtilsTest.php +++ b/tests/system/Database/Live/DbUtilsTest.php @@ -118,6 +118,7 @@ public function testUtilsOptimizeTableFalseOptimizeDatabaseDebugTrue() $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); + $util->optimizeDatabase(); // this point in code execution will never be reached diff --git a/tests/system/Models/DeleteModelTest.php b/tests/system/Models/DeleteModelTest.php index 56c548d0ba2f..0e47d8535a90 100644 --- a/tests/system/Models/DeleteModelTest.php +++ b/tests/system/Models/DeleteModelTest.php @@ -36,10 +36,13 @@ public function testDeleteFail(): void { // WARNING this value will persist! take care to roll it back. $this->disableDBDebug(); + $this->createModel(JobModel::class); + $this->seeInDatabase('job', ['name' => 'Developer']); $result = $this->model->where('name123', 'Developer')->delete(); + $this->assertFalse($result); $this->seeInDatabase('job', ['name' => 'Developer']); @@ -73,10 +76,13 @@ public function testDeleteWithSoftDeleteFail(): void { // WARNING this value will persist! take care to roll it back. $this->disableDBDebug(); + $this->createModel(UserModel::class); + $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); $result = $this->model->where('name123', 'Derek Jones')->delete(); + $this->assertFalse($result); $this->seeInDatabase('user', ['name' => 'Derek Jones', 'deleted_at IS NULL' => null]); diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 2db16beabc62..a648c73da5b3 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -148,12 +148,14 @@ public function testInsertResultFail(): void 'name123' => 'Apprentice', 'description' => 'That thing you do.', ]; - $this->createModel(JobModel::class); + $result = $this->model->protect(false)->insert($data, false); + $this->assertFalse($result); $lastInsertId = $this->model->getInsertID(); + $this->assertSame(0, $lastInsertId); $this->dontSeeInDatabase('job', ['id' => $lastInsertId]); diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index 984ae4df1bd7..0ff142375fde 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -63,8 +63,8 @@ public function testSaveNewRecordArrayFail(): void 'name123' => 'Apprentice', 'description' => 'That thing you do.', ]; - $result = $this->model->protect(false)->save($data); + $this->assertFalse($result); $this->dontSeeInDatabase('job', ['name' => 'Apprentice']); @@ -96,8 +96,8 @@ public function testSaveUpdateRecordArrayFail(): void 'name123' => 'Apprentice', 'description' => 'That thing you do.', ]; - $result = $this->model->protect(false)->save($data); + $this->assertFalse($result); $this->dontSeeInDatabase('job', ['name' => 'Apprentice']); diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 29d7fb12e2ad..6ebe8e9fd738 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -98,6 +98,7 @@ public function testUpdateResultFail(): void { // WARNING this value will persist! take care to roll it back. $this->disableDBDebug(); + $this->createModel(UserModel::class); $data = [ 'name' => 'Foo', @@ -105,12 +106,12 @@ public function testUpdateResultFail(): void 'country' => 'US', 'deleted' => 0, ]; - - $this->createModel(UserModel::class); $this->model->insert($data); $this->setPrivateProperty($this->model, 'allowedFields', ['name123']); + $result = $this->model->update(1, ['name123' => 'Foo Bar 1']); + $this->assertFalse($result); $this->dontSeeInDatabase('user', ['id' => 1, 'name' => 'Foo Bar 1']); From 3e373b5011811c709445122216d98bd926d75b69 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 12:42:35 +0900 Subject: [PATCH 55/78] test: fix missing email (not null column) --- tests/system/Models/UpdateModelTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 6ebe8e9fd738..1c7b4f6b1cf1 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -330,6 +330,7 @@ public function testUpdateWithEntityNoAllowedFields(): void $entity->id = 1; $entity->name = 'Jones Martin'; + $entity->email = 'jones@example.org'; $entity->country = 'India'; $entity->deleted = 0; From 623f7789c5e20a6e2582992e31202de94f9cd2c5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 21:30:28 +0900 Subject: [PATCH 56/78] fix: migrate --all causes `Class "SQLite3" not found` error --- system/Database/MigrationRunner.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index e92d31b02450..2c71189d140d 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -402,6 +402,10 @@ public function findMigrations(): array $migrations = []; foreach ($namespaces as $namespace) { + if (ENVIRONMENT !== 'testing' && $namespace === 'Tests\Support') { + continue; + } + foreach ($this->findNamespaceMigrations($namespace) as $migration) { $migrations[$migration->uid] = $migration; } From 8f0a2ad17935dee1907f16777a28d0bbc0579c00 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 08:46:24 +0900 Subject: [PATCH 57/78] docs: add note about $setUpMethods --- user_guide_src/source/testing/overview.rst | 20 ++++++++++++++++--- .../source/testing/overview/004.php | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 77dbf9f3da80..1836e3e46180 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -101,8 +101,9 @@ parent as well so extended test cases do not interfere with staging: .. literalinclude:: overview/003.php -In addition to these methods, ``CIUnitTestCase`` also comes with a convenience property for -parameter-free methods you want run during set up and tear down: +In addition to these methods, ``CIUnitTestCase`` also comes with a convenience property +``$setUpMethods`` and ``$tearDownMethods`` for +parameter-free methods you want to run during set up and tear down: .. literalinclude:: overview/004.php @@ -111,12 +112,25 @@ that or provide their own: .. literalinclude:: overview/005.php +.. note:: When you override ``$setUpMethods`` properties, do not remove the following items that are set in the parent class by default unless you know they are truly unnecessary. + + .. code-block:: php + + protected $setUpMethods = [ + 'resetFactories', + 'mockCache', + 'mockEmail', + 'mockSession', + ]; + Traits ------ A common way to enhance your tests is by using traits to consolidate staging across different test cases. ``CIUnitTestCase`` will detect any class traits and look for staging methods -to run named for the trait itself. For example, if you needed to add authentication to some +to run named for the trait itself. + +For example, if you needed to add authentication to some of your test cases you could create an authentication trait with a set up method to fake a logged in user: diff --git a/user_guide_src/source/testing/overview/004.php b/user_guide_src/source/testing/overview/004.php index 257da38142a4..4fcd53b52ffc 100644 --- a/user_guide_src/source/testing/overview/004.php +++ b/user_guide_src/source/testing/overview/004.php @@ -7,6 +7,8 @@ final class OneOfMyModelsTest extends CIUnitTestCase { protected $setUpMethods = [ + 'resetFactories', + 'mockCache', 'mockEmail', 'mockSession', ]; From fce156189c1fda469e1f183a35bbd959fd44da4c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 10:40:21 +0900 Subject: [PATCH 58/78] docs: remove $setUpMethods and $tearDownMethods It is not so convenient. --- user_guide_src/source/testing/overview.rst | 22 ------------------- .../source/testing/overview/004.php | 17 -------------- .../source/testing/overview/005.php | 17 -------------- 3 files changed, 56 deletions(-) delete mode 100644 user_guide_src/source/testing/overview/004.php delete mode 100644 user_guide_src/source/testing/overview/005.php diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 1836e3e46180..ba0e160d1013 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -101,28 +101,6 @@ parent as well so extended test cases do not interfere with staging: .. literalinclude:: overview/003.php -In addition to these methods, ``CIUnitTestCase`` also comes with a convenience property -``$setUpMethods`` and ``$tearDownMethods`` for -parameter-free methods you want to run during set up and tear down: - -.. literalinclude:: overview/004.php - -You can see by default these handle the mocking of intrusive services, but your class may override -that or provide their own: - -.. literalinclude:: overview/005.php - -.. note:: When you override ``$setUpMethods`` properties, do not remove the following items that are set in the parent class by default unless you know they are truly unnecessary. - - .. code-block:: php - - protected $setUpMethods = [ - 'resetFactories', - 'mockCache', - 'mockEmail', - 'mockSession', - ]; - Traits ------ diff --git a/user_guide_src/source/testing/overview/004.php b/user_guide_src/source/testing/overview/004.php deleted file mode 100644 index 4fcd53b52ffc..000000000000 --- a/user_guide_src/source/testing/overview/004.php +++ /dev/null @@ -1,17 +0,0 @@ -model->purgeDeleted(); - } -} From 91075b0fd5e5bc0f3d44504ca74abc7b4f4d0416 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 10:47:39 +0900 Subject: [PATCH 59/78] docs: improve explanation on setUp/tearDown --- user_guide_src/source/testing/overview.rst | 6 ++++-- user_guide_src/source/testing/overview/003.php | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index ba0e160d1013..98e74d55905d 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -95,8 +95,10 @@ to help with staging and clean up:: protected function setUp(): void protected function tearDown(): void -The static methods run before and after the entire test case, whereas the local methods run -between each test. If you implement any of these special functions make sure you run their +The static methods ``setUpBeforeClass()`` and ``tearDownAfterClass()`` run before and after the entire test case, whereas the protected methods ``setUp()`` and ``tearDown()`` run +between each test. + +If you implement any of these special functions make sure you run their parent as well so extended test cases do not interfere with staging: .. literalinclude:: overview/003.php diff --git a/user_guide_src/source/testing/overview/003.php b/user_guide_src/source/testing/overview/003.php index ac01a937d341..fe9f163246b1 100644 --- a/user_guide_src/source/testing/overview/003.php +++ b/user_guide_src/source/testing/overview/003.php @@ -8,8 +8,10 @@ final class OneOfMyModelsTest extends CIUnitTestCase { protected function setUp(): void { - parent::setUp(); + parent::setUp(); // Do not forget helper('text'); } + + // ... } From 609e41fc843a78515d2a9a28b0faa413c9d1c0a4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 10:59:52 +0900 Subject: [PATCH 60/78] docs: add Warning --- system/Test/CIUnitTestCase.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index ba3c81b028c7..b5a105c6886b 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -45,6 +45,9 @@ abstract class CIUnitTestCase extends TestCase /** * Methods to run during setUp. * + * WARNING: Do not override unless you know exactly what you are doing. + * This property may be deprecated in the future. + * * @var array of methods */ protected $setUpMethods = [ @@ -57,6 +60,8 @@ abstract class CIUnitTestCase extends TestCase /** * Methods to run during tearDown. * + * WARNING: This property may be deprecated in the future. + * * @var array of methods */ protected $tearDownMethods = []; From 63fa376f1135f5a4b2c085cabd736400ab2229ed Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 12:20:16 +0900 Subject: [PATCH 61/78] docs: fix syntax error in files.rst --- user_guide_src/source/libraries/files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index c6fe88a7d00c..0c394eb35cc9 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -140,7 +140,7 @@ Inputting Files *************** add(string[]|string $paths, bool $recursive = true) ---------------------------------------------------- +=================================================== Adds all files indicated by the path or array of paths. If the path resolves to a directory then ``$recursive`` will include sub-directories. From 7f7e7cfec43675269462f606408ad4639bb281e5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Jun 2022 18:25:05 +0900 Subject: [PATCH 62/78] fix: Time::setTestNow() does not work with fa Locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ErrorException : DateTime::modify(): Failed to parse time string (۲۰۱۷-۰۳-۱۰ ۰۰:۰۰:۰۰) at position 0 (�): Unexpected character .../CodeIgniter4/system/I18n/Time.php:96 --- system/I18n/Time.php | 2 +- tests/system/I18n/TimeTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 64b4d350e8fd..dd97815f66cf 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -82,7 +82,7 @@ public function __construct(?string $time = null, $timezone = null, ?string $loc // If a test instance has been provided, use it instead. if ($time === '' && static::$testNow instanceof self) { $timezone = $timezone ?: static::$testNow->getTimezone(); - $time = (string) static::$testNow->toDateTimeString(); + $time = static::$testNow->format('Y-m-d H:i:s'); } $timezone = $timezone ?: date_default_timezone_get(); diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 03f142479478..7571f66eca99 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -1058,4 +1058,18 @@ public function testUnserializeTimeObject() $this->assertTrue($time2->equals($time1)); $this->assertNotSame($time1, $time2); } + + public function testSetTestNowWithFaLocale() + { + $currentLocale = Locale::getDefault(); + Locale::setDefault('fa'); + + Time::setTestNow('2017/03/10 12:00', 'Asia/Tokyo'); + + $now = Time::now()->format('c'); + + $this->assertSame('2017-03-10T12:00:00+09:00', $now); + + Locale::setDefault($currentLocale); + } } From 15cd4ca05020b1aa25090ff4186aa6fa97ccc0a1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 14:38:56 +0900 Subject: [PATCH 63/78] fix: Time::humanize() causes error with ar locale Fixes #4708 --- system/I18n/Time.php | 4 ++-- tests/system/I18n/TimeTest.php | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/system/I18n/Time.php b/system/I18n/Time.php index dd97815f66cf..659a0a252db2 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -1005,7 +1005,7 @@ public function isAfter($testTime, ?string $timezone = null): bool */ public function humanize() { - $now = IntlCalendar::fromDateTime(self::now($this->timezone)->toDateTimeString()); + $now = IntlCalendar::fromDateTime(self::now($this->timezone)); $time = $this->getCalendar()->getTime(); $years = $now->fieldDifference($time, IntlCalendar::FIELD_YEAR); @@ -1106,7 +1106,7 @@ public function getUTCObject($time, ?string $timezone = null) */ public function getCalendar() { - return IntlCalendar::fromDateTime($this->toDateTimeString()); + return IntlCalendar::fromDateTime($this); } /** diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 7571f66eca99..2f2980f2411e 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -11,8 +11,10 @@ namespace CodeIgniter\I18n; +use CodeIgniter\Config\Factories; use CodeIgniter\I18n\Exceptions\I18nException; use CodeIgniter\Test\CIUnitTestCase; +use Config\App; use DateTime; use DateTimeZone; use IntlDateFormatter; @@ -1025,6 +1027,31 @@ public function testHumanizeNow() $this->assertSame('Just now', $time->humanize()); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4708 + */ + public function testHumanizeWithArLocale() + { + $this->resetServices(); + + $currentLocale = Locale::getDefault(); + Locale::setDefault('ar'); + + $config = new App(); + $config->supportedLocales = ['ar']; + $config->defaultLocale = 'ar'; + Factories::injectMock('config', 'App', $config); + + Time::setTestNow('2022-06-14 12:00', 'America/Chicago'); + + $date = '2022-06-07 12:00'; + $time = Time::parse($date, 'America/Chicago'); + + $this->assertSame('١ week ago', $time->humanize()); + + Locale::setDefault($currentLocale); + } + public function testSetTimezoneDate() { $time = Time::parse('13 May 2020 10:00', 'GMT'); From dfa4c3adba939b16e05b5890dd5bc5d97d2d33f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 16:07:14 +0900 Subject: [PATCH 64/78] docs: fix title level --- user_guide_src/source/libraries/time.rst | 49 ++++++++++++------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 6183b4c5f1a8..59fe9cbf1d4c 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -13,9 +13,9 @@ is the ``Time`` class and lives in the ``CodeIgniter\I18n`` namespace. :local: :depth: 2 -============= +************* Instantiating -============= +************* There are several ways that a new Time instance can be created. The first is simply to create a new instance like any other class. When you do it this way, you can pass in a string representing the desired time. This can @@ -31,7 +31,7 @@ provided, the application defaults will be used. .. literalinclude:: time/002.php now() ------ +===== The Time class has several helper methods to instantiate the class. The first of these is the ``now()`` method that returns a new instance set to the current time. You can pass in strings representing the timezone and the locale @@ -40,7 +40,7 @@ in the second and parameters, respectively. If no locale or timezone is provided .. literalinclude:: time/003.php parse() -------- +======= This helper method is a static version of the default constructor. It takes a string acceptable as DateTime's constructor as the first parameter, a timezone as the second parameter, and the locale as the third parameter: @@ -48,7 +48,7 @@ constructor as the first parameter, a timezone as the second parameter, and the .. literalinclude:: time/004.php today() -------- +======= Returns a new instance with the date set to the current date, and the time set to midnight. It accepts strings for the timezone and locale in the first and second parameters: @@ -56,7 +56,7 @@ for the timezone and locale in the first and second parameters: .. literalinclude:: time/005.php yesterday() ------------ +=========== Returns a new instance with the date set to the yesterday's date and the time set to midnight. It accepts strings for the timezone and locale in the first and second parameters: @@ -64,7 +64,7 @@ for the timezone and locale in the first and second parameters: .. literalinclude:: time/006.php tomorrow() ------------ +========== Returns a new instance with the date set to tomorrow's date and the time set to midnight. It accepts strings for the timezone and locale in the first and second parameters: @@ -72,7 +72,7 @@ for the timezone and locale in the first and second parameters: .. literalinclude:: time/007.php createFromDate() ----------------- +================ Given separate inputs for **year**, **month**, and **day**, will return a new instance. If any of these parameters are not provided, it will use the current value to fill it in. Accepts strings for the timezone and locale in the @@ -81,7 +81,7 @@ fourth and fifth parameters: .. literalinclude:: time/008.php createFromTime() ----------------- +================ Like ``createFromDate()`` except it is only concerned with the **hours**, **minutes**, and **seconds**. Uses the current day for the date portion of the Time instance. Accepts strings for the timezone and locale in the @@ -90,7 +90,7 @@ fourth and fifth parameters: .. literalinclude:: time/009.php create() --------- +======== A combination of the previous two methods, takes **year**, **month**, **day**, **hour**, **minutes**, and **seconds** as separate parameters. Any value not provided will use the current date and time to determine. Accepts strings for the @@ -99,7 +99,7 @@ timezone and locale in the fourth and fifth parameters: .. literalinclude:: time/010.php createFromFormat() ------------------- +================== This is a replacement for DateTime's method of the same name. This allows the timezone to be set at the same time, and returns a ``Time`` instance, instead of DateTime: @@ -107,14 +107,14 @@ and returns a ``Time`` instance, instead of DateTime: .. literalinclude:: time/011.php createFromTimestamp() ---------------------- +===================== This method takes a UNIX timestamp and, optionally, the timezone and locale, to create a new Time instance: .. literalinclude:: time/012.php createFromInstance() --------------------- +==================== When working with other libraries that provide a DateTime instance, you can use this method to convert that to a Time instance, optionally setting the locale. The timezone will be automatically determined from the DateTime @@ -123,7 +123,7 @@ instance passed in: .. literalinclude:: time/013.php toDateTime() ------------- +============ While not an instantiator, this method is the opposite of the **instance** method, allowing you to convert a Time instance into a DateTime instance. This preserves the timezone setting, but loses the locale, since DateTime is @@ -131,16 +131,17 @@ not aware of locales: .. literalinclude:: time/014.php -==================== + +******************** Displaying the Value -==================== +******************** Since the Time class extends DateTime, you get all of the output methods that provides, including the format() method. However, the DateTime methods do not provide a localized result. The Time class does provide a number of helper methods to display localized versions of the value, though. toLocalizedString() -------------------- +=================== This is the localized version of DateTime's ``format()`` method. Instead of using the values you might be familiar with, though, you must use values acceptable to the `IntlDateFormatter `__ class. @@ -149,7 +150,7 @@ A full listing of values can be found `here year``, and so on. Getters -------- +======= The following basic getters exist: From cdf297778480ad611d9eeb291fe1869a25b25442 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 16:07:37 +0900 Subject: [PATCH 65/78] docs: add links, explanations --- user_guide_src/source/libraries/time.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 59fe9cbf1d4c..8259f3a6607a 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -7,7 +7,7 @@ extension's features to convert times across timezones and display the output co is the ``Time`` class and lives in the ``CodeIgniter\I18n`` namespace. .. note:: Since the Time class extends DateTime, if there are features that you need that this class doesn't provide, - you can likely find them within the DateTime class itself. + you can likely find them within the `DateTime `_ class itself. .. contents:: :local: @@ -136,7 +136,7 @@ not aware of locales: Displaying the Value ******************** -Since the Time class extends DateTime, you get all of the output methods that provides, including the format() method. +Since the Time class extends DateTime, you get all of the output methods that provides, including the ``format()`` method. However, the DateTime methods do not provide a localized result. The Time class does provide a number of helper methods to display localized versions of the value, though. @@ -152,22 +152,22 @@ A full listing of values can be found `here `_ without having to remember their values. +This will return a localized version of string formatted as you would commonly use for datetime columns in a database (Y-m-d H:i:s): .. literalinclude:: time/016.php toDateString() ============== -Displays just the date portion of the Time: +Displays just the localized version of date portion of the Time: .. literalinclude:: time/017.php toTimeString() ============== -Displays just the time portion of the value: +Displays just the localized version of time portion of the value: .. literalinclude:: time/018.php From 731cf02f7e5dc62295309ff8ee9962cf6c5cfa21 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 16:28:25 +0900 Subject: [PATCH 66/78] docs: remove "you would commonly use for datetime columns in a database" --- 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 8259f3a6607a..89062bf7abf9 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -153,7 +153,7 @@ toDateTimeString() ================== This is the first of three helper methods to work with the `IntlDateFormatter `_ without having to remember their values. -This will return a localized version of string formatted as you would commonly use for datetime columns in a database (Y-m-d H:i:s): +This will return a localized version of string formatted as (Y-m-d H:i:s): .. literalinclude:: time/016.php From 5701bb809a32702c84d3f21944a279c20e5060b0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 16:29:10 +0900 Subject: [PATCH 67/78] docs: add output in locale fa --- user_guide_src/source/libraries/time/015.php | 5 +++++ user_guide_src/source/libraries/time/016.php | 5 +++++ user_guide_src/source/libraries/time/017.php | 5 +++++ user_guide_src/source/libraries/time/018.php | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/user_guide_src/source/libraries/time/015.php b/user_guide_src/source/libraries/time/015.php index 959309b33c92..0545c0247cc3 100644 --- a/user_guide_src/source/libraries/time/015.php +++ b/user_guide_src/source/libraries/time/015.php @@ -1,4 +1,9 @@ toLocalizedString('MMM d, yyyy'); // March 9, 2016 + +// Locale: fa +$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); +echo $time->toLocalizedString('MMM d, yyyy'); // مارس ۹, ۲۰۱۶ diff --git a/user_guide_src/source/libraries/time/016.php b/user_guide_src/source/libraries/time/016.php index 32fa8a8fe83f..0645fd9b49ce 100644 --- a/user_guide_src/source/libraries/time/016.php +++ b/user_guide_src/source/libraries/time/016.php @@ -1,4 +1,9 @@ toDateTimeString(); // 2016-03-09 12:00:00 + +// Locale: fa +$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); +echo $time->toDateTimeString(); // ۲۰۱۶-۰۳-۰۹ ۱۲:۰۰:۰۰ diff --git a/user_guide_src/source/libraries/time/017.php b/user_guide_src/source/libraries/time/017.php index 5ff0734c8add..c0283d9d2e90 100644 --- a/user_guide_src/source/libraries/time/017.php +++ b/user_guide_src/source/libraries/time/017.php @@ -1,4 +1,9 @@ toDateString(); // 2016-03-09 + +// Locale: fa +$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); +echo $time->toDateString(); // ۲۰۱۶-۰۳-۰۹ diff --git a/user_guide_src/source/libraries/time/018.php b/user_guide_src/source/libraries/time/018.php index 4d0fcaf8c216..d3001a7749f4 100644 --- a/user_guide_src/source/libraries/time/018.php +++ b/user_guide_src/source/libraries/time/018.php @@ -1,4 +1,9 @@ toTimeString(); // 12:00:00 + +// Locale: fa +$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); +echo $time->toTimeString(); // ۱۲:۰۰:۰۰ From 17fd4ea45394b23a77c11b5d674f828b7c2fa078 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Jun 2022 20:11:21 +0900 Subject: [PATCH 68/78] docs: add method name examples Co-authored-by: MGatner --- user_guide_src/source/testing/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 98e74d55905d..af7fc550bea7 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -108,7 +108,7 @@ Traits A common way to enhance your tests is by using traits to consolidate staging across different test cases. ``CIUnitTestCase`` will detect any class traits and look for staging methods -to run named for the trait itself. +to run named for the trait itself (i.e. `setUp{NameOfTrait}()` and `tearDown{NameOfTrait}()`). For example, if you needed to add authentication to some of your test cases you could create an authentication trait with a set up method to fake a From a19128b64fb08ab8f77cdf8f1e36c515f56f1625 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 11:51:58 +0900 Subject: [PATCH 69/78] fix: trigger DBQuery is not fired when query error and DBDebug is true --- phpstan-baseline.neon.dist | 2 +- system/Database/BaseConnection.php | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 17f71d164f29..b855e1f7664c 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -137,7 +137,7 @@ parameters: - message: "#^Negated boolean expression is always true\\.$#" - count: 1 + count: 2 path: system/Database/BaseConnection.php - diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 9d7e69bf5256..0e103a515f00 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -14,6 +14,7 @@ use Closure; use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Events\Events; +use Exception; use stdClass; use Throwable; @@ -603,7 +604,14 @@ public function query(string $sql, $binds = null, bool $setEscapeFlags = true, s $this->lastQuery = $query; // Run the query for real - if (! $this->pretend && false === ($this->resultID = $this->simpleQuery($query->getQuery()))) { + try { + $exception = null; + $this->resultID = $this->simpleQuery($query->getQuery()); + } catch (Exception $exception) { + $this->resultID = false; + } + + if (! $this->pretend && $this->resultID === false) { $query->setDuration($startTime, $startTime); // This will trigger a rollback if transactions are being used @@ -626,6 +634,15 @@ public function query(string $sql, $binds = null, bool $setEscapeFlags = true, s } } + if (! $this->pretend) { + // Let others do something with this query. + Events::trigger('DBQuery', $query); + } + + if ($exception !== null) { + throw $exception; + } + return false; } From 0d8f818cbfea4d289937924a29c2930d36198a80 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 12:07:25 +0900 Subject: [PATCH 70/78] docs: fix DBQuery explanation --- user_guide_src/source/extending/events.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/extending/events.rst b/user_guide_src/source/extending/events.rst index aa4f99e797c8..bdc43bfbc0bd 100644 --- a/user_guide_src/source/extending/events.rst +++ b/user_guide_src/source/extending/events.rst @@ -91,5 +91,5 @@ The following is a list of available event points within the CodeIgniter core co * **post_controller_constructor** Called immediately after your controller is instantiated, but prior to any method calls happening. * **post_system** Called after the final rendered page is sent to the browser, at the end of system execution after the finalized data is sent to the browser. * **email** Called after an email sent successfully from ``CodeIgniter\Email\Email``. Receives an array of the ``Email`` class's properties as a parameter. -* **DBQuery** Called after a successfully-completed database query. Receives the ``Query`` object. +* **DBQuery** Called after a database query whether successful or not. Receives the ``Query`` object. * **migrate** Called after a successful migration call to ``latest()`` or ``regress()``. Receives the current properties of ``MigrationRunner`` as well as the name of the method. From 1fda6d459f32d6addf202e8e24575b87fe21b7ce Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 12:59:04 +0900 Subject: [PATCH 71/78] docs: fix title underline --- user_guide_src/source/database/events.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/database/events.rst b/user_guide_src/source/database/events.rst index 628f2316ef8b..08fe73b09081 100644 --- a/user_guide_src/source/database/events.rst +++ b/user_guide_src/source/database/events.rst @@ -11,11 +11,12 @@ uses this to collect the queries to display in the Toolbar. :local: :depth: 2 -========== +********** The Events -========== +********** -**DBQuery** +DBQuery +======= This event is triggered whenever a new query has been run, whether successful or not. The only parameter is a :doc:`Query ` instance of the current query. You could use this to display all queries From 05c6b49523bae0f64779befa214333983dad6421 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 12:59:37 +0900 Subject: [PATCH 72/78] docs: fix config file path --- user_guide_src/source/database/events/001.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/events/001.php b/user_guide_src/source/database/events/001.php index 2065ef3d426b..4461b715af19 100644 --- a/user_guide_src/source/database/events/001.php +++ b/user_guide_src/source/database/events/001.php @@ -1,4 +1,4 @@ Date: Thu, 16 Jun 2022 08:39:47 +0900 Subject: [PATCH 73/78] docs: update about mainly Changelog --- contributing/pull_request.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index eaa0c0f24c5a..b8fe38a9fe8e 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -98,24 +98,31 @@ show up in more than one place. If you change anything that requires a change to documentation, then you will need to add to the documentation. -New classes, methods, parameters, changing default values, etc. +New classes, methods, parameters, changing default values, changing behavior etc. are all changes that require a change to documentation. -Also, the [changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html) must be updated for every change, + +Also, the [Changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html) must be updated for every change, and [PHPDoc](https://github.com/codeigniter4/CodeIgniter4/blob/develop/phpdoc.dist.xml) blocks must be maintained. See [Writing CodeIgniter Documentation](./documentation.rst). -### Changelog +#### Changelog + +The [Changelog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html), in the user guide, needs to be kept up-to-date. Not +all changes will need an entry in it, but the following items should. + +- all breaking changes (BCs) +- all enhancements (new features, new classes, new APIs) +- other behavior changes +- deprecations +- major bug fixes + +#### Upgrading Guide -The changelog, in the user guide root, needs to be kept up-to-date. Not -all changes will need an entry in it, but new classes, major or BC -changes to existing classes should. Once we have a stable release, bug -fixes would appear in the changelog too. +If your PR requires users to do something when they upgrade CodeIgniter, the +[Upgrading Guide](https://codeigniter4.github.io/CodeIgniter4/installation/upgrading.html) is also needed. -The changelog is independently maintained by the framework release -manager Make sure that your PR descriptions help us decide if the -contribution should be highlighted in the next release after it has been -merged. +Add an instruction what to do. ### CSS @@ -138,7 +145,7 @@ break with earlier versions of the framework. #### Breaking Changes -In general, any change that would disrupt existing uses of the framework is considered a "breaking change" and will not be favorably considered. A few specific examples to pay attention to: +In general, any change that would disrupt existing uses of the framework is considered a "Breaking Change" (BC) and will not be favorably considered. A few specific examples to pay attention to: 1. New classes/properties/constants in `system` are acceptable, but anything in the `app` directory that will be used in `system` should be backwards-compatible. 2. Any changes to non-private methods must be backwards-compatible with the original definition. From 1f837bbcec8d67353c0cca0f115705b62d2515b8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Jun 2022 08:55:34 +0900 Subject: [PATCH 74/78] docs: fix PHPDoc --- system/CodeIgniter.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 82b08e318879..5a0072a223fc 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -256,9 +256,7 @@ protected function initializeKint() require_once SYSTEMPATH . 'ThirdParty/Kint/init.php'; } - /** - * Config\Kint - */ + /** @var \Config\Kint $config */ $config = config(KintConfig::class); Kint::$depth_limit = $config->maxDepth; From ed22aa5ce674dbf74b5c49fb4eee6f3559d6b026 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Jun 2022 11:53:03 +0900 Subject: [PATCH 75/78] Revert "Merge pull request #5653 from kenjis/refactor-CLI-Incomming-Request" This reverts commit 93b8bca5d68652fca97de495cfb9a376345adcad, reversing changes made to 048d9973029803471f73d489bb418729587e1244. --- system/HTTP/CLIRequest.php | 2 +- system/HTTP/IncomingRequest.php | 2 +- tests/system/HTTP/IncomingRequestTest.php | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index 5f2c70b19ff7..0563be287cd4 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -212,6 +212,6 @@ protected function parseCommand() */ public function isCLI(): bool { - return true; + return is_cli(); } } diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 8bd5f33efbe2..d37f498e2d44 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -347,7 +347,7 @@ public function negotiate(string $type, array $supported, bool $strictMatch = fa */ public function isCLI(): bool { - return false; + return is_cli(); } /** diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index f19f9cf53ee4..603f493df932 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -438,7 +438,8 @@ public function testCanGrabGetRawInput() public function testIsCLI() { - $this->assertFalse($this->request->isCLI()); + // this should be the case in unit testing + $this->assertTrue($this->request->isCLI()); } public function testIsAJAX() From a25b93a5a00ad41261cf8cc731e5a2ab5926db55 Mon Sep 17 00:00:00 2001 From: Mattias Sandstrom <1013635+tangix@users.noreply.github.com> Date: Thu, 16 Jun 2022 11:15:38 +0200 Subject: [PATCH 76/78] Updated to use ::class in $returnType example --- user_guide_src/source/models/model.rst | 3 ++- user_guide_src/source/models/model/021.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 18eb6630a7ec..77bf4a674999 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -116,7 +116,8 @@ The Model's CRUD methods will take a step of work away from you and automaticall the resulting data, instead of the Result object. This setting allows you to define the type of data that is returned. Valid values are '**array**' (the default), '**object**', or the **fully qualified name of a class** that can be used with the Result object's ``getCustomResultObject()`` -method. +method. Using the ``::class`` suffix of the class will allow most IDEs to +auto-complete the name and allow functions like refactoring to better understand your code. $useSoftDeletes --------------- diff --git a/user_guide_src/source/models/model/021.php b/user_guide_src/source/models/model/021.php index f0367b5044e2..155938ea61be 100644 --- a/user_guide_src/source/models/model/021.php +++ b/user_guide_src/source/models/model/021.php @@ -7,7 +7,7 @@ class JobModel extends Model { protected $table = 'jobs'; - protected $returnType = '\App\Entities\Job'; + protected $returnType = \App\Entities\Job::class; protected $allowedFields = [ 'name', 'description', ]; From 6be86cffd3eb977bcf13d5661d139a2d90d6d038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Sandstr=C3=B6m?= <1013635+tangix@users.noreply.github.com> Date: Thu, 16 Jun 2022 11:54:51 +0200 Subject: [PATCH 77/78] Update user_guide_src/source/models/model.rst Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/models/model.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 77bf4a674999..f671fc10a709 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -116,7 +116,7 @@ The Model's CRUD methods will take a step of work away from you and automaticall the resulting data, instead of the Result object. This setting allows you to define the type of data that is returned. Valid values are '**array**' (the default), '**object**', or the **fully qualified name of a class** that can be used with the Result object's ``getCustomResultObject()`` -method. Using the ``::class`` suffix of the class will allow most IDEs to +method. Using the special ``::class`` constant of the class will allow most IDEs to auto-complete the name and allow functions like refactoring to better understand your code. $useSoftDeletes From de8d05714bcd807e0d180b38788d0a4baf2d6cc2 Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 16 Jun 2022 13:12:19 +0000 Subject: [PATCH 78/78] Prep for 4.2.1 release --- CHANGELOG.md | 28 +++++++++++++++++++++ system/CodeIgniter.php | 2 +- user_guide_src/source/changelogs/v4.2.1.rst | 2 +- user_guide_src/source/conf.py | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03e7223b90cd..3b2306247740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [v4.2.1](https://github.com/codeigniter4/CodeIgniter4/tree/v4.2.1) (2022-06-16) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.2.0...v4.2.1) + +### Breaking Changes +* Fix MIME guessing of extension from type by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6059 +* fix: get_cookie() may not use the cookie prefix by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6082 + +### Fixed Bugs +* fix: get_cookie() does not take Config\Cookie::$prefix by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6080 +* fix: session cookie name bug by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6091 +* fix: Session Handlers do not take Config\Cookie by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6081 +* fix: reverse routing does not work with full classname starting with `\` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6104 +* fix: insert error message in QueryBuilder by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6108 +* fix: `spark routes` shows "ERROR: 404" by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6098 +* fix: Time::setTestNow() does not work with fa Locale by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6116 +* fix: `migrate --all` causes `Class "SQLite3" not found` error by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6117 +* fix: event DBQuery is not fired on failed query when DBDebug is true by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6127 +* fix: `Time::humanize()` causes error with ar locale by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6120 +* Fix decorators by @lonnieezell in https://github.com/codeigniter4/CodeIgniter4/pull/6090 +* Fix lost error message by test when after testInsertResultFail. by @ytetsuro in https://github.com/codeigniter4/CodeIgniter4/pull/6113 +* test: fix forgetting to restore DBDebug value by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6115 + +### Refactoring +* Apply AutoRouterImproved::translateURIDashes() by @pjsde in https://github.com/codeigniter4/CodeIgniter4/pull/6084 +* Remove useless catch by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/6095 +* Move preload.php example to starter app by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/6088 +* style: compile sass by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6099 + ## [v4.2.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.2.0) (2022-06-03) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.9...v4.2.0) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 5a0072a223fc..a4a05233a071 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -47,7 +47,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.2.0'; + public const CI_VERSION = '4.2.1'; private const MIN_PHP_VERSION = '7.4'; diff --git a/user_guide_src/source/changelogs/v4.2.1.rst b/user_guide_src/source/changelogs/v4.2.1.rst index fddd5ca08f7d..486197688894 100644 --- a/user_guide_src/source/changelogs/v4.2.1.rst +++ b/user_guide_src/source/changelogs/v4.2.1.rst @@ -1,7 +1,7 @@ Version 4.2.1 ############# -Release Date: Unreleased +Release Date: June 16, 2022 **4.2.1 release of CodeIgniter4** diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index 3cc7e4d615de..79d03fee730f 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -24,7 +24,7 @@ version = '4.2' # The full version, including alpha/beta/rc tags. -release = '4.2.0' +release = '4.2.1' # -- General configuration ---------------------------------------------------